Virtual Interface
Gün 5: Arayüzler, Assertion ve Coverage | Sınıflar içinden fiziksel arayüze erişim
Bu derste virtual interface (sanal arayüz) kavramını öğreneceğiz: nesne tabanlı doğrulama sınıflarının (Driver, Monitor) statik modül hiyerarşisindeki fiziksel arayüze nasıl bağlandığını göreceğiz.
Virtual Interface Neden Gerekli?
SystemVerilog'da interface ve module örnekleri statiktir; simülasyon başlamadan önce elaboration aşamasında oluşturulur ve sabit bir hiyerarşide yer alır. Sınıflar (class) ise dinamiktir; çalışma zamanında new() ile oluşturulur, kopyalanır, mailbox üzerinden taşınır.
Bir sınıf doğrudan fiziksel bir arayüz örneğini içeremez. İşte bu boşluğu virtual interface doldurur:
- Köprü görevi görür: Statik dünyadaki arayüz örneğine, dinamik sınıf dünyasından bir tutamaç (handle) ile erişim sağlar.
- Yeniden kullanılabilir bileşenler: Aynı
Driversınıfı, kendisine hangi sanal arayüz verilirse o fiziksel arayüzü sürer. Sınıf, hangi DUT'a bağlandığını bilmek zorunda kalmaz. - UVM'in temelidir: UVM driver ve monitor'leri tamamen bu mekanizma üzerine kuruludur.
Çalışma Mantığı
Sınıf içinde virtual simple_if.tb vif; şeklinde bir tutamaç tanımlanır. Top modülde fiziksel arayüz (sif) oluşturulur ve sınıf kurucusuna (new(sif)) aktarılır. Bu andan sonra sınıf, vif.cb.valid gibi ifadelerle gerçek sinyalleri sürebilir. Burada arayüzün tb modport'u ve içindeki clocking block (cb) kullanıldığı için sürüş ve örnekleme senkronizasyonu otomatik yönetilir.
Kaynak Kod
// =============================================================================
// GUN 5 - Konu 3: Virtual Interface (Interface'e Class'tan Erişim)
// =============================================================================
interface simple_if(input logic clk);
logic valid;
logic ready;
logic [7:0] data;
// Clocking block sinyalleri clock edge'i ile senkronize eder
clocking cb @(posedge clk);
default input #1step output #0;
output valid, data;
input ready;
endclocking
modport tb (clocking cb, input clk);
modport dut (input clk, valid, data, output ready);
endinterface
// --- Class: Virtual Interface kullanan Driver ---
class Driver;
virtual simple_if.tb vif; // Virtual interface handle
int txn_count = 0;
function new(virtual simple_if.tb vif);
this.vif = vif;
endfunction
task drive(input logic [7:0] data);
@(vif.cb);
vif.cb.valid <= 1;
vif.cb.data <= data;
// Senkron bir şekilde ready'i bekle
do begin
@(vif.cb);
end while (vif.cb.ready !== 1'b1);
vif.cb.valid <= 0;
txn_count++;
$display(" [%0t][Driver] Sent: data=0x%02h (#%0d)", $time, data, txn_count);
endtask
task reset();
vif.cb.valid <= 0;
vif.cb.data <= 0;
@(vif.cb);
$display(" [%0t][Driver] Reset applied", $time);
endtask
endclass
// --- Class: Monitor ---
class Monitor;
virtual simple_if.tb vif;
int observed_count = 0;
logic [7:0] observed_data [$];
function new(virtual simple_if.tb vif);
this.vif = vif;
endfunction
task run();
$display(" [Monitor] Listening started");
forever begin
@(vif.cb);
// === equality check kullan! X ve Z geldiğinde false positive durum olabilir
if (vif.cb.valid === 1'b1 && vif.cb.ready === 1'b1) begin
observed_count++;
observed_data.push_back(vif.cb.data);
$display(" [%0t][Monitor] Observed: data=0x%02h (#%0d)",
$time, vif.cb.data, observed_count);
end
end
endtask
endclass
// Simple DUT
module simple_dut(simple_if.dut sif);
always @(posedge sif.clk) begin
sif.ready <= sif.valid; // Ready - 1 cycle delay
end
endmodule
// Top-level
module virtual_interface;
logic clk = 0;
always #5 clk = ~clk;
simple_if sif(clk);
simple_dut dut(sif);
Driver drv;
Monitor mon;
initial begin
$dumpfile("dump.vcd"); $dumpvars;
end
initial begin
$display("=== Virtual Interface ===\n");
drv = new(sif);
mon = new(sif);
// Monitor'ü çalıştır
fork
mon.run();
join_none
// Reset sequence
drv.reset();
#20;
// Send data
for (int i = 0; i < 8; i++) begin
drv.drive(i * 16 + 'hA0);
end
// Monitor'un son transaction'ı da algılaması için biraz beklet!
// ÖNEMLİ NOT: Beklesek bile algılamayacak, sizce neden?
// fixed.sv'de cevabı var, bu dosyanın içeriğini silip onu yapıştırabilirsin.
#50;
$display("\n --- Results ---");
$display(" Driver sent : %0d", drv.txn_count);
$display(" Monitor observed: %0d", mon.observed_count);
$display(" Observed data : %p", mon.observed_data);
$display("\n=== End of Virtual Interface ===");
$finish;
end
endmodule
Kodun Açıklaması
interface simple_if:valid,ready,datasinyallerini içerir. İçindekiclocking cbbloğu sinyalleri saat kenarına senkronize eder (output valid, data; input ready). İki modport vardır:tb(clocking block veclkgörünümü) vedut(sentezlenebilir taraf).Driversınıfı:virtual simple_if.tb viftutamacını tutar. Kurucusunew(vif)ile bu tutamacı dışarıdan alır.drivetask'i@(vif.cb)ile senkronlanıpvif.cb.valid/vif.cb.data'yı sürer vedo ... while (vif.cb.ready !== 1'b1)ileready'yi bekler.txn_countgönderilen işlem sayısını tutar.resettask'i sinyalleri sıfırlar.Monitorsınıfı: Yineviftutamacı üzerinden çalışır.runtask'iforeverdöngüsünde her clocking olayındavif.cb.valid === 1'b1 && vif.cb.ready === 1'b1koşulunu kontrol eder; gözlenen veriyiobserved_datakuyruğunapush_backile ekler veobserved_count'u artırır.simple_dutmodülü: Her saattesif.ready <= sif.validyaparakready'yivalid'in bir saat gecikmeli kopyası olarak üretir.virtual_interface(top): Fizikselsimple_if sif(clk)örneklenir, DUT bağlanır.drv = new(sif)vemon = new(sif)ile her iki sınıfa aynı fiziksel arayüz sanal arayüz olarak verilir.fork ... join_noneile monitör arka planda başlatılır, ardından reset uygulanıp 8 veri gönderilir.
Önemli Noktalar
- Sınıf statik arayüz örneğini tutamaz:
virtualanahtar kelimesi tam da bu yüzden gereklidir; sınıfa fiziksel arayüze dinamik bir tutamaç verir. ===(case equality) kullanın: Koddaki yorumun da vurguladığı gibi,valid/readykontrolünde==yerine===kullanmak,XveyaZdeğerleri geldiğinde yanlış pozitif eşleşmeleri engeller.- Aynı arayüz birçok sınıfa verilebilir:
drvvemonaynısif'i paylaşır; sınıflar birbirinden bağımsız kalır ama aynı sinyalleri görür. - Senkronizasyonu clocking block yapar: Sürüş ve örnekleme
vif.cbüzerinden yapıldığı için TB ile DUT arasındaki yarış koşulları engellenir. - Son işlem gözlem sorunu: Dosyadaki yorumun işaret ettiği gibi, monitör son transaction'ı bu kurguda algılamayabilir; bu, clocking block örnekleme zamanlaması ve simülasyonun sonlanma anıyla ilgili bilinçli bir tartışma noktasıdır.