EDA Playground'da Dene

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] data gibi).
  • Metodlar (methods): Sınıfın davranışını tanımlayan function ve task'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ğeri null olur (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ı

  • Packet sınıfı: id, data ve name özelliklerinden oluşur. Bu üç değişken her Packet nesnesinin kendine ait verisidir.
  • new() constructor'ı: Varsayılan değerli argümanlar (id = 0, data = 0, name = "default") alır. this.id = id ifadesi, nesnenin id özelliğine parametre olarak gelen id değerini atar; this ile özellik ve parametre ayrıştırılır.
  • display() metodu: Nesnenin güncel değerlerini ekrana yazdırır. void dö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. Her new() çağrısı bellekte ayrı bir nesne üretir.
  • Özellik erişimi: pkt1.id = 99 gibi nokta operatörü (.) ile nesnenin özelliklerine doğrudan erişilip değer atanabilir.
  • Handle davranışı: pkt_ref = pkt2 satırı pkt2'nin işaret ettiği nesneyi kopyalamaz; pkt_ref ile pkt2 aynı nesneyi gösterir. Bu yüzden pkt_ref.data = 8'h00 yapıldığında pkt2.data da 0x00 olur.
  • null kontrolü: pkt_null tanımlanır ama new() çağrılmadığı için null'dır. if (pkt_null == null) ile bu durum kontrol edilir; ardından new(10, 8'hBB, "yeni") ile gerçek bir nesneye bağlanır.
  • Nesne dizisi: Packet pkt_arr [5] beş adet handle tutar. foreach döngüsünde her eleman için ayrı ayrı new() çağrılır; aksi halde dizinin tüm elemanları null kalı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 handle null kalır.
  • null bir handle üzerinden özelliğe veya metoda erişmek (örneğin pkt_null.display() nesne yokken) çalışma zamanı hatasına yol açar. Erişimden önce gerekirse == null kontrolü yapın.
  • Handle ataması (pkt_ref = pkt2) kopya değildir; gerçek bir kopya gerekiyorsa özel bir copy() metodu yazılmalıdır.
  • Nesne dizilerinde dizinin kendisini bildirmek elemanları oluşturmaz; her elemana ayrı new() gerekir.
  • this anahtar kelimesi, parametre adı ile özellik adı çakıştığında özelliği işaret etmek için kullanılır ve kodu okunaklı kılar.