在FPGA开发中,会经常使用到ROM IP核,特别是存储一些序列号、版本信息、加密信息时。ROM IP核使用比较简单,但是利用Quartus软件下子程序Modelsim-Altera联合仿真时,按正常的使用流程却往往仿真不了。例如上节课学习7段译码显示的代码(注意这里将代码修改到易于仿真,将1s的显示间隔换成了10 个时钟周期)。下面按照一定的步骤逐步解决仿真中的各个问题。
1.仿真文件组织及仿真测试
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
module rom_7SEG # ( parameter SIM_DEBUG = "FALSE" ) ( input inclk, //50Mhz input rst, output DP, output [5:0] SEAT, output [6:0] SEVEN_SEG ); reg [26:0] div; reg f_s; reg [3:0] seg_addr; assign DP = 1'b1; assign SEAT = 6'b11_1110; localparam PARAM_1S = (SIM_DEBUG == "FALSE") ? 49999999 : 9; always@(posedge inclk or posedge rst) //分频 if(rst) begin div = 0; f_s = 0; end else begin if(div == PARAM_1S) begin div = 0; f_s = 1'b1; end else begin div = div + 1; f_s = 0; end end always@(posedge inclk or posedge rst) //地址计数 if(rst) begin seg_addr = 0; end else begin if(f_s) seg_addr = seg_addr + 1; end p1_rom p1_rom_inst ( .address (seg_addr), .clock (inclk), .q (SEVEN_SEG) //ROM.q是8位输出,这里只用了低7位 ); endmodule |
tb 文件如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
`timescale 1ns/1ps module tb(); reg inclk = 0; always #5 inclk = ~inclk; reg rst = 0; initial begin rst = 1; #20; rst = 0; #20000; $stop; end wire DP; wire [5:0] SEAT; wire [6:0] SEVEN_SEG; rom_7SEG #(.SIM_DEBUG("TRUE")) rom_7SEG_inst ( .inclk (inclk), //50Mhz .rst (rst), .DP (DP), .SEAT (SEAT), .SEVEN_SEG(SEVEN_SEG) ); endmodule |
原本是一个非常简单的工程,也配置了ROM IP核以及对应的*.mif文件作为初始化文件,但是仿真不正常。ModelSim运行后得不到ROM里的数据,SEVEN_SEG的值无法显示,如图1中橙色信号所示:

图1
ModelSim控制台中能看到下面的提示信息,如图2所示,找不到 *.mif 文件(使用的软件版本:ModelSim Starter Edition 2020.1,Quartus Prime Version 20.1.1 Lite Edition)。

图2
2. 仿真结果分析
-
找不到*.mif文件的原因
问题如仿真控制台中所说的,找不到*.mif文件,打开失败。这个ROM的配置在工程下载时是可以工作的,那怎么会在仿真时找不到文件呢?经过多次实验,最终发现最初生成ROM IP核时可用的*.mif文件路径是工程的主目录,如图3-图6所示。注意这个时候ROM IP核寻找*.mif文件的默认路径是 rom_7SEG\ 下,在这层目录寻找*.mif文件,所以相对的寻找地址是 ./p1_rom.mif 。

图3 ROM IP核中添加*.mif文件路径

图4 初次生成ROM IP核,点击Browse添加*.mif文件

图5 *.mif文件所在路径

图6 访问*.mif文件的路径
此相对路径,是相对于Quartus 而言的,也就是相对于“ rom_7SEG.qpf”这个文件,是在同一层目录下。ModelSim 在遇到这个路径的时候,会将其当作相对于它自己(rom_7SEG_run_msim_rtl_verilog.do)路径的同一层目录,也是正确的。因为在仿真的时候,*.mif文件会被复制一份,放到rom_7SEG\simulation\modelsim路径下,如图7所示。

图7 *.mif和*.do文件出现在同一级目录下
但是,问题出现在Quartus 已经使用programmer工具下载后,需要再次修改ROM IP核时,注意这个时候打开ROM IP核添加*.mif文件的默认路径由 rom_7SEG\ 变成了 rom_7SEG\output_files 。如图8-图9所示。

图8 使用programmer工具下载后,修改ROM IP核*.mif文件时打开的目录

图9 相对路径已经改变
注意这里图9所示的*.mif寻址的相对路径已经改变,由 ./p1_rom.mif 变为 ../p1_rom.mif。 ./p1_rom.mif 表示在当前同一目录下,而 ../p1_rom.mif 表示转移到上一级目录。这个时候,*.mif文件路径还是 rom_7SEG\ 下。经过多次实验发现Quartus 使用programmer工具下载后,ROM IP核的当前路径由 rom_7SEG\ 变成了 rom_7SEG\output_files 。
同样的,这个相对路径,是相对于Quartus 而言,也就是相对于“output_files”这个文件夹,*.mif文件是在上一级目录下,rom_7SEG\ 。ModelSim仿真工具 在遇到这个路径(../p1_rom.mif)的时候,会将其当作相对于它自己(rom_7SEG_run_msim_rtl_verilog.do)路径的上一级目录,也就是 rom_7SEG\simulation\ 。然而在前文提及到在仿真的时候,*.mif文件会被复制一份,放到rom_7SEG\simulation\modelsim 路径下(如图7所示,和rom_7SEG_run_msim_rtl_verilog.do 路径的同一层目录),所以这次仿真时无法寻找到 *.mif 文件,因为路径 rom_7SEG\simulation\ 下没有*.mif文件,如图10所示。

图7 *.mif和*.do文件出现在同一级目录下

图10 rom_7SEG\simulation\ 下没有*.mif文件
从上述中可以看出,如果需要在使用programmer工具下载后更改ROM IP核的*.mif文件,需要对Quartus和ModelSim的相对路径进行匹配。
3.针对路径匹配的解决办法
- 让ModelSim 按照相对路径也能找到*.mif文件。按上图的配置,则只需要把*.mif所在文件夹复制到rom_test_run_msim_rtl_verilog.do的上层目录 rom_7SEG\simulation\ 。
上述方法确实可以解决路径匹配的问题,但是仿真目录下的文件可能在重新设置仿真后被删除,也就需要在每次仿真前都手动将*.mif文件移动,比较麻烦。那么可以进一步探究这个问题出现的原因吗?
前文说到过Quartus 和ModelSim的相对路径路径不匹配的问题是出现在使用programmer工具下载后更改ROM IP核的*.mif文件时,在使用programmer工具下载前,修改ROM IP核的*.mif文件后仿真,是不会有找不到*.mif文件的错误出现的。可见问题出现在使用programmer工具下载后。下面在使用programmer工具下载后,用Quartus自带控制台,将Quartus 的路径手动匹配。也就是说,可以在使用programmer工具下载后,修改ROM IP核的*.mif文件,并且使仿真和综合下载都不发生错误。
这里要介绍一个新的语言:Tcl,读作 tickle 。这门语言通常被嵌入到应用程序中,用于脚本化应用程序,GUI(Graphical User Interface)和测试。Quartus中有专门的Tcl 解析器,提供了一个可编写脚本的接口。
点击Quartus界面的View –> Utility Windows –> Tcl Console,即可调出Tcl控制台,如图11-图12所示。

图11 Tcl控制台

图12 Tcl控制台
在Tcl控制台中输入 pwd (表示打印出当前的工作目录),会显示出当前的工作目录,可以看到在打开Programmer工具之前的工作目录是 rom_7SEG/,如图13所示。

图13 需要的工程路径
在打开Programmer工具后,当前的工作路径换成了rom_7SEG/output_files。可以在Tcl控制台处,使用 cd .. 指令退回到上一级主工作目录下,rom_7SEG/ ,并再次用 pwd 验证,如图14所示。在换成主工作目录后,即可以修改ROM IP核的*.mif文件,这个时候*.mif寻址的相对路径是 ./p1_rom.mif 这个时候再进行仿真,就不会出现找不到*.mif文件的错误了。

图14 在打开Programmer工具后当前的文件夹
在解决了上述ROM IP核*.mif文件路径匹配的问题后,仿真不再出现错误,但是SEVEN_SEG仍然没有结果,如图15所示。

图15 SEVEN_SEG没有仿真结果
注意观察仿真控制台的信息,有警告如图16所示。

图16 ModelSim警告
图13所示警告是指在例化p1_rom IP核时,seg_addr和 address长度不匹配。
4.仿真中其他问题的解决方法
进一步仿真发现,IP核相关的信号如图17所示,可以看出地址之间出现了 Z 信号的传递,这个与图13中出现的警告是一致的。分析代码后,看出因为seg_addr是4-bit,ROM IP核的address是8-bit,所以在例化ROM IP核的时候出现了错误。

图17 查看ROM IP核细节
|
1 2 3 4 5 6 |
p1_rom p1_rom_inst ( .address (seg_addr), .clock (inclk), .q (SEVEN_SEG) //ROM.q是8位输出,这里只用了低7位 ); |
|
1 2 3 4 5 6 |
p1_rom p1_rom_inst ( .address ({4'b0000, seg_addr}), .clock (inclk), .q (SEVEN_SEG) //ROM.q是8位输出,这里只用了低7位 ); |
修改后,仿真即正确,正确的仿真图如图18所示:

图18 正确的仿真图