zoukankan      html  css  js  c++  java
  • modelsim 独立仿真vivado的IP核及仿真脚本

    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_project2LCD_projecthistogram_sim tl,如下面的第二张图所示

     

    第四步:在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

  • 相关阅读:
    洛谷P2292 [HNOI2004]L语言
    洛谷P4052 [JSOI2007]文本生成器(AC自动机)
    洛谷P3193 [HNOI2008]GT考试(KMP,矩阵)
    创建目录命令
    ssh免密码登录机器(使用公钥和秘钥进行加密来实现)
    kafka工作原理介绍
    KafKa集群安装、配置
    Kafka的partions和replication-factor参数的理解
    linux之find命令详解
    将用户需求和新型技术输入,优质服务和价值体验输出。
  • 原文地址:https://www.cnblogs.com/Xwangzi66/p/15042139.html
Copyright © 2011-2022 走看看