SystemVerilog’ta Polymorphism ve Virtuality#
Bu bölümde, SystemVerilog’ta polymorphism (çok biçimlilik) ve virtuality (sanal yöntemler) kavramlarını inceliyoruz. Ayrıca casting, metod çözümleme ve abstract sınıflar ile ilgili ipuçlarını da detaylandırıyoruz.
1️⃣ Polymorphism ve Virtuality#
Polymorphism, bir temel sınıf handle’ının çalışma zamanında farklı türetilmiş sınıf nesnelerine işaret etmesine olanak tanır. Bu, dinamik metod çağrılarını mümkün kılar.
Virtuality, SystemVerilog’da metodlara virtual
anahtar kelimesi eklenerek sağlanır. Bu, metod çağrısının nesnenin gerçek tipine göre çalıştırılmasını sağlar.
Örnek:
// File: tb_polymorphism.sv
`timescale 1ns/1ps
// Virtual class definition
virtual class Packet;
// Virtual display function
virtual function void display();
$display("Packet Display");
endfunction
endclass
// DataPacket class extending Packet
class DataPacket extends Packet;
// Overriding the display function
function void display();
$display("DataPacket Display");
endfunction
endclass
// Testbench module
module tb_polymorphism;
// Packet handle declared at module level
Packet pkt;
DataPacket dpkt;
initial begin
DataPacket dpkt;
dpkt = new();
pkt = dpkt; // assign derived class object to base handle
pkt.display(); // Calls DataPacket's display() method
end
endmodule
2️⃣ Polymorphism’te Sınıf Üyelerine Erişim#
Varsayılan olarak, sınıf üyesine erişim her zaman handle’ın tipine göre yapılır, nesnenin içeriğine göre değil.
- Değişkenlere erişimde her zaman handle’ın statik tipi baz alınır.
- Yöntemlerde ise
virtual
kullanılırsa dinamik dispatch yapılır.
Örnek:
// File: tb_inheritance.sv
`timescale 1ns/1ps
// Base class
class Base;
int id = 1;
endclass
// Derived class
class Derived extends Base;
int id = 2;
endclass
// Testbench module
module tb_inheritance;
Base b;
Derived d;
initial begin
d = new(); // Derived nesnesi oluştur
b = d; // Base handle'a atama yap
$display("ID = %0d", b.id); // Base class'ın id'si yazdırılır
end
endmodule
3️⃣ Sınıf Metodu Çözümleme (Method Resolution)#
- Non-virtual (sanal olmayan) metodlar: Handle’ın statik tipine göre çözülür.
- Virtual metodlar: Nesnenin gerçek tipine göre çözülür.
Virtual metodlar override edilerek dinamik dispatch sağlanır. Virtual olmayan metodlarda her zaman base sınıfın metodu çağrılır.
4️⃣ Virtual Method Kullanımı Neden Önemli?#
Çünkü varsayılan olarak metod çözümlemesi handle’ın tipine göre yapılır. Nesnenin gerçek tipine göre metodun çağrılmasını sağlamak için virtual
kullanılır.
- Statik çözümleme:
// File: tb_static_resolution.sv
`timescale 1ns/1ps
// Base class
class Packet;
function void display();
$display("Packet Display");
endfunction
endclass
// Derived class
class DataPacket extends Packet;
function void display();
$display("DataPacket Display");
endfunction
endclass
// Testbench module
module tb_static_resolution;
Packet pkt;
DataPacket dpkt;
initial begin
dpkt = new();
pkt = dpkt;
pkt.display(); // Static resolution: calls Packet's display()
end
endmodule
Bu durumda pkt.display()
çalışma zamanında doğru türetilmiş sınıf metodunu çağırır.
5️⃣ Sub-Class Nesnesini Parent Handle’a Kopyalamak#
- Bir alt sınıf örneği her zaman doğrudan bir üst sınıfın işaretçisine kopyalanabilir.
- Ancak, varsayılan olarak bu işaretçiden yalnızca üst sınıf üyelerine erişilebilir:
- Alt sınıf örneğini içerse bile bu kural geçerlidir.
Bu oldukça basittir:
// File: tb_copy_subclass.sv
`timescale 1ns/1ps
// Base class
class Packet;
function void display();
$display("Packet Display");
endfunction
endclass
// Derived class
class DataPacket extends Packet;
function void display();
$display("DataPacket Display");
endfunction
endclass
// Testbench module
module tb_copy_subclass;
DataPacket dp;
Packet pkt;
initial begin
dp = new();
pkt = dp; // Sub-class instance assigned to parent handle (upcasting)
pkt.display(); // Calls Packet's display() (static resolution)
end
endmodule
Burada pkt
, dp
ile aynı nesneyi işaret eder ancak sadece temel sınıf üyelerine erişebilir.
6️⃣ Parent Nesnesini Sub-Class Handle’a Kopyalamak#
- Bir üst sınıf işaretçisini doğrudan bir alt sınıf işaretçisine atamak hiçbir zaman geçerli değildir.
- Bu işlem ancak üst sınıf işaretçisi, hedef alt sınıfın bir örneğine işaret ediyorsa geçerli olabilir.
Bu doğrudan yapılamaz çünkü base sınıfın içinde sub-class’a ait alanlar bulunmayabilir. Bunu güvenli şekilde yapmak için $cast
kullanılır.
Örnek:
// File: tb_downcasting.sv
`timescale 1ns/1ps
// Base class
class Packet;
function void display();
$display("Packet Display");
endfunction
endclass
// Derived class
class DataPacket extends Packet;
function void display();
$display("DataPacket Display");
endfunction
endclass
// Testbench module
module tb_downcasting;
Packet pkt;
DataPacket dp;
initial begin
dp = new();
pkt = dp; // only parent method visible
if (!$cast(dp, pkt)) begin
$display("Cast failed");
end
else begin
dp.display();
end
end
endmodule
7️⃣ $cast
Kullanımı#
$cast
, bir üst sınıf handle’ını alt sınıf handle’ına güvenli şekilde dönüştürür. Eğer başarılı olursa 1 döner, başarısız olursa 0 döner ve simülasyon hatası oluşmaz.
Sözdizimi:
if (!$cast(child_handle, parent_handle)) begin
// Cast başarısız
end
8️⃣ Polymorphism’in Avantajları#
✅ Esnek ve yeniden kullanılabilir doğrulama mimarileri sağlar.
✅ Testbench bileşenlerinin farklı implementasyonlarla çalışmasına izin verir.
✅ Dinamik davranış seçimi sayesinde kod tekrarını azaltır.
✅ UVM gibi doğrulama frameworkleri için gereklidir.
9️⃣ Virtual Method Resolution#
SystemVerilog’da, virtual metodlar, çalışma zamanında nesnenin gerçek tipi baz alınarak dinamik olarak çözülür; handle’ın statik tipi dikkate alınmaz.
🔍 Çözümleme Kuralları:
- Simülatör, hangi
display()
fonksiyonunun çağrılacağına karar verirken gerçek nesne tipini (instantiate edilen sınıf) kullanır. - Eğer fonksiyon
virtual
olarak tanımlanmışsa handle’ın tipi önemli değildir. - Eğer bir türetilmiş sınıf virtual fonksiyonu override ederse, base class handle üzerinden çağrılsa bile override edilen fonksiyon çalışır.
Örnek:
// File: tb_virtual_dispatch.sv
`timescale 1ns/1ps
// Base class
class Packet;
virtual function void display();
$display("Packet Display");
endfunction
endclass
// Derived class
class DataPacket extends Packet;
function void display();
$display("DataPacket Display");
endfunction
endclass
// Testbench module
module tb_virtual_dispatch;
Packet pkt;
DataPacket dpkt;
initial begin
dpkt = new();
pkt = dpkt; // Base handle assigned to derived object
pkt.display(); // Calls DataPacket's display() because display() is virtual
end
endmodule
1️⃣0️⃣ Abstract Sınıflar ve Pure Virtual Metodlar#
Abstract sınıflar, doğrudan örneklenemez. Genellikle pure virtual metodlar içerir ve bu metodlar mutlaka türetilmiş sınıflarda override edilmelidir.
- Pure virtual metodlara sahip olabilir ve sadece prototip olarak tanımlanır, implemente edilmez.
- Altsınıf implemente etmelidir.
Örnek:
virtual class Packet;
pure virtual function void display();
endclass
class DataPacket extends Packet;
function void display();
$display("DataPacket Display");
endfunction
endclass
Bu örnekte Packet
abstract bir sınıftır ve örneklenemez. Her türetilmiş sınıf display()
metodunu implement etmek zorundadır.
1️⃣1️⃣ Shallow Copy ve Deep Copy#
SystemVerilog’ta sınıf nesnelerinin kopyalanması biraz dikkat ister çünkü sınıflar her zaman referans tipindedir. Yani, bir sınıf nesnesi kopyalandığında aslında handle kopyalanır, tüm nesne değil—bu işleme shallow copy (yüzeysel kopyalama) denir. Eğer nesnenin tüm iç özelliklerini (ve varsa iç içe nesneleri) de kopyalamak istenirse buna deep copy (derin kopyalama) denir.
🔄 Shallow Copy#
Shallow copy yapıldığında, handle kopyalanır ve her iki referans da aynı nesneyi işaret eder. Yani bir handle ile yapılan değişiklik diğer handle’ı da etkiler.
Örnek:
// File: tb_shallow_copy.sv
`timescale 1ns/1ps
// Base class
class Packet;
bit [7:0] data;
endclass
// Testbench module
module tb_shallow_copy;
Packet pkt1;
Packet pkt2;
initial begin
pkt1 = new();
pkt1.data = 8'hAB;
pkt2 = pkt1; // Shallow copy
pkt2.data = 8'hCD; // Actually changes pkt1.data too
$display("pkt1.data = %0h", pkt1.data); // Prints CD
end
endmodule
Hem pkt1
hem de pkt2
aynı nesneyi işaret eder, dolayısıyla pkt2
ile yapılan değişiklik pkt1
’i de etkiler.
📦 Deep Copy#
Deep copy ise yeni bir nesne oluşturur ve tüm özellikler (ve varsa iç içe nesneler) orijinal nesneden yeni nesneye kopyalanır. Bu sayede kopyalar tamamen bağımsız olur.
SystemVerilog’ta built-in bir deep copy mekanizması yoktur; elle kodlamak gerekir.
Örnek:
// File: tb_deep_copy.sv
`timescale 1ns/1ps
// Base class
class Packet;
bit [7:0] data;
// Deep copy function
function Packet deepCopy();
Packet copy = new();
copy.data = this.data;
return copy;
endfunction
endclass
// Testbench module
module tb_deep_copy;
Packet pkt1;
Packet pkt2;
initial begin
pkt1 = new();
pkt1.data = 8'hAB;
pkt2 = pkt1.deepCopy(); // Deep copy
pkt2.data = 8'hCD;
$display("pkt1.data = %0h", pkt1.data); // Prints AB
$display("pkt2.data = %0h", pkt2.data); // Prints CD
end
endmodule
📖 Sonuç#
SystemVerilog’ta polymorphism ve virtuality, güçlü ve dinamik testbench’ler geliştirmek için kritik öneme sahiptir. Casting, dinamik metod çözümleme ve abstract sınıfları anlamak, doğrulama ortamlarını çok daha esnek hale getirir.