使用Verilog編寫好了功能模塊以及對應的testbench之后,一般需要對其功能進行仿真測試。由于工作場合、必須使用正版軟件,然而ModelSim的license又非常有限、經常出現(xiàn)的狀況是一方在使用其進行仿真、另一方就不能夠進行仿真了。
在這個情況下,可以有的選擇包括:
1、繼續(xù)等待別人用完,然后再使用ModelSim進行仿真;
2、使用集成在VIVADO里的simulation工具(ISE下自帶的是ISim),基本可以勝任絕大多數(shù)的功能仿真任務;操作也很簡單,直接Run Simulation就可以了;
3、使用開源的工具:iverilog+gtkwave工具。
下面對第三種方式的操作流程進行記錄。系統(tǒng)環(huán)境為Windows7
從官網下載包含iverilog+GTKWave的安裝包,地址為http://bleyer.org/icarus/。安裝好之后開始逐步執(zhí)行命令。(或者也可以將命令編寫在一個腳本文件中。)
本文所仿真的verilog小實例如下,是一個簡單的loadable四位加一計數(shù)器:(代碼來自在學習testbench期間在網上找到的Lattice公司的“A Verilog HDL Test Bench Primer”手冊中的示例代碼)
//------------------------------------------------- // File: count16.v // Purpose: Verilog Simulation Example //------------------------------------------------- `timescale 1 ns / 100 ps module count16 (count, count_tri, clk, rst_l, load_l, enable_l, cnt_in, oe_l); output [3:0] count; output [3:0] count_tri; input clk; input rst_l; input load_l; input enable_l; input [3:0] cnt_in; input oe_l; reg [3:0] count; // tri-state buffers assign count_tri = (!oe_l) ? count : 4'bZZZZ; // synchronous 4 bit counter always @ (posedge clk or negedge rst_l) begin if (!rst_l) begin count <= #1 4'b0000; end else if (!load_l) begin count <= #1 cnt_in; end else if (!enable_l) begin count <= #1 count + 1; end end endmodule //of count16
為其編寫的testbench文件如下:
//------------------------------------------------- // File: cnt16_tb.v // Purpose: Verilog Simulation Example // Test Bench //----------------------------------------------------------- `timescale 1 ns / 100 ps module cnt16_tb (); //--------------------------------------------------------- // inputs to the DUT are reg type reg clk_50; reg rst_l, load_l, enable_l; reg [3:0] count_in; reg oe_l; //-------------------------------------------------------- // outputs from the DUT are wire type wire [3:0] cnt_out; wire [3:0] count_tri; //--------------------------------------------------------- // instantiate the Device Under Test (DUT) // using named instantiation count16 U1 ( .count(cnt_out), .count_tri(count_tri), .clk(clk_50), .rst_l(rst_l), .load_l(load_l), .cnt_in(count_in), .enable_l(enable_l), .oe_l(oe_l) ); //---------------------------------------------------------- // create a 50Mhz clock always #10 clk_50 = ~clk_50; // every ten nanoseconds invert //----------------------------------------------------------- // initial blocks are sequential and start at time 0 initial begin $dumpfile("cnt16_tb.vcd"); $dumpvars(0,cnt16_tb); end initial begin $display($time, " << Starting the Simulation >>"); clk_50 = 1'b0; // at time 0 rst_l = 0; // reset is active enable_l = 1'b1; // disabled load_l = 1'b1; // disabled count_in = 4'h0; oe_l = 4'b0; // enabled #20 rst_l = 1'b1; // at time 20 release reset $display($time, " << Coming out of reset >>"); @(negedge clk_50); // wait till the negedge of // clk_50 then continue load_count(4'hA); // call the load_count task // and pass 4'hA @(negedge clk_50); $display($time, " << Turning ON the count enable >>"); enable_l = 1'b0; // turn ON enable // let the simulation run, // the counter should roll wait (cnt_out == 4'b0001); // wait until the count // equals 1 then continue $display($time, " << count = %d - Turning OFF the count enable >>", cnt_out); enable_l = 1'b1; #40; // let the simulation run for 40ns // the counter shouldn't count $display($time, " << Turning OFF the OE >>"); oe_l = 1'b1; // disable OE, the outputs of // count_tri should go high Z. #20; $display($time, " << Simulation Complete >>"); $stop; // stop the simulation end //-------------------------------------------------------------- // This initial block runs concurrently with the other // blocks in the design and starts at time 0 /*initial begin // $monitor will print whenever a signal changes // in the design $monitor($time, " clk_50=%b, rst_l=%b, enable_l=%b, load_l=%b, count_in=%h, cnt_out=%h, oe_l=%b, count_tri=%h", clk_50, rst_l, enable_l, load_l, count_in, cnt_out, oe_l, count_tri); end*/ //-------------------------------------------------------------- // The load_count task loads the counter with the value passed task load_count; input [3:0] load_value; begin @(negedge clk_50); $display($time, " << Loading the counter with %h >>", load_value); load_l = 1'b0; count_in = load_value; @(negedge clk_50); load_l = 1'b1; end endtask //of load_count endmodule //of cnt16_tb
為了方便執(zhí)行,編寫了批處理腳本,如下:
set iverilog_path=C:iverilogin; set gtkwave_path=C:iveriloggtkwavein; set path=%iverilog_path%%gtkwave_path%%path% set source_module=count16 set testbentch_module=cnt16_tb iverilog -o "%testbentch_module%.vvp" %testbentch_module%.v %source_module%.v vvp -n "%testbentch_module%.vvp" set gtkw_file="%testbentch_module%.gtkw" if exist %gtkw_file% (gtkwave %gtkw_file%) else (gtkwave "%testbentch_module%.vcd") pause
首先,設置iverilog和GTKWave可執(zhí)行文件路徑到PATH。由于工作場合下、本人只是所使用電腦系統(tǒng)的普通用戶權限、而不是管理員權限,所以不方便為本機系統(tǒng)添加環(huán)境變量,所以需要在開始執(zhí)行上述操作。
然后設置兩個變量,后面會使用
testbentch_module設置為testbench文件的模塊名
source_module設置為DUT模塊名
然后使用iverilog編譯verilog
-o指定輸出文件名,這里使用模塊名+.vvp
之后指定源文件
在制定源文件的時候可以用通配符*,如本人用的批處理中通常使用這種方式指定RTL文件:set rtl_file="../rtl/*.v"。
然后使用vvp開始仿真,參數(shù)為上面iverilog的輸出文件
之后開始仿真數(shù)據(jù)波形顯示
設置了一個變量,為GTKWave保存文件的文件名,這里使用模塊名+.gtkw
然后判斷GTKWave保存文件是否存在,若存在則直接使用GTKWave打開該.gtkw文件,否則打開剛仿真生成的.vcd文件。
這里有兩點需要注意:
1、vvp命令使用了-n選項是為了讓testbench在執(zhí)行完測試流程之后自動結束,也可以不在執(zhí)行命令這里使用-n、而通過在testbench文件的initial塊中添加"$finish"命令來結束。(testbentch中結束仿真推薦用$finish而不用$stop;因為$finish可以直接結束仿真并退出,而不需要手動退出,這樣運行類似以上例子批處理后可以直接打開GTKWave窗口)
2、為了讓vvp命令有輸出,需要在testbench文件中額外添加一個initial塊,在上面的代碼中為:
initial begin $dumpfile("cnt16_tb.vcd"); $dumpvars(0,cnt16_tb); end
dumpfile的內容為輸出的vcd文件名,可以隨意指定,這里指定為testbench模塊名;
dumpvar的參數(shù)需要為testbench的模塊名。
添加了這兩個命令之后就可以將生成的波性文件保存在本地。
在GTKWave中打開的仿真波形結果如下圖所示:
直接運行iverilog -help或iverilog則會顯示以下幫助信息,顯示了iverilog支持的參數(shù)
Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile] [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g] [-D macro[=defn]] [-I includedir] [-M [mode=]depfile] [-m module] [-N file] [-o filename] [-p flag=value] [-s topmodule] [-t target] [-T min|typ|max] [-W class] [-y dir] [-Y suf] source_file(s)
此外,如果運行批處理需要在DOS窗口查看verilog中$display的打印,有時iverilog編譯打印的信息較多時會導致部分信息無法查看,所以需要加大DOS窗口的高度:在DOS窗口標題欄右鍵->默認值->布局中設置屏幕緩沖區(qū)中高度為較大的值(如1000)即可。
審核編輯:湯梓紅
-
仿真
+關注
關注
50文章
4023瀏覽量
133341 -
WINDOWS
+關注
關注
3文章
3521瀏覽量
88321 -
Verilog
+關注
關注
28文章
1343瀏覽量
109927 -
計數(shù)器
+關注
關注
32文章
2253瀏覽量
94289 -
開源
+關注
關注
3文章
3218瀏覽量
42335
原文標題:Windows上使用iverilog+gtkwave仿真
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論