EDA Playground'da Dene

Metodlar ve Constructor

Gün 2: Nesne Yönelimli Programlama (OOP) | Sınıf metodları (task/function), new() constructor, copy, compare

Bu derste bir sınıfın davranışını tanımlayan metodları öğreneceğiz: anında sonuç döndüren function'lar, simülasyon zamanı tüketebilen task'lar, nesneyi başlatan new() constructor'ı ve doğrulamada çok kullanılan copy() ile compare() yardımcı metodları.

Function ve Task Farkı

SystemVerilog'da iki tür metod vardır ve aralarındaki en temel fark zaman ile ilgilidir:

  • function: Simülasyon zamanı tüketemez (içinde #, @, wait gibi gecikme yapıları bulunamaz). Anında çalışır ve genellikle bir değer döndürür. Hesaplama, dönüştürme, karşılaştırma gibi işler için idealdir.
  • task: Simülasyon zamanı tüketebilir (gecikme ve olay bekleme içerebilir). Zaman içinde gerçekleşen davranışları (örneğin bir protokol adımını) modellemek için kullanılır.

Constructor (new) ve Yardımcı Metodlar

Her sınıfın bir constructor'ı (new) vardır; nesne oluşturulurken çağrılır ve özelliklere başlangıç değerleri atar. Varsayılan argümanlar sayesinde aynı constructor hem parametresiz hem parametreli çağrılabilir.

Doğrulama ortamlarında iki yardımcı metod kalıbı çok yaygındır:

  • copy(): Mevcut nesnenin özelliklerini yeni bir nesneye aktararak bağımsız bir kopya üretir.
  • compare(): İki nesnenin alanlarını karşılaştırıp eşit olup olmadıklarını döndürür; beklenen ve gözlemlenen veriyi kıyaslamak için kullanılır.

Kaynak Kod

// =============================================================================
// GUN 2 - Konu 2: Sinif Metodlari (Tasks ve Functions), new() Constructor
// =============================================================================

class ALU_Transaction;
  typedef enum {ADD, SUB, MUL, DIV, AND, OR, XOR} op_e;

  logic [15:0] operand_a;
  logic [15:0] operand_b;
  op_e         operation;
  logic [31:0] result;
  bit          done;

  // Constructor: Varsayilan ve parametreli
  function new(logic [15:0] a = 0, logic [15:0] b = 0, op_e op = ADD);
    this.operand_a = a;
    this.operand_b = b;
    this.operation = op;
    this.result    = 0;
    this.done      = 0;
  endfunction

  // Function: Aninda sonuc doner (zaman tuketmez)
  function logic [31:0] calculate();
    case (operation)
      ADD: result = operand_a + operand_b;
      SUB: result = operand_a - operand_b;
      MUL: result = operand_a * operand_b;
      DIV: result = (operand_b != 0) ? operand_a / operand_b : 'hFFFF_FFFF;
      AND: result = operand_a & operand_b;
      OR:  result = operand_a | operand_b;
      XOR: result = operand_a ^ operand_b;
    endcase
    done = 1;
    return result;
  endfunction

  // Task: Zaman tuketebilir (simulasyon zamani ilerleyebilir)
  task execute(input int delay_ns);
    #delay_ns;
    void'(calculate());
    $display("  [%0t] Islem tamamlandi: %s", $time, to_string());
  endtask

  // Function: String formatinda dondur
  function string to_string();
    return $sformatf("0x%04h %s 0x%04h = 0x%08h",
                     operand_a, operation.name(), operand_b, result);
  endfunction

  // Function: Paketi kopyala
  function ALU_Transaction copy();
    ALU_Transaction c = new();
    c.operand_a = this.operand_a;
    c.operand_b = this.operand_b;
    c.operation = this.operation;
    c.result    = this.result;
    c.done      = this.done;
    return c;
  endfunction

  // Function: Iki islemi karsilastir
  function bit compare(ALU_Transaction other);
    return (this.operand_a == other.operand_a &&
            this.operand_b == other.operand_b &&
            this.operation == other.operation);
  endfunction

  // Function: Yazdir
  function void display(string prefix = "");
    $display("  %s%s [done=%0b]", prefix, to_string(), done);
  endfunction

endclass

module metodlar_ve_constructor;
  initial begin
    ALU_Transaction txn1, txn2, txn3;

    $display("=== Sinif Metodlari ve Constructor ===\n");

    // --- Constructor kullanimi ---
    $display("--- Constructor ---");
    txn1 = new();                            // Varsayilan
    txn2 = new(16'h000A, 16'h0005, ALU_Transaction::SUB); // Parametreli
    txn3 = new(16'h00FF, 16'h0003, ALU_Transaction::MUL);
    
    txn1.display("Varsayilan: ");
    txn2.display("Parametreli: ");

    // --- Function kullanimi ---
    $display("\n--- Function: calculate() ---");
    void'(txn2.calculate());
    txn2.display("Hesaplandi: ");
    void'(txn3.calculate());
    txn3.display("Hesaplandi: ");

    // --- Task kullanimi (zaman tuketir) ---
    $display("\n--- Task: execute() ---");
    txn1 = new(16'h0064, 16'h0032, ALU_Transaction::ADD);
    txn1.execute(10);

    txn1 = new(16'h00FF, 16'h0001, ALU_Transaction::AND);
    txn1.execute(5);

    // --- copy() ---
    $display("\n--- Kopyalama ---");
    begin
      ALU_Transaction original, copied;
      original = new(16'h1234, 16'h5678, ALU_Transaction::XOR);
      void'(original.calculate());
      copied = original.copy();
      $display("  Orijinal:");
      original.display("    ");
      $display("  Kopya:");
      copied.display("    ");
      
      copied.operand_a = 16'hAAAA;
      $display("  Kopya degistirildi - Orijinal etkilenmez:");
      original.display("    Orijinal: ");
      copied.display("    Kopya:    ");
    end

    // --- compare() ---
    $display("\n--- Karsilastirma ---");
    begin
      ALU_Transaction a, b;
      a = new(16'h10, 16'h20, ALU_Transaction::ADD);
      b = new(16'h10, 16'h20, ALU_Transaction::ADD);
      $display("  a == b ? %s", a.compare(b) ? "EVET" : "HAYIR");
      b.operation = ALU_Transaction::SUB;
      $display("  a == b ? %s (op degisti)", a.compare(b) ? "EVET" : "HAYIR");
    end

    $display("\n=== Sinif Metodlari Sonu ===");
    $finish;
  end
endmodule

Kodun Açıklaması

  • ALU_Transaction sınıfı: Bir aritmetik-mantık işlemini modeller. operand_a, operand_b, operation, result ve done özelliklerine sahiptir. operation, sınıf içinde typedef enum ile tanımlanan op_e türündedir (ADD, SUB, MUL, DIV, AND, OR, XOR).
  • new() constructor'ı: Varsayılan değerli argümanlar alır ve this ile gelen parametreleri özelliklere atar; result ve done alanlarını sıfırlar.
  • calculate() function'ı: Bir case bloğuyla operation değerine göre sonucu hesaplar, done bayrağını 1 yapar ve result'ı döndürür. function olduğu için anında çalışır. DIV durumunda sıfıra bölmeye karşı koruma vardır.
  • execute() task'ı: #delay_ns ile simülasyon zamanını ilerletir, sonra void'(calculate()) ile hesaplamayı yapar. task olduğu için zaman tüketebilir; bu yüzden gecikme içerir.
  • to_string() function'ı: $sformatf ile işlemi okunur bir metne dönüştürür ve operation.name() ile enum değerinin ismini metin olarak alır.
  • copy() function'ı: new() ile yeni bir nesne (c) oluşturur, tüm alanları this'ten kopyalar ve döndürür. Bu sayede kopya üzerinde yapılan değişiklik (copied.operand_a = 16'hAAAA) orijinali etkilemez.
  • compare() function'ı: İki nesnenin operand_a, operand_b ve operation alanlarını kıyaslayıp bit döndürür. Örnekte b.operation değişince karşılaştırma sonucunun HAYIR'a döndüğü gösterilir.
  • void'(...) kullanımı: calculate() bir değer döndürür; bu değer kullanılmayacaksa void'(...) ile açıkça yok sayılır.

Önemli Noktalar

  • Bir function içinde gecikme (#, @, wait) kullanılamaz. Zaman tüketmesi gereken davranışlar için task kullanın.
  • Dönüş değeri olan bir metodu yan etkisi için çağırıyor ve dönüşü kullanmıyorsanız, void'(metot()) ile derleyici uyarılarını engelleyebilirsiniz.
  • copy() metodu burada alan alan kopyalama yapar; bu, sınıf içinde başka nesne handle'ları yoksa güvenli bir tam kopyadır (içinde alt-nesne olsaydı sığ/derin kopya ayrımına dikkat edilmeliydi).
  • compare()'in hangi alanları karşılaştıracağı bir tasarım kararıdır; örnekte result ve done dışarıda bırakılıp yalnızca girdi alanları kıyaslanmıştır.
  • Enum sabitlerine sınıf dışından ALU_Transaction::SUB gibi kapsam çözümleme operatörü (::) ile erişilir.
  • Constructor'da varsayılan argümanlar tanımlamak, aynı new()'i hem new() hem new(a, b, op) şeklinde esnekçe çağırmayı sağlar.