Modelsim独立仿真vivado的IP

最近一直在做local dimming项目的FPGA硬件实现,算法的其中一步就是直方图统计,即数字图像的某一灰度级的像素数,这个直方图的源码找了半天才搞到,就在<<牟新刚周晓郑晓亮著: 基千FPGA的数字图像处理原理及应用>>这一本书有详细的描述。但有了这个代码,还得查看直方图处理的效果,那我只有搭建仿真查看,但modelsim一直出错,提示直方图模块调用的双口ram不存在,于是下面介绍modelsim独立仿真带有vivado的IP的解决办法。

后面还会附上我一直在用的仿真脚本,十分方便!

一:实现步骤

第一步在vivado中编译仿真库,将编译后的仿真库放在自己新建的文件夹,如D:/xilinx/xlib,我已经编译好了,如下图

第二步,找到编译库路径下的modelsim.ini文件,即下面右图中的红框文件,去掉只读属性,打开后选择包含编译库的代码,图2中的63-72即vivado中包含的编译库,复制后粘贴到modelsim10.5安装根目录下的modelsim.ini文件中,如第三张图中的83-94行,即为粘贴注释的,为了以后避免和alter及ISE14.7等编译库混合,用分号注释加上分割线,下次用到其他的编译库则注释就行。保存后勾选只读属性,如下图所示

第三步,仿真带IP核的文件前提是你在vivado生成了IP核,如下图所示,找到下面红框中的两个文件路径,复制后这两个文件加入到仿真工程路径D:\3FPGA_project\02LCD_project\histogram_sim\rtl,如下面的第二张图所示

第四步:在modelsim中独立仿真,我一般是用脚本,即do文件的形式,通过编译do文件tb_top.do和波形添加do文件tb_top_wave.do实现自动仿真,这样相对于手工的形式可以避免很多体力活,先打开modelsim切换路径到sim下,直接在modelsim中输入do tb_top.do就可加载波形,如下图所示:

第五步,波形显示

二:源码

1.设计模块源码histogram_2d的源码,已经将其中的双口ram的IP核调用和其中一些代码注释(报错的),因为书中的vivado版本比较老,故不能仿真运行,会报错。

  1 `timescale 1ns/1ns
2
3 module histogram_2d(
4 rst_n,
5 clk,
6 din_valid,
7 din,
8 dout,
9 vsync,
10 dout_valid,
11 rdyOutput,
12 //`ifdef Equalize
13 hist_cnt_addr,
14 hist_cnt_out,
15 //`endif
16 //`ifdef LinearTransfer
17 lowCnt,
18 highCnt,
19 lowIndex,
20 highIndex,
21 //`endif
22 int_flag
23 );
24
25 parameter DW = 14;
26 parameter IH = 512;
27 parameter IW = 640;
28 parameter TW = 32;
29
30 localparam TOTAL_CNT = IW * IH;
31 localparam HALF_WIDTH = (TW>>1);
32
33 input rst_n;
34 input clk;
35 input din_valid;
36 input [DW-1:0]din;
37 input rdyOutput;
38
39 output reg [HALF_WIDTH:0]dout;
40 input vsync;
41 output reg dout_valid;
42 output reg int_flag;
43
44 //`ifdef LinearTransfer
45 input [TW-1:0]lowCnt;
46 input [TW-1:0]highCnt;
47 output reg[DW-1:0]lowIndex;
48 output reg[DW-1:0]highIndex;
49 //`endif
50
51 //`ifdef Equalize
52 input [DW-1:0]hist_cnt_addr;
53 output reg [TW-1:0]hist_cnt_out;
54 //`endif
55
56 reg vsync_r;
57 reg dvalid_r;
58 reg dvalid_r2;
59 reg [DW-1:0]din_r;
60 reg [DW-1:0]din_r2;
61 wire hsync_fall;
62 wire hsync_rise;
63 reg [9:0]hsync_count;
64 reg count_en;
65 wire [DW-1:0]mux_addr_b;
66 wire [DW-1:0]mux_addr_b2;
67 wire [TW-1:0]q_a;
68 wire [TW-1:0]q_b;
69 reg [TW-1:0]counter;
70 wire [TW-1:0]count_value;
71 wire rst_cnt;
72 wire inc_en;
73 wire we_a;
74 wire we_b;
75 wire we_b_l;
76 reg we_b_h;
77
78 reg int_r;
79
80 wire [DW-1:0]addr_a;
81 wire [DW-1:0]clr_addr;
82 reg [DW-1:0]clr_addr_r;
83 reg [DW:0]out_pixel;
84
85 reg count_all;
86 //reg count_all_r;
87 reg count_en_r;
88
89 reg [TW-1:0]hist_cnt;
90 wire rstOutput;
91
92
93 wire [TW-1:0]dataTmp2;
94 wire clr_flag;
95
96 assign #1 hsync_fall = dvalid_r & (~(din_valid));
97 assign #1 hsync_rise = (~(dvalid_r)) & din_valid;
98
99 always @(posedge clk or negedge rst_n)
100 if (((~(rst_n))) == 1'b1)
101 hsync_count <= #1 {10{1'b0}};
102 else
103 begin
104 if (vsync_r == 1'b1)
105 hsync_count <= #1 {10{1'b0}};
106 else if (hsync_fall == 1'b1)
107 hsync_count <= hsync_count + 10'b1;
108 end
109
110 always @(posedge clk or negedge rst_n)
111 if (((~(rst_n))) == 1'b1)
112 count_en <= #1 1'b0;
113 else
114 begin
115 if (hsync_count >= IH)
116 count_en <= #1 1'b0;
117 else if (hsync_rise == 1'b1)
118 count_en <= #1 1'b1;
119 else
120 count_en <= #1 count_en;
121 end
122
123 assign mux_addr_b = ((count_en == 1'b1)) ? din_r :
124 clr_addr;
125 assign mux_addr_b2 = ((count_en == 1'b1)) ? din_r :
126 clr_addr_r;
127
128
129 always @(posedge clk)
130 begin
131 din_r2 <= #1 din_r;
132 dvalid_r2 <= #1 dvalid_r;
133 end
134
135 always @(posedge clk)
136 begin
137 if (rst_cnt == 1'b1)
138 counter <= #1 {{TW-1{1'b0}},1'b1};
139 else if (inc_en == 1'b1)
140 counter <= #1 counter + {{TW-1{1'b0}},1'b1};
141 else
142 counter <= #1 counter;
143 end
144
145 assign #1 rst_cnt = (((din_r != din_r2) | ((dvalid_r2 == 1'b1) & (dvalid_r == 1'b0)))) ? 1'b1 :
146 1'b0;
147 assign #1 inc_en = (((din_r == din_r2) & (dvalid_r2 == 1'b1))) ? 1'b1 :
148 1'b0;
149
150 assign #1 we_a = ((((din_r != din_r2) & (dvalid_r2 == 1'b1)) | ((dvalid_r2 == 1'b1) & (dvalid_r == 1'b0)))) ? 1'b1 :
151 1'b0;
152 assign #1 count_value = ((count_en == 1'b1)) ? counter + q_b :
153 {TW{1'b0}};
154
155 assign #1 addr_a = din_r2;
156
157 assign dataTmp2 = {TW{1'b0}};
158
159 // hist_buffer dpram_bin_l(
160 // .address_a(addr_a), //addra
161 // .address_b(mux_addr_b), //addrb
162 // .clock(clk),
163 // .data_a(count_value[HALF_WIDTH - 1:0]), //dina
164 // .data_b(dataTmp2[HALF_WIDTH - 1:0]),
165 // .wren_a(we_a),
166 // .wren_b(we_b_l),
167 // .q_a(q_a[HALF_WIDTH - 1:0]), //douta
168 // .q_b(q_b[HALF_WIDTH - 1:0]) //doutb
169 // );
170 //
171 hist_buffer dpram_bin_l (
172 .clka(clk), // input wire clka
173 .ena(1), // input wire ena
174 .wea(we_a), // input wire [0 : 0] wea
175 .addra(addr_a[9 : 0]), // input wire [9 : 0] addra
176 .dina(count_value[HALF_WIDTH - 1:0]), // input wire [31 : 0] dina
177 .douta(q_a[HALF_WIDTH - 1:0]), // output wire [31 : 0] douta
178 .clkb(clk), // input wire clkb
179 .enb(1), // input wire enb
180 .web(we_b_l), // input wire [0 : 0] web
181 .addrb(mux_addr_b[9 : 0]), // input wire [9 : 0] addrb
182 .dinb(0), // input wire [31 : 0] dinb
183 .doutb(q_b[HALF_WIDTH - 1:0]) // output wire [31 : 0] doutb
184 );
185 //
186 // defparam dpram_bin_l.AW = DW;
187 // defparam dpram_bin_l.DW = HALF_WIDTH;
188
189 // hist_buffer dpram_bin_h(
190 // .address_a(addr_a),
191 // .address_b(mux_addr_b2),
192 // .clock(clk),
193 // .data_a(count_value[TW - 1:HALF_WIDTH]),
194 // .data_b(dataTmp2[TW - 1:HALF_WIDTH]),
195 // .wren_a(we_a),
196 // .wren_b(we_b_h),
197 // .q_a(q_a[TW - 1:HALF_WIDTH]),
198 // .q_b(q_b[TW - 1:HALF_WIDTH])
199 // );
200
201 hist_buffer dpram_bin_h (
202 .clka(clk), // input wire clka
203 .ena(1), // input wire ena
204 .wea(we_a), // input wire [0 : 0] wea
205 .addra(addr_a[9 : 0]), // input wire [9 : 0] addra
206 .dina(count_value[TW - 1:HALF_WIDTH]), // input wire [31 : 0] dina
207 .douta(q_a[TW - 1:HALF_WIDTH]), // output wire [31 : 0] douta
208 .clkb(clk), // input wire clkb
209 .enb(1), // input wire enb
210 .web(we_b_h), // input wire [0 : 0] web
211 .addrb(mux_addr_b2[9 : 0]), // input wire [9 : 0] addrb
212 .dinb(0), // input wire [31 : 0] dinb
213 .doutb(q_b[TW - 1:HALF_WIDTH]) // output wire [31 : 0] doutb
214 );
215
216 // defparam dpram_bin_h.AW = DW;
217 // defparam dpram_bin_h.DW = HALF_WIDTH;
218
219 always @(posedge clk or negedge rst_n)
220 if (((~(rst_n))) == 1'b1)
221 count_en_r <= #1 1'b0;
222 else
223 count_en_r <= #1 count_en;
224
225 assign rstOutput = count_en_r | (~(rdyOutput));
226
227 reg [DW-1:0]lowIndex_tmp;
228 reg [DW-1:0]highIndex_tmp;
229 reg [DW-1:0]highIndex_tmp2;
230 reg bFindMax;
231 reg bFindMin;
232
233 always @(posedge clk or negedge rst_n)
234 if ((~(rst_n)) == 1'b1)
235 begin
236 lowIndex_tmp <= {DW{1'b0}};
237 highIndex_tmp <= {DW{1'b1}};
238 bFindMin <= 1'b0;
239 bFindMax <= 1'b0;
240 highIndex_tmp2 <= {DW{1'b0}};
241 end
242 else
243 begin
244 if (vsync_r == 1'b0 & vsync == 1'b1)
245 begin
246 lowIndex_tmp <= {DW{1'b0}};
247 highIndex_tmp <= {DW{1'b1}};
248 highIndex_tmp2 <= {DW{1'b0}};
249 lowIndex <= lowIndex_tmp;
250 if (bFindMax == 1'b1)
251 highIndex <= highIndex_tmp;
252 else
253 highIndex <= highIndex_tmp2;
254 bFindMin <= 1'b0;
255 bFindMax <= 1'b0;
256 end
257 else
258 begin
259 if (out_pixel[0] == 1'b1)
260 begin
261 if ((~(q_b == {HALF_WIDTH{1'b0}})))
262 highIndex_tmp2 <= clr_addr - 4'h1;
263 if ((hist_cnt >= lowCnt) & bFindMin == 1'b0)
264 begin
265 lowIndex_tmp <= clr_addr - 4'h1;
266 bFindMin <= 1'b1;
267 end
268 if (hist_cnt >= (TOTAL_CNT - highCnt) & bFindMax == 1'b0)
269 begin
270 highIndex_tmp <= clr_addr - 4'h1;
271 bFindMax <= 1'b1;
272 end
273 end
274 end
275 end
276
277 // hist_buffer hist_cnt_buf(
278 // .address_a(out_pixel_r2),
279 // .address_b(hist_cnt_addr),
280 // .clock(clk),
281 // .data_a(hist_cnt),
282 // .data_b(),
283 // .wren_a(dout_valid),
284 // .wren_b(1'b0),
285 // .q_a(),
286 // .q_b(hist_cnt_temp)
287 // );
288 // defparam hist_cnt_buf.AW = DW;
289 // defparam hist_cnt_buf.DW = TW;
290
291 hist_buffer hist_cnt_buf (
292 .clka(clk), // input wire clka
293 .ena(1), // input wire ena
294 .wea(dout_valid), // input wire [0 : 0] wea
295 .addra(out_pixel[9:0]), // input wire [9 : 0] addra
296 .dina(hist_cnt), // input wire [31 : 0] dina
297 .douta(), // output wire [31 : 0] douta
298 .clkb(clk), // input wire clkb
299 .enb(1), // input wire enb
300 .web(0), // input wire [0 : 0] web
301 .addrb(hist_cnt_addr[9:0]), // input wire [9 : 0] addrb
302 .dinb(0), // input wire [31 : 0] dinb //data_b
303 .doutb(hist_cnt_temp) // output wire [31 : 0] doutb
304 );
305
306 endmodule

histogram_2d

2.原创的脚本文件

A添加信号和显示波形的tb_top_wave.do

 1 #添加信号和显示其波形
2 onerror {resume}
3 quietly WaveActivateNextPane {} 0
4 add wave -noupdate -divider {input paramters}
5 add wave -noupdate -radix unsigned /tb_top/CLK_FREQ
6 add wave -noupdate -radix unsigned /tb_top/CLK_PERIOD
7
8 add wave -noupdate -divider {histogram_2d input}
9 add wave -noupdate /tb_top/inst_hist/clk
10 add wave -noupdate /tb_top/inst_hist/rst_n
11 add wave -noupdate /tb_top/inst_hist/din_valid
12 add wave -noupdate /tb_top/inst_hist/din
13
14 add wave -noupdate -divider {histogram_2d output}
15 add wave -noupdate /tb_top/inst_hist/dout
16 add wave -noupdate /tb_top/inst_hist/vsync
17 add wave -noupdate /tb_top/inst_hist/dout_valid
18
19 add wave -noupdate -divider {end signal}
20
21 TreeUpdate [SetDefaultTree]
22 WaveRestoreCursors {{Cursor 1} {912366093 ps} 0}
23 configure wave -namecolwidth 150
24 configure wave -valuecolwidth 100
25 configure wave -justifyvalue left
26 configure wave -signalnamewidth 0
27 configure wave -snapdistance 10
28 configure wave -datasetprefix 0
29 configure wave -rowmargin 4
30 configure wave -childrowmargin 2
31 configure wave -gridoffset 0
32 configure wave -gridperiod 1
33 configure wave -griddelta 40
34 configure wave -timeline 0
35 configure wave -timelineunits ns
36 update
37 WaveRestoreZoom {891247063 ps} {925431255 ps}

tb_top_wave.do

B新建work库,编译.v文件和启动顶层仿真文件,及执行添加信号和显示波形的tb_top_wave.do的编译do文件tb_top.do

 1 #不需要新建modelsim工程,直接运行.do文件就可以仿真
2 quit -sim
3 #新建work库
4 vlib work
5
6 #将work库映射到当前工作目录
7 #vmap [-help] [-c] [-del] [<logical_name>] [<path>]
8 vmap work
9
10 #编译所有.v文件到work工作库
11 #-work <path> Specify library WORK
12 #-vlog01compat Ensure compatibility with Std 1364-2001
13 #-incr Enable incremental compilation
14 #"rtl/*.v" 当前工作目录下的rtl文件夹中的所有.v文件,支持相对路径,但是要加双引号“”
15 #vlog
16
17 vlog -work work -vlog01compat -incr "../testbench/prim_sim.v"
18 vlog -work work -vlog01compat -incr "../testbench/tb_top.v"
19
20 vlog -work work -vlog01compat -incr "../rtl/histogram_2d.v"
21 vlog -work work -vlog01compat -incr "../rtl/*.v"
22 #vlog -work work -vlog01compat -incr "../rtl/uart_master_src/*.v"
23
24
25 #编译所有.vhd文件
26 #-work <path> Specify library WORK
27 #-93 Enable support for VHDL 1076-1993
28 #-2002 Enable support for VHDL 1076-2002
29 #vcom
30
31 #启动仿真顶层文件
32 #-L <libname> Search library for design units instantiated from Verilog and for VHDL default component binding
33 #+nowarn<CODE | Number> Disable specified warning message (Example: +nowarnTFMPC)
34 #-t [1|10|100]fs|ps|ns|us|ms|sec Time resolution limit VHDL default: resolution setting from .ini file)
35 # (Verilog default: minimum time_precision in the design)
36 #-novopt Force incremental mode (pre-6.0 behavior)
37
38 vsim +nowarnTFMPC -L work -novopt -l tb_top.log work.tb_top
39
40 #产生一个wave log format(WLF)......
41 log -r /*
42
43 #打开wave窗口
44 view wave
45
46 #添加仿真信号
47 #在已经添加好信号和设置好格式的wave窗口,点击【File】->【Save Fomat】
48 #存为任意名字的.do文件,该文件包含了加载哪些信号及其显示格式的命令
49 do tb_top_wave.do
50
51 #设置运行时间
52 run -all
53
54 #dataflow调试
55 #具体方法是在仿真后执行命令 view dataflow 就可以打开dataflow文件,
56 #在dataflow的窗口菜单中点击add中的view all nets就可以观察到各个模块之间的逻辑联系,
57 #模块一般都为initial模块、always模块、assign模块等等。点击中一个模块,则这个模块变为红色。
58 #这时候在view菜单下点击show wave就可以在窗口下方弹出wave窗口,
59 #不同的是这个wave窗口所显示的信号变量仅为点击中的模块所包括的信号变量,
60 #这时候也可以点击仿真run –all小图标来仿真有关这个模块的输入输出关系。
61 #view dataflow

tb_top.do

三,总结

本文通过实践得出,不同于下面的博客。书中的设计思路及网上资料很有帮助,但具体细节实现上会碰到问题。故多尝试自己动手编写代码实现,多借鉴别人的算法框架和思路。

参考博客:

https://www.cnblogs.com/ninghechuan/p/8305925.html

Modelsim独立仿真Vivado Clocking Wizard IP Core

https://cloud.tencent.com/developer/article/1529571

modelsim 独立仿真vivado的IP核及仿真脚本的更多相关文章

  1. 调用altera IP核的仿真流程—下

    调用altera IP核的仿真流程—下 编译 在 WorkSpace 窗口的 counter_tst.v上点击右键,如果选择Compile selected 则编译选中的文件,Compile All是 ...

  2. 调用altera IP核的仿真流程—上

    调用altera IP核的仿真流程—上 在学习本节内容之后,请详细阅读<基于modelsim-SE的简单仿真流程>,因为本节是基于<基于modelsim-SE的简单仿真流程>的 ...

  3. Altera三速以太网IP核快速仿真与使用(上篇)

    对于比较高级的ip核,altera一般都会提供仿真案例,网上有关于这个IP核的各种仿真方法,但都比较繁琐,前几日,朋友跟我分享了一个比较快速高效的仿真方法,这个方法也是他摸索折腾了一段时间才总结出来的 ...

  4. Mdoelsim10.4怎么脚本单独仿真ISE14.7 IP核

    软件版本: Modelsim10.4SE ISE14.7 仿真IP:时钟管理IP(clock wizard)   流程: 1.对于Modelsim10.4SE,并不自带Xilinx家的仿真库,因此首先 ...

  5. altera DDR2 IP核之仿真

    在生成的IP核文件夹下,有一个testbench文件夹,里面包含了一个example测试激励和DDR2仿真模型. 如下 20 -rw-r--r-- 1 Administrator 197121 171 ...

  6. 用Modelsim SE 直接仿真 Altera(Intel PSG) IP核 需要注意的问题

    如果我们直接用Modelsim SE仿真 Altera IP核,首先会进入Quartus II目录下找到IP核对应的仿真库源文件,然后在Modelsim SE中进行编译,添加到Modelsim SE的 ...

  7. Lattice 的 DDR IP核使用调试笔记之DDR 的 仿真

    —— 远航路上ing 整理于 博客园.转载请标明出处. 在上节建立完工程之后,要想明确DDR IP的使用细节,最好是做仿真.然后参考仿真来控制IP 核. 仿真的建立: 1.在IP核内的以下路径找到以下 ...

  8. System Generator 生成IP核在Vivado中进行调用

    System Generator 生成IP核在Vivado中进行调用 1.首先在Simulink中搭建硬件模型 2.查看仿真结果 3.资源分析与时序分析 4.启动vivado,关联生成的IP核 5.调 ...

  9. 如何用ModelsimSE仿真IP核-以PLL为例

    我们之前介绍了如何使用Modelsim SE进行仿真和利用do文件的仿真方法,但是其中待仿真的模块是我们自己编写的Verilog模块,但是在实际工作中,我们的设计中会经常用到FPGA厂商给我们提供的现 ...

随机推荐

  1. 如何运行具有奇点的NGC深度学习容器

    如何运行具有奇点的NGC深度学习容器 How to Run NGC Deep Learning Containers with Singularity 高性能计算机和人工智能的融合使新的科学突破成为可 ...

  2. GPU端到端目标检测YOLOV3全过程(下)

    GPU端到端目标检测YOLOV3全过程(下) Ubuntu18.04系统下最新版GPU环境配置 安装显卡驱动 安装Cuda 10.0 安装cuDNN 1.安装显卡驱动 (1)这里采用的是PPA源的安装 ...

  3. (1)http基础

    HTTP服务基础 • 基于 B/S (Browser/Server)架构的网页服务– 服务端提供网页– 浏览器下载并显示网页 • Hyper Text Transfer Protocol,超文本传输协 ...

  4. 【NX二次开发】Block UI 选择小平面区域

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  5. csp-s模拟测试50(9.22)「施工(单调栈优化DP)」·「蔬菜(二维莫队???)」·「联盟(树上直径)」

    改了两天,终于将T1,T3毒瘤题改完了... T1 施工(单调栈优化DP) 考场上只想到了n*hmaxn*hmaxn的DP,用线段树优化一下变成n*hmaxn*log但显然不是正解 正解是很**的单调 ...

  6. mturoute 最大传输单元路由检测Host

    mturoute检测mtu字符 下载地址:https://www.elifulkerson.com/projects/mturoute.php mturoute.exe                ...

  7. ClickHouse学习系列之五【系统库system说明】

    背景 之前介绍过ClickHouse相关的系列文章,现在ClickHouse已经能正常使用起来了,包括副本和分片.因为ClickHouse已经可以提供服务了,现在需要关心的就是服务期间该数据库的各项性 ...

  8. VisualCom软件仿真平台V1.0发布(附安装包下载链接)

    自我们借助VisualCom(暂定名称,后续可能会变更)软件平台撰写技术文章以来,有不少粉丝发私信询问该软件哪里来的,以及哪里有安装包,这里回复一下:VisualCom软件平台是由本微信公众号组织开发 ...

  9. vue项目打包成html,在本地点击直接能打开

    默认情况下vue项目打包后,本地打开index.html是空白的,有报错.Failed to load resource: net::ERR_FILE_NOT_FOUND 这时需要修改config-& ...

  10. Task异常捕获的方式

    这节来讲一下如果捕获Task的异常. 当Task运行中出现了异常,正常情况下我们在主线程的Try是捕获不到的,而如果在Task内部写try,出现了异常我们会完全不知道.下面就来介绍几个主线程捕获Tas ...