【DDR3 控制器设计】(7)DDR3 的用户端口读写模块设计

news2025/3/14 10:23:47

写在前面

本系列为 DDR3 控制器设计总结,此系列包含 DDR3 控制器相关设计:认识 MIG、初始化、读写操作、FIFO 接口等。通过此系列的学习可以加深对 DDR3 读写时序的理解以及 FIFO 接口设计等,附上汇总博客直达链接。

【DDR3 控制器设计】系列博客汇总篇(附直达链接)


目录

实验任务

实验环境

实验介绍

接口详解

用户写控制模块

接口申明

用户读控制模块

程序设计

写控制模块

读控制模块

顶层模块

仿真测试

汇总篇


实验任务

在之前设计的 DDR3 控制器的基础上,添加用户写、读模块,便于在用户端更容易的对 DDR3 进行写读控制。

实验环境

开发环境:Vivado 2018.2

FPGA 芯片型号:xc7a100tffg484-2

DDR3 型号:MT41J256M16HA-125

实验介绍

经过前几部分的控制器设计,已经包含有DDR3的读写模块、读写仲裁模块,读写指令 FIFO以及读写数据 FIFO 模块,现在便可以对此项设计进行写读验证,但是直接对 FIFO 端的信号进行控制的话,信号过多设计起来较为麻烦,因此考虑在外围添加用户端的写、读控制模块,减少信号交互数,便于用户端进行写读控制。

接口详解

用户写控制模块

用户端的写控制模块是与写指令 FIFO 和写数据 FIFO 的接口进行交互的,因此可以依据 FIFO 的相关信号进行用户写模块的设计,大致设计思路为:当用户写使能信号拉高时,依次将写数据累加,并且定义一个计数器用于计算写入数据的个数,这个可以作为突发长度的设计,当数据完全写入写数据 FIFO 中时,输出相应的指令信号:指令类型、突发长度、初始地址。其中指令类型可以固定为全0表示进行写操作,突发长度可以根据写入数据计数值得到,初始地址根据每次指令使能信号拉高累加。最后当写数据 FIFO 的空信号拉高时,拉个一个时钟周期的单次写完成信号。

接口申明

信号

方向

描述

clk

input

用户端时钟信号

rst_n

input

用户端复位,低有效

wr_en

input

写数据使能信号

wr_data

input

写入的数据

fifo_wr_data_empty

input

写fifo为空信号

fifo_wr_data_en

output

写数据fifo写使能信号

fifo_wr_data

output

写入fifo的数据

fifo_wr_cmd_en

output

写指令fifo写使能信号

fifo_wr_cmd_brust_len

output

写数据突发长度

fifo_wr_cmd_addr

output

此次写数据初始地址

fifo_wr_cmd_instr

output

操作指令信号

user_wr_end

output

单次写操作完成标志信号

用户读控制模块

用户端的读控制模块是与读指令 FIFO 和读数据 FIFO 的接口进行交互的,因此可以依据 FIFO 的相关信号进行用户读模块的设计,大致设计思路为:当开始读信号拉高时,依次累加读地址信号,并定义一个计数器,用于计算读出数据的个数,当读出的数据数量达到单次突发长度,并拉低读使能信号,并且拉高读完成信号,表示单次的读操作完成。

程序设计

写控制模块

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Engineer    : Linest-5                                                             
// File        : user_wr_ctrl.v                                                              
// Create      : 2022-09-29 15:07:20                                                   
// Revise      : 2022-09-29 16:26:45                                                  
// Module Name : user_wr_ctrl                                                                 
// Description : 用户端写控制模块                                                                         
// Editor : sublime text3, tab size (4)                                                                                                 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

module user_wr_ctrl(
	input                 clk,                   //用户端时钟
	input                 rst_n,                 //用户端复位,低有效
	input                 wr_en,                 //写数据使能信号
	input       [127:0]   wr_data,               //写入的数据
	input                 fifo_wr_data_empty,    //写fifo为空信号
	output reg            fifo_wr_data_en,       //写数据fifo写使能信号
	output reg  [127:0]   fifo_wr_data,          //写入fifo的数据
	output reg            fifo_wr_cmd_en,        //写指令fifo写使能信号
	output reg  [7:0]     fifo_wr_cmd_brust_len, //写数据突发长度
	output reg  [28:0]    fifo_wr_cmd_addr,      //此次写数据初始地址
	output      [2:0]     fifo_wr_cmd_instr,     //操作指令信号
	output reg            user_wr_end            //单次写操作完成标志信号
	);

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*     信号定义                                                                   */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
reg     [7:0]             data_cnt;              //写入数据个数计数信号
reg                       fifo_wr_data_empty_reg;//写数据fifo空标志打拍信号

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*     Main Code                                                                 */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
//写指令:3'b000,读指令:3'b001
assign fifo_wr_cmd_instr = 3'b000;

//写入的数据个数计数信号
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		data_cnt <= 'd0;
	end
	else if (wr_en) begin
		data_cnt <= data_cnt + 'd1;
	end
	else begin
		data_cnt <= 'd0;
	end
end

//对数据使能信号打拍输出
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		fifo_wr_data_en <= 'd0;
	end
	else begin
		fifo_wr_data_en <= wr_en;		
	end
end

//对写入的数据打拍输出
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		fifo_wr_data <= 'd0;
	end
	else begin
		fifo_wr_data <= wr_data;
	end
end

//当数据完全写入fifo中后,启动命令使能信号
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		fifo_wr_cmd_en <= 'd0;
	end
	else if ((~wr_en) && fifo_wr_data_en) begin
		fifo_wr_cmd_en <= 'd1;
	end
	else begin
		fifo_wr_cmd_en <= 'd0;
	end
end

//根据写入的数据计数得到突发长度输出
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		fifo_wr_cmd_brust_len <= 'd0;
	end
	else if ((~wr_en) && fifo_wr_data_en) begin
		fifo_wr_cmd_brust_len <= data_cnt;
	end
	else begin
		fifo_wr_cmd_brust_len <= 'd0;
	end
end

//根据每次的写数据的个数确定下一次写的初始地址
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		fifo_wr_cmd_addr <= 'd0;
	end
	else if (fifo_wr_cmd_en) begin
		fifo_wr_cmd_addr <= fifo_wr_cmd_addr + (fifo_wr_cmd_brust_len << 'd3);
	end
	else begin
		fifo_wr_cmd_addr <= fifo_wr_cmd_addr;
	end
end

//对写数据fifo的空标志拉高信号打拍
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		fifo_wr_data_empty_reg <= 'd0;
	end
	else begin
		fifo_wr_data_empty_reg <= fifo_wr_data_empty;
	end
end

//一次写完成信号生成
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		user_wr_end <= 'd0;
	end
	else if (fifo_wr_data_empty && (~fifo_wr_data_empty_reg)) begin
		user_wr_end <= 'd1;
	end
	else begin
		user_wr_end <= 'd0;
	end
end

endmodule

读控制模块

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Engineer    : Linest-5                                                             
// File        : user_rd_ctrl.v                                                              
// Create      : 2022-09-29 16:27:57                                                   
// Revise      : 2022-09-29 16:27:57                                                  
// Module Name : user_rd_ctrl                                                                 
// Description : 用户端读控制模块                                                                         
// Editor : sublime text3, tab size (4)                                                                                                 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

module user_rd_ctrl(
	input                 clk,                   //用户端时钟
	input                 rst_n,                 //用户端复位,低有效
	input                 rd_start,
	input       [6:0]     fifo_rd_data_count,
	output reg            fifo_rd_data_en,
	output reg            fifo_rd_cmd_en,
    output      [7:0]     fifo_rd_cmd_brust_len,
    output reg  [28:0]    fifo_rd_cmd_addr,
    output      [2:0]     fifo_rd_cmd_instr,
    output reg            user_rd_end
	);

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*     信号定义                                                                   */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
reg    [7:0]              rd_data_cnt;

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*     Main Code                                                                 */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
//对开始读信号打拍输出
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		fifo_rd_cmd_en <= 'd0;
	end
	else begin
		fifo_rd_cmd_en <= rd_start;		
	end
end

assign fifo_rd_cmd_brust_len = 'd64;
assign fifo_rd_cmd_instr     = 3'b001;

//每次读操作的初始地址
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		fifo_rd_cmd_addr <= 'd0;
	end
	else if (fifo_rd_cmd_en) begin
		fifo_rd_cmd_addr <= fifo_rd_cmd_addr + (fifo_rd_cmd_brust_len << 'd3);
	end
	else begin
		fifo_rd_cmd_addr <= fifo_rd_cmd_addr;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		fifo_rd_data_en <= 'd0;
	end
	else if (fifo_rd_data_en && (rd_data_cnt == (fifo_rd_cmd_brust_len - 'd1))) begin
		fifo_rd_data_en <= 'd0;
	end
	else if (fifo_rd_data_count == (fifo_rd_cmd_brust_len - 'd6)) begin
		fifo_rd_data_en <= 'd1;
	end
	else begin
		fifo_rd_data_en <= fifo_rd_data_en;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		rd_data_cnt <= 'd0;
	end
	else if (fifo_rd_data_en && (rd_data_cnt == (fifo_rd_cmd_brust_len - 'd1))) begin
		rd_data_cnt <= 'd0;
	end
	else if (fifo_rd_data_en) begin
		rd_data_cnt <= rd_data_cnt + 'd1;
	end
	else begin
		rd_data_cnt <= 'd0;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		user_rd_end <= 'd0;
	end
	else if (fifo_rd_data_en && (rd_data_cnt == (fifo_rd_cmd_brust_len - 'd1))) begin
		user_rd_end <= 'd1;
	end
	else begin
		user_rd_end <= 'd0;
	end
end

endmodule

顶层模块

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Engineer    : Linest-5                                                         
/* File        : top_ddr3_init.v                                                         
/* Create      : 2022-09-15 09:58:59
/* Revise      : 2022-09-24 21:11:50                                                  
/* Module Name :                                                   
/* Description :                                                                          
/* Editor : sublime text3, tab size (4)                                                                                
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

module top_ddr3_init(
  // Inouts
    inout [15:0]       ddr3_dq,
    inout [1:0]        ddr3_dqs_n,
    inout [1:0]        ddr3_dqs_p,
    // Outputs
    output [14: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
    // Differential system clocks
    input              sys_clk,
    input              rst_n
);

wire                   init_calib_complete;
wire                   ui_clk;
wire                   ui_clk_sync_rst;
wire   [127:0]         wr_data;
wire   [7:0]           wr_brust_len;
wire                   wr_start;
wire   [28:0]          wr_addr;
wire   [2:0]           wr_cmd;
wire   [15:0]          wr_mask;
wire                   data_req;
wire                   wr_end;
wire                   app_rdy;
wire                   app_wdf_rdy;
wire   [2:0]           app_cmd;
wire                   app_en;
wire   [28:0]          app_addr;
wire   [127:0]         app_wdf_data;
wire                   app_wdf_wren;
wire   [15:0]          app_wdf_mask;
wire                   app_wdf_end;

wire   [7:0]           rd_brust_len;
wire                   rd_start;
wire   [28:0]          rd_addr;
wire   [2:0]           rd_cmd;
wire   [127:0]         rd_data;
wire                   rd_data_valid;
wire                   rd_end;
wire   [127:0]         app_rd_data;
wire                   app_rd_data_end;
wire                   app_rd_data_valid;

wire   [2:0]           app_wr_cmd;
wire                   app_wr_en;
wire   [28:0]          app_wr_addr;

wire   [2:0]           app_rd_cmd;
wire                   app_rd_en;
wire   [28:0]          app_rd_addr;

/**************FIFO控制部分*******************/
wire                   user_clk;
//写指令部分
wire                   fifo_wr_cmd_en;
wire   [7:0]           fifo_wr_cmd_brust_len;
wire   [28:0]          fifo_wr_cmd_addr;
wire   [2:0]           fifo_wr_cmd_instr;
wire                   fifo_wr_cmd_empty;
wire                   fifo_wr_cmd_full;

//写数据部分
wire                   fifo_wr_data_en;
wire   [127:0]         fifo_wr_data;
wire                   fifo_wr_data_full ;
wire                   fifo_wr_data_empty;
wire   [6:0]           fifo_wr_data_count;

//读指令部分                
wire                   fifo_rd_cmd_en;
wire   [7:0]           fifo_rd_cmd_brust_len;
wire   [28:0]          fifo_rd_cmd_addr;
wire   [2:0]           fifo_rd_cmd_instr;
wire                   fifo_rd_cmd_empty;
wire                   fifo_rd_cmd_full;

//读数据部分
wire                   fifo_rd_data_en;
wire   [127:0]         fifo_rd_data;
wire                   fifo_rd_data_full;
wire                   fifo_rd_data_empty;
wire   [6:0]           fifo_rd_data_count;

//用户写控制模块
wire                   user_wr_en;
wire   [127:0]         user_wr_data;
wire                   user_wr_end;

//用户读控制模块
wire                   user_rd_start;
wire                   user_rd_end;

assign app_en   = app_wr_en | app_rd_en;
assign app_addr = app_wr_addr | app_rd_addr;
assign app_cmd  = (app_wr_en == 'd1) ? 3'b000 : 3'b001;

//DDR工作时钟PLL例化
ddr3_clock ddr3_clock_inst(
    .clk_out1(sys_clk_in),     // output clk_out1
    .clk_in1(sys_clk)          // input clk_in1
);      

//DDR初始化模块例化
ddr3_init u_ddr3_init (

    // 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 [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 [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 [127:0]   app_wdf_data
    .app_wdf_end           (app_wdf_wren),  // 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            (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          (app_wdf_mask),  // input [15:0]    app_wdf_mask
    // System Clock Ports
    .sys_clk_i             (sys_clk_in),  // input     sys_clk_i
    .sys_rst               (rst_n) // input sys_rst
);

//用户端写控制模块例化
user_wr_ctrl inst_user_wr_ctrl (
    .clk                   (user_clk),
    .rst_n                 ((~ui_clk_sync_rst) || (init_calib_complete)),
    .wr_en                 (user_wr_en),
    .wr_data               (user_wr_data),
    .fifo_wr_data_empty    (fifo_wr_data_empty),
    .fifo_wr_data_en       (fifo_wr_data_en),
    .fifo_wr_data          (fifo_wr_data),
    .fifo_wr_cmd_en        (fifo_wr_cmd_en),
    .fifo_wr_cmd_brust_len (fifo_wr_cmd_brust_len),
    .fifo_wr_cmd_addr      (fifo_wr_cmd_addr),
    .fifo_wr_cmd_instr     (fifo_wr_cmd_instr),
    .user_wr_end           (user_wr_end)
);

//用户端读控制模块
user_rd_ctrl inst_user_rd_ctrl (
    .clk                   (user_clk),
    .rst_n                 ((~ui_clk_sync_rst) || (init_calib_complete)),
    .rd_start              (user_rd_start),
    .fifo_rd_data_count    (fifo_rd_data_count),
    .fifo_rd_data_en       (fifo_rd_data_en),
    .fifo_rd_cmd_en        (fifo_rd_cmd_en),
    .fifo_rd_cmd_brust_len (fifo_rd_cmd_brust_len),
    .fifo_rd_cmd_addr      (fifo_rd_cmd_addr),
    .fifo_rd_cmd_instr     (fifo_rd_cmd_instr),
    .user_rd_end           (user_rd_end)
);


//写指令FIFO控制模块例化
wr_cmd_fifo_ctrl inst_wr_cmd_fifo_ctrl (
    .wr_cmd_clk            (user_clk),//input
    .ui_clk                (ui_clk),//input
    .rst                   (ui_clk_sync_rst || (~init_calib_complete)),//input
    .fifo_wr_cmd_en        (fifo_wr_cmd_en),//input
    .fifo_wr_cmd_brust_len (fifo_wr_cmd_brust_len),//input
    .fifo_wr_cmd_addr      (fifo_wr_cmd_addr),//input
    .fifo_wr_cmd_instr     (fifo_wr_cmd_instr),//input
    .fifo_wr_cmd_start     (wr_start),//input
    .fifo_wr_cmd_empty     (fifo_wr_cmd_empty),
    .fifo_wr_cmd_full      (fifo_wr_cmd_full),
    .wr_brust_len          (wr_brust_len),
    .wr_addr               (wr_addr),
    .wr_cmd                (wr_cmd)
);

//写数据FIFO控制模块例化
wr_data_fifo_ctrl inst_wr_data_fifo_ctrl (
    .wr_data_clk           (user_clk),//input
    .ui_clk                (ui_clk),//input
    .rst                   (ui_clk_sync_rst || (~init_calib_complete)),//input
    .fifo_wr_data_en       (fifo_wr_data_en),//input
    .fifo_wr_data          (fifo_wr_data),//input
    .data_req              (data_req),//input
    .wr_data               (wr_data),
    .fifo_wr_data_full     (fifo_wr_data_full),
    .fifo_wr_data_empty    (fifo_wr_data_empty),
    .fifo_wr_data_count    (fifo_wr_data_count)
);

//读指令FIFO控制模块例化
rd_cmd_fifo_ctrl inst_rd_cmd_fifo_ctrl (
    .rd_cmd_clk            (user_clk),//input
    .ui_clk                (ui_clk),//input
    .rst                   (ui_clk_sync_rst || (~init_calib_complete)),//input
    .fifo_rd_cmd_en        (fifo_rd_cmd_en),//input
    .fifo_rd_cmd_brust_len (fifo_rd_cmd_brust_len),//input
    .fifo_rd_cmd_addr      (fifo_rd_cmd_addr),//input
    .fifo_rd_cmd_instr     (fifo_rd_cmd_instr),//input
    .fifo_rd_cmd_start     (rd_start),//input
    .fifo_rd_cmd_empty     (fifo_rd_cmd_empty),
    .fifo_rd_cmd_full      (fifo_rd_cmd_full),
    .rd_brust_len          (rd_brust_len),
    .rd_addr               (rd_addr),
    .rd_cmd                (rd_cmd)
);

//读数据FIFO控制模块例化
rd_data_fifo_ctrl inst_rd_data_fifo_ctrl (
    .rd_data_clk           (user_clk),//input
    .ui_clk                (ui_clk),//input
    .rst                   (ui_clk_sync_rst || (~init_calib_complete)),//input
    .fifo_rd_data_en       (fifo_rd_data_en),//input
    .rd_data_valid         (rd_data_valid),//input
    .rd_data               (rd_data),//input
    .fifo_rd_data          (fifo_rd_data),
    .fifo_rd_data_full     (fifo_rd_data_full),
    .fifo_rd_data_empty    (fifo_rd_data_empty),
    .fifo_rd_data_count    (fifo_rd_data_count)
);


//DDR仲裁模块例化
ddr3_arbit inst_ddr3_arbit (
    .ui_clk              (ui_clk),
    .rst                 (ui_clk_sync_rst || (~init_calib_complete)),
    .wr_req              (~fifo_wr_cmd_empty),
    .rd_req              (~fifo_rd_cmd_empty),
    .wr_end              (wr_end),
    .rd_end              (rd_end),
    .wr_start            (wr_start),
    .rd_start            (rd_start)
);

//DDR写操作模块例化
ddr3_wr_ctrl inst_ddr3_wr_ctrl (
    .ui_clk              (ui_clk),
    .rst                 (ui_clk_sync_rst || (~init_calib_complete)),
    .wr_data             (wr_data),
    .wr_brust_len        (wr_brust_len),
    .wr_start            (wr_start),
    .wr_addr             (wr_addr),
    .wr_cmd              (wr_cmd),
    .wr_mask             (wr_mask),
    .data_req            (data_req),
    .wr_end              (wr_end),
    .app_rdy             (app_rdy),
    .app_wdf_rdy         (app_wdf_rdy),
    .app_cmd             (app_wr_cmd),
    .app_en              (app_wr_en),
    .app_addr            (app_wr_addr),
    .app_wdf_data        (app_wdf_data),
    .app_wdf_wren        (app_wdf_wren),
    .app_wdf_mask        (app_wdf_mask),
    .app_wdf_end         (app_wdf_end)
);

//DDR读操作模块例化
ddr3_rd inst_ddr3_rd (
    .ui_clk              (ui_clk),
    .rst                 (ui_clk_sync_rst || (~init_calib_complete)),
    .init_calib_complete (init_calib_complete),
    .rd_brust_len        (rd_brust_len),
    .rd_start            (rd_start),
    .rd_addr             (rd_addr),
    .rd_cmd              (rd_cmd),
    .rd_data             (rd_data),
    .rd_data_valid       (rd_data_valid),
    .rd_end              (rd_end),
    .app_rdy             (app_rdy),
    .app_rd_data         (app_rd_data),
    .app_rd_data_end     (app_rd_data_end),
    .app_rd_data_valid   (app_rd_data_valid),
    .app_cmd             (app_rd_cmd),
    .app_en              (app_rd_en),
    .app_addr            (app_rd_addr)
);

endmodule

最后编写测试文件即可观察仿真波形,提供激励的信号不多,按照写读时序依次给出使能等信号即可。

仿真测试

模块信号分类

开启仿真将顶层信号调出,由于模块和信号众多,所以将各个模块信号分类,依次分析观察。分别为以下几类:

  • 用户写模块
  • 写指令 FIFO 模块
  • 写数据 FIFO 模块
  • DDR 写控制模块
  • DDR 读控制模块
  • 读指令 FIFO 模块
  • 读数据 FIFO 模块
  • 用户读模块
  • 仲裁模块

用户写模块

当用户端的写使能信号拉高,依次将写数据加1,数据 0-63 慢一拍写入 FIFO 中,同时写入的数据量计数,并指明指令有效信号和指令内容。

写指令 FIFO 模块

有用户端口传来的命令使能信号,当指令 FIFO 的空信号拉低时,表示有指令内容存入,给到仲裁模块输出写开始信号,并且指令会传递下去。可以看到首次写的地址从0开始,而下一次写的初始地址则为512,因为突发长度为64,每个地址16位,每次写入的数据为128,因此每次数据占据8个地址,突发长度64所以一共需要占据8*64=512位,也就是0-511,因此下一次写操作的初始地址为512。

写数据 FIFO 模块

首先将数据写入 FIFO 中,然后当数据请求来临时,将数据从 FIFO 中读出,当全部数据读出后,FIFO 空信号拉高,由于数据太多不好展开,和前面的读写 FIFO 仿真一样。

DDR 写控制模块

开始写信号拉高后,依次将数据写入 DDR3 中,并含有命令握手信号和写操作握手信号,当完成写操作后将写完成信号拉高。

DDR 写控制模块

初始化完成信号拉高,可以进行读写操作;读开始信号拉高,若干个时钟周期后数据读出以及同步的有效信号,由于速率比为4:1,采用的8突发模式,因此读最后一个数据标志信号和读出数据有效信号一致;剩余为命令握手信号以及读指令相关信号,当命令握手有效表示指令有效。

读指令 FIFO 模块

读使能信号拉高以及同步的指令内容,当指令 FIFO 被读空后,发起下一次的读指令开始信号。可以看到首次读的地址从0开始,而下一次读的初始地址则为512,因为突发长度为64,每个地址16位,每次读出的数据为128,因此每次数据占据8个地址,突发长度64所以一共需要占据8*64=512位,也就是0-511,因此下一次读操作的初始地址为512。

读数据 FIFO 模块

这个时序比较简单,读出的数据写入 FIFO,当写入的数据达到设定值时,开始将数据读出,注意利用 FIFO 自带的计数器不是绝对准确的,最初设计就是因为计数器不准的原因导致仿真出现错误,因此在设定读出阈值时,尽量比预期的小一些,我这里设定的是比突发长度小6,当然小十几也是可以,只是别卡在边界值,这样容易出错!

用户读模块

开始读信号拉高,用户端从 FIFO 中读出数据,这里没有设计读出数据信号,但是从读数据使能和读数据计数信号来看也是可以证明设计无误,当将数据全部读出后,拉高读完成信号。

仲裁模块

仲裁模块逻辑设计不复杂,优先写操作,写完成开始读,读完成后开始写,循环往复,井然有序,在仲裁模块那篇有详细描述仲裁的功能设计。

至此,完成了 DDR MIG 控制器外围用户接口的设计,通过此设计可以使得用户更加方便的对 DDR 进行读写操作!


汇总篇

本系列为 DDR3 控制器设计总结,此系列包含 DDR3 控制器相关设计:认识 MIG、初始化、读写操作、FIFO 接口等。通过此系列的学习可以加深对 DDR3 读写时序的理解以及 FIFO 接口设计等,附上汇总博客直达链接。

【DDR3 控制器设计】系列博客汇总篇(附直达链接)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/21897.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSS---复合选择器

目录 一&#xff1a;复合选择器的介绍 二、复合选择器的讲解 &#xff08;1&#xff09;后代选择器 &#xff08;2&#xff09;子元素选择器 &#xff08;3&#xff09;并集选择器 &#xff08;4&#xff09;链接伪类选择器 &#xff08;5&#xff09;focus伪类选择器 一&…

基于SpringBoot的线上买菜系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SpringBoot 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目…

【Spring系列】- Spring事务底层原理

Spring事务底层原理 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 一个有梦有戏的人 怒放吧德德 &#x1f31d;分享学习心得&#xff0c;欢迎指正&#xff0…

Vue-CLI的安装、使用及环境配置(超详细)

Vue CLI 是一个基于 Vue 进行快速项目开发的工具。它可以提供可交互式的项目脚手架和运行时的服务依赖&#xff0c;帮助你快速完成一个风格统一、拓展性强的现代化 web 单页面应用。 Vue-CLI 所需环境 Vue-CLI 是一个需要全局安装的NPM包&#xff0c;安装需要在 Node.js 环境下…

一、openCV+TensorFlow环境搭建

目录一、anaconda安装二、tensorflow安装三、Opencv安装四、pycharm新建项目使用Anaconda的环境五、验证环境安装六、tensorflow安装jupyter notebook一、anaconda安装 anaconda官网&#xff1a;https://www.anaconda.com/anaconda下载&#xff1a;https://repo.anaconda.com/…

【k8s】10.网络插件

文章目录一、etcd详解1、etcd的特点2、准备签发证书的环境二、网络插件原理1、flannel1.1 UDP模式&#xff08;性能差&#xff09;1.2 VXLAN模式&#xff08;性能较好&#xff09;1.3 host-gw模式&#xff08;性能最高&#xff09;2、calico插件3、总结一、etcd详解 etcd是Cor…

Redis_第二章_实战篇_第一节_ 短信登录

Redis_第二章_实战篇_第一节_ 短信登录 文章目录Redis_第二章_实战篇_第一节_ 短信登录短信登录1.1、导入黑马点评项目1.1.1 、导入SQL1.1.2、有关当前模型1.1.3、导入后端项目1.1.4、导入前端工程1.1.5 运行前端项目:1.2 、基于Session实现登录流程1.3 、实现发送短信验证码功…

ANDI数据集介绍|补充信息|2022数维杯国际赛C题

目录 1.患者基本信息 2.生物标记物量化值 3.认知评估 4.解剖结构量化值 5.Other 6.上述各信息的bl值 1.患者基本信息 RID (Participant roster ID) ex. 2、PTID (Original study protocol) ex. 011_S_0002、VISCODE (Visit code) ex. bl、SITE ex. 11、COLPROT (Study p…

服务拆分和远程调用(微服务)

博客主页&#xff1a;踏风彡的博客 博主介绍&#xff1a;一枚在学习的大学生&#xff0c;希望在这里和各位一起学习。 所属专栏&#xff1a;SpringCloud 文章创作不易&#xff0c;期待各位朋友的互动&#xff0c;有什么学习问题都可在评论区留言或者私信我&#xff0c;我会尽我…

课程设计 | 教学设备管理系统

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…

SpringCloud微服务(二)——Eureka服务注册中心

Eureka服务注册中心 SpringCloud组件&#xff0c;Eureka已停更。 内容简介 1、Eureka是什么 Eureka 是 Netflix 开发的&#xff0c;一个基于 REST 服务的&#xff0c;服务注册与发现的组件&#xff0c;以实现中间层服务器的负载平衡和故障转移。服务注册&#xff1a;将服务…

[杂记]算法: 单调栈

0. 引言 单调栈, 顾名思义就是从栈底到栈顶元素单调递增或者单调递减的栈. 往往, 我们在解决寻找一个元素前面/后面的最远/最近处满足某条件的另一个元素的时候可以用到单调栈. 也是用两道算法题作为例子. 在这之前, 先简单写一下构造单调栈的模板. 如果我们需要从一个数组中…

ES6 入门教程 18 Iterator 和 for...of 循环 18.7 for...of 循环

ES6 入门教程 ECMAScript 6 入门 作者&#xff1a;阮一峰 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 文章目录ES6 入门教程18 Iterator 和 for...of 循环18.7 for...of 循环18.7.1 数组18.7.2 Set 和 Map 结构18.7.3 计算生成的数据结构18.7.4 类似…

供应叶酸PEG试剂Folic acid-PEG-Azide,FA-PEG-N3,叶酸-聚乙二醇-叠氮

1、名称 英文&#xff1a;Folic acid-PEG-Azide&#xff0c;FA-PEG-N3 中文&#xff1a;叶酸-聚乙二醇-叠氮 2、CAS编号&#xff1a;N/A 3、所属分类&#xff1a;Azide PEG Folic acid&#xff08;FA&#xff09; PEG 4、分子量&#xff1a;可定制&#xff0c;FA-PEG-N3 5…

Web安全之CTF测试赛

Web安全之CTF测试赛 1.000-我是谁 题目描述&#xff1a; 找到诈骗网站bsde.cn的域名注册人及邮箱&#xff0c;将域名注册人的126邮箱填写到下方答案框并点击送出 考察点&#xff1a;whois查询 whois查询网址&#xff1a; https://x.threatbook.com/ //微步在线 http://wh…

ES6 入门教程 17 Promise 对象 17.11 Promise.reject() 17.12 应用 17.13 Promise.try()

ES6 入门教程 ECMAScript 6 入门 作者&#xff1a;阮一峰 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 文章目录ES6 入门教程17 Promise 对象17.11 Promise.reject()17.12 应用17.12.1 加载图片17.12.2 Generator 函数与 Promise 的结合17.13 Promise…

ES6 入门教程 15 Proxy 15.2 Proxy 实例的方法 15.2.2 set() 15.2.3 apply()

ES6 入门教程 ECMAScript 6 入门 作者&#xff1a;阮一峰 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 文章目录ES6 入门教程15 Proxy15.2 Proxy 实例的方法15.2.2 set()15.2.3 apply()15 Proxy 15.2 Proxy 实例的方法 拦截方法的详细介绍。 15.2.…

【附源码】Python计算机毕业设计天润律师事务所管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

〖全域运营实战白宝书 - 运营角色认知篇③〗- 运营的底层逻辑是什么?

大家好&#xff0c;我是 哈士奇 &#xff0c;一位工作了十年的"技术混子"&#xff0c; 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 &#x1f4ac; 人生格言&#xff1a;优于别人,并不高贵,真正的高贵应该是优于过去的自己。&#x1f4ac; &#x1f4e…

【笔试题】【day24】

文章目录第一题&#xff08;完全二叉树的最多结点个数&#xff09;第二题&#xff08;哈夫曼树的带权路径长度&#xff09;第三题&#xff08;堆的重建&#xff09;第四题&#xff08;哈希映射的冲突&#xff09;第一题&#xff08;完全二叉树的最多结点个数&#xff09; 一棵…