• 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: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可执行文件路径到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 

  • 相关阅读:
    LeetCode 64. 最小路径和
    LeetCode 344. 反转字符串
    LeetCode 162. 寻找峰值
    LeetCode 227. 基本计算器 II
    LeetCode 232. 用栈实现队列
    LeetCode 160. 相交链表
    LeetCode 112. 路径总和
    谈谈反作弊风控的实践经验
    LeetCode 704. 二分查找
    Hive SQL rank()/dense_rank()/row_number()的区别
  • 原文地址:https://www.cnblogs.com/lazypigwhy/p/10523712.html
Copyright © 2020-2023  润新知