Windows上使用iverilog+gtkwave仿真


主要參考了:

https://www.cnblogs.com/lsgxeva/p/8280662.html

謝謝!

 

--------------------------------------------------------------------------------------------------------------------

使用Verilog編寫好了功能模塊以及對應的testbench之后,一般需要對其功能進行仿真測試。由於工作場合、必須使用正版軟件,然而ModelSim的license又非常有限、經常出現的狀況是一方在使用其進行仿真、另一方就不能夠進行仿真了。

在這個情況下,可以有的選擇包括:

1、繼續等待別人用完,然后再使用ModelSim進行仿真;

2、使用集成在VIVADO里的simulation工具(ISE下自帶的是ISim),基本可以勝任絕大多數的功能仿真任務;操作也很簡單,直接Run Simulation就可以了;

3、使用開源的工具:iverilog+gtkwave工具。

下面對第三種方式的操作流程進行記錄。系統環境為Windows7

從官網下載包含iverilog+GTKWave的安裝包,地址為http://bleyer.org/icarus/ 。安裝好之后開始逐步執行命令。(或者也可以將命令編寫在一個腳本文件中。)

本文所仿真的verilog小實例如下,是一個簡單的loadable四位加一計數器:(代碼來自在學習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

為了方便執行,編寫了批處理腳本,如下:

set iverilog_path=C:\iverilog\bin;
set gtkwave_path=C:\iverilog\gtkwave\bin;
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可執行文件路徑到PATH。由於工作場合下、本人只是所使用電腦系統的普通用戶權限、而不是管理員權限,所以不方便為本機系統添加環境變量,所以需要在開始執行上述操作。

然后設置兩個變量,后面會使用

  testbentch_module設置為testbench文件的模塊名

  source_module設置為DUT模塊名

然后使用iverilog編譯verilog

  -o指定輸出文件名,這里使用模塊名+.vvp

  之后指定源文件

在制定源文件的時候可以用通配符*,如本人用的批處理中通常使用這種方式指定RTL文件:set rtl_file="../rtl/*.v"。

然后使用vvp開始仿真,參數為上面iverilog的輸出文件

之后開始仿真數據波形顯示

  設置了一個變量,為GTKWave保存文件的文件名,這里使用模塊名+.gtkw

  然后判斷GTKWave保存文件是否存在,若存在則直接使用GTKWave打開該.gtkw文件,否則打開剛仿真生成的.vcd文件。

這里有兩點需要注意:

1、vvp命令使用了-n選項是為了讓testbench在執行完測試流程之后自動結束,也可以不在執行命令這里使用-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的參數需要為testbench的模塊名。

添加了這兩個命令之后就可以將生成的波性文件保存在本地。

在GTKWave中打開的仿真波形結果如下圖所示:

 

 直接運行iverilog -helpiverilog則會顯示以下幫助信息,顯示了iverilog支持的參數

Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile]
                [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g<feature>]
                [-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)

詳細參數列表請查看http://iverilog.wikia.com/wiki/Iverilog_Flags

 此外,如果運行批處理需要在DOS窗口查看verilog中$display的打印,有時iverilog編譯打印的信息較多時會導致部分信息無法查看,所以需要加大DOS窗口的高度:在DOS窗口標題欄右鍵->默認值->布局中設置屏幕緩沖區中高度為較大的值(如1000)即可。

 

最后是可能會用到的網址:

iverilog 官網:http://iverilog.icarus.com/

iverilog windows版本:http://bleyer.org/icarus/

iverilog User Guide:http://iverilog.wikia.com/wiki/User_Guide

iverilog GitHub:https://github.com/steveicarus/iverilog

GTKWave 官網:http://gtkwave.sourceforge.net/

GTKWave 手冊:http://gtkwave.sourceforge.net/gtkwave.pdf 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM