Final Testbench
Gün 7: Bitirme Projesi - Bölüm 2 | Tüm bileşenleri bir araya getiren son testbench
Testbench Top (en üst modül), tüm projeyi bir araya getiren statik modüldür. ALU mimarimizin "ana sahnesidir": saat üretir, interface ve DUT'u somutlaştırır, bunları bağlar ve komut satırından seçilen testi başlatır.
Testbench Top ve Mimarideki Yeri
Top, hiyerarşinin en tepesinde yer alır ve sınıf tabanlı doğrulama dünyası ile statik donanım dünyasını birleştirir. Görevleri:
- Dosyaları dahil etmek: Tüm bileşen sınıflarını
`includeile derlemeye dahil eder. - Saat üretmek:
always #5 clk = ~clkile 100 MHz'lik saat sağlar. - Bağlamak:
alu_if aif(clk)interface'ini vealu dut(...)modülünü oluşturup pinleri arayüze bağlar. - Test seçmek:
$value$plusargsile komut satırından (+TEST=...) hangi senaryonun koşacağını belirler.
Komut Satırından Test Seçimi
+TEST=Random_Test veya +TEST=Corner_Test argümanı, simülatöre hangi test sınıfının örnekleneceğini söyler. Bu, polymorphism'in son halkasıdır: ALU_Base_Test test handle'ı türetilmiş bir nesneye (ALU_Random_Test veya ALU_Corner_Test) işaret eder ve test.run() doğru senaryoyu çalıştırır.
Dalga Formu (Waveform) Kaydı
$dumpfile/$dumpvars ile tüm hiyerarşi bir VCD dosyasına kaydedilir; hata ayıklarken sinyalleri görsel olarak incelemeyi sağlar.
Kaynak Kod
// =============================================================================
// GUN 7 KONU 6: Final Testbench Top-Level
// =============================================================================
// =============================================================================
// Statik tasarim ogeleri once: interface ve DUT
`include "alu_if.sv" // Ders 36
`include "alu.sv" // Ders 36-1
// Siniflar, bagimlilik sirasiyla
`include "6_2_transaction.sv" // Ders 37 - herkes bunu kullanir
`include "7_5_coverage.sv" // Ders 45 - scoreboard ve environment kullanir
`include "6_3_generator.sv" // Ders 38
`include "6_4_driver.sv" // Ders 39
`include "7_1_monitor.sv" // Ders 41
`include "7_2_scoreboard.sv" // Ders 42 - ALU_Coverage'i bilmeli
`include "7_3_environment.sv" // Ders 43 - tum bilesenleri bilmeli
`include "7_4_test.sv" // Ders 44 - environment'i bilmeli
module tb_top_final;
// Clock generation
logic clk = 0;
always #5 clk = ~clk; // 100MHz (period = 10ns)
// Interface
alu_if aif(clk);
// DUT (Design Under Test)
alu dut (
.clk (aif.clk),
.rst_n (aif.rst_n),
.in_valid (aif.in_valid),
.operand_a (aif.operand_a),
.operand_b (aif.operand_b),
.opcode (aif.opcode),
.out_valid (aif.out_valid),
.result (aif.result),
.flags (aif.flags)
);
// Test selection
initial begin
ALU_Base_Test test;
// Declare handles for derived classes
ALU_Random_Test rand_test;
ALU_Corner_Test corner_test;
string test_name;
// Test selection from command line: +TEST=Random_Test
if (!$value$plusargs("TEST=%s", test_name))
test_name = "Random_Test"; // Default
$display("============================================================");
$display(" ALU VERIFICATION PROJECT - FINAL");
$display(" Selected Test: %s", test_name);
$display("============================================================");
case (test_name)
"Random_Test": begin
rand_test = new(aif, aif);
test = rand_test;
end
"Corner_Test": begin
corner_test = new(aif, aif);
test = corner_test;
end
default: begin
$display(" Unknown test: %s, Random_Test is being used", test_name);
rand_test = new(aif, aif);
test = rand_test;
end
endcase
test.run();
$display("\n============================================================");
$display(" SIMULATION COMPLETED");
$display("============================================================");
$finish;
end
// VCD waveform
initial begin
$dumpfile("alu_tb_final.vcd");
$dumpvars(0, tb_top_final);
end
endmodule
Kodun Açıklaması
- **
`includedirektifleri**: Önce statik tasarım öğeleri (interface, DUT), sonra sınıflar bağımlılık sırasıyla derlemeye dahil edilir. Bir sınıf, kullandığı diğer sınıflardan **önce** derlenmiş olmalıdır:coveragescoreboard'dan,scoreboard/monitor/driver/generatorenvironment'tan,environmenttest'ten önce gelir. Interface'in en başta olması,virtual alu_if.drivergibi tiplerin sınıflar derlenirken bilinmesini sağlar (bazı araçlar geç tanımı tolere eder, ama önce tanımlamak her araçta güvenlidir). - Saat üreteci:
logic clk = 0;ile başlatılır,always #5 clk = ~clk;her 5 ns'de tersine döner, böylece 10 ns periyot (100 MHz) oluşur. alu_if aif(clk): Interface, üretilen saatle somutlaştırılır.alu dut (...): DUT, tüm pinleriaifarayüzünün ilgili sinyallerine bağlanarak örneklenir.- Test seçimi:
$value$plusargs("TEST=%s", test_name)komut satırı argümanını okur; yoksa varsayılan"Random_Test"kullanılır.casebloğundaRandom_Test→ALU_Random_Test,Corner_Test→ALU_Corner_Testörneklenir veALU_Base_Test testhandle'ına atanır. Bilinmeyen isimde varsayılana düşülür. test.run(): Seçilen testin sanalrun()metodu çağrılır; tüm doğrulama akışı buradan başlar. Bitince$finishile simülasyon sonlandırılır.- VCD:
$dumpfile("alu_tb_final.vcd")ve$dumpvars(0, tb_top_final)ile tüm hiyerarşi dalga formuna kaydedilir.
Önemli Noktalar
`includesırası derleme bağımlılıklarını yansıtmalıdır; yanlış sıra "tanımlanmamış tip" hatalarına yol açar.Test handle'ının taban tip (
ALU_Base_Test) olması ve türetilmiş nesneye atanması, çalışma zamanı çok biçimliliğinin (polymorphism) tüm sistemi sürdüğü noktadır.+TEST=argümanı, tek bir derlemeyle farklı senaryoları koşmayı sağlar; regresyon (regression) otomasyonu için idealdir.Saat üreteci interface dışında, top'ta tutulur ve interface'e parametre olarak geçirilir; bu, tek bir saat kaynağının tüm tasarımı beslemesini garanti eder.
$dumpvars(0, tb_top_final)sıfır seviyesiyle tüm alt hiyerarşiyi kaydeder; büyük tasarımlarda dosya boyutu için kapsamı daraltmak gerekebilir.new(aif, aif)çağrısında aynı interface iki farklı modport tipine dönüşür: İlkaif,virtual alu_if.driver, ikincisivirtual alu_if.monitorparametresine gider. SystemVerilog interface örneğini uygun modport görünümüne otomatik çevirir; bu, Ders 32'de öğrendiğiniz dönüşümün aynısıdır.**
`includeilepackagefarkı:** Bu proje`includekullanır çünkü EDA Playground'da tek derleme birimi vardır ve öğrenmesi kolaydır. Gerçek projelerde sınıflar birpackage alu_tb_pkg; ... endpackageiçine konur, top modüldeimport alu_tb_pkg::*;yapılır. Paket; isim çakışmalarını önler, çift tanımı imkânsız kılar ve derleme sırasını tek dosyada toplar. UVM derslerinde bu yapıya geçeceksiniz.+TEST=ile seçilebilen bir regresyon için küçük bir betik yeterlidir:for t in Random_Test Corner_Test; do xrun -f filelist.f +TEST=$t -l $t.log # arac komutu simulatore gore degisir done grep -l "HATA TESPIT" *.log || echo "Tum testler gecti"Tek derleme, farklı
+TEST=argümanları; işte regresyon otomasyonunun temeli.
Tüm Proje Bir Bakışta
tb_top_final
├── clk (always #5)
├── alu_if aif(clk) ───────────────────────┐
├── alu dut(.clk(aif.clk), ...) ◀─────────┤ pinler
└── initial: test = new(aif, aif); test.run()
│
└── ALU_<X>_Test.run()
└── ALU_Environment
├── gen : ALU_Generator / ALU_Corner_Generator ──gen2drv──▶ drv
├── drv : ALU_Driver (vif = aif.driver) ──drv_cb──▶ DUT ──drv2scb──▶ scb
├── mon : ALU_Monitor (vif = aif.monitor) ◀──mon_cb── DUT ──mon2scb──▶ scb
├── scb : ALU_Scoreboard (referans model + karsilastirma) ──sample──▶ cov
└── cov : ALU_Coverage (tek ornek, env raporlar)
Bu şemayı Gün 1'deki "Doğrulama Mühendisinin Günlük Hayatında" tablosuyla yan yana koyun: her satır bu şemada bir kutuya dönüştü.
Sık Yapılan Hatalar
- **
`includesırasını bozmak:** "Unknown typeALU_Coverage" gibi hatalar neredeyse her zaman sıralama hatasıdır. - Aynı dosyayı iki kez
includeetmek: Sınıf çift tanımlanır. Include guard (`ifndef ALU_TRANSACTION_SV) ekleyin (Makro dersi). +TESTadını yanlış yazmak:caseeşleşmez,defaultdalı sessizceRandom_Testkoşturur ve siz köşe testini koştuğunuzu sanırsınız.defaultdalındaki uyarı mesajını mutlaka okuyun.$finish'itest.run()dönmeden çağırmak: Scoreboard raporu basılamaz.run()tüm boşaltma zincirini beklediği için$finishondan sonra gelmelidir.- Saati interface içinde üretmek: Birden fazla interface örneğinde saatler kayar; saat tek kaynaktan (top) gelsin.
Kendinizi Deneyin
- EDA Playground'da projeyi
+TEST=Corner_Testile çalıştırın ("Run options" alanına yazın). Scoreboard raporundaToplam : 240ve kapsam raporundacp_op_a%100 görmelisiniz. - DUT'a bilinçli hata enjekte edin (Ders 36-1, ek görev 2:
OP_SUBoperandlarını ters çevirin).Random_Testkaç hata yakaladı?Corner_Test? Hangi girişlerde hata görünmedi (a == b)? - Tüm sınıf dosyalarını
package alu_tb_pkg; ... endpackageiçine alın ve top'taimport alu_tb_pkg::*;kullanın.virtual alu_ifreferansları için interface'in paketten önce derlenmesi gerektiğini gözlemleyin. - Yukarıdaki regresyon betiğini kendi simülatörünüze uyarlayın; her iki test için log dosyalarını üretin ve
grepile özet çıkarın.
Hızlı Kontrol: ALU_Base_Test test handle'ının türetilmiş bir nesneye atanması neden tüm sistemi "sürer"?
test.run() çağrısı, run() virtual olduğu için handle'ın tipine değil nesnenin gerçek tipine göre çözülür: ALU_Corner_Test nesnesiyse onun run()'ı çalışır ve köşe generator kurulur. Bu tek satır, Gün 2'deki polimorfizm dersinin en üst katmandaki uygulamasıdır; +TEST= argümanı yalnızca hangi nesnenin yaratılacağını seçer.