ModelSim仿真入门

一、FPGA设计仿真验证简介
严格来讲,FPGA设计验证包括功能仿真、时序仿真和电路验证,它们分别对应整个开发流程的每一个步骤。仿真是指使用设计软件包对已实现的设计进行完整的测试,并模拟实际物理环境下的工作情况。

功能仿真是指仅对逻辑功能进行模拟测试,以了解其实现的功能是否满足原设计的要求,仿真过程没有加入时序信息,不涉及具体器件的硬件特性,如延时特性等,因此又叫前仿真,它是对HDL硬件描述语言的功能实现情况进行仿真,以确保HDL语言描述能够满足设计者的最初意图。

时序仿真则是在HDL可以满足设计者功能要求的基础上,在布局布线后,提取有关的器件延迟、连线延时等时序参数信息,并在此基础上进行的仿真,也成为后仿真,它是接近于器件真实运行状态的一种仿真。
二、仿真软件ModelSim及其应用
HDL的仿真软件有很多种,如VCS、VSS、NC-Verilog、NC-VHDL、ModelSim等,对于开发FPGA来说,一般是使用FPGA厂家提供的集成开发环境,他们都有自己的仿真器,如Xilinx公司的ISE,Altera公司的Quartus II等,但是这些厂家开发的仿真器的仿真功能往往比不上专业的EDA公司的仿真工具,如ModelSim AE(Altera Edition)、ModelSim XE(Xilinx Edition)等。Quartus II设有第三方仿真工具的接口,可以直接调用其他EDA公司的仿真工具,这极大地提高了EDA设计的水平和质量。

ModelSim是Model Technology(Mentor Graphics的子公司)的HDL硬件描述语言的仿真软件,该软件可以用来实现对设计的VHDL、Verilog HDL 或是两种语言混合的程序进行仿真,同时也支持IEEE常见的各种硬件描述语言标准。

无论是从使用界面和调试环境,还是从仿真速度和效果上看,ModelSim都可以算的上是业界比较优秀的HDL语言仿真软件。它是唯一的单内核支持VHDL和Verilog HDL混合仿真的仿真器,是做FPGA/ASIC设计的RTL级和门级电路仿真的好选择,它采用直接优化的编译技术,Tcl/Tk技术和单一内核仿真技术,具有仿真速度快,编译的代码与仿真平台无关,便于IP核的保护和加快错误程序定位等优点。

ModelSim分几种不同的版本:ModelSim SE、ModelSim PE、ModelSim LE和ModelSim OEM,其中的SE、PE、LE是其最高版本,编译速度是所有版本中最快的,而OEM版本就是集成在FPGA厂家设计工具中的版本,它们专门和某个厂家的FPGA配套来使用,如后面使用到的ModelSim AE就是专门针对Altera公司QuartusII的配套的OEM产品。
三、ModelSim的仿真流程
ModelSim不仅可以用于数字电路系统设计的功能仿真,还可以应用于数字电路系统设计的时序仿真。 ModelSim的使用中,最基本的步骤包括创建工程、编写源代码、编译、启动仿真器和运行仿真五个步骤,仿真流程如图1所示:
在这里插入图片描述
这个是基于工程的流程,还有一种是基于库文件的,和基于工程的相比,它需要自己创建工作库,另外关闭ModelSim软件后,下次还得自己手动打开设计文件,而基于工程的就不会这样,工程是一直保持的状态,不用每次启动软件后再手工加载,除非我们自己关掉这个工程。还有另外两个流程,这里不提了,详细内容可参看ModelSim AlteraTutorial.PDF 。在软件的安装目录的DOCS文件夹内是全部的参考文档,包括使用手册等。

四、仿真测试文件(Test Bench)程序的设计方法
随着设计量和复杂度的不断增加,数字验证变得越来越难,所消耗的成本也越来越高,面对这种挑战,验证工程师必须依靠相应的验证工具和方法。对于大型的设计,比如上百万门的设计验证,工程师必须使用一整套规范的验证工具,而对于较小的设计,使用具有HDL Test Bench的仿真器是一个不错的选择。

一般来说,Test Bench使用工业标准VHDL或者Verilog HDL语言来描述,简单的Test Bench通过调用用户设计的功能模块,然后进行仿真,较为复杂的Test Bench还包括一些其他的功能,比如包含特定的激励向量或者进行实际输出与期望的比较等。

在开始写Test Bench之前,很重要的一点就是要设计实例化DUT(Design Under Test,即就是被测元件),还要详细了解整个的测试计划和测试案例。整个的测试Test Bench环境如图2所示:
在这里插入图片描述
从图中可以看见,Test Bench和被测对象Counter构成了一个封闭的循环,Test Bench负责向被测元器件的输入端口提供激励(时钟)和一些控制信号(复位和置位信号),另外Test Bench还监测被测元器件的输出端口所输出的信号值是否和我们的设计预期相符,并把监测的情况显示给我们。

由于Test Bench程序和被测对象构成了一个封闭的循环,因此Test Bench的输入端口需要与被测对象的输出端口连接,Test Bench的输出端口则要与被测对象的输入端口相连接。所以在端口的定义上,Test Bench程序需要和被测对象相对应。

被测元器件是一个已经设计好的电路或系统,Test Bench是用元件例化语句将其嵌入程序中。VerilogHDL测试平台是一个设有输入输出端口的设计模块,被测元器件的输入端定义为reg(寄存器)型变量,在always块或initial块中赋值(产生测试条件),被测元器件的输出端定义为wire(线网)型变量,产生相应输入变化的输出结果(波形)。

4.1 组合逻辑电路Test Bench的设计
组合逻辑的设计验证,主要就是检查设计结果是不是符合该电路的真值表功能,因此在编写组合逻辑Test Bench时,用initial块把被测电路的输入按照真值表提供的数据变化作为测试条件,就能实现Test Bench的设计。

例1. 编写一位全加器的Test Bench程序
全加器的A和B两个是1位二进制加数的输入端,CI是低位来的进位输入端,CO是向高位进位的输出端,SO是全加器的本位和值。

用Verilog HDL语言编写的全加器程序adder.v如下:

//adder.v
module adder(
a 	,
b 	,         //a,b为输入变量
ci  ,
so  ,
co
);

// 定义端口
input a;
input b;
input ci;
output so;
output co;

//定义变量
wire     a;
wire     b;
wire     ci;
wire     so;
wire     co;
//CodeStarts Here

assign {co, so} = a + b + ci;

endmodule

根据全加器的真值表写的全加器的Test Bench程序test_adder1.v如下:

//testbeach_adder.v

`timescale 1ns/1ns

module testbeach_adder;

wire so;
wire co;
reg a;
reg b;
reg c;
adder U(

          .a(a),

          .b(b),

          .ci(c),

          .so(so),

          .co(co)

          );

   

initial
begin

          #20 a = 0; b = 0; c = 0;

          #20 a = 0; b = 0; c = 1;

          #20 a = 0; b = 1; c = 0;

          #20 a = 0; b = 1; c = 1;

          #20 a = 1; b = 0; c = 0;

          #20 a = 1; b = 0; c = 1;

          #20 a = 1; b = 1; c = 0;

          #20 a = 1; b = 1; c = 1;

          #200 $stop;

end

endmodule

test beach代码分析:
①首先看程序第二行的timescale1ns/1ns这句代码,这个是时间尺度指令,它是用来定义模块的仿真时间单位和时间精度的,其使用格式为:timescale 仿真时间单位/时间精度,用于说明仿真时间单位和时间精度的数字只能是1、10或100,不能为其它的数字,单位可以是s、ms、us、ns、ps和fs。仿真时间单位是指的模块仿真时间和延时的基准单位,也就是说只有定义了仿真时间单位,程序中的延时符号"#"才有意义,如程序中的一行 #20 a = 0; b = 0; c = 0; 前面的 #20 就是延时20个时间基准单位,按照程序中的1ns这个基准,就延时了20个ns。需要说明的是该行程序的下一行 #20 a =0; b = 0; c = 1; 前面的延时20个ns是相对于前一个的延时来说的,也就是第二行在第一行完了之后延时20ns执行。这时候再看看仿真的波形图就不难理解最开始的线为什么是红色而不是正常的绿色的原因了,因为我们在程序中begin的下一行就是 #20 a =0; b = 0; c = 0; 它前面的延时20个ns是相对于begin的延时,也就是说程序开始的时候是什么都不做的,输出为不确定的值,过了20个ns才将全0赋给了a、b和ci,这个时候才是最开始的绿线的部分。

②在Test Bench程序中,把全加器的输入a、b和ci定义为了reg型变量,把输出so和co定义为了wire型变量,这个和被测元件的定义情况刚好是反的,这样也说明了TestBench程序和被测元件是封闭的一个循环。用元件例化语句adder U( .a(a), .b(b), .ci(ci), .so(so), .co(co) ) ; 把全加器设计电路嵌入到Test Bench程序中。

③程序的后面有一句 #200 $stop; 这个是一个系统任务,用来暂停仿真过程的,将控制权交还给用户,用户在取得控制权以后可以输入其它的控制命令或者查看仿真结果等,之后可以从暂停的地方恢复仿真过程。$stop有两种表达形式,带参数的和不带参数的:
$stop;
$stop(n); //n可以取0、1或2
不带参数的$stop等同于$stop(0),在暂停时不输出任何信息;$stop(1)在暂停时输出当前仿真时刻和暂停处在程序中的位置;$stop(2)不仅有$stop(1)的作用,还能输出仿真时占用内存大小和CPU时间。
而用于退出仿真过程的系统任务是 $finish,我们在点击Run(开始运行)的时候,系统会询问我们是否要结束仿真,假如我们选"是",这个系统任务会把ModelSim软件在完成仿真后关闭,假如我们选"否",则可以继续留在仿真界面。

和一位全加器的真值表进行全部的对比后发现和该仿真波形完全一致,仿真结束。

下面进行功能仿真:
实验步骤如下:

  1. 打开ModelSim软件
    
  2. 软件的启动画面如图2所示,进入界面后如图3所示:
    

在这里插入图片描述
在这里插入图片描述
3. 进入ModelSim主窗口后,选择File菜单下的"New→Project",新建一个工程,在弹出的对话框中,给该工程命名并指定一个存放的路径,如图4所示:
在这里插入图片描述
在这里,工程名和你的顶层文件名保持一致是推荐的做法。路径的注意事项已经说过,这里不再提及。默认的库名就是"work",这个无需更改,点击"OK"即可。
4. 之后会弹出如图5的对话框,选择是新建一个文件还是添加已存在的文件,这两个都可以选择,假如事先编好了文件,就选择添加进来,假如没有就新建。在这里使用添加已有文件,在软件开始之前就编好所用的程序,这样比较方便些。软件自带的编辑环境不是很好,使用第三方的编辑工具是推荐的方法。建议使用UltraEdit或Notepad++这些专业的代码编辑软件。

UltraEdit偏重于功能的强大和丰富的用户可定制化特性,而Notepad++更加注重易用性。两者在普通在这里插入图片描述功能上差异不是特别大,根据自己的喜好选择一款即可。
我这里就选择上面已经写好的程序
在我的桌面

在这里插入图片描述
添加后:
在这里插入图片描述
然后选中文件右击:
在这里插入图片描述
如果没出错:
在这里插入图片描述
然后点击到libarry中:
在这里插入图片描述
接着:
在这里插入图片描述
调整一下:
在这里插入图片描述
ok
来看看效果:
在这里插入图片描述

发布了69 篇原创文章 · 获赞 28 · 访问量 9886

猜你喜欢

转载自blog.csdn.net/weixin_44146373/article/details/104319617
今日推荐