使用MIG IP核的native接口进行DDR3的配置

目录

一、完成DDR3芯片的初始化工作。

1)top_ddr3_hdmi.v

2)top_ddr3_hdmi_tb.v

二、讨论分析DDR3芯片native接口的工作时序。

三、着手设计DDR3的接口突发时序。

四、设计DDR3突发模块的仿真代码。

一、完成DDR3芯片的初始化工作。

此次步骤是接着上篇文档进行设计的。(写文章-CSDN创作中心

在这里我们需要用到的文件有三个:

这三个文件在同一文件夹下,前两个用于进行仿真,因为它们包含了仿真模型。最后一个用于复制例化语句。

此次初始化操作,我们的任务是实现在modelsim上观察到信号init_calib_complete拉高。

并且在此次项目最终,我们需要实现的效果是在hdmi上实现图片显示,这里是利用串口进行传图。因此需要创建两个.v文件,顶层与测试文件。

正如本节标题所示,我们在此仅仅实现初始化,在这里我们的主要任务是模块复用工作。先一个一个来。

1)top_ddr3_hdmi.v

在此模块下需要例化我们生成的ddr3_ctrl  ip,这需要从生成的。veo文件进行复制。

比较长,我就截取部分代码,其中需要自己进行归类一下。注意我们还要生成一个pll时钟给ddr3供时。这里自行生成一个pll的ip核放在里面即可。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/03/03 15:44:43
// Design Name: 
// Module Name: top_ddr3_hdmi
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module top_ddr3_hdmi(
//--system---
	input 		sys_clk,
	input 		sys_rst,

//--ddr3---
	output [13:0]	ddr3_addr           ,
	output [2:0]	ddr3_ba	            ,
	output			ddr3_cas_n          ,
	output [0:0]	ddr3_ck_n           ,
	output [0:0]	ddr3_ck_p           ,
	output [0:0]	ddr3_cke            ,
	output			ddr3_ras_n          ,
	output			ddr3_reset_n        ,
	output			ddr3_we_n           ,
	inout [31:0]	ddr3_dq             ,
	inout [3:0]		ddr3_dqs_n          ,
	inout [3:0]		ddr3_dqs_p          ,
	output			init_calib_complete ,
	output [0:0]	ddr3_cs_n			,
	output [3:0]	ddr3_dm			    ,
	output [0:0]	ddr3_odt			
);
//中间端口线路
//pll
	wire clk_200M;
//app
	wire [27:0]		app_addr         ;    
	wire [2:0]		app_cmd          ;
	wire 			app_en           ;
	wire [255:0]	app_wdf_data     ;
	wire 			app_wdf_end      ;
	wire 			app_wdf_wren     ;
	wire [255:0]	app_rd_data      ;
	wire 			app_rd_data_end  ;
	wire 			app_rd_data_valid;
	wire 			app_rdy          ;
	wire 			app_wdf_rdy      ;
	wire 			app_sr_req       ;
	wire 			app_ref_req      ;
	wire 			app_zq_req       ;
	wire 			app_sr_active    ;
	wire 			app_ref_ack      ;
	wire 			app_zq_ack       ;

	wire 			ui_clk           ;
	wire 			ui_clk_sync_rst  ;
	wire [31:0]		app_wdf_mask     ;



//-----ddr3 ip
ddr3_ctrl u_ddr3_ctrl (

    // 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 [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 [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 [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                     (app_sr_req			),  // input			app_sr_req
    .app_ref_req                    (app_ref_req		),  // input			app_ref_req
    .app_zq_req                     (app_zq_req			),  // 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 [31:0]		app_wdf_mask


    // System Clock Ports

    .sys_clk_i                      (clk_200M			),
    .sys_rst                        (sys_rst			) // input sys_rst

);

//-----clk ip
ddr3_clk_gen uut_ddr3_clk_gen(
    .clk_out1	(clk_200M	),     		// output clk_out1
    .clk_in1	(sys_clk	)			// input clk_in1
);    

上面就是完整的代码,这个模块引出的端口就是只有ddr引脚接口,内部用户接口没做引出。只是接了连线。至此第一个模块设计完成。

2)top_ddr3_hdmi_tb.v

这个模块也比较简单,就是把引用第一个模块,以及引用ddr3_model.sv这个模块。而ddr3_model的例化语句可以从sim_tb_top.v中找到。具体标在下面。

值得注意的是,因为我们之前设置的32位位宽的双片ddr3,因此需要高两位和低两位分别例化,也就是例化两次(这个非常重要!!!)(ddr3仿真初始化失败,DDR4仿真没有效果_ddr初始化失败-CSDN博客

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/03/03 16:05:56
// Design Name: 
// Module Name: top_ddr3_hdmi_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module top_ddr3_hdmi_tb;


//端口
reg sys_clk;
reg sys_rst;

wire   [13:0]	ddr3_addr           ;
wire   [2:0]	ddr3_ba	            ;
wire  			ddr3_cas_n          ;
wire   [0:0]	ddr3_ck_n           ;
wire   [0:0]	ddr3_ck_p           ;
wire   [0:0]	ddr3_cke            ;
wire  			ddr3_ras_n          ;
wire  			ddr3_reset_n        ;
wire  			ddr3_we_n           ;
wire  [31:0]	ddr3_dq             ;
wire  [3:0]		ddr3_dqs_n          ;
wire  [3:0]		ddr3_dqs_p          ;
wire  			init_calib_complete ;
wire   [0:0]	ddr3_cs_n			;
wire   [3:0]	ddr3_dm			    ;
wire   [0:0]	ddr3_odt			;

//--top---
top_ddr3_hdmi uut_top_ddr3_hdmi(
//--system---
	.sys_clk			(sys_clk			),
	.sys_rst			(sys_rst			),

//--ddr3---
	.ddr3_addr          (ddr3_addr          ),
	.ddr3_ba	        (ddr3_ba	        ),
	.ddr3_cas_n         (ddr3_cas_n         ),
	.ddr3_ck_n          (ddr3_ck_n          ),
	.ddr3_ck_p          (ddr3_ck_p          ),
	.ddr3_cke           (ddr3_cke           ),
	.ddr3_ras_n         (ddr3_ras_n         ),
	.ddr3_reset_n       (ddr3_reset_n       ),
	.ddr3_we_n          (ddr3_we_n          ),
	.ddr3_dq            (ddr3_dq            ),
	.ddr3_dqs_n         (ddr3_dqs_n         ),
	.ddr3_dqs_p         (ddr3_dqs_p         ),
	.init_calib_complete(init_calib_complete),
	.ddr3_cs_n			(ddr3_cs_n			),
	.ddr3_dm			(ddr3_dm			),
	.ddr3_odt			(ddr3_odt			)
);

//--ddr3_model
//	ddr3_model uut_ddr3_model(
//		.rst_n   (ddr3_reset_n	),
//		.ck      (ddr3_ck_p		),
//		.ck_n    (ddr3_ck_n		),
//		.cke     (ddr3_cke		),
//		.cs_n    (ddr3_cs_n		),
//		.ras_n   (ddr3_ras_n	),
//		.cas_n   (ddr3_cas_n	),
//		.we_n    (ddr3_we_n		),
//		.dm_tdqs (ddr3_dm		),
//		.ba      (ddr3_ba		),
//		.addr    (ddr3_addr		),
//		.dq      (ddr3_dq		),
//		.dqs     (ddr3_dqs_p	),
//		.dqs_n   (ddr3_dqs_n	),
//		.tdqs_n  (				),
//		.odt     (ddr3_odt		)
//	);	


ddr3_model inst_ddr3_model_h (
            .rst_n   (ddr3_reset_n),
            .ck      (ddr3_ck_p),
            .ck_n    (ddr3_ck_n),
            .cke     (ddr3_cke),
            .cs_n    (ddr3_cs_n),
            .ras_n   (ddr3_ras_n),
            .cas_n   (ddr3_cas_n),
            .we_n    (ddr3_we_n),
            .dm_tdqs (ddr3_dm[3:2]),
            .ba      (ddr3_ba),
            .addr    (ddr3_addr),
            .dq      (ddr3_dq[31:16]),
            .dqs     (ddr3_dqs_p[3:2]),
            .dqs_n   (ddr3_dqs_n[3:2]),
            .tdqs_n  (),
            .odt     (ddr3_odt)
        );
 
    ddr3_model inst_ddr3_model_l (
            .rst_n   (ddr3_reset_n),
            .ck      (ddr3_ck_p),
            .ck_n    (ddr3_ck_n),
            .cke     (ddr3_cke),
            .cs_n    (ddr3_cs_n),
            .ras_n   (ddr3_ras_n),
            .cas_n   (ddr3_cas_n),
            .we_n    (ddr3_we_n),
            .dm_tdqs (ddr3_dm[1:0]),
            .ba      (ddr3_ba),
            .addr    (ddr3_addr),
            .dq      (ddr3_dq[15:0]),
            .dqs     (ddr3_dqs_p[1:0]),
            .dqs_n   (ddr3_dqs_n[1:0]),
            .tdqs_n  (),
            .odt     (ddr3_odt)
        );


initial begin
	sys_clk =  1'b1;
	sys_rst <= 1'b0;
	#10
	sys_rst <= 1'b1;
end

always #10 sys_clk = ~sys_clk;


endmodule

别的就没有了,现在看看仿真效果吧。

在107.560us完成了初始化。

二、讨论分析DDR3芯片native接口的工作时序。

上图是native接口的时序。主要分为命令,读数据和写数据。

总的来说关于DDR的native接口的使用分为三个

1)写命令

2)写数据

3)读数据

关于写命令时序如下:

这里的命令只能为写(000)和读(001),其他都是不被允许的。同时还要注意的是只有当app_en和app_rdy同时为高时,即两者完成握手后,才算是将命令写入成功。

关于写数据时序如下:

实际官方文档是给了三种时序,一种是写命令和写数据同时到达,另外两种是不同时到达,这里并未列出。

这里还有一个信号需要注意app_wdf_end此信号是输入信号,输入到MIG IP核中,此信号与设置的物理层 - 用户端” 的速率比值有关。还有首先明确的是我们的速率比值在上次使用的是4:1。一次的突发长度为8,8*32=256,此时正好一个时钟周期完成8byte的数据输入,因此app_wdf_end与app_wdf_wren是同步的。如果是2:1则不在同步,下面是仿真代码对比(来源于官网)因此在设计的时候需要注意此项。

关于读数据时序如下:

此时,存在两个信号,app_rd_data和app_rd_data_valid。

        以上便是native接口的时序,下面在这些时序的基础上,我们需要将MIG IP核的时序进行封装,以便于我们后面方便使用。

三、着手设计DDR3的接口突发时序。

状态机的设计:

状态机的介绍:

1.IDLE状态,此状态作为最开始的状态,在完成所有数据的写入以及最后一个数据读出后都会到达此状态。
2.ABRIT状态,此状态为仲裁状态,用于判断是否进入下一状态跳转。
3.WR状态,此状态为写数据地址状态(这里采用第一种方式),完成数据的写入。
4.RD_ADDR状态,此状态完成读地址的写入,知道此次突发读的最后一个地址完成握手才可以。
5.RD_WAIT状态,读等待状态,读地址和读数据肯定不是同时的,因此需要等待所有的数据读出。

写数据时序:

读数据时序:

注意:在书写状态机时,我们按照野火的教程,将状态跳转与输出变量(burst_wr_done和burst_rd_done)拆开来了。

//**************************************************************************
// *** 名称 : DDR3_burst_wf.v
// *** 作者 : wangfeng
// *** 博客 : 参考  https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2024年3月
// *** 描述 : 完成一次DDR3的突发读写操作
//**************************************************************************
module DDR3_burst_wf
//============================< 参数 >======================================
#(
parameter DDR_DM_W              = 4                     ,   //芯片dm位宽
parameter DDR_DQS_W             = 4                     ,   //芯片dqs位宽
parameter DDR_BANK_W            = 3                     ,   //芯片bank位宽
parameter DDR_ADDR_W            = 14                    ,   //芯片地址位宽
parameter DDR_DATA_W            = 32                    ,   //芯片数据位宽
//-------------------------------------------------------
parameter APP_DATA_W            = 256                   ,   //用户数据位宽
parameter APP_ADDR_W            = 28                    ,   //用户地址位宽
//-------------------------------------------------------
parameter BURST_ADDR_W          = 25                        //外部突发位宽 28-3
)
//============================< 信号 >======================================
(
//时钟和复位 --------------------------------------------
input                           sys_clk_i               ,   //DDR3 参考时钟
input                           sys_rst                 ,   //FPGA 全局复位
output                          ui_clk                  ,   //DDR3 工作时钟
output                          DDR3_rst                ,   //DDR3 同步复位
//突发读写接口 ------------------------------------------
input                           burst_rd_req            ,   //突发读请求   
input                           burst_wr_req            ,   //突发写请求
input   [BURST_ADDR_W   -4:0]   burst_rd_len            ,   //突发读长度
input   [BURST_ADDR_W   -4:0]   burst_wr_len            ,   //突发写长度
input   [BURST_ADDR_W   -1:0]   burst_rd_addr           ,   //突发读地址
input   [BURST_ADDR_W   -1:0]   burst_wr_addr           ,   //突发写地址
output  [APP_DATA_W     -1:0]   burst_rd_data           ,   //突发读数据
input   [APP_DATA_W     -1:0]   burst_wr_data           ,   //突发写数据
output                          burst_rd_ack            ,   //突发读应答,连接FIFO
output                          burst_wr_ack            ,   //突发写应答,连接FIFO
output  reg                     burst_rd_done           ,   //突发读完成信号
output  reg                     burst_wr_done           ,   //突发写完成信号
//DDR3芯片接口 ------------------------------------------
output  [DDR_ADDR_W     -1:0]   ddr3_addr               ,
output  [DDR_BANK_W     -1:0]   ddr3_ba                 ,
output                          ddr3_cas_n              ,
output                          ddr3_ck_n               ,
output                          ddr3_ck_p               ,
output                          ddr3_cke                ,
output                          ddr3_ras_n              ,
output                          ddr3_cs_n               ,
output                          ddr3_reset_n            ,
output                          ddr3_we_n               ,
inout   [DDR_DATA_W     -1:0]   ddr3_dq                 ,
inout   [DDR_DQS_W      -1:0]   ddr3_dqs_n              ,
inout   [DDR_DQS_W      -1:0]   ddr3_dqs_p              ,
output  [DDR_DM_W       -1:0]   ddr3_dm                 ,
output                          ddr3_odt
);
//============================< 信号 >======================================
reg     [APP_ADDR_W     -1:0]   app_addr                ;
wire    [2:0]                   app_cmd                 ;
wire                            app_en                  ;
wire    [APP_DATA_W     -1:0]   app_wdf_data            ;
wire                            app_wdf_end             ;
wire                            app_wdf_wren            ;
wire    [APP_DATA_W     -1:0]   app_rd_data             ;
wire                            app_rd_data_end         ;
wire                            app_rd_data_valid       ;
wire                            app_rdy                 ;
wire                            app_wdf_rdy             ;
//-------------------------------------------------------
reg     [4:0]                   state                   ;
reg     [BURST_ADDR_W   -4:0]   rd_len                  ;
reg     [BURST_ADDR_W   -4:0]   wr_len                  ;
reg     [BURST_ADDR_W   -1:0]   rd_addr_cnt             ;   //读地址计数器
reg     [BURST_ADDR_W   -1:0]   rd_data_cnt             ;   //读数据计数器
reg     [BURST_ADDR_W   -1:0]   wr_data_cnt             ;   //一次突发写内的计数器
//============================< 参数 >======================================
localparam DDR3_BL               = 8                    ;
//-------------------------------------------------------
localparam IDLE                  = 5'b00001             ;   //空闲状态
localparam ARBIT                 = 5'b00010             ;   //仲裁状态
localparam WR                    = 5'b00100             ;   //写准备状态
localparam RD_ADDR               = 5'b01000             ;   //读状态
localparam RD_WAIT               = 5'b10000             ;   //读等待状态
//==========================================================================
//==    DDR3 IP, input 200Mhz, get 400Mhz, ui 100Mhz
//==========================================================================
ddr3_ctrl uddr3_ctrl
(
    .ddr3_addr                  (ddr3_addr              ),  //output [13:0]
    .ddr3_ba                    (ddr3_ba                ),  //output [ 2:0]
    .ddr3_cas_n                 (ddr3_cas_n             ),  //output
    .ddr3_ck_n                  (ddr3_ck_n              ),  //output
    .ddr3_ck_p                  (ddr3_ck_p              ),  //output
    .ddr3_cke                   (ddr3_cke               ),  //output
    .ddr3_ras_n                 (ddr3_ras_n             ),  //output
    .ddr3_reset_n               (ddr3_reset_n           ),  //output
    .ddr3_we_n                  (ddr3_we_n              ),  //output
    .ddr3_dq                    (ddr3_dq                ),  //inout  [32:0]
    .ddr3_dqs_n                 (ddr3_dqs_n             ),  //inout  [ 3:0]
    .ddr3_dqs_p                 (ddr3_dqs_p             ),  //inout  [ 3:0]
    .init_calib_complete        (init_calib_complete    ),  //output
    .ddr3_cs_n                  (ddr3_cs_n              ),  //output
    .ddr3_dm                    (ddr3_dm                ),  //output [ 3:0]
    .ddr3_odt                   (ddr3_odt               ),  //output
    //---------------------------------------------------
    .app_addr                   (app_addr               ),  //input  [27:0]
    .app_cmd                    (app_cmd                ),  //input  [ 2:0]
    .app_en                     (app_en                 ),  //input
    .app_wdf_data               (app_wdf_data           ),  //input  [256:0]
    .app_wdf_end                (app_wdf_end            ),  //input
    .app_wdf_wren               (app_wdf_wren           ),  //input
    .app_rd_data                (app_rd_data            ),  //output [256:0]
    .app_rd_data_end            (app_rd_data_end        ),  //output
    .app_rd_data_valid          (app_rd_data_valid      ),  //output
    .app_rdy                    (app_rdy                ),  //output
    .app_wdf_rdy                (app_wdf_rdy            ),  //output
    .app_sr_req                 (1'b0                   ),  //input
    .app_ref_req                (1'b0                   ),  //input
    .app_zq_req                 (1'b0                   ),  //input
    .app_sr_active              (                       ),  //output
    .app_ref_ack                (                       ),  //output
    .app_zq_ack                 (                       ),  //output
    .ui_clk                     (ui_clk                 ),  //output 100Mhz
    .ui_clk_sync_rst            (ui_clk_sync_rst        ),  //output
    .app_wdf_mask               (0						),  //input  [31:0]32'b0000_0000_0000_0000
    //---------------------------------------------------
    .sys_clk_i                  (sys_clk_i              ),  //input  200Mhz
    .sys_rst                    (sys_rst                )   //input  系统复位
);

//复位信号
assign DDR3_rst = ui_clk_sync_rst | (~init_calib_complete);
//==========================================================================
//==    状态机  状态的跳转   state
//==========================================================================
always@(posedge ui_clk) begin
	if(DDR3_rst == 1'b1) begin
		state <= IDLE;
	end
	else begin
		case(state)
			IDLE: begin
				state <= ARBIT;
				end
			ARBIT: begin
				if(burst_wr_req == 1'b1)
					state <= WR;
				else if(burst_rd_req == 1'b1)
					state <= RD_ADDR;
				else 
					state <= state;
				end
			WR: begin
				if(wr_data_cnt == wr_len - 1'b1 && app_wdf_rdy && app_rdy)
					state <= IDLE;
				else 
					state <= state;
				end
			RD_ADDR: begin
				if(rd_addr_cnt == rd_len - 1'b1 && app_rdy)
					state <= RD_WAIT;
				else 
					state <= state;
				end
			RD_WAIT: begin
				if(rd_data_cnt == rd_len - 1'b1)
					state <= IDLE;
				else 
					state <= state;
				end
			default: state <= IDLE;
		endcase
	end

end

//==========================================================================
//==    状态机  输出的变量 burst_wr_done  burst_rd_done
//==========================================================================
always@(posedge ui_clk) begin
	if(DDR3_rst == 1'b1) begin
		burst_wr_done <= 1'b0;
		burst_rd_done <= 1'b0;
	end
	else begin
		case(state)
			IDLE,ARBIT,RD_ADDR: begin
					burst_wr_done <= 1'b0;
					burst_rd_done <= 1'b0;
				end
			WR: begin
				if(wr_data_cnt == wr_len - 1'b1 && app_wdf_rdy && app_rdy)
					burst_wr_done <= 1'b1;
				else 
					burst_wr_done <= 1'b0;
				end
			RD_WAIT: begin
				if(rd_data_cnt == rd_len - 1'b1)
					burst_rd_done <= 1'b1;
				else 
					burst_rd_done <= 1'b0;
				end
			default: begin
					burst_wr_done <= 1'b0;
					burst_rd_done <= 1'b0;
				end
		endcase
	end
end

//状态机名称,Modelsim测试用
//---------------------------------------------------
reg [55:0] state_name; //1个字符8位宽
always @(*) begin
    case(state)
        IDLE    :   state_name = "IDLE";
        ARBIT   :   state_name = "ARBIT";
        WR      :   state_name = "WR";
        RD_ADDR :   state_name = "RD_ADDR";
        RD_WAIT :   state_name = "RD_WAIT";
        default :   state_name = "IDLE";
    endcase
end

//==========================================================================
//==    在进入读写状态前锁存读写突发长度
//==========================================================================
always @(posedge ui_clk) begin
    if(DDR3_rst == 1'b1)
        rd_len <= 'b0;
    else if(state == ARBIT && burst_rd_req)
        rd_len <= burst_rd_len;
end
always @(posedge ui_clk) begin
    if(DDR3_rst == 1'b1)
        wr_len <= 'b0;
    else if(state == ARBIT && burst_wr_req)
        wr_len <= burst_wr_len;
end
//==========================================================================
//==    在一次写突发内,写数据个数计数器不断递增
//==========================================================================
always @(posedge ui_clk) begin
    if(DDR3_rst == 1'b1)
        wr_data_cnt <= 'b0;
    else if(state == WR && app_wdf_rdy && app_rdy) begin
        if(wr_data_cnt >= wr_len - 1)
            wr_data_cnt <= 'b0;
        else
            wr_data_cnt <= wr_data_cnt + 'b1;
    end
end
//==========================================================================
//==    每次给出读指令时,读地址递增一个突发
//==========================================================================
always @(posedge ui_clk) begin
    if(DDR3_rst == 1'b1)
        rd_addr_cnt <= 'b0;
    else if(state == RD_ADDR && app_rdy) begin
        if(rd_addr_cnt >= rd_len - 1)
            rd_addr_cnt <= 'b0;
        else
            rd_addr_cnt <= rd_addr_cnt + 1;
    end
end
//==========================================================================
//==    每读出一个数据时,数据个数递增1
//==========================================================================
always @(posedge ui_clk) begin
    if(DDR3_rst == 1'b1)
        rd_data_cnt <= 'b0;
    else if(app_rd_data_valid) begin
        if(rd_data_cnt >= rd_len - 1)
            rd_data_cnt <= 'b0;
        else
            rd_data_cnt <= rd_data_cnt + 'b1;
    end
end
//==========================================================================
//==    锁存local_address,并且在完成一次突发读写时递增读写地址
//==========================================================================
always @(posedge ui_clk) begin
    if(DDR3_rst == 1'b1) begin
        app_addr <= 'b0;
    end
    else if(state == ARBIT && burst_wr_req) begin
        app_addr <= burst_wr_addr;   //?和外界呈8倍关系
    end
    else if(state == ARBIT && burst_rd_req) begin
        app_addr <= burst_rd_addr;   //?和外界呈8倍关系
    end
    else if(state == WR && (wr_data_cnt < wr_len - 1) && app_wdf_rdy && app_rdy) begin
        app_addr <= app_addr + DDR3_BL;
    end
    else if(state == RD_ADDR && (rd_addr_cnt < rd_len - 1) && app_rdy) begin
        app_addr <= app_addr + DDR3_BL;
    end
end
//==========================================================================
//==    DDR3其他信号
//==========================================================================
//命令
assign app_cmd = (state == RD_ADDR || state == RD_WAIT) ? 3'b001 : 3'b000;

//使能
assign app_en = (state == WR || state == RD_ADDR) ? 1'b1 : 1'b0;

//读数据
assign burst_rd_data = app_rd_data;

//读应答,即读FIFO的写使能
assign burst_rd_ack = app_rd_data_valid;

//写数据
assign app_wdf_data = burst_wr_data;

//写应答,即写FIFO的读使能
assign burst_wr_ack = (state == WR && app_wdf_rdy && app_rdy) ? 1'b1 : 1'b0;

//写使能,指示数据写入
assign app_wdf_wren = burst_wr_ack;

//写结束,4:1模式下二者相等
assign app_wdf_end = app_wdf_wren;



endmodule

四、设计DDR3突发模块的仿真代码。

此次仿真测试代码是这样的,

1.进行第一次数据的写入,这里写入5个数据,0 1 2 3 4(地址: 0  8 16 24 32)

2.进行第一次数据的读出,这里读出6个数据,0 1 2 3 4 x(地址: 0  8 16 24 32 40)

3.写                        ,这里写入6个数据,5 6 7 8 9 10(地址: 40 48 56 64 72)

4.读                        ,这里读出6个数据,4 5 6 7 8  9 (地址:32 40 48 56 64)

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/03/03 16:05:56
// Design Name: 
// Module Name: DDR3_burst_wf_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module DDR3_burst_wf_tb;
//============================< 参数 >======================================
parameter DDR_DM_W              = 4                     ;   //芯片dm位宽
parameter DDR_DQS_W             = 4                     ;   //芯片dqs位宽
parameter DDR_BANK_W            = 3                     ;   //芯片bank位宽
parameter DDR_ADDR_W            = 14                    ;   //芯片地址位宽
parameter DDR_DATA_W            = 32                    ;   //芯片数据位宽
//-------------------------------------------------------
parameter APP_DATA_W            = 256                   ;   //用户数据位宽
parameter APP_ADDR_W            = 27                    ;   //用户地址位宽
//-------------------------------------------------------
parameter BURST_ADDR_W          = 27                    ;   //外部突发位宽 
//============================< 端口 >======================================
reg                             sys_clk                 ;   //DDR3 参考时钟
reg                             sys_rst                 ;   //FPGA 全局复位
wire                            ui_clk                  ;   //DDR3 工作时钟
wire                            DDR3_rst                ;   //DDR3 同步复位
//突发读写接口 ------------------------------------------
reg                             burst_rd_req            ;   //突发读请求
reg                             burst_wr_req            ;   //突发写请求
reg     [BURST_ADDR_W   -4:0]   burst_rd_len            ;   //突发读长度 
reg     [BURST_ADDR_W   -4:0]   burst_wr_len            ;   //突发写长度
reg     [BURST_ADDR_W   -1:0]   burst_rd_addr           ;   //突发读地址
reg     [BURST_ADDR_W   -1:0]   burst_wr_addr           ;   //突发写地址
wire    [APP_DATA_W     -1:0]   burst_rd_data           ;   //突发读数据
reg     [APP_DATA_W     -1:0]   burst_wr_data           ;   //突发写数据
wire                            burst_rd_ack            ;   //突发读应答,连接FIFO
wire                            burst_wr_ack            ;   //突发写应答,连接FIFO
wire                            burst_rd_done           ;   //突发读完成信号
wire                            burst_wr_done           ;   //突发写完成信号
//DDR3芯片接口 ------------------------------------------
wire    [DDR_ADDR_W     -1:0]   ddr3_addr               ;
wire    [DDR_BANK_W     -1:0]   ddr3_ba                 ;
wire                            ddr3_cas_n              ;
wire                            ddr3_ck_n               ;
wire                            ddr3_ck_p               ;
wire                            ddr3_cke                ;
wire                            ddr3_ras_n              ;
wire                            ddr3_cs_n               ;
wire                            ddr3_reset_n            ;
wire                            ddr3_we_n               ;
wire    [DDR_DATA_W     -1:0]   ddr3_dq                 ;
wire    [DDR_DQS_W      -1:0]   ddr3_dqs_n              ;
wire    [DDR_DQS_W      -1:0]   ddr3_dqs_p              ;
wire    [DDR_DM_W       -1:0]   ddr3_dm                 ;
wire                            ddr3_odt                ;
//==========================================================================
//==    模块例化
//==========================================================================
DDR3_burst_wf
#(
    .DDR_DM_W                   (DDR_DM_W               ),   //芯片dm位宽
    .DDR_DQS_W                  (DDR_DQS_W              ),   //芯片dqs位宽
    .DDR_BANK_W                 (DDR_BANK_W             ),   //芯片bank位宽
    .DDR_ADDR_W                 (DDR_ADDR_W             ),   //芯片地址位宽
    .DDR_DATA_W                 (DDR_DATA_W             ),   //芯片数据位宽
    //---------------------------------------------------
    .APP_DATA_W                 (APP_DATA_W             ),   //用户数据位宽
    .APP_ADDR_W                 (APP_ADDR_W             ),   //用户地址位宽
    //---------------------------------------------------
    .BURST_ADDR_W               (BURST_ADDR_W           )    //外部突发位宽 
)
u_DDR3_burst_wf
(
    .sys_clk_i                  (sys_clk                ),   //DDR3 参考时钟
    .sys_rst                    (sys_rst                ),   //FPGA 全局复位
    .ui_clk                     (ui_clk                 ),   //DDR3 工作时钟
    .DDR3_rst                   (DDR3_rst               ),   //DDR3 同步复位
    //---------------------------------------------------
    .burst_rd_req               (burst_rd_req           ),   //突发读请求
    .burst_wr_req               (burst_wr_req           ),   //突发写请求
    .burst_rd_len               (burst_rd_len           ),   //突发读长度
    .burst_wr_len               (burst_wr_len           ),   //突发写长度
    .burst_rd_addr              (burst_rd_addr          ),   //突发读地址
    .burst_wr_addr              (burst_wr_addr          ),   //突发写地址
    .burst_rd_data              (burst_rd_data          ),   //突发读数据
    .burst_wr_data              (burst_wr_data          ),   //突发写数据
    .burst_rd_ack               (burst_rd_ack           ),   //突发读应答,连接FIFO
    .burst_wr_ack               (burst_wr_ack           ),   //突发写应答,连接FIFO
    .burst_rd_done              (burst_rd_done          ),   //突发读完成信号
    .burst_wr_done              (burst_wr_done          ),   //突发写完成信号
    //---------------------------------------------------
    .ddr3_addr                  (ddr3_addr              ),
    .ddr3_ba                    (ddr3_ba                ),
    .ddr3_cas_n                 (ddr3_cas_n             ),
    .ddr3_ck_n                  (ddr3_ck_n              ),
    .ddr3_ck_p                  (ddr3_ck_p              ),
    .ddr3_cke                   (ddr3_cke               ),
    .ddr3_ras_n                 (ddr3_ras_n             ),
    .ddr3_cs_n                  (ddr3_cs_n              ),
    .ddr3_reset_n               (ddr3_reset_n           ),
    .ddr3_we_n                  (ddr3_we_n              ),
    .ddr3_dq                    (ddr3_dq                ),
    .ddr3_dqs_n                 (ddr3_dqs_n             ),
    .ddr3_dqs_p                 (ddr3_dqs_p             ),
    .ddr3_dm                    (ddr3_dm                ),
    .ddr3_odt                   (ddr3_odt               )
);

ddr3_model inst_ddr3_model_h (
            .rst_n   (ddr3_reset_n),
            .ck      (ddr3_ck_p),
            .ck_n    (ddr3_ck_n),
            .cke     (ddr3_cke),
            .cs_n    (ddr3_cs_n),
            .ras_n   (ddr3_ras_n),
            .cas_n   (ddr3_cas_n),
            .we_n    (ddr3_we_n),
            .dm_tdqs (ddr3_dm[3:2]),
            .ba      (ddr3_ba),
            .addr    (ddr3_addr),
            .dq      (ddr3_dq[31:16]),
            .dqs     (ddr3_dqs_p[3:2]),
            .dqs_n   (ddr3_dqs_n[3:2]),
            .tdqs_n  (),
            .odt     (ddr3_odt)
        );
 
    ddr3_model inst_ddr3_model_l (
            .rst_n   (ddr3_reset_n),
            .ck      (ddr3_ck_p),
            .ck_n    (ddr3_ck_n),
            .cke     (ddr3_cke),
            .cs_n    (ddr3_cs_n),
            .ras_n   (ddr3_ras_n),
            .cas_n   (ddr3_cas_n),
            .we_n    (ddr3_we_n),
            .dm_tdqs (ddr3_dm[1:0]),
            .ba      (ddr3_ba),
            .addr    (ddr3_addr),
            .dq      (ddr3_dq[15:0]),
            .dqs     (ddr3_dqs_p[1:0]),
            .dqs_n   (ddr3_dqs_n[1:0]),
            .tdqs_n  (),
            .odt     (ddr3_odt)
        );


//==========================================================================
//==    时钟信号和复位信号
//==========================================================================

initial begin
	sys_clk =  1'b1;
	sys_rst <= 1'b0;
	#10
	sys_rst <= 1'b1;
end

always #2.5 sys_clk = ~sys_clk;


//==========================================================================
//==    设计输入信号
//==========================================================================
initial begin
    burst_wr_req     = 0;
    burst_rd_req     = 0;
    burst_wr_len     = 0;
    burst_rd_len     = 0;
    burst_wr_addr    = 0;
    burst_rd_addr    = 0;
    burst_wr_data    = 0;
	@(negedge DDR3_rst);  	//初始化完成
	#10
	//----进行第一次数据的写入,这里写入5个数据,0 1 2 3 4
    @(posedge ui_clk);
    burst_wr_addr    = {3'b000,24'd0};
    burst_wr_req     = 1;
	burst_wr_len     = 5;
    @(posedge burst_wr_ack);
    burst_wr_req     = 0;
	//----进行第一次数据的读出,这里读出6个数据,0 1 2 3 4 x
    @(negedge burst_wr_done);
    @(posedge ui_clk);
    burst_rd_addr    = {3'b000,24'd0};
    burst_rd_req     = 1;
	burst_rd_len     = 6;
    @(posedge ui_clk);
    burst_rd_req     = 0;
    //--------------------------------------------------- 第2次
    //写						,这里写入6个数据,5 6 7 8 9 10
    @(negedge burst_rd_done);
    @(posedge ui_clk);
    burst_wr_addr    = {3'b000,24'd40};
    burst_wr_req     = 1;
	burst_wr_len     = 6;
    @(posedge ui_clk);
    burst_wr_req     = 0;
    //读						,这里读出6个数据,4 5 6 7 8 9
    @(negedge burst_wr_done);
    @(posedge ui_clk);
    burst_rd_addr    = {3'b000,24'd32};
    burst_rd_req     = 1;
	burst_rd_len     = 6;
    @(posedge ui_clk);
    burst_rd_req     = 0;
	
end

always@(posedge ui_clk) begin
	if(DDR3_rst == 1'b1)
		burst_wr_data <= 'b0;
	else if(burst_wr_ack == 1'b1)
		burst_wr_data <= burst_wr_data + 1'b1;
end

endmodule


1.进行第一次数据的写入,这里写入5个数据,0 1 2 3 4(地址: 0  8 16 24 32)

2.进行第一次数据的读出,这里读出6个数据,0 1 2 3 4 x(地址: 0  8 16 24 32 40)

3.写                        ,这里写入6个数据,5 6 7 8 9 10(地址: 40 48 56 64 72)

4.读                        ,这里读出6个数据,4 5 6 7 8  9 (地址:32 40 48 56 64)

至此突发模块设计完毕。

参考内容:DDR3(4):IP核再封装 - 咸鱼IC - 博客园 (cnblogs.com)

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值