编写RTL功能代码

    要进行功能仿真,首先得用需要仿真的模块,也就是RTL功能代码,简称待测试的模块,该模块也就是在设计下载到FPGA的电路。一个电路模块想要有输出,就得有输出,数字电路也是一样的,时钟和复位信号是必不可少的测试激励信号之一,同时可能还包括控制信号、数据信号。这里总结一下,一般系统中包括的测试激励信号主要为四大类:

  1. 系统信号(时钟、时钟使能信号、复位信号等);
  2. 控制信号(使能信号、片选信号、握手信号,状态机控制信号等);
  3. 数据信号(并行接口数据信号、串行接口数据信号等);
  4. 地址信号(模块的地址信号、内部寄存/存储器地址信号等)。

 

而对于测试结果,在放在不同的测试激励信号的条件下分析,不同的测试激励产生相应的测试结果,通过分析就可以知道相应的测试结果与目标结果是否一致,如果不一致便进行RTL的修改,如果一致则修改测试激励信号,遍历完不同情况下的测试激励,完成整体100%的功能测试,才能确保RTL功能模块的设计功能完整性。

这里需要注意一点,功能仿真正确不一定能确保最后综合、布局布线后下载到FPGA产生的功能结果正确,但是功能仿真不正确,FPGA产生的功能结果一定不正确!所以功能仿真是很必要的!

基于modelsim-SE的简单仿真流程—上

    本实验需要设计一个8bit的计数器,功能很简单,该计数器在每个时钟的上升沿进行加一并将结果输出,当计数到255的时候返回到0重新计数,以此循环,模块接口如下所示。

测试激励信号是时钟和复位信号,时钟信号为50M,复位信号为低电平有效。测试结果为8bit的计数值,范围为0~255,如果从波形上看是一个锯齿波。

基于modelsim-SE的简单仿真流程—上

 

module counter(

clk,

reset_n,

counter_out

);

input clk;

input reset_n;

output [7:0]counter_out;

reg [7:0]counter_reg;

assign counter_out = counter_reg;

always @(posedge clk or negedge reset_n)

begin

if(reset_n == 1'b0)

begin

counter_reg <= 8'd0;

end

else

begin

counter_reg <= counter_reg + 1'b1;

end

end

endmodule

 

编写testbench代码

    TestBench基本概念:测试激励->待测RTL功能模块->观察比对波形/在终端打印或生产文本/自动对比输出结果。

 

TestBench编写三步曲

  1. 对被测试设计的顶层接口进行例化;
  2. 给被测试设计的输入接口添加激励信号;
  3. 判断被测试设计的输出想要是否满足设计要求;

 

TestBench内容主要分为

  1. 时钟的产生;
  2. 复位的产生;
  3. 控制信号的产生;
  4. 其他激励信号的产生(用户自定义 )。

 

    相应于被测试模块的输入激励设置为reg型,输出相应设置为wire类型,双向端口inout在测试中需要进行处理。

    双向端口inout的设置方法:

    为双向端口inout设置中间变量inout_reg作为该inout的输出寄存,inout口在testbench中要定义为wire型变量,然后用输出使能控制传输方向。

inout pin_dir_port;

wire pin_dir_port;

reg pin_dir_port_reg;

reg pin_dir_port_oe;

assign pin_dir_port = pin_dir_port_oe ? pin_dir_port_reg:1'bz;

 

    用pin_dir_port_oe控制端口数据方向,并利用中间变量寄存器改变其值,等于两个模块之间用inout双向口互连。

    本实验的testbench主要是为8bit的计数器产生测试激励信号,即产生50M的时钟信号clk和复位信号reset_n。

    一个完成的testbench文件内容主要包括三个部分:

  1. 仿真时间单位;
  2. 待测试模块信号映射;
  3. 激励信号产生;

基于modelsim-SE的简单仿真流程—上

仿真时间单位

    如上图标注所示:`timescale 1 ns/ 10 ps表示,时间单位为1ns,精度为10ps,时间单位应该大于时间精度,不然仿真过程将会报错,同时仿真的时间精度越小,仿真结果的波形的可视精度就越小,对仿真花费时间的要求越高,精度越小,仿真时间越长。

 

待测试模块信号映射

    将测试功能模块映射到testbench中,如图中的标注2所示,一般采用如下格式进行映射,其中测试功能模块的输入信号在testbench中定义为reg信号,因为要在always中进行赋值操作,而测试功能模块的输出信号定义为wire信号,该信号只用于观察,不用于赋值操作。

测试功能模块 例化测试功能模块名(

.输入信号(测试激励信号),

.输出信号(定义为wire型信号进行观察)

);

激励信号产生

    激励信号的产生涉及到两个阶段:初始化阶段和赋值操作阶段。初始化阶段在initial模块中进行操作,赋值操作阶段在always模块进行,如下格式。$display为显示语句,括号内双引号内的内容为要显示的内容,该内容将会在modelsim软件的脚本显示窗口中显示出来。

    Initial模块只执行一次。

initial

begin

// code that executes only once

// insert code here --> begin

对激励信号进行初赋值操作

// --> end

$display("Running testbench");

end

    在初始化完成后,需要对激励信号进行赋值操做,赋值操作在always中进行,always模块一直在执行。本实验时钟信号为50M,定义的时间单位为1ns,所以在每个10ns进行一次翻转,复位信号为低电平有效,所以在初始化的时候设置为低电平,在always模块里面设置为高电平。格式如下所示:

always

// optional sensitivity list

// @(event1 or event2 or .... eventn)

begin

// code executes for every event on sensitivity list

// insert code here --> begin

激励信号赋值操作,持续执行

// --> end

end

 

 

 

testbench代码:

`timescale 1 ns/ 10 ps

module counter_tst();

// constants

// general purpose registers

// test vector input registers

reg clk;

reg reset_n;

// wires

wire [7:0]counter_out;

 

counter counter_1(

.clk (clk),

.reset_n (reset_n),

.counter_out(counter_out)

);

initial

begin

// code that executes only once

// insert code here --> begin

clk<=1'b0;

reset_n<=1'b0;

// --> end

$display("Running testbench");

end

 

always

// optional sensitivity list

// @(event1 or event2 or .... eventn)

begin

// code executes for every event on sensitivity list

// insert code here --> begin

#10 clk<=~clk;

reset_n<=1'b1;

// --> end

end

endmodule

 

创建工程

    运行 ModelSim,方法是点击开始->程序->ModelSim SE->ModelSim 或双击桌面上的快捷方式,会出现如下图所示的界面,如果上一次使用ModelSim 建立过工程,这时候会自动打开上一次所建立的工程,可以close project,具体操作:选中工程的文件,右击,在出现的栏目中选择close project。

基于modelsim-SE的简单仿真流程—上

 

    点击 File->New->Project,会出现如下图所示的界面。

基于modelsim-SE的简单仿真流程—上

    选择project后,会出现如下界面在 Project Name 中我们输入建立的工程名字为counter,在Project Location 中点击browse按键,选择工程保存的路径,注意 ModelSim 不能为一个工程自动建立一个目录,这里最好是选择已经创建好的一个工程文件夹作为目录,在 Default Library Name 中为我们的设计编译到哪一个库中,这里使用默认值,这样,在编译设计文件后,在 Workspace 窗口的 Library中就会出现 work 库。这里我们输入完以后,点击 OK。

基于modelsim-SE的简单仿真流程—上

    在点击OK按键后会出现选择仿真文件的界面,如下图所示,可以点击不同的图标来为工程添加不同的项目,点击 Create New File 可以为工程添加新建的文件, 点击 Add Existing File为工程添加已经存在的文件,点击 Create Simulation 为工程添加仿真,点击Create New Folder 可以为工程添加新的目录。这里我们点击Add Existing File;

基于modelsim-SE的简单仿真流程—上

基于modelsim-SE的简单仿真流程—上

    这里将前面设计的counter.v文件和counter_tst.v文件包含进工程里面,点击browse按键,将文件包含进来,如下图所示,然后点击ok按键。

基于modelsim-SE的简单仿真流程—上

    接着会在modelsim的工程工作窗口出现如下图所示,即已经将两个文件包含进来,其中在状态那一栏出现两个问号,表明文件包含进来了,还没有进行编译。

基于modelsim-SE的简单仿真流程—上

 

大西瓜FPGA-->https://daxiguafpga.taobao.com

 

博客资料、代码、图片、文字等属大西瓜FPGA所有,切勿用于商业! 若引用资料、代码、图片、文字等等请注明出处,谢谢!

 

每日推送不同科技解读,原创深耕解读当下科技,敬请关注微信公众号“科乎”。

基于modelsim-SE的简单仿真流程—上

相关文章: