testbanch編寫

書寫testbench是數字電路設計中不可或缺的一項設計方法,主要是提供的是激勵。儘管現在各種開發工具都通過繪製波形圖的方法生成測試激勵,測試書寫的代碼,但是其不可移植性,不可通用性,還有有些功能無法是實現,如監視變量的值的變化,顯示數據的狀態等。

一個完整的testbench包含下列幾個部分:

1module的定義,一般無輸入輸出端口。

2)信號的定義,定義哪些是你要輸入,輸入的定義爲reg類型,輸出的定義爲wire

3)實例化待測試的模塊

4)提供測試激勵

1.如何書寫測試激勵;

1)時鐘信號的產生

    時間單位設置:`timescale 1 ns/ 1 ns

   initial

      begin

         clk 0

      forever

         #clk_period/2 clk ~clk;  

      end

或者是

 always

    begin 

       #clk_period/2 clk 0;

       #clk_period/2 clk 1; 

       end

    產生時鐘的原理,是利用always或者是initial forever產生不斷重複的信號,構成時鐘信號。

2)復位信號的產生

復位信號就是在復位電平下延時一段時間,然後再將復位電平信號取反即可。如:
    initial 

 begin

    rst 0

    100

   rst 1

 end

在實際應用將其封裝爲task,使用時掉調用即可。

  調用如下:

 initial

   begin

   sys_time100); //復位100個時間單位

  .....

  end

 任務的定義如下:

task  sys_rst ;

 input  [10:0] rst_time;   //調用task的時候,將參數賦值給rst_time

 begin

    rst 0

    #rst_time

 rst_time 1

 end

endtask

3)產生一種複雜的信號。如下面的實例產生一個vshs信號

//-------------------------------------------------------------------------------------

 parameter  10;

//-------------------------------------------------------------------------------------  

 initial

    begin

    cmos_hs 1'b0;   // time 時刻

 cmos_vs 1'b0;

 repeat(n)  //重複n

       begin

     200   cmos_vs 1'b1;    // time 200 

  repeat(10*n)

      begin

  #100   cmos_hs 1'b1;   //time 300

  #100   cmos_hs 1'b0;   //time  700

   end

  #100   cmos_vs 1'b0;  

    end

 end  

     該程序段可以生成10vs信號,每個vs信號下有100hs信號。由於initial信號只能執行一次,所以爲了得到有限的重複信號,可以採用repeat關鍵詞得到。

這樣基本上就可以完成一些簡單的測試testbench了。

2.如何將我們的測試儘可能的簡單明瞭化

   ModelsimVerilog HDL進行仿真的人都會知道,看一大堆波形會很麻煩,如果代碼變量很多,很複雜,出了問題都不知道問你在哪裏,或者看了半天,發現圖形是個錯的。運用合適的方法將自己需要的變量以文本方式顯示,監視變量的變化不很好嘛?

下面介紹幾種常用的系統函數

  (1)$time

   作用:返回所在模塊的仿真時間,可以查看信號的出現的時間,用來把握信號的時序。

   如:$display(''the time is %t'',$time) ;//顯示當時的時間

 2$display

作用: 將需要顯示的內容在命令欄顯示出來

如: $display("the signal is d",ad); //ad信號以十進制的方式顯示出來

 3$monitor

作用:監視變量的變化,一旦變量變化,則將變量顯示出來

如:$monitor ("at time is %t and the signal is %b\n",$time signal) ;

  (3) 文件操作類

     $fopen

作用:打開一個文件面,對文件的操作

 $fdisplay

作用:在打開的文件裏,寫入顯示的內容

 $fmonitor

作用:在打開的文件裏,寫入監視的變量變化時的內容

 $fclose

作用:關閉當前的內容

如:initial

      Begin block  //可以在內部聲明局部變量

      Integer  out_file

      out_file $fopen("data.out","w") //打開data.out這個文件後,從第一行開始寫,如果該文件沒有,則首先創建該文件,然後再寫。打開文件後返回out_file這個文件整形指針

      $fdisplayout_file"at the time is %t "$time;

      .....

      $fmonitor(out_file"at the time is %t and the signal is %b\n "$time ,signal);

       ......

      $fclose(out_file);

      End

爲什麼要寫testbench

我們爲什麼要寫testbench

經常看到論壇裏有人問我們爲什麼要寫testbench,總是覺得不好回答,下面是整理出來的一些理由供大家參考。
與寫testbench相對應的功能手段還有畫波形圖,兩者相比,畫波形圖的方法更加直觀和易於入門,那爲什麼我們還要寫Testbench呢?原因有以下五點:
第一,畫波形圖只能提供極低的功能覆蓋。
    畫波形無法產生複雜的激勵,因此它只產生極其有限的輸入,從而只能對電路的極少數功能進行測試;而testbench以語言的方式描述激勵源,容易進行高層次的抽象,可以產生各種激勵源,輕鬆地實現遠高於畫波形圖所能提供的功能覆蓋率。以PCI轉以太網電路設計爲例,該設計並不複雜,但卻已經需要考慮多種情況:PCI配置讀寫、存儲器讀寫等操作;以太網的短包、長包等。如果這些激勵都用畫波形圖完成,其工作量是難以想象的;用testbench則可以輕鬆完成這些工作。
第二,畫波形無法實現驗證自動化。
    對於規模設計來說,仿真時間很長,如果一個需要仿真一天設計在檢錯時僅通過畫波形圖來觀測,將幾乎不能檢查出任何錯誤;而testbench是以語言的方式進行描述的,能夠很方便地實現對仿真結果的自動比較,並以文字的方式報告仿真結果。我們甚至可以在下班時開始仿真,然後第二天早上上班時再查看驗證結果。
第三,畫波形圖難於定位錯誤。
    用畫波形圖進行仿真是一種原始的墨盒驗證法,無法使用新的驗證技術;而testbench可以通過在內部設置觀測點,或者使用斷言等技術,快速地定位問題。
第四,畫波形的可重用性和平臺移植性極差。
    如果將一個PCI100Mb以太網的設計升級到PCI1000Mb以太網,這時原來畫的波形圖將不得不重新設計,耗費大量的人力物力及時間;但若使用testbench,只需要進行一些小的修改就可以完成一個新的測試平臺,極大地提高了驗證效率。
第五,通過畫波形的驗證速度極慢。
    Testbench的仿真速度比畫波形圖的方式快幾個數量級,在Quartus下畫波形需半個小時才能跑出來的仿真結果,在ModelSim下使用testbench可能只需幾秒鐘就可以完成。
    所以,在設計中除了那些極簡單的設計(如調用廠商提供的MegaCore),推薦通過寫testbench的方法來做功能驗證。

 

Testbench巧解!

=================================概念=========================
testbench
是一種驗證的手段。

首先,任何設計都是會有輸入輸出的。但是在軟環境中沒有激勵輸入,也不會對你設計的輸出正確性進行評估。那麼此時便有一種,模擬實際環境的輸入激勵和輸出校驗的一種虛擬平臺的產生。在這個平臺上你可以對你的設計從軟件層面上進行分析和校驗,這個就是testbench的含義。
==============================================================

======================
初步認識=================================
就初學而言,testbench更像一個激勵的產生器。
舉例:一個ram,可能有幾個inputoutput。分別列在下面。

clk
,時鐘輸入
addr
,地址輸入
wen
,寫使能
data
,數據輸入


然後還有一個dataout的數據輸出。
那麼你可以寫一個文件,給clkaddrwendata送入你預想的一些信號,然後觀察q的輸出,看看ram是否工作正常。那麼這個文件從一定意義上可以叫做"testbench"

聯想(幫助理解):從quartus裏面你仿真,你可能對着那個畫圖一樣的東西畫上輸入,然後編譯以後看他的輸出。對吧。那麼在modelsim裏面,我告訴你,可以不用畫圖了~,你只需要按照一定規則寫一個.v或者.vhd的文件,這個文件可以給你的設計提供你預想的輸入。這個就是testbench的文件。然後在modelsim這個特定的軟件環境下,這個軟件能根據你的代碼給你的設計提供輸入,又可以把你設計的輸出在屏幕上顯示出來給你debug。那麼這個時候,一個在modelsim上的testbench就完成了。

狹義的總結一下:FPGAtestbench就是一個.v(verilog)或者.vhd(vhdl)的文件。這個文件能給你的設計提供激勵,並能在一些專用的軟件中提供良好的debug接口。這個就是一個testbench
==============================================================

=====================
高級應用================================
關於testbench的高級應用。
剛纔說了初步的testbench。其實testbenchverification(驗證)中的一個手段。
驗證是什麼呢?舉例:做魚了,你往裏面加了調料,然後再嚐嚐味道,這個就是驗證的過程。同樣你可以分成幾個部分,一條魚,好比你的設計,然後你給他一定的激勵,也就是調料啦。然後你再嘗一嘗,看看魚是不是達到你想要的味道了。那就是一種驗證的手段,如果淡了。那麼加點鹽,再嚐嚐,這個就是反覆驗證。

testbench裏面包含了三個東西:
1
激勵生成。也就是我們剛纔初級時候說的所謂的“testbench”。英文麼就是simulator,這個只用來生成輸出,他自己沒有輸入,只是按照一定的規律去給你的設計激勵,激勵通過設計的輸入端口送到你的設計中。其餘的事情不管。這裏的激勵,都是預先設想好的,比如根據某個協議,或者某種通信方式傳遞。

2
你的設計。英文可以叫做DUTdesign under testbench或者DUVdesign under verification。當然咯。這個是你主要目標。

3
輸出校驗。校驗你的輸出。英文叫markerboard,他所管的事情就是,接收你設計的輸入,然後通過校驗,找出對應的問題。然後報錯,或者統計錯誤。等等。通俗的講,你設計它就是把你自己解脫出來,讓他來幫你找錯誤。他輸出給你的可能就是通過打印啊,通知啊,等等方法瞭解你設計的正確性。

那麼你有可能問了,這個東西用verilog或者VHDL能寫麼,modelsim裏能用麼?的確是可以的,有寫甚至可以用c的代碼通過程序接口來轉換到modelsim裏面來幫助驗證。
========================
高級應用結束==========================

最後小說兩句:testbench是一個平臺,幫助你從軟件方面驗證的。對於這個概念不需強求,等你自己的驗證寫多了,自然而然就會了解其中深刻的含義。先開始慢慢的寫一些激勵,然後再寫寫校驗。到時候你收穫的東西自然而然的能幫助你理解testbenchverification 

Testbench編寫技巧

測試平臺是個沒有輸入輸出端口的模塊。仿真在一個模塊設計中是很關鍵的步驟,而testbench是仿真的很好工具。

與待測模塊接口

與輸入端口相連接的變量定義爲reg

與輸出端口相連的定義爲wire

 

initial塊中初始化變量,必須的。

$stop$finish暫停或結束仿真

wait(z==1’b1);//等待變量值改變,變量可以是待測試模塊的輸出或者內部變量

時鐘產生:

always # 10 clk =~clk;產生時鐘

initial repeat(13) #5 clk =~clk; //控制只產生13個時鐘。

 

同步數據:

initial forever @ (posedge clk) #3 x = $random;

爲了降低多個輸入同時翻轉的概率,對時序電路的輸入一般採用素數作爲時間間隔。

同步顯示:

l         initial$monitor (“%d is changed at %t”,MUT.current,$time);//

一般在initial中調用,採用$monitor顯示模塊MUT內部current的值以及發生變化的時間,$monitor是一個後臺運行任務函數,多個模塊下,任意時間只能有一個$monitor起作用,可用$monitoron $monitoroff來控制。

l         always @(z) $display(“Output changed at %t to %b”,$time,z);z發生變化輸出z值以及變化時間,自動換行。

l         always @(z) $strobe(“Output changed at %t to %b”,$time,z);//仿真結束後顯示輸出,查看非阻塞賦值變量的值。

 

隨機數據

initial repeat(5) #7 x = $random;

a = $random`; //產生-59~59之間隨機數

a = {$random}`; //產生0~59之間隨機數

 

產生隨機時間間隔

always begin

       t= $random;

#(t) x = $random;

end



 



初學TestBench

 

初學TestBench

 

`timescale 1ns/10ps //單位時間/精度

`include "adder.v"

 

module adder_testbench;

    reg a,b;

    wire sum,cout;

 

    adder adder_t(   //調用待測模塊

        .sum(sum),

        .c(count),

        .a(a),

        .b(b)

    );

 

    initial begin

        a = 0; //初始值a=0

        forever #20 a = ~a; //每經過20個單位時間,a取反

    end

 

   initial begin

        b = 0;  //初始值b=0

        forever #10 b = ~b; //每經過10個單位時間,b取反

    end

 

    initial begin

        $monitor ($time,,,"%d + %d = {%d,%d}",a,b,cout,sum); //監控輸出

        #40 $stop;

    end

 

小結:

    $monitor 輸出打印顯示

    $stop停止當前仿真

    $finish結束仿真,詢問是否退出ModelSim

 

    時鐘產生方法:

   1.intial語句

        reg clock;

        initial begin

            clock = 0;

            forever #10 clock = ~clock;

        end

    2.always語句

        reg clock;

        initial

            clock = 0;

        always

            #10 clock = ~clock;

 

以上寫法產生的時鐘如下:

Testbench學習筆記


 

如何編寫testbench的總結(轉)

如何編寫testbench的總結

如何編寫testbench的總結(非常實用的總結)

1.激勵的設置

相應於被測試模塊的輸入激勵設置爲reg型,輸出相應設置爲wire類型,雙向端口inout在測試中需要進行處理。

方法1:爲雙向端口設置中間變量inout_reg作爲該inout的輸出寄存,inout口在testbench中要定義爲wire型變量,然後用輸出使能控制傳輸方向。

eg

inout [0:0] bi_dir_port;

wire [0:0] bi_dir_port;

reg [0:0] bi_dir_port_reg;

reg bi_dir_port_oe;

assign bi_dir_port=bi_dir_port_oe?bi_dir_port_reg:1'bz;

bi_dir_port_oe控制端口數據方向,並利用中間變量寄存器改變其值。等於兩個模塊之間用inout雙向口互連。往端口寫(就是往模塊裏面輸入)

方法2:使用forcerelease語句,這種方法不能準確反映雙向端口的信號變化,但這種方法可以反映塊內信號的變化。具體如示:

module test();

wire data_inout;

reg data_reg;

reg link;

#xx; //延時

force data_inout=1'bx; //強制作爲輸入端口

...............

#xx;

release data_inout; //釋放輸入端口

endmodule

從文本文件中讀取和寫入向量

1)讀取文本文件:用 $readmemb系統任務從文本文件中讀取二進制向量(可以包含輸入激勵和輸出期望值)。$readmemh 用於讀取十六進制文件。例如:

reg [7:0] mem[1:256] // a 8-bit, 256-word定義存儲器mem

initial $readmemh ( "mem.data", mem ) // .dat文件讀入寄存器mem

initial $readmemh ( "mem.data", mem, 128, 1 ) // 參數爲寄存器加載數據的地址始終

2)輸出文本文件:打開輸出文件用?$fopen 例如:

integer out_file; // out_file 是一個文件描述,需要定義爲 integer類型

out_file = $fopen ( " cpu.data " ); // cpu.data 是需要打開的文件,也就是最終的輸出文本

設計中的信號值可以通過$fmonitor, $fdisplay,

2. VerilogNcverilog命令使用庫文件或庫目錄
ex). ncverilog -f run.f -v lib/lib.v -y lib2 +libext+.v //
一般編譯文件在run.f, 庫文件在lib.v,lib2目錄中的.v文件系統自動搜索
使用庫文件或庫目錄,只編譯需要的模塊而不必全部編譯

3Verilog Testbench信號記錄的系統任務:

1). SHM數據庫可以記錄在設計仿真過程中信號的變化. 它只在probes有效的時間內記錄你set probe on的信號的變化.
ex). $shm_open("waves.shm"); //
打開波形數據庫
$shm_probe(top, "AS"); // set probe on "top",
第二個參數: A -- signals of the specific scrope
S -- Ports of the specified scope and below, excluding library cells
C -- Ports of the specified scope and below, including library cells
AS -- Signals of the specified scope and below, excluding library cells
AC -- Signals of the specified scope and below, including library cells
還有一個 M ,表示當前scopememories, 可以跟上面的結合使用, "AM" "AMS" "AMC"
什麼都不加表示當前scopeports;
$shm_close //
關閉數據庫
2). VCD
數據庫也可以記錄在設計仿真過程中信號的變化. 它只記錄你選擇的信號的變化.
ex). $dumpfile("filename"); //
打開數據庫
$dumpvars(1, top.u1); //scope = top.u1, depth = 1
第一個參數表示深度, 爲0時記錄所有深度; 第二個參數表示scope,省略時表當前的scope.
$dumpvars; //depth = all scope = all
$dumpvars(0); //depth = all scope = current
$dumpvars(1, top.u1); //depth = 1 scope = top.u1
$dumpoff //
暫停記錄數據改變,信號變化不寫入庫文件中
$dumpon //
重新恢復記錄
3). Debussy fsdb
數據庫也可以記錄信號的變化,它的優勢是可以跟debussy結合,方便調試.
如果要在ncverilog仿真時,記錄信號, 首先要設置debussy:
a. setenv LD_LIBRARY_PATH :$LD_LIBRARY_PATH
(path for debpli.so file (/share/PLI/nc_xl//nc_loadpli1))
b. while invoking ncverilog use the +ncloadpli1 option.
ncverilog -f run.f +debug +ncloadpli1=debpli:deb_PLIPtr
fsdb
數據庫文件的記錄方法,是使用$fsdbDumpfile$fsdbDumpvars系統函數,使用方法參見VCD
注意: 在用ncverilog的時候,爲了正確地記錄波形,要使用參數: "+access+rw", 否則沒有讀寫權限

在記錄信號或者波形時需要指出被記錄信號的路徑,如:tb.module.u1.clk.

………………………………………………………………………………………………………

關於信號記錄的系統任務的說明:

testbench中使用信號記錄的系統任務,就可以將自己需要的部分的結果以及波形文件記錄下來(可採用sigalscan工具查看),適用於對較大的系統進行仿真,速度快,優於全局仿真。使用簡單,在testbench中添加:initial begin

$shm_open("waves.shm");

$shm_probe("要記錄信號的路徑”AS“);

10000

$shm_close; 即可。

4. ncverilog編譯的順序: ncverilog file1 file2 ....
有時候這些文件存在依存關係,如在file2中要用到在file1中定義的變量,這時候就要注意其編譯的順序是
從後到前,就先編譯file2然後纔是file2.

5.
 信號的強制賦值force
首先, force語句只能在過程語句中出現,即要在initial 或者 always 中間. 去除force 用 release語句.
initial begin force sig1 = 1'b1; ... ; release sig1; end
force
可以對wire賦值,這時整個net都被賦值; 也可以對reg賦值.

6.加載測試向量時,避免在時鐘的上下沿變化

爲了模擬真實器件的行爲,加載測試向量時,避免在時鐘的上下沿變化,而是在時鐘的上升沿延時一個時間單位後,加載的測試向量發生變化。如:

assign #5 c="a"^b

……

@(posedge clk) #(0.1*`cycle) A=1;

******************************************************************************

//testbench的波形輸出

module top;

...

initial

begin

$dumpfile("./top.vcd"); //存儲波形的文件名和路徑,一般是.vcd格式.

$dumpvars(1,top); //存儲top這一層的所有信號數據

$dumpvars(2,top.u1); //存儲top.u1之下兩層的所有數據信號(包含top.u1這一層)

$dumpvars(3,top.u2); //存儲top.u2之下三層的所有數據信號(包含top.u2這一層)

$dumpvars(0,top.u3); //存儲top.u3之下所有層的所有數據信號

end

endmodule

//產生隨機數,seed是種子

$random(seed);

ex: din <= $random(20);

//仿真時間,unsigned型的64位數據

$time

ex:

...

time condition_happen_time;

...

condition_happen_time = $time;

...

$monitor($time,"data output = %d", dout);

...

//參數

parameter para1 = 10,

para2 = 20,

para3 = 30;

//顯示任務

$display();

//監視任務

$monitor();

//延遲模型

specify

...

//describ pin-to-pin delay

endspecify

ex:

module nand_or(Y,A,B,C);

input A,B,C;

output Y;

AND2 #0.2 (N,A,B);

OR2 #0.1 (Y,C,N);

specify

(A*->Y) = 0.2;

(B*->Y) = 0.3;

(C*->Y) = 0.1;

endspecify

endmodule

//時間刻度

`timescale 單位時間/時間精確度

//文件I/O

1.打開文件

integer file_id;

file_id = fopen("file_path/file_name");

2.寫入文件

//$fmonitor只要有變化就一直記錄

$fmonitor(file_id, "%format_char", parameter);

eg:$fmonitor(file_id, "%m: %t in1=%d o1=%h", $time, in1, o1);

//$fwrite需要觸發條件才記錄

$fwrite(file_id, "%format_char", parameter);

//$fdisplay需要觸發條件才記錄

$fdisplay(file_id, "%format_char", parameter);

$fstrobe();

3.讀取文件

integer file_id;

file_id = $fread("file_path/file_name", "r");

4.關閉文件

$fclose(fjile_id);

5.由文件設定存儲器初值

$readmemh("file_name", memory_name"); //初始化數據爲十六進制

$readmemb("file_name", memory_name"); //初始化數據爲二進制

//仿真控制

$finish(parameter); //parameter = 0,1,2

$stop(parameter);

//讀入SDF文件

$sdf_annotate("sdf_file_name", module_instance, "scale_factors");

//module_instance: sdf文件所對應的instance.

//scale_factors:針對timming delay中的最小延時min,典型延遲typ,最大延時max調整延遲參數

//generate語句,Verilog-2001中定義.用於表達重複性動作

//必須事先聲明genvar類型變量作爲generate循環的指標

eg:

genvar i;

generate for(i = 0; i < 4; i = i + 1)

begin

assign = din[i] = i % 2;

end

endgenerate

//資源共享

always @(A or B or C or D)

sum = sel ? (A+B):(C+D);

//上面例子使用兩個加法器和一個MUX,面積大

//下面例子使用一個加法器和兩個MUX,面積小

always @(A or B or C or D)

begin

tmp1 = sel ? A:C;

tmp2 = sel ? B:D;

end

always @(tmp1 or tmp2)

sum = tmp1 + tmp2;

******************************************************************************

模板:

module testbench; //定義一個沒有輸入輸出的module

reg …… //DUT的輸入定義爲reg類型

……

wire…… //DUT的輸出定義爲wire類型

……

//在這裏例化DUT

initial

begin

…… //在這裏添加激勵(可以有多個這樣的結構)

end

always…… //通常在這裏定義時鐘信號

initial

//在這裏添加比較語句(可選)

end

initial

//在這裏添加輸出語句(在屏幕上顯示仿真結果)

end

endmodule

以下介紹一些書寫Testbench的技巧:

1.如果激勵中有一些重複的項目,可以考慮將這些語句編寫成一個task,這樣會給書寫和仿真帶來很大方便。例如,一個存儲器的testbench的激勵可以包含writereadtask

2.如果DUT中包含雙向信號(inout),在編寫testbench時要注意。需要一個reg變量來表示其輸入,還需要一個wire變量表示其輸出。

3.如果initial塊語句過於複雜,可以考慮將其分爲互補相干的幾個部分,用數個initial塊來描述。在仿真時,這些initial塊會併發運行。這樣方便閱讀和修改。

4.每個testbench都最好包含$stop語句,用以指明仿真何時結束。

最後提供一個簡單的示例(轉自Xilinx文檔)

DUT

module shift_reg (clock, reset, load, sel, data, shiftreg);

input clock;

input reset;

input load;

input [1:0] sel;

input [4:0] data;

output [4:0] shiftreg;

reg [4:0] shiftreg;

always @ (posedge clock)

begin

if (reset)

shiftreg = 0;

else if (load)

shiftreg = data;

else

case (sel)

2’b00 : shiftreg = shiftreg;

2’b01 : shiftreg = shiftreg << 1;

2’b10 : shiftreg = shiftreg >> 1;

default : shiftreg = shiftreg;

endcase

end

endmodule

Testbench

module testbench; // declare testbench name

reg clock;

reg load;

reg reset; // declaration of signals

wire [4:0] shiftreg;

reg [4:0] data;

reg [1:0] sel;

// instantiation of the shift_reg design below

shift_reg dut(.clock (clock),

.load (load),

.reset (reset),

.shiftreg (shiftreg),

.data (data),

.sel (sel));

//this process block sets up the free running clock

initial begin

clock = 0;

forever #50 clock = ~clock;

end

initial begin// this process block specifies the stimulus.

reset = 1;

data = 5’b00000;

load = 0;

sel = 2’b00;

#200

reset = 0;

load = 1;

#200

data = 5’b00001;

#100

sel = 2’b01;

load = 0;

#200

sel = 2’b10;

#1000 $stop;

end

initial begin// this process block pipes the ASCII results to the

//terminal or text editor

$timeformat(-9,1,"ns",12);

$display(" Time Clk Rst Ld SftRg Data Sel");

$monitor("%t %b %b %b %b %b %b", $realtime,

clock, reset, load, shiftreg, data, sel);

end

endmodule

 

 

 

有關testbench的一些問題

task test_task;//task的定義,以task關鍵字開始,緊接後面是taskid,名字
input [1:0] a;  //task
的輸入輸出定義,用來和外面的變量進行交換,是通向外面的接口
output [1:0] b;

begin
 b = ~a;

end
endtask

reg [1:0] task_a;
reg [1:0] task_b;  //
因爲task必須在過程語句中調用,所以其實參必須爲reg類型的
initial
  begin
    task_a = 2'b0;
    test_task (task_a,task_b);//task
的調用,直接調用,沒有什麼像module一樣例化的東西
    #10 task_a = 2'b10;
  end 

initial
  begin
    #20 task_a = 2'b11;
    test_task (task_a,task_b);//
同樣可以改變task內部的值,和module不同,這是同一個task
    #10 task_a = 2'b10;
  end

reg [1:0] task1_a;
reg [1:0] task1_b;
task test_task1;
output [1:0] b;
assign b = ~task1_a;//
可以使用全局變量,不一定是task內部的變量
endtask
initial
  begin
   task1_a = 2'd0;
   #1  test_task1(task1_b);
   #10 task1_a = 2'd1;
   #1  test_task1(task1_b);
   #10 task1_a = 2'd2;
   #1  test_task1(task1_b);
   #10 task1_a = 2'd3;
   #1  test_task1(task1_b);
  end
 
task
module有點類似,都可以通過輸入輸出來和外面發生關係,這個時候module可以例化多次,這樣就是不同的單元,和task
還是有區別的。
1
task只能定義在module內部,不能單獨在一個文件中,不能定義在module外面。
2
,在task調用的是必須在過程性語句內部使用,initialbegin ... end
3
task可以沒有參數,直接使用全局變量來實現功能。
4
,可以使用延時控制,可以調用其他task和函數。


函數:可以調用函數,不能調用任務,不可有時序控制。

function [1:0] invert;   //只有一個返回值,invert,寄存器類型的
//input [1:0] a;         //
可以有一個輸入,或者多個,或者沒有輸入
//begin
invert = 2'd3;
//end

endfunction

reg [1:0] fun_a;
reg [1:0] fun_out;

initial
  begin
    fun_a = 2'd2;
    fun_out = invert();//(fun_a);//
調用函數,函數返回一個值,必須在過程性語句中調用。
    #50 fun_a = 2'd1;
     fun_out = invert();//(fun_a);
    #50 fun_a = 2'd0;
     fun_out = invert();//(fun_a);
    #50 fun_a = 2'd3;
     fun_out = invert();//(fun_a);
  end
 


task test_task1;   //
任務調用函數

output [1:0] b;
b = ~add(task1_a);
endtask

 

function [1:0] invert;//函數調用函數

input [1:0] a;
 invert = ~add(a);

endfunction


//
顯示和文件操作

integer i;
initial
begin
a1 = 0;
  for(i=0;i<100;i=i+1)
    begin
      if(a1 == 8'd50)
        begin
           $write("a1 is %d",a1);   //
顯示
           $write("\n\n\n\n\n\n");
          
           $fwrite(f_id,"a1 is %d",a1);//
寫入文件
           $fwrite(f_id,"\n\n\n\n\n\n");
        end
      else if(a1 == 8'd70)
        begin
           $display("a1 is %d\n\n",a1);//
顯示
           $fdisplay(f_id,"a1 is %d\n\n",a1);//
寫入文件
        end
      else if (a1 == 8'd90)
        begin
          $fclose(f_id);
        end
     
      #2 a1 = a1 +1;
    end
end


initial

 begin
   $monitor("test %d\n",a1);//
變量變化就會顯示
 end

integer f_id;

initial
  begin
    f_id = $fopen("./test.txt");//
打開一個文件
  end
 
initial

 begin
   $strobe("tes1t %d\n",a1);  //
在時間步0結束的時候顯示這一句
 end


integer cool;

initial
  begin
    cool = 4;                                          //
這是時間步0要執行的,
    $strobe ("strobe cool1 is %d at time %t\n",cool,$time);//
這是時間步0要執行的,在時間步的最後顯示
    $display("cool1 is %d at time %t\n",cool,$time);   //
這是時間步0要執行的,
   
    #4 cool = 8;                                           //
這是時間步4要執行的,
    $strobe ("strobe2 cool1 is %d at time %t\n",cool,$time);//
這是時間步4要執行的,
    $display("cool2 is %d at time %t\n",cool,$time);         //
這是時間步4要執行的,

標籤: testbench  模型  

testbench的一般模型

testbench的實現方法多樣,而且還不斷涌現出新方法,這些都是人們在爲更好的驗證設計做的努力。如VHDL,verilogsystemC,systemverilog均可以,但是真正的實際應用中絕對不是單獨應用,而是將他們結合起來,使你的驗證更方便,更全面。

 

由於系統驗證的龐大,我們還是從最簡單的,最熟悉的上手,就先單獨用VHDL語言來寫仿真語言,當然VHDL語言我們已經比較熟悉了,但是有個比較大的區別是,我們以前都是儘量學習能夠綜合的語言,但是在仿真中經常會用到一些行爲級描述的語言,他們是不能被綜合成邏輯的,但是卻絕對可以讓我們的驗證更加高效方便,但是我們也不單獨來討論VHDL中哪些語言是能夠綜合,哪些語言是不能綜合的,重點將會放在testbench的一般結構,編寫testbench的一般思想,以及更多的是實際接觸,以實際的例子與前面的可綜合邏輯相結合達到完整的系統設計的上的!

 

testbench的幾種思路:

 

一、只在testbench中實例化DUTdesign under test),激勵輸入是在testbench中臨時產生的,只能用於簡單邏輯。優點:簡單,易操作。缺點:複用性差 ,效率低   模型如圖1所示

 

二、DUT的輸入由單獨的一個文件產生,在testbench中實例化兩上entity,可以複雜輸入,簡單輸出的模塊。模型如圖2所示

 

三、DUT的輸入與測試輸出各由單獨文件產生,在testbench由三個實例化模塊產生,用於具有複雜輸入以及輸出的模塊,模型如圖3所示。

 

四、可以根據仿真輸出來修改輸入激勵的,可以自動通過輸出來修改輸入,使驗證更加準確。如圖4所示的模型

 

五、有文件做爲testbench的輸入,輸出的模型。仿真中需要順序的輸入大量數據,以及接收相應的數據,可以通過從文件中讀入數據,然後將產生的數據存入文件,使複雜系統驗證更加方便。模型如圖5所示。

 

六、可以將激勵同時輸入自己設計的模塊和已經驗證了相同模塊,比較二者輸出。模型如圖6所示。

 

                Testbench學習筆記

1

 

 

               Testbench學習筆記

2

 

 

     Testbench學習筆記

  圖3

 

 


                                Testbench學習筆記

 

圖4

Testbench學習筆記

圖5


Testbench學習筆記

6

 

 


 

 


 

本文來源於:電子工程世界

 

Testbench寫法簡要介紹

描述測試信號的變化和測試過程的模塊叫做測試平臺(Testbench),它可以對電路模塊進行動態的測試。通過觀測被測試模塊的輸出信號是否符合要求,可以調試和驗證邏輯系統的設計和結構是否正確,便於發現問題並修改。

Testbench用於測試模塊的示意圖如圖所示:

Testbench學習筆記

由示意圖可知,Testbench要對被測模塊進行測試,需要產生被測模塊所需的激勵信號(比如時鐘信號,復位信號等),這個就像我們用Quartus波形仿真時拖波形一樣,只是Testbench裏需要我們用代碼來實現波形的變化。

產生的激勵信號需要與被測模塊對口(比如產生的時鐘信號要送入時鐘輸入口,產生的復位信號要送入復位輸入口等),如何實現對口,這就需要對被測試模塊的例化來實現。例化的寫法如下:

被測模塊名                             例化進Testbench後的模塊名

.被測模塊輸入口              Testbench產生的激勵信號,

.被測模塊輸出口              Testbench裏用來顯示輸出的信號

);

上面的示意圖對應的例化寫法爲:

被測模塊名                                例化進Testbench後的模塊名

(

              .Input_1                              (In_1),

              .Input_2                              (In_2),

              .Input_3                              (In_3),

              .Output_1                            (Out_1),

              .Output_2                            (Out_2),

              .Output_3                            (Out_3)

);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章