【EDA软件】【联合Modelsim仿真使用方法】

背景

业界EDA工具仿真功能是必备的,例如Vivado自带仿真工具,且无需联合外部仿真工具,例如MoodelSim。 FUXI工具仿真功能需要联合Modelsim,才能实现仿真功能。

方法一:FUXI联合ModelSim

1 添加testbench文件

新建top_tb.v文件,可以新建一个sim文件夹,把tb文件保存在里面。

Porject Manager->Add Sources->Add or create simulation sources->Create File,创建top_tb.v,创建后界面如图1:

图1

2 编写仿真代码并保存

top.v只输出了led这个信号,所以仿真代码比较简单,如图1,top.v代码如下所示:

cpp 复制代码
// ============================================================
//
// Company:
// Engineer:
//
// Create Date: 05/14/2025 10:43:05   
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
// ============================================================
module top #(
    parameter  ADDR_WIDTH   = 10     ,
    parameter  DATA_WIDTH   = 16
)(
    output  reg     led
);

localparam  DEPTH = (1 << ADDR_WIDTH);
localparam  CNT_THD = 11'd10;

wire                        inner_osc_clk               ; // 80MHZ
wire                        mcu_clk                     ;
wire                        fpga_clk                    ;
wire                        pll_locked                  ;
wire                        sys_rst_n                   ;
wire                        por_locked                  ;

wire                        clk                         ;
wire                        rst_n                       ;

wire                        we                          ;
wire    [ADDR_WIDTH-1:0]    addr                        ;
wire    [DATA_WIDTH-1:0]    d_data                      ;
wire    [DATA_WIDTH-1:0]    q_data                      ;


reg     [DATA_WIDTH-1:0]    memory      [DEPTH-1:0]     ;
reg     [DATA_WIDTH-1:0]    wr_data                     ;
reg     [DATA_WIDTH-1:0]    rd_data                     ;
reg     [ADDR_WIDTH-1:0]    wr_addr                     ;
reg     [ADDR_WIDTH-1:0]    rd_addr                     ;
wire                        wr_en                       ;
wire                        rd_en                       ;

reg     [10:0]              wr_cnt                      ;
reg     [10:0]              rd_cnt                      ;

reg                         we_1ff                      ;
reg                         rd_en_1ff                   ;


oscillator_v1 u_oscillator_v1(
    .clkout     (  inner_osc_clk    )
);

pll_v1 u_pll_v1(
    .clkin0     (   inner_osc_clk   ), // i
    .locked     (   pll_locked      ), // o
    .clkout0    (   fpga_clk        ), // o
    .clkout1    (                   )  // o
);

por_v1_1 u_por_v1_1(
    .O          (   por_locked      )
);

assign  sys_rst_n = pll_locked & por_locked;


assign  clk = fpga_clk;
assign  rst_n = sys_rst_n;

/*First Write*/
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        wr_cnt <= 11'd0;
    end
    else if (wr_cnt < CNT_THD) begin
        wr_cnt <= wr_cnt + 1'b1;
    end
    else;
end

/*Write Full, then Read*/
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        rd_cnt <= 11'd0;
    end
    else if (rd_en & (rd_cnt < CNT_THD)) begin
        rd_cnt <= rd_cnt + 1'b1;
    end
    else;
end

assign we = wr_cnt < CNT_THD ? 1'b1 : 1'b0;

assign  wr_en = (we & (wr_cnt < CNT_THD)) ? 1'b1 : 1'b0;
assign  rd_en = ((~we) & (rd_cnt < CNT_THD)) ? 1'b1 : 1'b0;

/*Memory Write Address Option*/
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        wr_addr <= {ADDR_WIDTH{1'b0}};
    end
    else if (wr_en) begin
        wr_addr <= wr_addr + 1'b1;
    end
    else;
end

/*Memory Read Address Option*/
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        rd_addr <= {ADDR_WIDTH{1'b0}};
    end
    else if (rd_en) begin
        rd_addr <= rd_addr + 1'b1;
    end
    else;
end


/*Set Write Data Value*/
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        wr_data <= {DATA_WIDTH{1'b0}};
    end
    else if (wr_en) begin
        wr_data <= wr_data + 1'b1;
    end
    else;
end

/*Memory Write Data Option*/
always @ (posedge clk or negedge rst_n) begin : MEM_WRITE
    integer i;
    if (!rst_n) begin
        for (i = 0; i < DEPTH; i = i + 1) begin
            memory[i] <= {DATA_WIDTH{1'b0}};
        end
    end
    else if (wr_en) begin
        memory[wr_addr] <= wr_data;
    end
    else;
end

/*Memory Read Data Option*/
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        rd_data <= {DATA_WIDTH{1'b0}};
    end
    else if (rd_en) begin
        rd_data <= memory[rd_addr];
    end
    else;
end

always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        we_1ff <= 1'b0;
        rd_en_1ff <= 1'b0;
    end
    else begin
        we_1ff <= we;
        rd_en_1ff <= rd_en;
    end
end

always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        led <= 1'b1;
    end
    else if (we) begin
        led <= 1'b0;
    end
    else if ((~we_1ff) & rd_en_1ff) begin
        if (&(rd_data ^~ q_data)) begin
            led <= 1'b1;
        end
        else begin
            led <= 1'b0;
        end
    end
end


assign d_data = wr_data;
assign addr = we ? wr_addr : rd_addr;
assign ce = ((wr_cnt < CNT_THD) || (rd_cnt < CNT_THD)) ? 1'b1 : 1'b0;

emb_v1 emb_v1_SP (
    .clk        (   clk             ),
    .rstn       (   rst_n           ),
    .ce         (   ce              ), // i
    .we         (   we              ), // i
    .a          (   addr            ), // i
    .d          (   d_data          ), // i
    .q          (   q_data          )  // o
);

endmodule

以上代码比较简单,通过寄存器搭建Memory,实现单端口RAM,以此验证单端口RAM IP。

3 设置仿真内容

3.1 设置Modelsim路径

Options->Simulation->ModelSim Path,路径为Modelsim的安装路径,一般为XXXX\Modelsim_10.5\win64;

3.2 设置Test Bench的Module name

Options->Simulation->ModelSim Path->Top Module Name of Test Bench,填写Module name;

3.3 设置Design Top的Module name

Options->Simulation->ModelSim Path->Instance Name of Design Top Module,填写Module name;

3.4 设置Test Bench Files

Options->Simulation->ModelSim Path->Test Bench Files,添加编写的仿真文件。

3.5 设置Modelsim *.do File

Options->Simulation->ModelSim Path->Modelsim *.do File,添加*.do文件。

暂时不好使,不推荐使用。

设置结果如图2:

图2

4 开始仿真

Flow->Simulation->RTL Simulation,最后点击RTL Simulation,如图3,开始仿真。

图3

自动会联合Modelsim工具,并弹出Modelsim的工具界面。

5 缺点

5.1 弹出界面后,需要手动进行run -all或者点击按钮,且没有固定的仿真时间,需要手动停止;

5.2 弹出界面只有top_tb的信号,需要手动自行添加信号,再运行;

5.3 修改文件需要从新执行4,比较浪费时间。

6 优点

FUXI可以很快的检查出文件的语法错误。

方法二:脚本构建 推荐

与top_tb.v同级目录下,添加三种文件,如图4:

图4

1 files.f

添加需要编译仿真的testbench、 DUT(RTL)文件

内容如下:

bash 复制代码
top_tb.v
//rtl 仿真
D:/02_Fuxi/2025-03-28-win64-rel-99/data/lib/p0_sim.v
../src/ip/pll_v1.v
../src/ip/por_v1_1.v
../src/ip/oscillator_v1.v
../src/ip/emb_v1.v
../src/top.v

以上涉及1个问题,需要知道仿真模型;这个后续罗列出来。

2 start.do

汇总编译、波形设置的命令

bash 复制代码
#1 Create and Map the work lib
vlib work
vmap work work


#2  Now compile all the files
vlog -64 -sv +acc -incr +define+SIM -timescale 1ns/1ns -work work -f files.f -l rtl.log


#3  Start the simulator, log all waveforms, load wave file and run
vsim -voptargs="+acc" -sva +define+SIM -c work.top_tb -l sim.log -wlfdeleteonquit


#4 Set the window types
view wave
view structure
view signals


#5 Add signals or signals group to view wave
add wave -divider "System"
add wave -radix hexadecimal -group "System" top_tb/u_top/clk 
add wave -radix hexadecimal -group "System" top_tb/u_top/rst_n


add wave -divider "Memery Option"
add wave -radix hexadecimal -group "Memery" top_tb/u_top/mem_wr_en
add wave -radix hexadecimal -group "Memery" top_tb/u_top/mem_wr_addr
add wave -radix hexadecimal -group "Memery" top_tb/u_top/mem_wr_data
add wave -radix hexadecimal -group "Memery" top_tb/u_top/mem_rd_en
add wave -radix hexadecimal -group "Memery" top_tb/u_top/mem_rd_addr
add wave -radix hexadecimal -group "Memery" top_tb/u_top/mem_rd_data


add wave -divider "EMB Option"
add wave -radix hexadecimal -group "EMB" top_tb/u_top/emb_wr_en
add wave -radix hexadecimal -group "EMB" top_tb/u_top/emb_wr_addr
add wave -radix hexadecimal -group "EMB" top_tb/u_top/emb_wr_data
add wave -radix hexadecimal -group "EMB" top_tb/u_top/emb_rd_en
add wave -radix hexadecimal -group "EMB" top_tb/u_top/emb_rd_addr
add wave -radix hexadecimal -group "EMB" top_tb/u_top/emb_rd_data


add wave -radix hexadecimal top_tb/u_top/led 


#6 Set run Time
run 40ms

以上主要包含了6部分的设置。

3 批处理文件

如:run_sim.bat

bash 复制代码
echo pause  


::删除Modelsim生成的相关文件
RD work /s /q
DEL transcript vsim.wlf /q


vsim -do start.do 
pause

通过批处理文件,调用start.do进行仿真。

4 优点

4.1 文件修改后,只需要在Modelsim CLI界面执行do start.do;

4.2 编辑start.do,添加需要观察的信号,进行波形观察。

5 缺点

修改文件需要编译才能知道文件的语法有错误,这稍微一点好时间可以接受。

因此可以联合FUXI,通过检查语法,当无语法错误后,进行编译仿真。

举例:

下图是结合方法1和方法2的优点,对单端口RAM的仿真结果。

例子连接:待上传。

相关推荐
hahaha601612 小时前
3NRD降噪算法FPGA实现8并行度设计
fpga开发
松小白song12 小时前
一次“载电流显示为 0“的排查经历:负值钳位引发的踩坑
fpga开发
yingheceping16 小时前
复旦微FPGA开发板厂商TOP5甄选榜:2026选型参考
fpga开发·fpga
NamoAmitabha12818 小时前
PL 端的 GPIO IP(AXI GPIO)---PS控制----deepseek
fpga开发·zynq--ps
hahaha601621 小时前
3D降噪算法YUV降噪FPGA实现
fpga开发
Hello-FPGA2 天前
基于RFSOC FPGA ZCU216 的CoaXPress 采集demo
fpga开发
9527华安2 天前
FPGA基于ADV7182解码PAL视频,Video Processing Subsystem去隔行,提供6套工程源码和技术支持
fpga开发·音视频·pal·adv7182
hahaha60162 天前
数字图像时域滤波或者3D降噪算法FPGA实现
算法·计算机视觉·fpga开发
GateWorld2 天前
Xilinx 7系列FPGA时钟网络详解
fpga开发·时钟网络·xilinx 7系列
szxinmai主板定制专家2 天前
X86 工控机 vs RK3588 异构主控:AMR 控制器 BOM、散热、长期运维对比
运维·stm32·单片机·嵌入式硬件·fpga开发·am62x