Bir Testbench Aslında Nedir
Bir testbench sadece bir Verilog modülüdür. Sentezlenebilir bir modülden farkı içinde olandır:
- Portları yoktur - simülasyon hiyerarşisinin tepesidir.
- Design under test'i instantiate eder.
- DUT'un girişlerini
initialvealwaysbloklarından sürer. - DUT'un çıkışlarını
$display,$monitorile veya bir VCD dump ederek gözlemler. - Simülasyonu
$finishile sonlandırır.
Tüm iş bu. Özel bir "testbench" anahtar sözcüğü yoktur - bir şeyin testbench olduğunu anlama yolu ne yaptığını okumaktır.
Standart İskelet
Tüm kalıp budur. Beş bölüm, kopyala-yapıştırı kolay, uyarlamayı kolay.
Kombinasyonel DUT'lar için (adder gibi) bir saate ihtiyacın yok. Sıralı DUT'lar için ihtiyacın var - ve bu bir sonraki seviyedir.
Sıralı DUT'lar İçin Saat Üretimi
DUT'un bir clk girişi olduğunda, testbench'in bir tane üretmesi gerekir. Standart tek satır:
reg clk = 0;
always #5 clk = ~clk;
Bu her 5 zaman birimi clk'yi flip eder. Her flip saat periyodunun yarısıdır, bu yüzden tam periyot 10 birimdir (bir döngü = 5 yüksek + 5 düşük). Timescale'in 1ns / 1ps ise (çoğu simülatörde varsayılan), bu 100 MHz bir saattir.
Modellemek istediğin şeye göre yarı periyodu seç. Aynı timescale'de 10 MHz saat için #50 kullan. 200 MHz saat için #2.5 (veya timescale'i değiştir).
Reset Dizisi
Senkron tasarımlar, 0 zamanından sonra birkaç döngü yüksek tutulan ve sonra serbest bırakılan bir reset gerektirir. Geleneksel şekil:
reg reset = 1; // onaylanmış başla
initial begin
// Reset'i birkaç saat tut.
#20 reset = 0;
end
Bu reset'i 20 zamanına kadar yüksek tutar, sonra düşürür. reset düştüğünde, saat birkaç döngü yapmış olur, her flip-flop reset değerini yakalamış olur ve tasarım bilinen bir durumdadır.
Active-low reset için (reset yerine reset_n), başlangıç değerini ters çevir:
reg reset_n = 0; // active-low: 0 onaylandı demektir
initial begin
#20 reset_n = 1;
end
Tam Bir Sıralı Testbench
Saat, reset ve stimulus'u birleştirme:
Bu 4 bitlik bir counter için tam bir testbench'tir. Run'a bas ve counter'ın reset'ten çıkıp, enable'lıyken yukarı saydığını, enable düştüğünde duraklayıp, yükseldiğinde devam ettiğini ve sonra durduğunu göreceksin.
Yapı hakkında dikkat edilmesi gereken üç şey:
- Üç ayrı etkinlik odağı: saat üreticisi (bir
always), stimulus (birinitial) ve monitor (başka biralways). Her birinin bir işi var. - Stimulus bloğundaki
#gecikmeleri zaman birimleriyle ölçülür - saat döngüleri ile değil. Saat periyodun 10 birim ise,#10tam olarak bir döngüdür. Bazı testbench'ler bunun yerine periyottan bağımsız olarak bir döngü ilerleyen@(posedge clk)kullanır. - Monitor
$display'i biralways @(posedge clk)bloğundan kullanır. Bu her döngü yazdırır. Daha gelişmiş çıktı için$monitor'a geç (sonraki bölümde kapsanır).
Döngü Tabanlı Stimulus
Bazen "N döngü bekle", "N zaman birimi bekle"den daha iyi okunur:
initial begin
@(posedge clk); // sonraki saat kenarını bekle
reset = 0;
repeat (5) @(posedge clk); // 5 döngü daha bekle
enable = 1;
repeat (8) @(posedge clk);
enable = 0;
repeat (10) @(posedge clk);
$finish;
end
@(posedge clk), bir sonraki yükselen saat kenarına kadar bloklar. repeat (N) @(posedge clk); N döngü bekler. Bu stil saat periyodundan bağımsızdır - saat frekansını değiştirirsen, stimulus yine de döngü cinsinden aynı şeyi yapar.
Erken testbench'ler için # gecikmeleri daha basittir. Birden çok saat hızında çalışabilen production testbench'leri için döngü tabanlı daha güvenli stildir.
Self-Checking Testler
Şimdiye kadarki testbench ne olduğunu yazdırır ve çıktıyı okumayı sana bırakır. Self-checking bir testbench bunun yerine çıktıyı kontrol eder ve pass/fail raporlar:
initial begin
#1;
a = 10; b = 20;
#1;
if (sum !== 30) begin
$display("FAIL: 10 + 20 = %0d (30 bekleniyor)", sum);
$finish;
end
a = 250; b = 5;
#1;
if (sum !== 255) begin
$display("FAIL: 250 + 5 = %0d (255 bekleniyor)", sum);
$finish;
end
$display("PASS");
$finish;
end
Güvenlik için !== (case-inequality operatörü) kullan - bir operand'da bilinmeyen bitler olduğunda x döndürmez. Kalıp: girişleri sür, yerleşmesini bekle, beklenenle karşılaştır, pass veya fail raporla.
Self-checking, regression suite'lerinde paha biçilmezdir: binlerce test denetimsiz çalışabilir ve yalnızca başarısızlıkların dikkate alınması gerekir.
Sırada Ne Var
Artık herhangi bir modül için yeterli olan testbench şekline sahipsin. Sonraki doc'lar testbench'in içine giren araçları kapsar: daha zengin metin çıktısı için Display and Monitor, grafik waveform debug için Dumpfile and VCD ve simülasyon zamanının duvar saati zamanıyla nasıl ilişkili olduğunu kontrol etmek için Timescale and Delays.
Sıkça Sorulan Sorular
Verilog'da testbench nedir?
Bir testbench, yalnızca amacı bir design under test (DUT)'u çalıştırmak olan - genellikle portsuz - bir Verilog modülüdür. DUT'u instantiate eder, bir saat üretir, initial ve always blokları aracılığıyla stimulus sürer, çıktıları $display/$monitor ile gözlemler, isteğe bağlı olarak bir VCD waveform dump eder ve simülasyonu $finish ile sona erdirir.
Verilog testbench'inde bir saat nasıl üretilir?
Standart kalıp tek bir satırdır: always #5 clk = ~clk; (daha önce tanımlanmış reg clk = 0; ile). Bu her 5 simülasyon zaman birimi clk'yi flip eder, 10 birimlik bir periyot verir (timescale nanosaniyede ise 100 MHz saat). #5 yarı periyottur - zamanın yarısında clk yüksek, yarısında düşük.
Verilog'da DUT nedir?
DUT, Design Under Test anlamına gelir - testbench'in çalıştırdığı modül. Gelenek, DUT instance'ını testbench'te dut veya u_dut olarak adlandırmaktır: my_module dut(.clk(clk), .reset(reset), .in(in), .out(out));. Ad sadece bir etikettir; önemli olan instantiate edilmiş olması, portlarının testbench sinyallerine bağlı olması ve testbench'in o sinyalleri sürmesidir.
Bir Verilog simülasyonu ne kadar süre çalışmalı?
Doğrulamak istediğin her şeyi çalıştırmak için yeterince uzun, sonra $finish. Çoğu testbench açık bir zaman sınırı ayarlar (#1000 $finish) böylece simülasyon asla gelmeyen bir olayı beklerken takılamaz. O pencerede stimulus'ını sür, DUT'un yerleşmesine izin ver ve ideal olarak çıktı beklentilere uymazsa FAIL yazdıran bazı self-checking if ifadeleri ekle.