Sınıflar ve Nesneler
Gün 2: Nesne Yönelimli Programlama (OOP) | OOP temelleri: sınıf tanımlama, nesne oluşturma, handle kavramı
Bu derste SystemVerilog'da nesne yönelimli programlamanın temel taşı olan sınıfları (class) ve nesneleri (object) öğreneceğiz. Bir sınıfın nasıl tanımlandığını, nesnelerin new() ile nasıl oluşturulduğunu ve handle (referans) kavramının değişken kopyalamasından neden farklı olduğunu inceleyeceğiz.
Sınıf ve Nesne Nedir?
Sınıf (class), birbirine ait verileri (özellikleri) ve bu veriler üzerinde çalışan metodları tek bir şablon altında toplayan bir yapıdır. Sınıf yalnızca bir tasarımdır; bellekte yer kaplamaz. Nesne (object) ise bu şablondan new() ile üretilen, bellekte gerçekten var olan somut bir örnektir.
Donanım doğrulamada sınıflar; transaction, paket, sürücü (driver), monitör gibi test bileşenlerini modellemek için kullanılır. Sınıflar dinamik olduğundan yalnızca simülasyon ortamında (testbench) yaşarlar, sentezlenmezler.
- Özellikler (properties): Sınıfın verilerini tutan değişkenlerdir (
int id,bit [7:0] datagibi). - Metodlar (methods): Sınıfın davranışını tanımlayan
functionvetask'lardır. - Constructor (
new): Nesne oluşturulurken çalışan, özellikleri başlatan özel metoddur.
Handle (Referans) Kavramı
SystemVerilog'da bir sınıf değişkeni, nesnenin kendisini değil, nesneye işaret eden bir handle (referans/işaretçi) tutar. Bu, C/C++'daki pointer mantığına benzer ve OOP'yi anlamanın en kritik noktasıdır:
- Bir sınıf değişkeni tanımlandığında ama
new()çağrılmadığında, değerinullolur (henüz bir nesneyi işaret etmez). - İki handle aynı nesneye işaret edebilir. Bir handle'ı diğerine atamak nesneyi kopyalamaz, sadece aynı nesneye ikinci bir referans oluşturur.
- Bu nedenle bir handle üzerinden yapılan değişiklik, aynı nesneyi işaret eden tüm handle'lardan görülür.
Kaynak Kod
// =============================================================================
// GUN 2 - Konu 1: OOP Temelleri - Siniflar (Classes) ve Nesneler (Objects)
// =============================================================================
class Packet;
// Ozellikler (Properties)
int id;
bit [7:0] data;
string name;
// Constructor (Kurucu Metod)
function new(int id = 0, bit [7:0] data = 0, string name = "default");
this.id = id;
this.data = data;
this.name = name;
endfunction
// Metod: Paketi yazdir
function void display();
$display(" Packet: id=%0d, data=0x%02h, name=%s", id, data, name);
endfunction
endclass
module siniflar_ve_nesneler;
initial begin
Packet pkt1, pkt2, pkt3;
$display("=== Siniflar ve Nesneler ===\n");
// --- Nesne Olusturma (Instantiation) ---
$display("--- Nesne Olusturma ---");
pkt1 = new(); // Varsayilan degerlerle
pkt2 = new(1, 8'hAB, "veri_paketi"); // Parametreli
pkt3 = new(2, 8'hFF, "kontrol"); // Parametreli
pkt1.display();
pkt2.display();
pkt3.display();
// --- Nesne Ozelliklerine Erisim ---
$display("\n--- Ozellik Erisimi ---");
pkt1.id = 99;
pkt1.data = 8'hDE;
pkt1.name = "guncellenmis";
$display(" Guncellenen pkt1:");
pkt1.display();
// --- Handle (Referans) Davranisi ---
$display("\n--- Handle (Referans) ---");
begin
Packet pkt_ref;
pkt_ref = pkt2; // Kopyalama degil, ayni nesneye referans
pkt_ref.data = 8'h00;
$display(" pkt_ref.data = 0x%02h (degistirildi)", pkt_ref.data);
$display(" pkt2.data = 0x%02h (ayni nesne!)", pkt2.data);
end
// --- null Kontrolu ---
$display("\n--- null Kontrolu ---");
begin
Packet pkt_null; // Baslatilmamis -> null
if (pkt_null == null)
$display(" pkt_null henuz olusturulmadi (null)");
pkt_null = new(10, 8'hBB, "yeni");
if (pkt_null != null)
$display(" pkt_null artik mevcut:");
pkt_null.display();
end
// --- Nesne Dizisi ---
$display("\n--- Nesne Dizisi ---");
begin
Packet pkt_arr [5];
foreach (pkt_arr[i]) begin
pkt_arr[i] = new(i, i * 16, $sformatf("pkt_%0d", i));
end
foreach (pkt_arr[i])
pkt_arr[i].display();
end
$display("\n=== Siniflar ve Nesneler Sonu ===");
$finish;
end
endmodule
Kodun Açıklaması
Packetsınıfı:id,datavenameözelliklerinden oluşur. Bu üç değişken herPacketnesnesinin kendine ait verisidir.new()constructor'ı: Varsayılan değerli argümanlar (id = 0,data = 0,name = "default") alır.this.id = idifadesi, nesneninidözelliğine parametre olarak geleniddeğerini atar;thisile özellik ve parametre ayrıştırılır.display()metodu: Nesnenin güncel değerlerini ekrana yazdırır.voiddöndürdüğü için bir değer üretmez.- Nesne oluşturma:
pkt1 = new()varsayılan değerlerle,pkt2 = new(1, 8'hAB, "veri_paketi")ise parametreli olarak nesne yaratır. Hernew()çağrısı bellekte ayrı bir nesne üretir. - Özellik erişimi:
pkt1.id = 99gibi nokta operatörü (.) ile nesnenin özelliklerine doğrudan erişilip değer atanabilir. - Handle davranışı:
pkt_ref = pkt2satırıpkt2'nin işaret ettiği nesneyi kopyalamaz;pkt_refilepkt2aynı nesneyi gösterir. Bu yüzdenpkt_ref.data = 8'h00yapıldığındapkt2.datada0x00olur. nullkontrolü:pkt_nulltanımlanır amanew()çağrılmadığı içinnull'dır.if (pkt_null == null)ile bu durum kontrol edilir; ardındannew(10, 8'hBB, "yeni")ile gerçek bir nesneye bağlanır.- Nesne dizisi:
Packet pkt_arr [5]beş adet handle tutar.foreachdöngüsünde her eleman için ayrı ayrınew()çağrılır; aksi halde dizinin tüm elemanlarınullkalırdı.
Önemli Noktalar
- Bir sınıf değişkeni tanımlamak nesne oluşturmaz. Nesneyi bellekte var etmek için mutlaka
new()çağrılmalıdır; aksi halde handlenullkalır. nullbir handle üzerinden özelliğe veya metoda erişmek (örneğinpkt_null.display()nesne yokken) çalışma zamanı hatasına yol açar. Erişimden önce gerekirse== nullkontrolü yapın.- Handle ataması (
pkt_ref = pkt2) kopya değildir; gerçek bir kopya gerekiyorsa özel bircopy()metodu yazılmalıdır. - Nesne dizilerinde dizinin kendisini bildirmek elemanları oluşturmaz; her elemana ayrı
new()gerekir. thisanahtar kelimesi, parametre adı ile özellik adı çakıştığında özelliği işaret etmek için kullanılır ve kodu okunaklı kılar.