1)实验平台:正点原子新起点V2开发板
2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113
2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html
3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016
4)关注正点原子公众号,获取最新资料更新
第五章Modelsim软件的安装和使用
Mentor公司的ModelSim是工业界最优秀的语言仿真器,它支持Windows和Linux系统,是单一内核支持VHDL和Verilog混合仿真的仿真器。它采用直接优化的编译技术、单一内核仿真,不仅编译仿真速度业界最快、编译的代码与平台无关,而且便于保护IP核。它还提供了最友好的调试环境,具有个性化的图形界面和用户接口,为用户加快调试提供强有力的手段,它是FPGA/ASIC设计的首选仿真软件。
本章包括以下几个部分:
55.1Modelsim的安装
5.2Modelsim的使用
5.1Modelsim的安装
Modelsim有几种常见的版本:SE(System Edition)、PE(Personal Edition)和OEM(Orignal Equipment Manufactuce,即原始设备制造商),其中SE是最高级的版本,而集成在Altera、Xilinx以及Lattice等FPGA厂商设计工具中的均是OEM版本。我们这里选择使用的是功能最全的SE版本。
首先在新起点FPGA开发板资料盘(B盘)→Modelsim文件夹下找到Modelsim的安装包文件(注意:由于光盘容量有限,我们将FPGA开发软件Quartus II和仿真软件Modelsim放在B盘),文件列表如下图所示:
图 5.1.1 Modelsim安装包文件夹
双击运行“modelsim-win64-10.4-se.exe”文件,进入如图 5.1.2所示的modelsim软件的安装引导页面。
图 5.1.2 安装引导页面
我们直接点击【Next>】,进入如图 5.1.3所示页面。
图 5.1.3 选择安装路径
为了不占用系统盘空间和有条理的管理电脑安装的软件,这里我们不使用默认的安装路径,更改安装路径到D盘,如上图所示。
接下来点击【Next>】,弹出下图所示界面
图 5.1.4 创建安装目录
这是因为D盘下面没有该目录,所以我们点击“Yes”,创建该目录。然后进入下图所示界面。
图 5.1.5 协议认同
选择“Agree”,进入下图所示页面。
图 5.1.6 自动安装过程中
现在处于安装过程,在安装的过程中会出现两次信息提示框,第一次提示是否在桌面建立快捷方式,点击“Yes”,如下图所示:
图 5.1.7 桌面建立快捷方式
第二次提示是否将Modelsim可执行文件放入Path变量,选择“Yes”时可以从DOS提示符执行Modelsim,这里我们选择“Yes”,如下图所示:
图 5.1.8 添加Modelsim到Path变量
安装完成后进入下图所示界面,大致内容为:如果你有License,请选择“No”,选择“Yes”将会为Modelsim-64使用的HW安全key安装一个软件驱动,如果你不确定你电脑上的驱动是否适用于此版本,选择“Yes”会重启电脑完成整个安装。这里因为有License,所以选择“No”,当然了如果经过整个的指导操作还是使用不了,不妨卸载了选择“Yes“试试,一般选择“No“是没问题的。
图 5.1.9 安装硬件安全Key驱动
进入下图所示界面,选择“Done”完成整个安装。
图 5.1.10 完成安装
如果没有License或没有正确安装License,打开Modelsim时,结果如下:
图 5.1.11 未安装License时结果
使用Modelsim软件需要添加License,请多多支持正版。至此,Modelsim安装完成。
5.2Modelsim的使用
安装完ModelSim软件之后,接下来我们再来介绍一下ModelSim的使用流程。在介绍ModelSim的使用流程之前,我们先看一下典型的FPGA设计流程,流程图如下:
图 5.2.1 FPGA的设计流程
从上图可以看到,在设计输入之后,设计综合前进行RTL级仿真,称为综合前仿真,也称为前仿真或功能仿真。前仿真也就是纯粹的功能仿真,主旨在于验证电路的功能是否符合设计要求,其特点是不考虑电路门延迟与线延迟。在完成一个设计的代码编写工作之后,可以直接对代码进行仿真,检测源代码是否符合功能要求。这时,仿真的对象为HDL代码,可以比较直观的观察波形的变化,在设计的最初阶段发现问题,节省大量的精力。
在布局布线后进行的仿真称为布局布线后仿真,也称为后仿真或时序仿真。时序仿真可以真实地反映了逻辑的时延与功能,综合考虑电路的路径延迟与门延迟的影响,验证电路能否在一定时序条件下满足设计构想的过程,是否存在时序违规。
接下来我们说一下ModelSim软件的使用,ModelSim的使用主要分为两种情况,第一种就是直接使用ModelSim软件进行仿真,也就是手动仿真;第二种情况就是通过其它的EDA工具如Quartus II调用Modelsim进行仿真,这种情况也就是我们通常所说的自动仿真或者联合仿真。不管是手动仿真还是自动仿真,它们都遵循以下5个步骤:
1)新建工程。
2)编写Verilog文件和Testbench仿真文件。
3)编译工程
4)启动仿真器并加载设计顶层
5)执行仿真。
当我们执行了仿真以后,ModelSim软件会根据我们的设计文件和仿真文件生成波形图,最后,我们观察波形并判断设计的代码功能是否正确。前仿真完成以后,接下来我们就可以根据需要进行后仿真了,后仿真与前仿真的步骤大体相同,只不过中间需要添加仿真库、网表和延时文件等步骤。一般而言,对于时序要求不严格的小规模设计,我们一般只进行功能仿真。
功能仿真需要的文件:
1)设计HDL源代码:可以使VHDL语言或Verilog语言。
2)测试激励代码,也被称为TestBench:根据设计要求输入/输出的激励程序,由于不需要进行综合,书写具有很大的灵活性。
3)仿真模型/库:根据设计内调用的器件供应商提供的模块而定,如:FIFO、ADD_SUB等。
5.2.1手动仿真
说完了ModelSim的使用流程,接下来我们将对每个流程进行详细的操作演示,一步步、手把手带领大家学习使用ModelSim软件。首先我们讲解的是ModelSim手动仿真,对Modelsim有个基本的认识。
在第四章我们使用Quartus创建了LED流水灯的工程,现在我们使用Modelsim对该工程进行Modelsim的手动仿真。
5.2.1.1建立Modelsim工程并添加仿真文件
首先在LED流水灯的“sim”文件夹下新建文件夹“tb”,然后启动Modelsim软件,我们直接双击桌面上的Modelsim软件图标,打开Modelsim软件,在Modelsim中选择File->Change Directory,如下图所示:
图 5.2.2更改目录
在弹出的对话框中选择目录路径为刚才新建的tb文件夹。
在modelsim中建立project,选择File->New->Project,如下图所示:
图 5.2.3创建工程
弹出如下界面:
图 5.2.4编辑工程名和路径
在“Project Name”栏中填写工程名,这里的命名方式,我们建议大家最好根据仿真的文件来进行命名,时间久了,当我们记不得这个仿真工程是用来仿真什么的时候,我们看到这个工程名,就能够知道它是用来做什么的了。这里我们把工程命名为“flow_led_tb”,也就是在流水灯模块名“flow_led”后面添加“_tb”。“Project Location”是工程路径,可以根据需要把工程保存到不同的位置。因为前一步骤更改目录的时候已经做了选择,所以这里保持默认即可。下面这两部分是用来设置仿真库名称和路径的,这里我们使用默认即可。设置好工程名、工程位置,我们点击【OK】按钮,弹出如下图所示界面:
图 5.2.5添加和创建工程文件
我们可以从该图的选择窗口中看出,它共有四种操作:Create New File(创建新文件)、Add Existing File(添加已有文件)、Create Simulation(创建仿真)和 Create New Folder(创建新文件夹)。这里我们先选择“Add Existing File”(添加已有文件),如下图所示:
图 5.2.6添加工程文件
在该页面我们点击“Browse”按钮选择“flow_led.v”文件,其他的保持默认设置,最后点击【OK】按钮。
5.2.1.2建立TestBench仿真文件
我们选择“Create New File”(创建新文件),如下图所示:
图 5.2.7创建工程文件
在“File Name”栏中输入文件名“flow_led_tb”,与工程名一致。“Add file as type”栏中选择文件类型为“Verilog”类型,点击【OK】按钮,然后我们再关闭【Add items to the Project】对话框。此时可以看到,两个文件“flow_led.v”和“flow_led_tb.v”添加至我们的ModelSim仿真工程中,如下图所示。
图 5.2.8成功添加工程文件
双击“flow_led_tb.v”文件,弹出下图所示界面:
图 5.2.9编写测试代码
在其中编写TestBench仿真代码如下:
1 `timescale 1ns/1ns // 定义仿真时间单位1ns和仿真时间精度为1ns
2
3 module flow_led_tb(); // 测试模块
4
5 //parameter define
6 parameter T = 20; // 时钟周期为20ns
7
8 //reg define
9 reg sys_clk; // 时钟信号
10 reg sys_rst_n; // 复位信号
11
12 //wire define
13 wire [3:0] led;
14
15 //*****************************************************
16 //** main code
17 //*****************************************************
18
19 //给输入信号初始值
20 initial begin
21 sys_clk = 1'b0;
22 sys_rst_n = 1'b0; // 复位
23 #(T+1) sys_rst_n = 1'b1; // 在第21ns的时候复位信号信号拉高
24 end
25
26 //50Mhz的时钟,周期则为1/50Mhz=20ns,所以每10ns,电平取反一次
27 always #(T/2) sys_clk = ~sys_clk;
28
29 //例化flow_led模块
30 flow_led u0_flow_led (
31 .sys_clk (sys_clk ),
32 .sys_rst_n (sys_rst_n),
33 .led (led )
34 );
35
36 endmodule
编写完成后,单击下图所框的保存按钮。
图 5.2.10保存测试代码
为了让读者能够更好的理解,这里我们就简单介绍一下TestBench源代码。进行仿真首先要规定时间单位,我们建议大家最好在Testbench里面统一规定时间单位,不要在工程代码里定义,因为不同的模块如果时间单位不同可能会为仿真带来一些问题。代码的第1行的timescale是Verilog语法中的不可综合语法,用于定义仿真的时间单位和精度,此处表示仿真的单位时间为1ns,精度为1ns。代码的第3行就是TestBench的模块名定义,第5行设置时钟的周期,50MHz时钟对应周期为20ns,其中第9行至第13行是我们的数据类型定义,到了第20~24行是信号的初始化,第27行是时钟信号的生成。第30行是被测模块的调用。
接下来我们就需要编译我们的仿真文件。
在开始编译之前,有一点需要注意,我们在Quartus II软件中实现的功能是LED流水灯效果,它的间隔时间是0.5s,如果我们想要仿真这个功能,那么我们仿真软件运行时间最低就是0.5s。这0.5s在我们看来是很短很短的,而对仿真软件来说是很漫长的,毕竟我们的仿真时间单位可是1ns。为了便于我们仿真,这里我们需要稍微改动一下“flow_led.v”文件的代码,将计时器cnt的最大计时值设为10,如下图所示,方框中注释的代码即为修改的位置。
图 5.2.11修改源文件
要记得这是在仿真的时候修改的哦,在仿真结束后是要改回来的,接下来我们开始编译。
5.2.1.3编译仿真文件
编译的方式有两种:Compile Selected(编译所选)和Compile All(编译全部)。编译所选功能需要先选中一个或几个文件,执行该命令可以完成对选中文件的编译;编译全部功能不需要选中文件,该命令是按编译顺序对工程中的所有文件进行编译。我们可以在菜单栏【Compile】中找到这两个命令,也可以在快捷工具栏或者在工作区中的右键弹出的菜单中找到这两个命令。下面我们单击Compile All(编译全部),如下图所示。
图 5.2.12编译工程
编译完成后,结果如下图所示:
图 5.2.13编译完成
文件编译后“Status”列可能会有三个不同状态。除了上图的用“√”表示的通过状态外,还有两个在设计中不希望出现的状态:编译错误(显示红色的“×”)和包含警告的编译通过(对号的后面会出现一个黄色的三角符号)。编译错误即Modelsim无法完成文件的编译工作。通常这种情况是因为被编译文件中包含明显的语法错误,Modelsim会识别出这些语法错误并提示使用者,使用者可根据Modelsim的提示信息进行修改。编译结果中包含警告信息是一种比较特殊的状态,表示被编译的文件没有明显的语法错误,但是可能包含一些影响最终输出结果的因素。这种状态在实际使用中较少出现,这类信息一般在功能仿真的时候不会带来明显的影响,不过可能会在后续的综合和时序仿真中造成无法估计的错误,所以出现这种状态时推荐读者也要根据警告信息修改代码,确保后续使用的安全性。
5.2.1.4配置仿真环境
编译完成后,接下来我们就开始配置仿真环境,我们在ModelSim菜单栏中找到【Simulate】→【Start Simulation…】菜单并点击,弹出如下右图所示页面。
图 5.2.14开始仿真
从配置仿真功能页面中我们可以看出,该页面中包含6个标签,分别是:Design、VHDL、Verilog、Libraries、SDF和Others。对于这6个标签,我们用的最多的是Design、Libraries和SDF这三个标签了,下面我们就来简单的介绍一下这3个标签,其余的标签我们一般用不到,这里我们就不再进行介绍了。
首先看一下Design标签,该标签内居中的部分是Modelsim中当前包含的全部库,可展开看到库中包含的设计单元,这些库和单元是为仿真服务的,使用者可以选择需要进行仿真的设计单元开始仿真,此时被选中的仿真单元的名字就会出现在下方的Design Unit(s)位置。Modelsim支持同时对多个文件进行仿真,可以使用Ctrl和Shift键来选择多个文件,被选中的全部文件名都会出现在Design Unit(s)区域。在Design Unit(s)区域的右侧是Resolution选项,这里可以选择仿真的时间精度。在Modelsim进行仿真的时候,有一个最小的时间单位,这个单位是使用者可以指定的,如最小单位是1ns,仿真器在工作的时候按1ns为单位进行仿真,对小于1ns发生的信号变化不予考虑或不予显示。因而这个最小时间单位也就是仿真的时间精度。这个选项一般都是设置在默认状态,这时Modelsim依照仿真设计文件中指定的最小时间刻度来进行仿真,如果设计文件中没有指定,则按1ns来进行仿真。最下方的区域是Optimization区域,可以在仿真开始的时候使能优化。接下来我们来看一下Libraries标签,如下图所示。
图 5.2.15 Libraries标签
在该标签中,我们可以设置搜索库。Search Libraries和Search Libraries First的功能基本一致,唯一不同的是Search Libraries First中指定的库会在指定的用户库之前被搜索。现在我们来看一下SDF标签,如下图所示。
SDF是Standard Delay Format(标准延迟格式)的缩写,内部包含了各种延迟信息,也是用于时序仿真的重要文件。SDF Files区域用来添加SDF文件,可以选择Add按钮进行添加,选择Modify按钮进行修改,选择Delete按钮删除添加的文件。
图 5.2.16 SDF标签
SDF Options区域设置SDF文件的warning和error信息。第一个“Disable SDF warning”是禁用SDF警告,第二个“Reduce SDF errors to warnings”是把所有的SDF错误信息变成警告信息。区域Multi-Source delay中可以控制多个目标对同一端口的驱动,如果有多个控制信号同时控制同一个端口或互连,且每个信号的延迟值不同,可以使用此选项统一延迟。下拉列表中可供选择的有三个选项:latest、min和max。latest选项选择最后的延迟作为统一值,max选项选择所有信号中延迟最大的值作为统一值,min选项选择所有信号中延迟最小的值作为统一值。
至此,这三个标签我们就介绍完了,接下来我们在Design标签页面中选择work库中的flow_led_tb模块,在Optimization一栏中取消勾选(注意一定要取消优化的勾选,否则无法观察信号波形),然后点击【OK】就可以开始进行功能仿真了,其余标签页面中的配置我们使用默认就可以了,如下图所示。
图 5.2.17 Design窗口选项
点击【OK】后弹出下图所示界面:
图 5.2.18 Sim窗口
鼠标右键单击“u0_flow_led”,选择“Add Wave”选项,如下图所示:
图 5.2.19添加查看的信号
弹出下图所示界面,可以看到信号已经添加到窗口中。
图 5.2.20信号添加到仿真窗口
我们选择仿真时间为1ms,如下图所示,单击右边的运行按钮。
图 5.2.21设置仿真时间
运行后的结果如下图所示:
图 5.2.22仿真结果
为了方便大家更容易观察波形,我们这里将会对ModelSim软件中几个常用小工具进行简单的讲解。
图 5.2.23常用小工具
前面的几个放大镜模样的工具是放大、缩小和全局显示功能,鼠标放到图标上会显示出它们的快捷键,后边的黄色图标是用来在波形图上添加用来标志的黄色竖线,紧跟着的是将添加的黄色竖线对齐到信号的下降沿和上升沿。利用上述工具出来,可以看到在仿真结果中,当计时器cnt计到4时,led[0]由高电平变低电平,计时器cnt计到10时led[1]由低电平变成高电平,且cnt清零,形成了最初流水态,与预设的功能相同。
图 5.2.24结果局部波形图
到这里手动仿真的步骤就给大家介绍完了,最后再提醒大家一句,我们在仿真一些复杂的工程的时候往往需要对工程里的IP核进行仿真,当我们需要对IP核进行仿真时一定要事先将IP核的库文件加载到Modelsim库中去。具体加载方法在实战篇的PLL锁相环实验中有详细讲解。
5.2.2自动仿真(联合仿真)
所谓自动仿真,其实是在Quartus II中调用ModelSim软件来进行仿真,所以也称联合仿真。在调用过程中,Quartus II会帮我们完成ModelSim中的所有操作,我们只需要分析最后的仿真结果。下面我们就以“Quartus II安装和使用”章节中我们创建的Quartus II软件工程为例,进行仿真。
5.2.2.1选择EDA仿真工具
首先我们打开之前的Quartus II工程,在菜单栏中找到【Tool】→【Options】按钮,如下图所示:
图 5.2.25选择Options选项
单击此按钮,在打开的页面左侧我们找到“EDA Tool Options”点击,如下图所示页面。.
图 5.2.26添加Modelsim路径
在该页面中,ModelSim这一栏,我们需要设置ModelSim的安装路径下的可执行文件的路径,路径设置完成以后,我们点击【OK】返回我们的Quartus II软件界面。
我们在Quartus II软件页面的菜单栏中,我们找到【Assignments】→【Settings】按钮,如下图所示页面。
图 5.2.27选择Settings选项
单击此按钮,在打开的页面左侧我们找到“EDA Tool Settings”点击,如下图所示页面。
图 5.2.28选择Modelsim仿真
我们之前创建工程的时候,由于在Quartus II软件中没有用到仿真,所以我们将这里设置成了“None”,现在我们需要用到仿真工具了,我们需要在这里将“Simulation”设置成“ModelSim、Verilog HDL”。设置完成之后,我们点击【OK】返回Quartus II软件页面中。
5.2.2.2编写TestBench
接下来就是编写仿真文件了,由于我们在手动仿真中已经编写好了,就不用再编写了。不过我们还是介绍一下如何使用Quartus II软件生成TestBench模板,方便编写仿真文件。
在Quartus II软件页面的菜单栏中,我们找到【Processing】→【Start】→【Start TestBench Template Writer】按钮,如下图所示:
图 5.2.29生成TestBench模板
并点击该按钮,这时Message窗口中会显示,如下图所示:
图 5.2.30生成TestBench模板结果图
从画横线处我们可以看到Quartus II软件已自动给我们生成了一个TestBench模板并显示该模块的存放路径,我们只需要找到这个模板并稍作修改就能直接使用了。我们在工程目录下找到“flow_led.vt”文件,用记事本或Quartus II软件打开它进行修改,这里我们在Quartus II软件中进行,打开后如下图:
图 5.2.31 TestBench模板内容
在该图中我们可以看到,Quartus II软件已经为我们完成了一些基本工作,包括端口部分的代码、变量的声明以及例化测试的工程等,我们要做的就是在这个模板里添加我们需要的测试代码(也就是我们常说的激励)。eachvec和@eachvec是多余的信号,没有特殊的作用,我们可以将它删除也可以不删。修改后的代码如下:
1 `timescale 1 ns/ 1 ns
2 module flow_led_tb();
3 // constants
4 // general purpose registers
5 // test vector input registers
6 reg sys_clk;
7 reg sys_rst_n;
8 // wires
9 wire [3:0] led;
10
11 // assign statements (if any)
12 flow_led i1 (
13 // port map - connection between master ports and signals/registers
14 .led(led),
15 .sys_clk(sys_clk),
16 .sys_rst_n(sys_rst_n)
17 );
18 initial
19 begin
20 sys_clk = 1'b0;
21 sys_rst_n = 1'b0; // 复位
22 #100 sys_rst_n = 1'b1; // 在第100ns的时候复位信号拉高
23 #1000 $stop;
24 end
25
26 always #10 sys_clk = ~sys_clk;
27
28 endmodule
修改后将其另存为flow_led_tb.vt,以保持文件名与模块名一致。
5.2.2.3配置仿真环境
接下来我们需要在Quartus II软件中配置仿真环境,我们在Quartus II软件界面的菜单栏找到【Assigement】→【Settings】按钮并打开,在打开的页面中,我们找到左侧的Simulation点击,出现如下图所示的页面。
图 5.2.32配置仿真环境
我们选中“Compile Test bench”,然后单击后面的【Test Benches】按钮,则出现如下图所示的“Test Benches”窗口:
图 5.2.33添加Test Benche
接着我们单击【New】按钮,则会出现如下图所示的“New Test Bench Settings”窗口:
图 5.2.34设置Test Benche模块名
在该页面,我们将TestBench文件名输入到“Test bench name”,将TestBench顶层模块名输入到“Top level module in test bench”的编辑栏中,因为一般而言TestBench文件名和顶层模块名相同,所以这里只用在“Test bench name”这一栏输入即可,软件自动同步添加“Top level module in test bench”。接着我们在“Test bench and simulation files”列表框中添加TestBench仿真文件,这里我们选择Quartus II生成的TestBench模板文件“flow_led_tb.vt”。当然了,也可以选择在手动仿真节里编写的“flow_led_tb.v”文件。添加仿真文件如下图:
图 5.2.35添加Test Bench结果图
然后单击【Add】按钮添加到最下面的列表中。完成后我们单击【OK】按钮,便可看到下图所示的“Test benches”窗口的列表中出现了刚才添加的仿真文件相关信息。
图 5.2.36成功添加Test Bench
然后单击【OK】按钮,至此,我们仿真文件添加完成了,接着我们单击【OK】按钮,返回到Quartus II软件界面。
5.2.2.4运行RTL仿真(功能仿真)
我们在Quartus II软件界面中的菜单栏中找到【Tools】→【Run Simulation Tool】→【RTL Simulation】按钮,如下图所示界面。
图 5.2.37开始RTL仿真
单击此按钮,则会出现如下图所示的波形图界面。
图 5.2.38 RTL仿真结果图
在该软件启动过程中,我们不需要任何操作,它会自动完成仿真,并给出我们所需要的波形。从下图可以看到在310ns时led[0]由高电平变成低电平,led[1]由低电平变成高电平,形成了最初的流水态,然后经过220ns led[1]由高电平变成低电平,led[2]由低电平变成高电平。可能有读者会问为什么是220ns而不是200ns呢。这是因为计时器从0计到10共11个时钟周期,历经220ns。
图 5.2.39仿真结果局部图
至此,Modelsim的基本使用就讲完了。
5.2.2.5testbench(激励)文件讲解
Modelsim的手动仿真在项目开发中是比较常用的,此时需要手动编写testbench文件。对于初学者来说,可能觉得编写testbench文件比较困难,但其实并没有想象的那么复杂,我们只需要按照testbench的结构,编写基本的激励文件还是比较容易的。当编写完testbench文件后,如果以后需要仿真其它模块的话,只需要在此基础上稍作修改即可。
编写testbench文件的主要目的是为了对使用硬件描述语言(Verilog HDL或者VHDL)设计的电路进行仿真验证,测试设计电路的功能、部分性能是否与预期的目标相符。
基本的testbench结构如下:
timescale 仿真单位/仿真精度 module test_bench(); //通常testbench没有输入与输出端口 信号或变量定义声明 使用initial或always语句产生激励波形 例化设计模块 endmodule 1)声明仿真的单位和精度 激励文件的开头要声明仿真的单位和仿真的精度,声明的关键字为timescale,声明方法如下:
timescale 1 ns/ 1 ns
需要注意的是,timescale声明仿真单位和精度时,不需要以分号结尾。“/”之前的1ns表示仿真的单位是1ns,“/”之后的1ns表示仿真的精度是1ns。当代码中出现“#10”时,代表的意思是延时10ns,由于仿真的精度为1ns,所以最低的延时精度只能到1ns,如果想要延时10.001ns,则需要更改仿真的精度(1ns=1000ps),代码如下:
`timescale 1ns/1ps
#10.001 rst_n = 0;
2)定义模块名
仿真的单位和精度声明完成后,接下来定义模块名,定义模块名的关键字为module,代码如下:
module flow_led_tb();
模块名的命名方式一般在被测模块名后面加上“tb”,或者在被测模块名前面加上“tb”,表示为哪个模块提供激励测试文件,通常激励文件不需要定义输入和输出端口。
3)信号或变量定义
代码中定义的常量有时需要频繁的修改,为了方便修改,可以把常量定义成参数的形式,定义参数的关键字为parameter,代码如下:
parameter T = 20;
Verilog代码中,常用声明信号或变量的关键字为reg和wire,在initial语句或者always语句中使用的变量定义成reg类型,在assign语句或者用于连接被例化模块名的信号定义成wire类型,声明方法如下:
//reg define
reg sys_clk; // 时钟信号
reg sys_rst_n; // 复位信号
//wire define
wire [3:0] led;
4)使用initial或always语句产生激励波形
产生时钟激励的代码如下:
always #10 sys_clk = ~sys_clk;
上述代码表示每10ns(假设仿真单位是1ns),sys_clk的电平状态翻转一次,由于一个完整的时钟周期包括一个高电平和一个低电平,因此sys_clk的时钟周期为20ns,占空比为50%。如果要生成其它占空比时钟的话,代码如下:
always begin
#6 sys_clk = 0;
#4 sys_clk = 1;
end
需要注意的是,在always语句中设置了sys_clk的时钟周期,并没有设置初始值,因此sys_clk需要在initial语句中进行初始化。代码如下:
initial begin
sys_clk = 1'b0; // 时钟初始值
sys_rst_n = 1'b0; // 复位初始值
#20 sys_rst_n = 1'b1; // 在第21ns的时候复位信号信号拉高
end
5)例化设计模块
例化的设计模块是指被测模块,例化被测模块的目的是把被测模块和激励模块实例化起来,并且把被测模块的端口与激励模块的端口进行相应的连接,使得激励可以输入到被测模块。如果被测模块是由多个模块组成的,激励模块中只需要例化多个模块的顶层模块,代码如下:
flow_led u0_flow_led (
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.led (led )
);
在实例化模块中,左侧带“.”的信号为flow_led模块定义的端口信号,右侧括号内的信号为激励模块中定义的信号,其信号名可以和被测模块中的信号名一致,也可以不一致,命名一致的好处是便于理解激励模块和被测模块信号之间的对应关系。在实例化被测模块后,以endmodule结束。
完整的testbench文件代码如下:
1 `timescale 1ns/1ns // 定义仿真时间单位1ns和仿真时间精度为1ns
2
3 module flow_led_tb(); // 测试模块
4
5 //parameter define
6 parameter T = 20; // 时钟周期为20ns
7
8 //reg define
9 reg sys_clk; // 时钟信号
10 reg sys_rst_n; // 复位信号
11
12 //wire define
13 wire [3:0] led;
14
15 //*****************************************************
16 //** main code
17 //*****************************************************
18
19 //给输入信号初始值
20 initial begin
21 sys_clk = 1'b0;
22 sys_rst_n = 1'b0; // 复位
23 #(T+1) sys_rst_n = 1'b1; // 在第21ns的时候复位信号信号拉高
24 end
25
26 //50Mhz的时钟,周期则为1/50Mhz=20ns,所以每10ns,电平取反一次
27 always #(T/2) sys_clk = ~sys_clk;
28
29 //例化flow_led模块
30 flow_led u0_flow_led (
31 .sys_clk (sys_clk ),
32 .sys_rst_n (sys_rst_n),
33 .led (led )
34 );
35
36 endmodule
事实上,用于仿真的关键字比较多,有些是可以综合的(能生成实际的电路),有些只能用于仿真,这里仅介绍testbench文件常用的关键字和基本的编写方法。