搭建Modelsim SE仿真环境-使用do文件仿真

来源:互联网 发布:gameboy知乎 编辑:程序博客网 时间:2024/04/29 22:43

转载地址:http://blog.csdn.net/lg2lh/article/details/51176467

本章我们介绍仿真环境搭建是基于Modelsim SE的。Modelsim有很多版本,比如说Modelsim-Altera,但是笔者还是建议大家使用Modelsim-SE,Modelsim-Altera实际是针对Altera 的OEM版本,它事先将Altera的一些IP核仿真库添加到了工具中,但功能上有一些缩减。而Modelsim-SE需要自己手动添加这些仿真库,但是功能更全,而且工作中,工程师更倾向用SE版本,因为今后的FPGA开发中我们会接触更多其他厂商的FPGA,比如Xilinx、Lattice的,遇到这些FPGA时,我们同样需要将他们的IP核的仿真库添加到Modelsim 中。

1.1.1.仿真基本概念

FPGA的仿真实际就是一个验证设计的过程,验证在“模拟的输入”的情况下,设计文件的输出是否和我们期望是一致的。这里的“模拟的输入”就是“测试激励”,设计文件就是待测设计,最终通过对输出结果的分析来验证设计的正确性。这就构成了仿真的三个基本组成部分:测试激励(Test_bench)、待测设计(DUT)和最终结果的输出验证。

       上面介绍可能还是有些抽象,我们通过一个简单的仿真例子来介绍仿真中的各个部分。大家打开我们的例程《05_clk_div_even》。

       待测设计(DUT):首先看src文件夹下的clk_div_even.v就是我们待测设计(DUT)。这个比较好理解,就是我们设计的模块。这是一个偶数分频的例子,每次计数从0-4,计数5次,计数器clk_div_cnt会清零一次,同时输出分频信号o_clk_div翻转一次,这样每五个时钟周期,输出信号都会翻转一次,十个时钟周期后又恢复到初始状态,使得输出信号10分频。这里大家需要额外关注一下这个模块的输入和输出,输入将来是我们激励信号进来的地方。

1.  module clk_div_even

2.      (

3.          input                  i_clk        , //模块输入时钟 ,50mhz

4.          input                  i_rst_n      ,    //复位信号,低电平有效

5.          outputreg             o_clk_div         //偶数分频输出

6.      );

7.      

8.      parameter        DIV_EVEN      =10  ;   //10分频,输入50MHz,输出频率为5Mhz

9.      reg    [3:0]clk_div_cnt           ;   //分频计数器

10.//-------------------------------------------------------------------

11.//  分频计数器,每次计数到N-1时归零

12.//-------------------------------------------------------------------

13.    always @ (posedge i_clk ornegedge i_rst_n)

14.    begin

15.        if(!i_rst_n)

16.            clk_div_cnt  <=4'd0;  

17.        else    if(clk_div_cnt  ==DIV_EVEN/2-1)

18.            clk_div_cnt  <=4'd0;  

19.        else  

20.            clk_div_cnt  <=clk_div_cnt   +   4'd1;                              

21.    end

22.//-------------------------------------------------------------------

23.//  分频计数器,每次计数N/2-1时,输出分频信号翻转

24.//-------------------------------------------------------------------    

25.    always @ (posedge i_clk ornegedge i_rst_n)

26.    begin

27.        if(!i_rst_n)

28.            o_clk_div  <=1'b0;  

29.        else    if(clk_div_cnt  ==DIV_EVEN/2-1)

30.            o_clk_div  <=~o_clk_div;

31.    end   

32.endmodule

测试激励(Testbench):Testbench是FPGA仿真的关键,Testbench可以理解为一个激励产生器。大家可以看到我们的待测设计的输入是i_clk和i_rst_n,实际在开发板上,板子上的晶振输出50MHz激励时钟信号给FPGA,同样电路中的复位电路给FPGA提供了i_rst_n的激励信号。在仿真过程中,Testbench就代替了实际的电路,通过Verilog模拟实现这些外部电路的激励信号,提供给DUT,从而通过输出验证设计。工程目录的sim文件夹下的tb_clk_div_even.v 就是我们已经编写好的Testbench。如下就是一个基本Testbench的设计。

下面从上图所示5个部分介绍Testbench基本写法。

1、`timescale 1ns/1ps 决定整个仿真中的时间单位信息,在文件中任何关于时间的信息都是基于此的,1ns表示仿真中的基本时间单位,1ps则表示仿真精度可以达到1ps。例如 #10.005表示的就是延时10.005ns。实际仿真中,精度是可以控制到0.005ns的,即5ps。

2、tb_clk_div_even() 是实际testbench的名称,同样用module定义,但是注意testbenc是没有端口描述的,这与我们待测文件DUT是不一样的。

3、激励信号和输出信号的定义,细心的同学应该可以看出,激励信号就是我们DUT文件的输入,输出信号也就是我们DUT文件的输出。不同的是在Testbench中,我们将激励信号定义为reg类型,输出信号定义为了wire类型。

4、第四部分就是产生激励信号,具体详细实现我们就不介绍了,大家可以阅读我们的文档《Testbench常用语法及技巧》,阅读之后这个地方就很容易理解了。

5、最后一部分是待测设计的实例化,在FPGA设计中,模块的实例化就类似C语言中的函数调用,我们在其他模块中调用当前模块时,就需要以实例化的方式来实现。不同的是,Verilog文件模块实例化时,我们需要标明每一个端口信号。在我们设计的Testbench中,通过模块实例化,将我们的激励信号最终传递给了待测设计文件。

输出验证:下图是我们仿真的最终输出的波形文件,可以看出输出信号o_clk_div是输入信号i_clk的10分频。

最后我们总结整个仿真过程中,各个部分之间的关系,如下图。

1.1.2.  建立Modelsim仿真工程

本节我们介绍如何建立Modelsim仿真工程,了解Modelsim仿真工具的使用。

第一步:打开Modelsim SE,点击菜单栏“File—>New—>Project”,准备新建工程。

第二步:弹出“Create Project”对话框,按下图填写仿真工程名称,以及工程的存储路径,以及默认库的的名称,这里默认库名为“work”,我们通常叫作工作库。设置好后点击OK。

这里介绍一下库的概念,即library。库是Modelsim仿真的载体,Modelsim会将仿真工程中的设计文件(DUT)和激励文件(Testbench)的编译(Compile)结果存放在work库中,在我们新建工程的时候就会带着生成一个work库,如下图在Modelsim工作区,选择Library选项卡,我们可以看到生成的work库,此时work库是空的,因为我们还没有添加并仿真设计文件和激励文件。

第三步:新建或添加设计文件,这里我们已经写好的testbench和待测模块,所以选择直接添加已存在文件即可。

第四步:依次添加testbench和待测模块文件。

第五步:编译我们的DUT和Testbench文件,如下图在工作区域选择Project选项卡,右键选择Compile—>Compile All,编译所有。

 

第六步:切回到Library,此时再看work库就不是空的了,work库里的clk_div_even和tb_clk_div_even分别是tb_clk_div_even.v(Testbench)和clk_div_even.v(DUT)的编译结果。选中Testbench仿真结果tb_clk_div_even,右键—>Simulate without Optimization,启动无优化仿真。

第七步:弹出仿真波形窗口(wave窗口),但是窗口内没有任何信号波形,工作区域多了一个sim选项卡,进入sim选项页,可以看到仿真实例clk_div_even和tb_clk_div_even。选择相应的实例,右键—>add wave,添加信号到wave窗口。

第八步:切到wave 窗口,如下图,设置仿真运行时间为100us,这个时间根据具体设计所需时间来决定,再点击旁边的,运行仿真。这样我们就可以看到输出的波形信号了,从而验证设计的正确性。

1.1.3.  使用do文件进行Modelsim仿真

上一节我们介绍了通过Modelsim建立仿真工程的方法,但是这种方法我们需要使用界面操作,这样会很费时很麻烦。这里我们介绍一种快捷的方法,通过do文件快速搭建仿真环境,并自动完成对Testbench和待验证设计文件的编译和仿真,并且可以自动将要观察的信号添加到wave窗口。


新建一个文件run,后缀名改为do

新建两个文件夹rtl和sim。

rtl下放置rtl代码。

sim文件夹下放置 testbench文件和run.do文件。


run.do:do文件是由tcl脚本语言编写的,这个参考例程中的do文件是最基本的tcl脚本语言。下面介绍一下关键脚本语言的用法。以下是do文件的内容。

1.  vlib work       

2.  vlog  ./*.v

3.  vlog  ../rtl/*.v

4.  vsim-t ns -novopt +notimingchecks  work.tb_clk_div_even 

5.  radix hex

6.  addwave -position insertpoint sim:/tb_clk_div_even/clk_div_even_inst/*

7. add wave -divider {tb_1111}

8.  run -all

vlib work:建立work库,相当于在上一节中新建工程时所生成的work库,后期我们编译的结果信息存放到work库中。

vlog ../sim/*.v:vlog相当于modelsim工具中的compile,“../sim/*.v ”表示编译05_clk_div_even\sim路径下所有的verilog文件。vlog ../src/*.v表示编译05_clk_div_even /src/路径下的所有verilog文件。

vsim -t  ns  -novopt  +notimingchecks  work.tb_clk_div_even:编译完成所有verilog文件后,就要启动仿真了,vsim就是启动仿真功能,vsim后面有许多关键词,这里简单说明一下,-t表示仿真时间单位为ns,-novopt表示仿真时无优化,+notimingchecks表示无时序检查,work.tb_clk_div_even表示对work库中的tb_clk_div_even进行仿真,实际相当于在界面操作时,展开work库,右键—>Simulate without Optimization,启动仿真。

radix hex :表示要添加wave窗口的信号,以16进制的显示。

add wave–position  insertpoint  sim:/tb_clk_div_even/clk_div_even_inst/*:表示将clk_div_even_inst中的所有信号添加到wave窗口中去,执行这句以后,我们每次仿真时,就不用每次都手动去添加仿真波形了。但是这句话实际是Modelsim生成的,不需要我们自己编写。最开始我们写的do文件是不包含这条语句的,当我们运行到如下图状态时,选择要添加的信号,右键—>add wave后,下面的脚本窗口会弹出相应操作的tcl脚本语句。这样我们把这条语句赋值到我们的do文件中即可。第二次再调用sim.do文件时,就不用再手动添加波形了。


add wave -divider {tb_1111} 添加分割栏,分隔栏上边的文字显示为tb_1111

run –all :  运行全过程。当然也可以运行一段时间。run 10us 表示运行10us。

掌握这些最基本的tcl脚本,使用do文件仿真会为我们节省很多时间。后续的教程里我们都会默认以这种方式进行仿真。当然这里只是介绍了最基本的仿真脚本语言,今后我们仿真时可能还会有第三方的IP核文件,如altera的PLL、FIFO、RAM等需要添加到仿真用例中,这些我们后面在介绍IP核使用时会给大家介绍如何利用do文件仿真含有IP核的设计。

在modelsim的TCL窗口输入do run.do就可以执行代码了


code中状态机名字显示的办法

如下 使用virtual type脚本命令
virtual type { {0x000001 IDLE} {0x000002 INIT_PRE} {0x000004 INIT_PRE_NOP} {0x000008 INIT_REF} {0x000010 INIT_REF_NOP} {0x000020 INIT_MRS} {0x000040 INIT_MRS_NOP} {0x000080 IDLE_REF} {0x000100 IDLE_REF_NOP} {0x000200 RW_LATCH} {0x000400 WR_ACT} {0x000800 WR_ACT_NOP} {0x001000 WR_COL} {0x002000 WR_BURST} {0x004000 WR_END} {0x008000 RD_ACT} {0x010000 RD_ACT_NOP} {0x020000 RD_COL} {0x040000 WAIT_CL} {0x080000 RD_BURST} {0x100000 PRE_CHG} {0x200000 BURST_TERM} {0x400000 PRE_CHG_NOP} } FSM_TYPE

virtual function {(FSM_TYPE)/sdr_tb/uut/sdram_control/state} state6

注释:
1、0x000001 IDLE 前面是状态机的编码,后面是要显示的状态的名称。替换为自己的编码和状态机名称即可。
2、virtual function中“ /sdr_tb/uut/sdram_control/state“路径表示你要替换的状态机变量的路径。


可以将上述内容添加到自己的sim.do文件中。

0 0
原创粉丝点击