MIG调试总结:
对vivado软件中用于控制DDR2 / DDR3 的 控制器MIG(Memory Interface Generator)IP核进行了仿真测试,以学习如何用IP核来控制FPGA板载SDRAM的读写。我们只需要学会MIG的接口控制就可以。
①配置IP核
Xilinx 的 DDR 控制器的名称简写为 MIG(Memory Interface Generator),在 Vivado 左侧窗口点击 IP Catalog,然后在 IP Catalog 窗口直接搜索关键字“mig”,就可以很容易的找到
MIG IP核有user interface 和 AXI4 interface两种接口以供选择,我们可以选择熟悉的接口来控制MIG。这里我选择用user interface。
创建完IP核后,可以通过观察它的仿真模型的波形来学习控制信号的设计,vivado提供的仿真例子从下图中打开:
打开后会创建一个新的工程文件,找到该工程便可直接进行simulation,进行波形的观察。
为了进行逻辑设计,先打开ip的例化模板(instance module),查看它的IO口,以确定需要设计哪些信号(不要关注太多信号,容易懵,看与所需功能相关的就好);或者直接打开此IP核的user guide,查看它的接口和对应注释,如下:
根据仿真波形的观察和user guide的注释,确定input的作用和output的时序,进行总结:
①根据mig IP的user interface 的output 反馈:
ui_clk : 此UI时钟必须是DRAM时钟的一半或四分之一。(用来设计读写逻辑)
ui_clk_sync_rst : This is the active-High UI reset.(有用,1-指示用户逻辑复位)
init_calib_complete : PHY在校准完成(初始化ddr3完成,(要用,指示可以开始读写了))
app_rdy : 1 - UI可以接收命令 (要用)
app_rd_data : 读取的数据 (要用)
app_rd_data_valid : 高电平时表示读出的数据有效 (要用)
app_wdf_rdy : 该输出表示写入数据FIFO已准备好接收数据。当app_wdf_rdy=1'b1和app_wdf_wren=1'b1时,接受写入数据 (要用)
app_sr_active : 此输出是保留的。(暂时不用)
app_rd_data_end : 暂时不知道是否要用到,看波形一直为1,注释也不太清楚(暂时不用)
app_ref_ack : 1-表示内存控制器已将请求的刷新命令发送到PHY接口(暂时不用)
app_zq_ack : 1-指示存储器控制器已将所请求的ZQ校准命令发送到PHY接口。(暂时不用)
app_ecc_multiple_err[7:0] : This signal should only be used when ECC is enabled 当ECC被启用并且与app_rd_data_valid一起有效时,该信号适用。如果来自外部存储器的读取数据在读取突发的每个节拍具有两个比特错误,则app_ecc_multiple_err[3:0]信号为非零。SECDED算法不校正相应的读取数据,并在此信号上设置一个非零值,以通知UI上损坏的读取数据。(暂时不用)
app_ecc_single_err[7:0] : 该信号在启用ECC时适用,并且与app_rd_data_vali一起有效。如果来自外部存储器的读取数据在读取突发的每个节拍具有单个比特错误,则app_ecc_single_err信号为非零(暂时不用)
②设计mig输入信号:
app_addr : 当前请求的地址
app_cmd : 当前请求的命令 :001-读 ; 000 – 写
app_en : 这是app_addr、app_cmd、app_sz、app_hi_pri信号的选通信;
app_wdf_data : 要写的数据
app_wdf_wren : 选通app_wdf_data ;
app_wdf_end : 该活动的高输入表示当前时钟周期是app_wdf_data[]上输入数据的最后一个周期。从仿真波形上看,与app_adf_wren保持一致即可。
app_hi_pri : 高输入提高当前请求的优先级。简单操作的话应该用不上?(不管,置0)
app_sz : 此输入是保留的,应绑定到0(置0)
app_sr_req : 此输入是保留的,应绑定到0(置0)
app_wdf_mask : 这为app_wdf_data[]提供了掩码(先不管,置0)
app_ref_req :高输入请求向DRAM发出刷新命令。(刷新用的,暂时不用,置0)
app_zq_req : 高输入请求向DRAM发出ZQ校准命令 (校准用的,先不用,置0)
app_correct_en_i : 当断言时,该有效的高信号校正单比特数据错误。只有在GUI中启用ECC时,此输入才有效。在示例设计中,该信号总是与1绑定。(校正单比特数据,只有启动ECC时有效,置1即可)
根据以上总结设计控制信号如下:
memc_en即app_en,其他同理。wr_sig和rd_sig为自己设计的由外部输入的读信号和写信号,根据这两个信号来启动读和写操作。
app_cmd :000 为写 , 001 为读。
app_wr_en : 写信号产生且写准备高电平时置高,否则为低。
app_wr_end : 与app_wr_en一致。
app_addr : 读信号高时为读地址,否则为写地址。
app_en : 写状态时:写准备高电平、命令准备高电平时置高;
读状态:命令准备信号高电平时置高。
设计完控制信号后,完成模块间的连线,然后设计测试模块。
从vivado提供的测试工程中复制出ddr3仿真模型和wire_delay模块,在test_bench中完成连线,并从例子中复制出对应的逻辑。(testbench最好直接copy测试工程的,然后替换我们设计的控制模块,否则跟我一样仅仅例化了ddr3模块并连线,得到的结果是init_calib_done信号一直没有拉高)。
设计时注意位宽参数的参数传递,确保对应位宽正确;根据资料,DDR3的burst length(突发长度)固定为8,所以我们可能不需要进行模式寄存器的加载?目前还不知怎么用user interface加载模式寄存器。
输入激励信号进行测试:值得注意的是,每次ddr3读写8个数据,对于mig端来说,意味着读写一个数据,地址位需要改变8(因为mig端数据位宽是ddr3读写位宽的8倍)。
读写时地址位改变小于8会造成重复读写,导致出错(没错就是我)。
仿真结果如下:
可以看到,72没有在wren高电平时写入,所以读出来不是72(而是ddr3原本存的数据)。
结尾:本次测试mig的user interface接口,引入读写信号wr_sig和rd_sig,设计的app逻辑如下:
结果符合要求。后续根据设计要求,增删wr_sig和rd_sig信号,对上述信号进行逻辑设计即可。
PS:
如果需要查看IP核的user guide,点击下图:
如果跳出网页:
则直接通过前面的网址进入官网,然后搜索最后圈出来的文件即可找到。
//
// Create Date: 2023/11/25 17:44:55
//
`timescale 1ps/1ps
module mig_ctrl #(
parameter DATA_WIDTH = 64,
parameter ADDR_WIDTH = 32
)
( //system
input clk ,
input rst_n ,
input memc_init_done ,
//user
input wr_sig ,
input rd_sig ,
input [ADDR_WIDTH - 1:0]wr_addr ,
input [ DATA_WIDTH - 1 : 0]wr_data,
input [ADDR_WIDTH - 1:0]rd_addr ,
//cmd
input memc_cmd_rdy ,
output wire memc_en ,
output wire[2:0]app_cmd ,
output wire[ADDR_WIDTH - 1:0]memc_addr ,
//write
input memc_wr_rdy ,
output wire memc_wr_en ,
output wire memc_wr_end ,
output wire [ DATA_WIDTH - 1 : 0]memc_wr_data ,
output wire [ DATA_WIDTH/8 - 1 : 0]memc_wr_mask ,
//read
input memc_rd_data,
input memc_rd_valid
);
localparam wr_cmd = 3'b000;
localparam rd_cmd = 3'b001;
assign memc_en = (app_cmd == wr_cmd)?(memc_init_done && memc_wr_rdy && memc_cmd_rdy ):(memc_cmd_rdy);
assign app_cmd = ((memc_init_done && rd_sig))?rd_cmd:wr_cmd;
assign memc_addr = (memc_init_done && rd_sig)?rd_addr:(wr_sig?wr_addr:0);
assign memc_wr_en = (memc_init_done && memc_wr_rdy && memc_cmd_rdy && wr_sig )?1:0;
assign memc_wr_end = memc_wr_en;
assign memc_wr_mask = 0 ;
assign memc_wr_data = (memc_init_done && memc_wr_rdy && wr_sig)?wr_data:0;
endmodule
//
// Create Date: 2023/11/25 20:18:42
//
`timescale 1ps/1ps
module mig_test #(
//***************************************************************************
parameter PORT_MODE = "BI_MODE",
parameter DATA_MODE = 4'b0010,
parameter TST_MEM_INSTR_MODE = "R_W_INSTR_MODE",
parameter EYE_TEST = "FALSE",
parameter DATA_PATTERN = "DGEN_ALL",
parameter CMD_PATTERN = "CGEN_ALL",
parameter CMD_WDT = 'h3FF,
parameter WR_WDT = 'h1FFF,
parameter RD_WDT = 'h3FF,
parameter SEL_VICTIM_LINE = 0,
parameter BEGIN_ADDRESS = 32'h00000000,
parameter END_ADDRESS = 32'h00ffffff,
parameter PRBS_EADDR_MASK_POS = 32'hff000000,
parameter CK_WIDTH = 1,
parameter nCS_PER_RANK = 1,
parameter CKE_WIDTH = 1,
parameter DM_WIDTH = 2,
parameter ODT_WIDTH = 1,
parameter BANK_WIDTH = 3,
parameter COL_WIDTH = 10,
parameter CS_WIDTH = 1,
parameter DQ_WIDTH = 16,
parameter DQS_WIDTH = 2,
parameter DQS_CNT_WIDTH = 1,
parameter DRAM_WIDTH = 8,
parameter ECC = "OFF",
parameter ECC_TEST = "OFF",
//parameter nBANK_MACHS = 4,
parameter nBANK_MACHS = 4,
parameter RANKS = 1,
parameter ROW_WIDTH = 14,
parameter ADDR_WIDTH = 28,
parameter BURST_MODE = "8",
parameter CLKIN_PERIOD = 5000,
parameter CLKFBOUT_MULT = 4,
parameter DIVCLK_DIVIDE = 1,
parameter CLKOUT0_PHASE = 0.0,
parameter CLKOUT0_DIVIDE = 1,
parameter CLKOUT1_DIVIDE = 2,
parameter CLKOUT2_DIVIDE = 32,
parameter CLKOUT3_DIVIDE = 8,
parameter MMCM_VCO = 800,
parameter MMCM_MULT_F = 8,
parameter MMCM_DIVCLK_DIVIDE = 1,
parameter SIMULATION = "FALSE",
parameter TCQ = 100,
parameter DRAM_TYPE = "DDR3",
parameter nCK_PER_CLK = 4,
parameter DEBUG_PORT = "OFF",
parameter RST_ACT_LOW = 1
)
(
// Inouts
inout [15:0] ddr3_dq,
inout [1:0] ddr3_dqs_n,
inout [1:0] ddr3_dqs_p,
// Outputs
output [13:0] ddr3_addr,
output [2:0] ddr3_ba,
output ddr3_ras_n,
output ddr3_cas_n,
output ddr3_we_n,
output ddr3_reset_n,
output [0:0] ddr3_ck_p,
output [0:0] ddr3_ck_n,
output [0:0] ddr3_cke,
output [0:0] ddr3_cs_n,
output [1:0] ddr3_dm,
output [0:0] ddr3_odt,
// Inputs
// Single-ended system clock
input wr_sig ,
input rd_sig ,
input [ADDR_WIDTH-1:0] wr_addr ,
input [APP_DATA_WIDTH-1:0] wr_data ,
input [ADDR_WIDTH-1:0] rd_addr ,
input sys_clk_i,
output init_calib_complete,
output app_en ,
// System reset - Default polarity of sys_rst pin is Active Low.
// System reset polarity will change based on the option
// selected in GUI.
input sys_rst
);
localparam DATA_WIDTH = 16;
localparam PAYLOAD_WIDTH = (ECC_TEST == "OFF") ? DATA_WIDTH : DQ_WIDTH;
localparam APP_DATA_WIDTH = 2 * nCK_PER_CLK * PAYLOAD_WIDTH;
localparam APP_MASK_WIDTH = APP_DATA_WIDTH / 8;
localparam MASK_SIZE = DATA_WIDTH/8;
wire [ADDR_WIDTH-1:0] app_addr;
wire [2:0] app_cmd;
//wire app_en;
wire app_rdy;
wire [APP_DATA_WIDTH-1:0] app_rd_data;
wire app_rd_data_end;
wire app_rd_data_valid;
wire [APP_DATA_WIDTH-1:0] app_wdf_data;
wire app_wdf_end;
wire [APP_MASK_WIDTH-1:0] app_wdf_mask;
wire app_wdf_rdy;
wire app_sr_active;
wire app_ref_ack;
wire app_zq_ack;
wire app_wdf_wren;
wire ui_clk ;
wire ui_clk_sync_rst;
mig_16b u_mig_16b (
// Memory interface ports
.ddr3_addr (ddr3_addr), // output [13:0] ddr3_addr
.ddr3_ba (ddr3_ba), // output [2:0] ddr3_ba
.ddr3_cas_n (ddr3_cas_n), // output ddr3_cas_n
.ddr3_ck_n (ddr3_ck_n), // output [0:0] ddr3_ck_n
.ddr3_ck_p (ddr3_ck_p), // output [0:0] ddr3_ck_p
.ddr3_cke (ddr3_cke), // output [0:0] ddr3_cke
.ddr3_ras_n (ddr3_ras_n), // output ddr3_ras_n
.ddr3_reset_n (ddr3_reset_n), // output ddr3_reset_n
.ddr3_we_n (ddr3_we_n), // output ddr3_we_n
.ddr3_dq (ddr3_dq), // inout [15:0] ddr3_dq
.ddr3_dqs_n (ddr3_dqs_n), // inout [1:0] ddr3_dqs_n
.ddr3_dqs_p (ddr3_dqs_p), // inout [1:0] ddr3_dqs_p
.init_calib_complete (init_calib_complete), // output init_calib_complete
.ddr3_cs_n (ddr3_cs_n), // output [0:0] ddr3_cs_n
.ddr3_dm (ddr3_dm), // output [1:0] ddr3_dm
.ddr3_odt (ddr3_odt), // output [0:0] ddr3_odt
// Application interface ports
.app_addr (app_addr), // input [27:0] app_addr
.app_cmd (app_cmd), // input [2:0] app_cmd
.app_en (app_en), // input app_en
.app_wdf_data (app_wdf_data), // input [127:0] app_wdf_data
.app_wdf_end (app_wdf_end), // input app_wdf_end
.app_wdf_wren (app_wdf_wren), // input app_wdf_wren
.app_rd_data (app_rd_data), // output [127:0] app_rd_data
.app_rd_data_end (app_rd_data_end), // output app_rd_data_end
.app_rd_data_valid (app_rd_data_valid), // output app_rd_data_valid
.app_rdy (app_rdy), // output app_rdy
.app_wdf_rdy (app_wdf_rdy), // output app_wdf_rdy
.app_sr_req ('b0), // input app_sr_req
.app_ref_req ('b0), // input app_ref_req
.app_zq_req ('b0), // input app_zq_req
.app_sr_active (app_sr_active), // output app_sr_active
.app_ref_ack (app_ref_ack), // output app_ref_ack
.app_zq_ack (app_zq_ack), // output app_zq_ack
.ui_clk (ui_clk), // output ui_clk
.ui_clk_sync_rst (ui_clk_sync_rst), // output ui_clk_sync_rst
.app_wdf_mask (app_wdf_mask), // input [15:0] app_wdf_mask
// System Clock Ports
.sys_clk_i (sys_clk_i),
.sys_rst (sys_rst) // input sys_rst
);
mig_ctrl #(
.DATA_WIDTH(APP_DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
)
mig_ctrl_inst( //system
.clk(ui_clk) ,
.rst_n(~ui_clk_sync_rst) ,
.memc_init_done(init_calib_complete) ,
.wr_sig(wr_sig) ,
.rd_sig(rd_sig) ,
.wr_addr(wr_addr) ,
.wr_data(wr_data),
.rd_addr(rd_addr) ,
.memc_cmd_rdy(app_rdy) ,
.memc_en(app_en) ,
.app_cmd(app_cmd) ,
.memc_addr(app_addr) ,
.memc_wr_rdy(app_wdf_rdy) ,
.memc_wr_en(app_wdf_wren) ,
.memc_wr_end(app_wdf_end) ,
.memc_wr_data(app_wdf_data) ,
.memc_wr_mask(app_wdf_mask) ,
.memc_rd_data(app_rd_data),
.memc_rd_valid(app_rd_data_valid)
);
endmodule
`timescale 1ps/100fs
//
// Create Date: 2023/11/26 13:20:38
//
module mig_test_tb( );
parameter COL_WIDTH = 10;
// # of memory Column Address bits.
parameter CS_WIDTH = 1;
// # of unique CS outputs to memory.
parameter DM_WIDTH = 2;
// # of DM (data mask)
parameter DQ_WIDTH = 16;
// # of DQ (data)
parameter DQS_WIDTH = 2;
parameter DQS_CNT_WIDTH = 1;
// = ceil(log2(DQS_WIDTH))
parameter DRAM_WIDTH = 8;
// # of DQ per DQS
parameter ECC = "OFF";
parameter RANKS = 1;
// # of Ranks.
parameter ODT_WIDTH = 1;
// # of ODT outputs to memory.
parameter ROW_WIDTH = 14;
// # of memory Row Address bits.
parameter ADDR_WIDTH = 28;
parameter CLKIN_PERIOD = 5000;
parameter REFCLK_FREQ = 200.0;
parameter tCK = 2500;
parameter CA_MIRROR = "OFF";
wire ddr3_reset_n;
wire [DQ_WIDTH-1:0] ddr3_dq_fpga;
wire [DQS_WIDTH-1:0] ddr3_dqs_p_fpga;
wire [DQS_WIDTH-1:0] ddr3_dqs_n_fpga;
wire [ROW_WIDTH-1:0] ddr3_addr_fpga;
wire [3-1:0] ddr3_ba_fpga;
wire ddr3_ras_n_fpga;
wire ddr3_cas_n_fpga;
wire ddr3_we_n_fpga;
wire [1-1:0] ddr3_cke_fpga;
wire [1-1:0] ddr3_ck_p_fpga;
wire [1-1:0] ddr3_ck_n_fpga;
wire [DQ_WIDTH-1:0] ddr3_dq_sdram;
reg [ROW_WIDTH-1:0] ddr3_addr_sdram [0:1];
reg [3-1:0] ddr3_ba_sdram [0:1];
reg ddr3_ras_n_sdram;
reg ddr3_cas_n_sdram;
reg ddr3_we_n_sdram;
wire [(CS_WIDTH*1)-1:0] ddr3_cs_n_sdram;
wire [ODT_WIDTH-1:0] ddr3_odt_sdram;
reg [1-1:0] ddr3_cke_sdram;
wire [DM_WIDTH-1:0] ddr3_dm_sdram;
wire [DQS_WIDTH-1:0] ddr3_dqs_p_sdram;
wire [DQS_WIDTH-1:0] ddr3_dqs_n_sdram;
reg [1-1:0] ddr3_ck_p_sdram;
reg [1-1:0] ddr3_ck_n_sdram;
reg [ODT_WIDTH-1:0] ddr3_odt_sdram_tmp;
wire init_calib_complete;
wire [(CS_WIDTH*1)-1:0] ddr3_cs_n_fpga;
wire [DM_WIDTH-1:0] ddr3_dm_fpga;
wire [ODT_WIDTH-1:0] ddr3_odt_fpga;
reg sys_clk_i;
reg sys_rst;
reg [DM_WIDTH-1:0] ddr3_dm_sdram_tmp;
reg wr_sig ;
reg rd_sig ;
reg [ADDR_WIDTH-1:0]wr_addr ;
reg [127:0]wr_data ;
reg [ADDR_WIDTH-1:0]rd_addr ;
reg [(CS_WIDTH*1)-1:0] ddr3_cs_n_sdram_tmp;
// Local parameters Declarations
//**************************************************************************//
localparam real TPROP_DQS = 0.00;
// Delay for DQS signal during Write Operation
localparam real TPROP_DQS_RD = 0.00;
// Delay for DQS signal during Read Operation
localparam real TPROP_PCB_CTRL = 0.00;
// Delay for Address and Ctrl signals
localparam real TPROP_PCB_DATA = 0.00;
// Delay for data signal during Write operation
localparam real TPROP_PCB_DATA_RD = 0.00;
// Delay for data signal during Read operation
localparam MEMORY_WIDTH = 16;
localparam NUM_COMP = DQ_WIDTH/MEMORY_WIDTH;
localparam ECC_TEST = "OFF" ;
localparam ERR_INSERT = (ECC_TEST == "ON") ? "OFF" : ECC ;
localparam real REFCLK_PERIOD = (1000000.0/(2*REFCLK_FREQ));
localparam RESET_PERIOD = 200000; //in pSec
localparam real SYSCLK_PERIOD = tCK;
wire app_en ;
mig_test mig_test_inst
(
// Inouts
.ddr3_dq(ddr3_dq_fpga),
.ddr3_dqs_n(ddr3_dqs_n_fpga),
.ddr3_dqs_p(ddr3_dqs_p_fpga),
// Outputs
.ddr3_addr(ddr3_addr_fpga),
.ddr3_ba(ddr3_ba_fpga),
.ddr3_ras_n(ddr3_ras_n_fpga),
.ddr3_cas_n(ddr3_cas_n_fpga),
.ddr3_we_n(ddr3_we_n_fpga),
.ddr3_reset_n(ddr3_reset_n),
.ddr3_ck_p(ddr3_ck_p_fpga),
.ddr3_ck_n(ddr3_ck_n_fpga),
.ddr3_cke(ddr3_cke_fpga),
.ddr3_cs_n(ddr3_cs_n_fpga),
.ddr3_dm(ddr3_dm_fpga),
.ddr3_odt(ddr3_odt_fpga),
// Inputs
// Single-ended system clock
.wr_sig(wr_sig) ,
.rd_sig(rd_sig) ,
.wr_addr(wr_addr) ,
.wr_data(wr_data) ,
.rd_addr(rd_addr) ,
.sys_clk_i(sys_clk_i),
.init_calib_complete(init_calib_complete),
.app_en(app_en),
// System reset - Default polarity of sys_rst pin is Active Low.
// System reset polarity will change based on the option
// selected in GUI.
.sys_rst(sys_rst)
);
genvar r,i;
generate
for (r = 0; r < CS_WIDTH; r = r + 1) begin: mem_rnk
if(DQ_WIDTH/16) begin: mem
for (i = 0; i < NUM_COMP; i = i + 1) begin: gen_mem
ddr3_model u_comp_ddr3
(
.rst_n (ddr3_reset_n),
.ck (ddr3_ck_p_sdram),
.ck_n (ddr3_ck_n_sdram),
.cke (ddr3_cke_sdram[r]),
.cs_n (ddr3_cs_n_sdram[r]),
.ras_n (ddr3_ras_n_sdram),
.cas_n (ddr3_cas_n_sdram),
.we_n (ddr3_we_n_sdram),
.dm_tdqs (ddr3_dm_sdram[(2*(i+1)-1):(2*i)]),
.ba (ddr3_ba_sdram[r]),
.addr (ddr3_addr_sdram[r]),
.dq (ddr3_dq_sdram[16*(i+1)-1:16*(i)]),
.dqs (ddr3_dqs_p_sdram[(2*(i+1)-1):(2*i)]),
.dqs_n (ddr3_dqs_n_sdram[(2*(i+1)-1):(2*i)]),
.tdqs_n (),
.odt (ddr3_odt_sdram[r])
);
end
end
if (DQ_WIDTH%16) begin: gen_mem_extrabits
ddr3_model u_comp_ddr3
(
.rst_n (ddr3_reset_n),
.ck (ddr3_ck_p_sdram),
.ck_n (ddr3_ck_n_sdram),
.cke (ddr3_cke_sdram[r]),
.cs_n (ddr3_cs_n_sdram[r]),
.ras_n (ddr3_ras_n_sdram),
.cas_n (ddr3_cas_n_sdram),
.we_n (ddr3_we_n_sdram),
.dm_tdqs ({ddr3_dm_sdram[DM_WIDTH-1],ddr3_dm_sdram[DM_WIDTH-1]}),
.ba (ddr3_ba_sdram[r]),
.addr (ddr3_addr_sdram[r]),
.dq ({ddr3_dq_sdram[DQ_WIDTH-1:(DQ_WIDTH-8)],
ddr3_dq_sdram[DQ_WIDTH-1:(DQ_WIDTH-8)]}),
.dqs ({ddr3_dqs_p_sdram[DQS_WIDTH-1],
ddr3_dqs_p_sdram[DQS_WIDTH-1]}),
.dqs_n ({ddr3_dqs_n_sdram[DQS_WIDTH-1],
ddr3_dqs_n_sdram[DQS_WIDTH-1]}),
.tdqs_n (),
.odt (ddr3_odt_sdram[r])
);
end
end
endgenerate
initial
sys_clk_i = 1'b0;
always
sys_clk_i = #(CLKIN_PERIOD/2.0) ~sys_clk_i;
initial begin
wr_sig = 0 ;
rd_sig = 0 ;
wr_addr = 0 ;
rd_addr = 0 ;
wr_data = 0 ;
sys_rst = 0 ;
#1000;
sys_rst = 1;
wait(init_calib_complete);
wr_sig = 1 ;
repeat(32)begin
wait(app_en);
wr_sig = 1 ;
wr_addr = wr_addr + 8 ;
wr_data = wr_data + 8 ;
#10000;
wr_sig = 0 ;
end
#80000;
wr_addr = 0;
wr_sig = 0 ;
#200000 ;
rd_sig = 1 ;
repeat(32)begin
wait(app_en);
rd_sig = 1 ;
rd_addr = rd_addr + 8 ;
#10000;
rd_sig = 0 ;
end
#5000000;
$finish;
end
always @( * ) begin
ddr3_ck_p_sdram <= #(TPROP_PCB_CTRL) ddr3_ck_p_fpga;
ddr3_ck_n_sdram <= #(TPROP_PCB_CTRL) ddr3_ck_n_fpga;
ddr3_addr_sdram[0] <= #(TPROP_PCB_CTRL) ddr3_addr_fpga;
ddr3_addr_sdram[1] <= #(TPROP_PCB_CTRL) (CA_MIRROR == "ON") ?
{ddr3_addr_fpga[ROW_WIDTH-1:9],
ddr3_addr_fpga[7], ddr3_addr_fpga[8],
ddr3_addr_fpga[5], ddr3_addr_fpga[6],
ddr3_addr_fpga[3], ddr3_addr_fpga[4],
ddr3_addr_fpga[2:0]} :
ddr3_addr_fpga;
ddr3_ba_sdram[0] <= #(TPROP_PCB_CTRL) ddr3_ba_fpga;
ddr3_ba_sdram[1] <= #(TPROP_PCB_CTRL) (CA_MIRROR == "ON") ?
{ddr3_ba_fpga[3-1:2],
ddr3_ba_fpga[0],
ddr3_ba_fpga[1]} :
ddr3_ba_fpga;
ddr3_ras_n_sdram <= #(TPROP_PCB_CTRL) ddr3_ras_n_fpga;
ddr3_cas_n_sdram <= #(TPROP_PCB_CTRL) ddr3_cas_n_fpga;
ddr3_we_n_sdram <= #(TPROP_PCB_CTRL) ddr3_we_n_fpga;
ddr3_cke_sdram <= #(TPROP_PCB_CTRL) ddr3_cke_fpga;
end
always @( * )
ddr3_cs_n_sdram_tmp <= #(TPROP_PCB_CTRL) ddr3_cs_n_fpga;
assign ddr3_cs_n_sdram = ddr3_cs_n_sdram_tmp;
always @( * )
ddr3_dm_sdram_tmp <= #(TPROP_PCB_DATA) ddr3_dm_fpga;//DM signal generation
assign ddr3_dm_sdram = ddr3_dm_sdram_tmp;
always @( * )
ddr3_odt_sdram_tmp <= #(TPROP_PCB_CTRL) ddr3_odt_fpga;
assign ddr3_odt_sdram = ddr3_odt_sdram_tmp;
// Controlling the bi-directional BUS
genvar dqwd;
generate
for (dqwd = 1;dqwd < DQ_WIDTH;dqwd = dqwd+1) begin : dq_delay
WireDelay #
(
.Delay_g (TPROP_PCB_DATA),
.Delay_rd (TPROP_PCB_DATA_RD),
.ERR_INSERT ("OFF")
)
u_delay_dq
(
.A (ddr3_dq_fpga[dqwd]),
.B (ddr3_dq_sdram[dqwd]),
.reset (sys_rst_n),
.phy_init_done (init_calib_complete)
);
end
WireDelay #
(
.Delay_g (TPROP_PCB_DATA),
.Delay_rd (TPROP_PCB_DATA_RD),
.ERR_INSERT ("OFF")
)
u_delay_dq_0
(
.A (ddr3_dq_fpga[0]),
.B (ddr3_dq_sdram[0]),
.reset (sys_rst_n),
.phy_init_done (init_calib_complete)
);
endgenerate
genvar dqswd;
generate
for (dqswd = 0;dqswd < DQS_WIDTH;dqswd = dqswd+1) begin : dqs_delay
WireDelay #
(
.Delay_g (TPROP_DQS),
.Delay_rd (TPROP_DQS_RD),
.ERR_INSERT ("OFF")
)
u_delay_dqs_p
(
.A (ddr3_dqs_p_fpga[dqswd]),
.B (ddr3_dqs_p_sdram[dqswd]),
.reset (sys_rst_n),
.phy_init_done (init_calib_complete)
);
WireDelay #
(
.Delay_g (TPROP_DQS),
.Delay_rd (TPROP_DQS_RD),
.ERR_INSERT ("OFF")
)
u_delay_dqs_n
(
.A (ddr3_dqs_n_fpga[dqswd]),
.B (ddr3_dqs_n_sdram[dqswd]),
.reset (sys_rst_n),
.phy_init_done (init_calib_complete)
);
end
endgenerate
endmodule