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#,@,waitgibi 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_Transactionsınıfı: Bir aritmetik-mantık işlemini modeller.operand_a,operand_b,operation,resultvedoneözelliklerine sahiptir.operation, sınıf içindetypedef enumile tanımlananop_etüründedir (ADD,SUB,MUL,DIV,AND,OR,XOR).new()constructor'ı: Varsayılan değerli argümanlar alır vethisile gelen parametreleri özelliklere atar;resultvedonealanlarını sıfırlar.calculate()function'ı: Bircasebloğuylaoperationdeğerine göre sonucu hesaplar,donebayrağını1yapar veresult'ı döndürür.functionolduğu için anında çalışır.DIVdurumunda sıfıra bölmeye karşı koruma vardır.execute()task'ı:#delay_nsile simülasyon zamanını ilerletir, sonravoid'(calculate())ile hesaplamayı yapar.taskolduğu için zaman tüketebilir; bu yüzden gecikme içerir.to_string()function'ı:$sformatfile işlemi okunur bir metne dönüştürür veoperation.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 nesneninoperand_a,operand_bveoperationalanlarını kıyaslayıpbitdöndürür. Örnekteb.operationdeğişince karşılaştırma sonucununHAYIR'a döndüğü gösterilir.void'(...)kullanımı:calculate()bir değer döndürür; bu değer kullanılmayacaksavoid'(...)ile açıkça yok sayılır.
Önemli Noktalar
- Bir
functioniçinde gecikme (#,@,wait) kullanılamaz. Zaman tüketmesi gereken davranışlar içintaskkullanı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; örnekteresultvedonedışarıda bırakılıp yalnızca girdi alanları kıyaslanmıştır.- Enum sabitlerine sınıf dışından
ALU_Transaction::SUBgibi kapsam çözümleme operatörü (::) ile erişilir. - Constructor'da varsayılan argümanlar tanımlamak, aynı
new()'i hemnew()hemnew(a, b, op)şeklinde esnekçe çağırmayı sağlar. - Sınıf içinde tanımlanan metodlar varsayılan olarak
automatic'tir; yani her çağrı kendi yerel değişken kopyasını alır. Modül içindekitask/function'lar ise varsayılan olarakstatic'tir. Bu fark Gün 4'te paralel süreçlerle çalışırken önem kazanacak. - Bir sınıfın birden fazla constructor'ı olamaz (C++/Java'daki overloading yoktur). Farklı kurulum biçimleri için varsayılan argümanlar ya da
static function ALU_Transaction create_add(...)gibi "fabrika" metodları kullanılır.
function ve task Karşılaştırması
function |
task |
|
|---|---|---|
| Zaman tüketir mi? | Hayır (#, @, wait yasak) |
Evet |
| Değer döndürür mü? | Evet (void da olabilir) |
Hayır (output/ref argümanla veri döner) |
| Başka ne çağırabilir? | Yalnızca function |
function ve task |
| Çağrı biçimi | İfade içinde kullanılabilir: x = f(); |
Yalnızca ifade olarak: t(); |
| Tipik kullanım | Hesaplama, dönüştürme, karşılaştırma, display |
Protokol sürme, bekleme, el sıkışma |
| UVM'de karşılığı | build_phase, connect_phase (function) |
run_phase (task) |
Benzetme:
functionbir hesap makinesidir: tuşa basarsınız, anında sonuç gelir.taskise bir çamaşır makinesidir: başlatırsınız, zaman geçer, bitince devam edersiniz. Çamaşır makinesinin içine hesap makinesi koyabilirsiniz ama hesap makinesinin içinde çamaşır yıkayamazsınız.
Sık Yapılan Hatalar
functioniçine#delayyazmak: Derleme hatasıdır. Zaman gerekiyorsataskkullanın.- Dönüş değerini sessizce yok saymak:
txn.calculate();tek başına yazılırsa birçok simülatör uyarı verir. Niyetinizivoid'(txn.calculate())ile açıkça belirtin. copy()içindereturn this;yazmak: Bu bir kopya değil, aynı nesnenin handle'ıdır.copy()mutlakanew()ile yeni nesne üretmelidir.compare()'de çıkış alanlarını da karşılaştırmak: Scoreboard'da "beklenen" transaction'ınresultalanı henüz doluyken "gözlenen" transaction'ındonealanı farklı olabilir. Hangi alanların kıyaslanacağını bilinçli seçin.taskiçindereturnile değer döndürmeyi denemek:task'lar değer döndürmez;return;yalnızca erken çıkış içindir. Veri döndürmek içinoutputargüman kullanın.
Kendinizi Deneyin
execute()task'ınıfunctionolarak değiştirmeyi deneyin. Hangi hata mesajını aldınız?compare()metodunaresultalanını da ekleyin;a.calculate()çağrılmış amab.calculate()çağrılmamışken sonucun nasıl değiştiğini gözlemleyin.- Sınıfa
static function ALU_Transaction make_add(logic [15:0] a, b);adında bir fabrika metodu ekleyin veALU_Transaction::make_add(1, 2)ile çağırın. DIVdalında bölen sıfırsadonebayrağının0kalmasını sağlayacak şekildecalculate()'i düzenleyin.
Hızlı Kontrol: Bir function içinden task çağrılabilir mi?
Hayır. task zaman tüketebildiği için, zaman tüketemeyen bir function onu çağıramaz. Tersi serbesttir: task içinden function çağrılabilir. (Not: fork ... join_none içinde bir task başlatmak function'dan bile mümkündür çünkü çağıran bloklanmaz; ancak bu ileri düzey bir kalıptır ve dikkat gerektirir.)