Driver Modülü
Gün 6: Bitirme Projesi - Bölüm 1 | Transaction'ları DUT pin seviyesine süren modül
Driver (sürücü), soyut transaction nesnelerini gerçek pin seviyesindeki sinyal hareketlerine çeviren bileşendir. ALU mimarimizde generator ile DUT arasında köprü kurar: mailbox'tan aldığı ALU_Transaction'ı alu_if üzerinden DUT girişlerine uygular.
Driver ve Mimarideki Yeri
Driver'ın iki yüzü vardır:
- Üst taraf (transaction seviyesi):
gen2drvmailbox'ından transaction alır. - Alt taraf (sinyal seviyesi):
virtual alu_if.driver vifaracılığıyla clocking block üzerinden DUT pinlerini sürer.
Ayrıca driver, sürdüğü her transaction'ın bir kopyasını (txn.copy()) drv2scb mailbox'ı ile scoreboard'a iletir. Böylece scoreboard "ne uyguladık" bilgisini doğrudan kaynağından öğrenir ve referans modeliyle karşılaştırır.
Clocking Block ile Senkron Sürüş
Sinyaller vif.drv_cb clocking block'u üzerinden ve <= (nonblocking) ile sürülür. @(vif.drv_cb) ifadesi bir sonraki saat kenarını bekler. Bu yaklaşım:
- Yarış koşullarını önler (sinyaller doğru skew ile uygulanır).
- DUT'un
in_validel sıkışmasıyla senkron çalışmasını sağlar.
Reset Görevi
reset() task'ı rst_n'i düşürür, tüm girişleri sıfırlar, birkaç saat çevrimi bekler ve rst_n'i tekrar yükseltir. Reset sırasında rst_n doğrudan (clocking block dışından) atanır, çünkü modport'ta output rst_n olarak tanımlıdır.
Kaynak Kod
// =============================================================================
// GUN 6 - Konu 4: Driver - Uyariciyi DUT'ye Suren Modul
// =============================================================================
class ALU_Driver;
virtual alu_if.driver vif;
mailbox #(ALU_Transaction) gen2drv;
mailbox #(ALU_Transaction) drv2scb;
int driven_count = 0;
function new(virtual alu_if.driver vif,
mailbox #(ALU_Transaction) in_mbx,
mailbox #(ALU_Transaction) out_mbx);
this.vif = vif;
this.gen2drv = in_mbx;
this.drv2scb = out_mbx;
endfunction
task run();
ALU_Transaction txn;
$display("[Driver] Baslatildi");
forever begin
gen2drv.get(txn);
drive_transaction(txn);
drv2scb.put(txn.copy()); // Scoreboard'a kopya gonder
driven_count++;
end
endtask
task drive_transaction(ALU_Transaction txn);
@(vif.drv_cb);
vif.drv_cb.in_valid <= 1;
vif.drv_cb.operand_a <= txn.operand_a;
vif.drv_cb.operand_b <= txn.operand_b;
vif.drv_cb.opcode <= txn.opcode;
@(vif.drv_cb);
vif.drv_cb.in_valid <= 0;
endtask
task reset();
$display("[Driver] Reset baslatiliyor...");
vif.rst_n = 0;
vif.drv_cb.in_valid <= 0;
vif.drv_cb.operand_a <= 0;
vif.drv_cb.operand_b <= 0;
vif.drv_cb.opcode <= 0;
repeat(5) @(vif.drv_cb);
vif.rst_n = 1;
@(vif.drv_cb);
$display("[Driver] Reset tamamlandi");
endtask
endclass
Kodun Açıklaması
- Üyeler:
virtual alu_if.driver vifDUT sinyallerine erişimi sağlar;gen2drvgenerator'dan girişi,drv2scbscoreboard'a çıkışı taşır;driven_countsürülen işlem sayısını tutar. new(...): Yapıcı, virtual interface'i ve iki mailbox'ı dışarıdan alır (dependency injection), bunları kendi üyelerine bağlar.run(): Sonsuz döngüdegen2drv.get(txn)ile bir transaction bekler,drive_transaction(txn)ile pinlere uygular, ardındandrv2scb.put(txn.copy())ile kopyasını scoreboard'a yollar vedriven_count++yapar.drive_transaction(txn):@(vif.drv_cb)ile saat kenarını bekler,in_valid <= 1yapıp operandları veopcode'u sürer. Bir sonraki kenardain_valid <= 0ile geçerli darbeyi tek çevrimlik tutar.reset():vif.rst_n = 0ile reset'i etkinleştirir, tüm girişleri sıfırlar,repeat(5) @(vif.drv_cb)ile beş çevrim bekler, sonravif.rst_n = 1ile reset'ten çıkar.
Önemli Noktalar
drv2scb.put(txn.copy())kopyalama şarttır: Aynıtxnnesnesi paylaşılırsa, döngünün sonraki turunda değişebilir ve scoreboard yanlış beklenen değerle karşılaştırma yapar.- Tüm sürüşler clocking block (
vif.drv_cb) üzerinden nonblocking (<=) yapılır; bu, DUT ile aradaki yarış koşullarını ortadan kaldırır. in_validdarbesi yalnızca bir çevrim yüksek tutulur; DUT'un pipeline mantığı bu el sıkışmaya göre çıkış üretir.rst_ndoğrudan atanır (=), clocking block üzerinden değil; çünkü reset, clocking semantiğinin dışında kontrol edilmek istenen bir sinyaldir ve modport'taoutputolarak ayrılmıştır.run()sonsuz döngüdür; simülasyonun durması, generator'ın bitişi ve environment'taki bekleme/join_anymantığıyla yönetilir, driver kendi başına durmaz.