这段时间有个项目需要用到紫光的DDR3以及HSSTHP两个IP,这几天在整DDR3的仿真。经过我几天的努力终于能看到IP的ddr_init_done拉高了。紫光PDS软件直接生成的modelsim 可运行tcl文件有很多问题,这里对需要修改的地方做个总结
我的软件环境如下:
Pango Design Suite 2024.2-SP1.2-ads
Modelsim SE-64 10.6d
文章目录
- 1、简介
- 2、创建tb文件
-
- [1 打开工程后,工程架构如下](#1 打开工程后,工程架构如下)
- [2 创建tb文件](#2 创建tb文件)
- [3 将文件添加到工程](#3 将文件添加到工程)
- [4 pds软件运行一次仿真](#4 pds软件运行一次仿真)
- [3 修改tcl脚本](#3 修改tcl脚本)
1、简介
我这里不会介绍如何通过PDS软件编译modelsim的仿真库,这个很简单,同学们可自行网上查询,也可直接参考下面文章
【紫光同创国产FPGA教程】------PDS与Modelsim联合仿真教程
本次我使用的工程是正点原子的达芬奇Pro Logos2的37_top_ddr3_rw实验做说明。
2、创建tb文件
1 打开工程后,工程架构如下

2 创建tb文件
参考ddr3_test_top_tb.v的方式复制ddr3的模型以及参数到自己的tb文件内,可直接复制
c
`timescale 1 ns / 10 fs
module tb_top;
`include "ddr3_parameters.vh"
// Parameters
parameter CA_FIRST_DLY = 0.15;
parameter CA_GROUP_TO_GROUP_DLY = 0.05;
localparam real CLKIN_FREQ = 50.0 ;
parameter PLL_REFCLK_IN_PERIOD = 1000 / CLKIN_FREQ;
parameter MEM_DQ_WIDTH = 32;
parameter MEM_DQS_WIDTH = MEM_DQ_WIDTH/8;
parameter MEM_ROW_WIDTH = 14;
//Ports
reg sys_clk = 'd0;
reg sys_rst_n = 'd0;
wire [1:0] led;
wire mem_rst_n ;
wire mem_ck ;
wire mem_ck_n ;
wire mem_cke ;
wire mem_cs_n ;
wire mem_ras_n ;
wire mem_cas_n ;
wire mem_we_n ;
wire mem_odt ;
wire [MEM_ROW_WIDTH-1:0] mem_a ;
wire [2:0] mem_ba ;
wire [MEM_DQS_WIDTH-1:0] mem_dqs ;
wire [MEM_DQS_WIDTH-1:0] mem_dqs_n;
wire [MEM_DQ_WIDTH-1:0] mem_dq ;
wire [MEM_DQS_WIDTH-1:0] mem_dm ;
wire [ADDR_BITS-1:0] mem_addr;
ddr3_rw_top ddr3_rw_top_inst (
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.led(led),
.mem_rst_n(mem_rst_n),
.mem_ck(mem_ck),
.mem_ck_n(mem_ck_n),
.mem_cke(mem_cke),
.mem_ras_n(mem_ras_n),
.mem_cas_n(mem_cas_n),
.mem_we_n(mem_we_n),
.mem_odt(mem_odt),
.mem_a(mem_a),
.mem_ba(mem_ba),
.mem_dqs(mem_dqs),
.mem_dqs_n(mem_dqs_n),
.mem_dq(mem_dq),
.mem_cs_n(mem_cs_n),
.mem_dm(mem_dm)
);
always #10 sys_clk = ! sys_clk ;
wire [MEM_DQS_WIDTH+1:0] mem_ck_dly;
wire [MEM_DQS_WIDTH+1:0] mem_ck_n_dly;
wire [(MEM_DQS_WIDTH+2)*ADDR_BITS:0] mem_addr_dly;
wire [MEM_DQS_WIDTH+1:0] mem_cke_dly;
wire [MEM_DQS_WIDTH+1:0] mem_odt_dly;
wire [MEM_DQS_WIDTH+1:0] mem_ras_n_dly;
wire [MEM_DQS_WIDTH+1:0] mem_cas_n_dly;
wire [MEM_DQS_WIDTH+1:0] mem_we_n_dly;
wire [MEM_DQS_WIDTH*3+6:0] mem_ba_dly;
wire [MEM_DQS_WIDTH+1:0] mem_cs_n_dly;
wire [MEM_DQS_WIDTH+1:0] mem_rst_n_dly;
assign #CA_FIRST_DLY mem_ck_dly[1:0] = {mem_ck,mem_ck} ;
assign #CA_FIRST_DLY mem_ck_n_dly[1:0] = {mem_ck_n,mem_ck_n} ;
assign #CA_FIRST_DLY mem_addr_dly[ADDR_BITS*2-1:0] = {mem_addr,mem_addr} ;
assign #CA_FIRST_DLY mem_cke_dly[1:0] = {mem_cke,mem_cke} ;
assign #CA_FIRST_DLY mem_odt_dly[1:0] = {mem_odt,mem_odt} ;
assign #CA_FIRST_DLY mem_ras_n_dly[1:0] = {mem_ras_n,mem_ras_n} ;
assign #CA_FIRST_DLY mem_cas_n_dly[1:0] = {mem_cas_n,mem_cas_n} ;
assign #CA_FIRST_DLY mem_we_n_dly[1:0] = {mem_we_n,mem_we_n} ;
assign #CA_FIRST_DLY mem_ba_dly[5:0] = {mem_ba,mem_ba} ;
assign #CA_FIRST_DLY mem_cs_n_dly[1:0] = {mem_cs_n,mem_cs_n} ;
assign #CA_FIRST_DLY mem_rst_n_dly[1:0] = {mem_rst_n,mem_rst_n} ;
assign mem_addr = {{(ADDR_BITS-MEM_ROW_WIDTH){1'b0}},{mem_a}};
genvar gen_mem;
generate
for(gen_mem=0; gen_mem<(MEM_DQS_WIDTH/2); gen_mem=gen_mem+1) begin : i_mem
assign #CA_GROUP_TO_GROUP_DLY mem_addr_dly[(ADDR_BITS*(gen_mem+1)+ADDR_BITS)*2-1:(ADDR_BITS*(gen_mem+1))*2] = mem_addr_dly[(ADDR_BITS*gen_mem+ADDR_BITS)*2-1:(ADDR_BITS*gen_mem)*2];
assign #CA_GROUP_TO_GROUP_DLY mem_cke_dly[2*gen_mem+3:2*gen_mem+2] = mem_cke_dly[2*gen_mem+1:2*gen_mem];
assign #CA_GROUP_TO_GROUP_DLY mem_odt_dly[2*gen_mem+3:2*gen_mem+2] = mem_odt_dly[2*gen_mem+1:2*gen_mem];
assign #CA_GROUP_TO_GROUP_DLY mem_ras_n_dly[2*gen_mem+3:2*gen_mem+2] = mem_ras_n_dly[2*gen_mem+1:2*gen_mem];
assign #CA_GROUP_TO_GROUP_DLY mem_cas_n_dly[2*gen_mem+3:2*gen_mem+2] = mem_cas_n_dly[2*gen_mem+1:2*gen_mem];
assign #CA_GROUP_TO_GROUP_DLY mem_we_n_dly[2*gen_mem+3:2*gen_mem+2] = mem_we_n_dly[2*gen_mem+1:2*gen_mem];
assign #CA_GROUP_TO_GROUP_DLY mem_ba_dly[(gen_mem+1)*6+5:(gen_mem+1)*6] = mem_ba_dly[gen_mem*6+5:gen_mem*6];
assign #CA_GROUP_TO_GROUP_DLY mem_cs_n_dly[2*gen_mem+3:2*gen_mem+2] = mem_cs_n_dly[2*gen_mem+1:2*gen_mem];
assign #CA_GROUP_TO_GROUP_DLY mem_rst_n_dly[2*gen_mem+3:2*gen_mem+2] = mem_rst_n_dly[2*gen_mem+1:2*gen_mem];
assign #CA_GROUP_TO_GROUP_DLY mem_ck_dly[2*gen_mem+3:2*gen_mem+2] = mem_ck_dly[2*gen_mem+1:2*gen_mem];
assign #CA_GROUP_TO_GROUP_DLY mem_ck_n_dly[2*gen_mem+3:2*gen_mem+2] = mem_ck_n_dly[2*gen_mem+1:2*gen_mem];
ddr3 mem_core (
.rst_n (mem_rst_n_dly[2*gen_mem+1:2*gen_mem] ),
.ck (mem_ck_dly[2*gen_mem+1:2*gen_mem] ),
.ck_n (mem_ck_n_dly[2*gen_mem+1:2*gen_mem] ),
.cs_n (mem_cs_n_dly[2*gen_mem+1:2*gen_mem] ),
.ras_n (mem_ras_n_dly[2*gen_mem+1:2*gen_mem] ),
.cas_n (mem_cas_n_dly[2*gen_mem+1:2*gen_mem] ),
.we_n (mem_we_n_dly[2*gen_mem+1:2*gen_mem] ),
.addr (mem_addr_dly[(ADDR_BITS*gen_mem+ADDR_BITS)*2-1:ADDR_BITS*gen_mem*2] ),
.ba (mem_ba_dly[gen_mem*6+5:gen_mem*6] ),
.odt (mem_odt_dly[2*gen_mem+1:2*gen_mem] ),
.cke (mem_cke_dly[2*gen_mem+1:2*gen_mem] ),
.dq (mem_dq[16*gen_mem+15:16*gen_mem]),
.dqs (mem_dqs[2*gen_mem+1:2*gen_mem] ),
.dqs_n (mem_dqs_n[2*gen_mem+1:2*gen_mem] ),
.dm_tdqs (mem_dm[2*gen_mem+1:2*gen_mem] ),
.tdqs_n ( )
);
end
endgenerate
initial
begin
sys_rst_n = 1'b0;
#100 sys_rst_n = 1'b1;
end
reg grs_n;
//GTP_GRS I_GTP_GRS(
GTP_GRS GRS_INST(
.GRS_N (grs_n)
);
initial begin
grs_n = 1'b0;
#5 grs_n = 1'b1;
end
endmodule
仿真需要用到ddr3.v和ddr3_paramters.vh文件,将这两个文件复制到你创建的tb路径下。
打开ddr3.v文件,将115行修改成`include "ddr3_parameters.vh"

3 将文件添加到工程


4 pds软件运行一次仿真
先设置modelsim的路径以及仿真库路径

再执行仿真,这一步仿真肯定会出错,这步是为了让软件生成一个tcl脚本,后面我们对脚本进行修改。


3 修改tcl脚本
脚本路径如下,我们主要关注run_behav_compile.tcl和run_behav_simulate.tcl

这里我不直接解决所有问题,一个个解决问题,方便告诉你为什么会报这个错误。
上图那个错误是由于没有进行宏定义,导致没有创建这个参数引起的错误,看案例工程的ctrl_phy_sim.tcl和sim_file_list.f可以知道vlog了以下宏

这里我们打开run_behav_compile.tcl,进行下面修改

重新运行仿真

好家伙,错误更多了。不要怕,我们接着分析。
这是由于这些文件受到了保护,所以没办法仿真,那官方例程又为什么能仿真呢,我们对比下

好嘛!原来是自动生成的路径引用错误,把rtl修改成sim_lib后重新运行仿真,注意不要漏了哦。

你会惊喜的发现,ddr_init_done拉高了