图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 begin
sys_rst_n = 1'b0;
#RESET_PERIOD
sys_rst_n = 1'b1;
end
assign sys_rst = RST_ACT_LOW ? sys_rst_n : ~sys_rst_n;
//**************************************************************************//
// Clock Generation
//**************************************************************************//
initial
sys_clk_i = 1'b0;
always
sys_clk_i = #(CLKIN_PERIOD/2.0) ~sys_clk_i;
assign sys_clk_i_n = ~sys_clk_i;
initial
clk_ref_i = 1'b0;
always
clk_ref_i = #REFCLK_PERIOD ~clk_ref_i;
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
//============================< 被测试模块例化 >===============================
//例化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;
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
endmodule
ddr3_rw_top.v(借用他人的demo)
`timescale 1ns / 1ps
module 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,共256bit
parameter 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) begin
if(~rst_n)
cur_state <= IDLE;
else
cur_state <= next_state;
end
always @(*) begin
if(~rst_n)
next_state = IDLE;
else
case(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;
else
next_state = READ;
default:;
endcase
end
always @(posedge ui_clk or negedge rst_n) begin
if(~rst_n) begin
app_wdf_data <= 0;
wr_addr_cnt <= 0;
rd_addr_cnt <= 0;
app_addr <= 0;
end
else
case(cur_state)
IDLE:begin
app_wdf_data <= 0;
wr_addr_cnt <= 0;
rd_addr_cnt <= 0;
app_addr <= 0;
end
WRITE:begin
if(wr_proc)begin //写条件满足
app_wdf_data <= app_wdf_data + 1; //写数据自加
wr_addr_cnt <= wr_addr_cnt + 1; //写地址自加
app_addr <= app_addr + 8; //DDR3 地址加8
end
else begin //写条件不满足,保持当前值
app_wdf_data <= app_wdf_data;
wr_addr_cnt <= wr_addr_cnt;
app_addr <= app_addr;
end
end
WAIT:begin
rd_addr_cnt <= 0; //读地址复位
app_addr <= 0; //DDR3读从地址0开始
end
READ:begin //读到设定的地址长度
if(app_rdy)begin //若MIG已经准备好,则开始读
rd_addr_cnt <= rd_addr_cnt + 1'd1; //用户地址每次加一
app_addr <= app_addr + 8; //DDR3地址加8
end
else begin //若MIG没准备好,则保持原值
rd_addr_cnt <= rd_addr_cnt;
app_addr <= app_addr;
end
end
default:begin
app_wdf_data <= 0;
wr_addr_cnt <= 0;
rd_addr_cnt <= 0;
app_addr <= 0;
end
endcase
end
//==========================================================================
//== 其他
//==========================================================================
//读信号有效,且读出的数不是写入的数时,将错误标志位拉高
assign error = (app_rd_data_valid && (rd_cnt!=app_rd_data));
//寄存状态标志位
always @(posedge ui_clk or negedge rst_n) begin
if(~rst_n)
error_flag <= 0;
else if(error)
error_flag <= 1;
end
//对DDR3实际读数据个数编号计数
always @(posedge ui_clk or negedge rst_n) begin
if(~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 ) //读有效情况下每个时钟+1
rd_cnt <= rd_cnt + 1;
end
endmodule
仿真结果如下图所示: