图2-4-1为黑金开发板上两片DDR3原理图。
1. 搭建仿真模型时需要例化两个ddr3_model,不然仿真时init_calib_complete信号会一直低。
2.还要考虑信号的延时,需要例化WireDelay模块,如Xilinx官方中给的例程中所示,不然app_rd_data数据一直是红色的。
3.自己顶层模块中例化的MIG核中的app_wdf_mask信号一定要给32‘d0,不然读出的app_rd_data数据一直是乱的。
下面贴出test_bench顶层代码
`timescale 1ps/100fs
module tb_ddr3_rw_top();//***************************************************************************// Traffic Gen related parameters//***************************************************************************parameter SIMULATION = "TRUE";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 BEGIN_ADDRESS = 32'h00000000;parameter END_ADDRESS = 32'h00000fff;parameter PRBS_EADDR_MASK_POS = 32'hff000000;parameter COL_WIDTH = 10;parameter CS_WIDTH = 1;parameter DM_WIDTH = 4;parameter DQ_WIDTH = 32;parameter DQS_WIDTH = 4;parameter DQS_CNT_WIDTH = 2;parameter DRAM_WIDTH = 8;parameter ECC = "OFF";parameter RANKS = 1;parameter ODT_WIDTH = 1;parameter ROW_WIDTH = 15;parameter ADDR_WIDTH = 29;//***************************************************************************// The following parameters are mode register settings//***************************************************************************parameter BURST_MODE = "8";parameter CA_MIRROR = "OFF";parameter CLKIN_PERIOD = 5000;parameter SIM_BYPASS_INIT_CAL = "FAST";parameter TCQ = 100;parameter RST_ACT_LOW = 1;parameter REFCLK_FREQ = 200.0;parameter tCK = 2500;parameter nCK_PER_CLK = 4;parameter DEBUG_PORT = "OFF";parameter DRAM_TYPE = "DDR3";localparam real TPROP_DQS = 0.00;localparam real TPROP_DQS_RD = 0.00;localparam real TPROP_PCB_CTRL = 0.00;localparam real TPROP_PCB_DATA = 0.00;localparam real TPROP_PCB_DATA_RD = 0.00;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;localparam real SYSCLK_PERIOD = tCK;reg sys_rst_n;wire sys_rst;reg sys_clk_i;wire sys_clk_i_n;reg clk_ref_i;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 init_calib_complete;wire tg_compare_error;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 [(CS_WIDTH*1)-1:0] ddr3_cs_n_sdram_tmp;reg [DM_WIDTH-1:0] ddr3_dm_sdram_tmp;reg [ODT_WIDTH-1:0] ddr3_odt_sdram_tmp;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;//**************************************************************************//// Reset Generation//**************************************************************************//initial beginsys_rst_n = 1'b0;#RESET_PERIODsys_rst_n = 1'b1;endassign sys_rst = RST_ACT_LOW ? sys_rst_n : ~sys_rst_n;//**************************************************************************//// Clock Generation//**************************************************************************//initialsys_clk_i = 1'b0;alwayssys_clk_i = #(CLKIN_PERIOD/2.0) ~sys_clk_i;assign sys_clk_i_n = ~sys_clk_i;initialclk_ref_i = 1'b0;alwaysclk_ref_i = #REFCLK_PERIOD ~clk_ref_i;always @( * ) beginddr3_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;endalways @( * )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 generationassign 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 BUSgenvar dqwd;generatefor (dqwd = 1;dqwd < DQ_WIDTH;dqwd = dqwd+1) begin : dq_delayWireDelay #(.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));endWireDelay #(.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));endgenerategenvar dqswd;generatefor (dqswd = 0;dqswd < DQS_WIDTH;dqswd = dqswd+1) begin : dqs_delayWireDelay #(.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));endendgenerate//============================< 被测试模块例化 >===============================
//例化DDR3读写测试-------------------
ddr3_rw_top ddr3_rw_top_inst(.ddr3_dq (ddr3_dq_fpga ), //DDR3 数据.ddr3_dqs_n (ddr3_dqs_n_fpga ), //DDR3 dqs负.ddr3_dqs_p (ddr3_dqs_p_fpga ), //DDR3 dqs正 .ddr3_addr (ddr3_addr_fpga ), //DDR3 地址.ddr3_ba (ddr3_ba_fpga ), //DDR3 banck 选择.ddr3_ras_n (ddr3_ras_n_fpga ), //DDR3 行选择.ddr3_cas_n (ddr3_cas_n_fpga ), //DDR3 列选择.ddr3_we_n (ddr3_we_n_fpga ), //DDR3 读写选择.ddr3_reset_n (ddr3_reset_n ), //DDR3 复位.ddr3_ck_p (ddr3_ck_p_fpga ), //DDR3 时钟正.ddr3_ck_n (ddr3_ck_n_fpga ), //DDR3 时钟负.ddr3_cke (ddr3_cke_fpga ), //DDR3 时钟使能.ddr3_cs_n (ddr3_cs_n_fpga ), //DDR3 片选.ddr3_dm (ddr3_dm_fpga ), //DDR3_dm.ddr3_odt (ddr3_odt_fpga ), //DDR3_odt.sys_clk_p (sys_clk_i ), //system clock positive on board.sys_clk_n (sys_clk_i_n ), //system clock negative on board.rst_n (sys_rst ), //reset ,low active.error_flag (tg_compare_error ) //错误标志
); //**************************************************************************//// Memory Models instantiations//**************************************************************************////**************************************************************************//// Memory Models instantiations//**************************************************************************//genvar r,i;generatefor (r = 0; r < CS_WIDTH; r = r + 1) begin: mem_rnkif(DQ_WIDTH/16) begin: memfor (i = 0; i < NUM_COMP; i = i + 1) begin: gen_memddr3_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]));endendif (DQ_WIDTH%16) begin: gen_mem_extrabitsddr3_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]));endendendgenerateendmodule
ddr3_rw_top.v(借用他人的demo)
`timescale 1ns / 1psmodule ddr3_rw_top(
// Inouts
inout [31:0] ddr3_dq, //ddr3 data
inout [3:0] ddr3_dqs_n, //ddr3 dqs negative
inout [3:0] ddr3_dqs_p, //ddr3 dqs positive
// Outputs
output [14:0] ddr3_addr, //ddr3 address
output [2:0] ddr3_ba, //ddr3 bank
output ddr3_ras_n, //ddr3 ras_n
output ddr3_cas_n, //ddr3 cas_n
output ddr3_we_n, //ddr3 write enable
output ddr3_reset_n, //ddr3 reset,
output [0:0] ddr3_ck_p, //ddr3 clock negative
output [0:0] ddr3_ck_n, //ddr3 clock positive
output [0:0] ddr3_cke, //ddr3_cke,
output [0:0] ddr3_cs_n, //ddr3 chip select,
output [3:0] ddr3_dm, //ddr3_dm
output [0:0] ddr3_odt, //ddr3_odt
input sys_clk_p, //system clock positive on board
input sys_clk_n, //system clock negative on board
input rst_n , //reset ,low active
//标志相关------------------------------output error_flag //错误指示信号
);//============================< 信号定义 >======================================
//parameter define
parameter integer WR_LEN = 512 ; //读、写长度
parameter integer DATA_WIDTH = 256 ; //数据位宽,突发长度为8,32bit,共256bit
parameter integer ADDR_WIDTH = 29 ; //根据MIG例化而来
//wire define
wire ui_clk ; //用户时钟
wire [ADDR_WIDTH - 1:0] app_addr ; //DDR3 地址
wire [2:0] app_cmd ; //用户读写命令
wire app_en ; //MIG IP核使能
wire app_rdy ; //MIG IP核空闲
wire [DATA_WIDTH - 1:0] app_rd_data ; //用户读数据
wire app_rd_data_end ; //突发读当前时钟最后一个数据
wire app_rd_data_valid ; //读数据有效
wire [DATA_WIDTH - 1:0] app_wdf_data ; //用户写数据
wire app_wdf_end ; //突发写当前时钟最后一个数据
wire [31:0] app_wdf_mask ; //写数据屏蔽
wire app_wdf_rdy ; //写空闲
wire app_wdf_wren ; //DDR3 写使能
wire app_sr_active;
wire app_ref_ack;
wire app_zq_ack;
//wire clk_ref_i ; //DDR3参考时钟
//wire sys_clk_i ; //MIG IP核输入时钟
wire sys_clk_200MHz ; //200M时钟
wire ui_clk_sync_rst ; //用户复位信号
wire init_calib_complete ; //校准完成信号//*****************************************************************************************
//** main code
//*****************************************************************************************//============================< 例化DDR3读写测试模块 >======================================ddr3_rw #(.WR_LEN (WR_LEN ),.DATA_WIDTH (DATA_WIDTH ),.ADDR_WIDTH (ADDR_WIDTH ))u_ddr3_rw(.ui_clk (ui_clk ), .ui_clk_sync_rst (ui_clk_sync_rst ), .init_calib_complete (init_calib_complete ),.app_rdy (app_rdy ),.app_wdf_rdy (app_wdf_rdy ),.app_rd_data_valid (app_rd_data_valid ),.app_rd_data (app_rd_data ), .app_addr (app_addr ),.app_en (app_en ),.app_wdf_wren (app_wdf_wren ),.app_wdf_end (app_wdf_end ),.app_cmd (app_cmd ),.app_wdf_data (app_wdf_data ),.error_flag (error_flag ));IBUFDS sys_clk_ibufgds
(
.O (sys_clk_200MHz ),
.I (sys_clk_p ),
.IB (sys_clk_n )
);
//============================< 例化MIG IP核 >===============================================ddr3 u_ddr3_inst (// Memory interface ports.ddr3_addr (ddr3_addr ), // output [14: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 [31:0] ddr3_dq.ddr3_dqs_n (ddr3_dqs_n ), // inout [3:0] ddr3_dqs_n.ddr3_dqs_p (ddr3_dqs_p ), // inout [3: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 [3:0] ddr3_dm.ddr3_odt (ddr3_odt ), // output [0:0] ddr3_odt// Application interface ports.app_addr (app_addr ), // input [28: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 [255: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 [255: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 (1'b0 ), // input app_sr_req.app_ref_req (1'b0 ), // input app_ref_req.app_zq_req (1'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 (32'd0 ), // input [31:0] app_wdf_mask ***** must be set to zero ****// System Clock Ports.sys_clk_i (sys_clk_200MHz ),.sys_rst (rst_n ) // input sys_rst);ila_ddr3_32 u_ila (.clk (ui_clk ), // input wire clk.probe0 (app_rd_data_valid ), // input wire [0:0] probe0 .probe1 (app_rd_data ) // input wire [255:0] probe1
); endmodule
ddr3_rw.v(借用他人demo)
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/06/01 21:41:11
// Design Name:
// Module Name: ddr3_rw
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module ddr3_rw #
( parameter integer WR_LEN = 1024 , //读、写长度parameter integer DATA_WIDTH = 256 , //数据位宽,突发长度为8,32bit,共256bitparameter integer ADDR_WIDTH = 29 //根据MIG例化而来
)(
//DDR3相关 ------------------------------------------------------ input ui_clk , //用户时钟input ui_clk_sync_rst , //复位,高有效input init_calib_complete , //DDR3初始化完成
//DDR3相关 ------------------------------------------------------ input app_rdy , //MIG 命令接收准备好标致input app_wdf_rdy , //MIG数据接收准备好input app_rd_data_valid , //读数据有效input [DATA_WIDTH - 1:0] app_rd_data , //用户读数据output reg [ADDR_WIDTH - 1:0] app_addr , //DDR3地址 output app_en , //MIG IP发送命令使能output app_wdf_wren , //用户写数据使能output app_wdf_end , //突发写当前时钟最后一个数据 output [2:0] app_cmd , //MIG IP核操作命令,读或者写output reg [DATA_WIDTH - 1:0] app_wdf_data , //用户写数据
//指示 ---------------------------------------------------------- output reg error_flag //读写错误标志);//============================< 信号定义 >======================================
//测试状态机-----------------------------------------
localparam IDLE = 4'b0001 ; //空闲状态
localparam WRITE = 4'b0010 ; //写状态
localparam WAIT = 4'b0100 ; //读到写过度等待
localparam READ = 4'b1000 ; //读状态
//reg define ----------------------------------------
reg [3:0] cur_state ; //三段式状态机现态
reg [3:0] next_state ; //三段式状态机次态
reg [ADDR_WIDTH - 1:0] rd_addr_cnt ; //用户读地址计数
reg [ADDR_WIDTH - 1:0] wr_addr_cnt ; //用户写地址计数
reg [ADDR_WIDTH - 1:0] rd_cnt ; //实际读地址标记
//wire define ---------------------------------------
wire error ; //读写错误标记
wire rst_n ; //复位,低有效
wire wr_proc ; //拉高表示写过程进行
wire wr_last ; //拉高表示写入最后一个数据
wire rd_addr_last ; //拉高表示是最后一个读地址//*********************************************************************************************
//** main code
//**********************************************************************************************
//==========================================================================
//== 信号赋值
//==========================================================================
assign rst_n = ~ui_clk_sync_rst;
//当MIG准备好后,用户同步准备好
assign app_en = app_rdy && ((cur_state == WRITE && app_wdf_rdy) || cur_state == READ);
//写指令,命令接收和数据接收都准备好,此时拉高写使能
assign app_wdf_wren = (cur_state == WRITE) && wr_proc;
//由于DDR3芯片时钟和用户时钟的分频选择4:1,突发长度为8,故两个信号相同
assign app_wdf_end = app_wdf_wren;
assign app_cmd = (cur_state == READ) ? 3'd1 :3'd0; //处于读的时候命令值为1,其他时候命令值为0
assign wr_proc = ~app_cmd && app_rdy && app_wdf_rdy; //拉高表示写过程进行
//处于写使能且是最后一个数据
assign wr_last = app_wdf_wren && (wr_addr_cnt == WR_LEN - 1) ;
//处于读指令、读有效且是最后一个数据
assign rd_addr_last = (rd_addr_cnt == WR_LEN - 1) && app_rdy && app_cmd;//==========================================================================
//== 状态机
//========================================================================== always @(posedge ui_clk or negedge rst_n) beginif(~rst_n)cur_state <= IDLE;elsecur_state <= next_state;
endalways @(*) beginif(~rst_n)next_state = IDLE;elsecase(cur_state)IDLE:if(init_calib_complete) //MIG IP核初始化完成 next_state = WRITE; else next_state = IDLE; WRITE: if(wr_last) //写入最后一个数据next_state = WAIT; else next_state = WRITE; WAIT: next_state = READ; READ: if(rd_addr_last) //写入最后一个读地址,数据读出需要时间next_state = IDLE;elsenext_state = READ; default:;endcase
endalways @(posedge ui_clk or negedge rst_n) beginif(~rst_n) begin app_wdf_data <= 0; wr_addr_cnt <= 0; rd_addr_cnt <= 0; app_addr <= 0; endelsecase(cur_state)IDLE:beginapp_wdf_data <= 0; wr_addr_cnt <= 0; rd_addr_cnt <= 0; app_addr <= 0;endWRITE:beginif(wr_proc)begin //写条件满足app_wdf_data <= app_wdf_data + 1; //写数据自加wr_addr_cnt <= wr_addr_cnt + 1; //写地址自加app_addr <= app_addr + 8; //DDR3 地址加8endelse begin //写条件不满足,保持当前值app_wdf_data <= app_wdf_data; wr_addr_cnt <= wr_addr_cnt;app_addr <= app_addr; endendWAIT:begin rd_addr_cnt <= 0; //读地址复位app_addr <= 0; //DDR3读从地址0开始endREAD:begin //读到设定的地址长度 if(app_rdy)begin //若MIG已经准备好,则开始读rd_addr_cnt <= rd_addr_cnt + 1'd1; //用户地址每次加一app_addr <= app_addr + 8; //DDR3地址加8endelse begin //若MIG没准备好,则保持原值rd_addr_cnt <= rd_addr_cnt;app_addr <= app_addr; endenddefault:beginapp_wdf_data <= 0;wr_addr_cnt <= 0;rd_addr_cnt <= 0;app_addr <= 0;endendcase
end
//==========================================================================
//== 其他
//==========================================================================//读信号有效,且读出的数不是写入的数时,将错误标志位拉高
assign error = (app_rd_data_valid && (rd_cnt!=app_rd_data)); //寄存状态标志位
always @(posedge ui_clk or negedge rst_n) beginif(~rst_n) error_flag <= 0;else if(error)error_flag <= 1;
end//对DDR3实际读数据个数编号计数
always @(posedge ui_clk or negedge rst_n) beginif(~rst_n) rd_cnt <= 0;//若计数到读写长度,且读有效,地址计数器则置0 else if(app_rd_data_valid && rd_cnt == WR_LEN - 1)rd_cnt <= 0; else if (app_rd_data_valid ) //读有效情况下每个时钟+1rd_cnt <= rd_cnt + 1;
endendmodule
仿真结果如下图所示: