【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计

写在前面

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

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


目录

实验任务

实验环境

实验介绍

仲裁模块设计

程序设计

仲裁模块设计

顶层模块设计

testbench 设计

仿真波形

汇总篇


实验任务

在实验的基础上添加一个仲裁模块,控制写读指令的执行。

实验环境

开发环境:Vivado 2018.2,

FPGA 芯片型号:xc7a100tffg484-2

DDR3 型号:MT41J256M16HA-125

实验介绍

由于现在设计的框架是写命令和读命令分开执行的,当写命令和读命令同时执行时就会出错,并且现在的写和读命令总线是两根独立的总线,可以将其整合到一条总线上。因此可以添加一个仲裁模块,基本思路就是优先写操作,当写使能为高时,命令总线为写命令,否则为读命令,对于 DDR 读写模块的 app_addr 信号,可以在不使用时将其置为 0,这样将 DDR 读写模块的 app_addr 进行按位或,结果即为对MIG IP 核操作的 app_addr 信号。对于 app_en 也是用同样的方法。

仲裁模块设计

仲裁设计一般分为两种:设定优先级和轮询,这里采用的是设定优先级。基本设计思想就是写操作比读操作优先程度更高,当检测到wr_req为高时,仲裁模块输出wr_start信号,标志开始进行写操作,当写操作完成后等待rd_req的信号,如果检测到rd_req信号拉高,仲裁模块则输出rd_start开始执行读操作,直至读操作完成便可开始接收wr_req信号,一直这么循环操作,读写操作有条不紊的进行。

【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计_第1张图片

这种读写状态的来回切换很适合设计成状态机,以下为状态机跳转图,初始状态为IDLE,当复位完成后直接跳转到ARBIT仲裁状态,接收到写请求wr_req 跳转到写状态,写完成信号wr_end拉高后又进入到仲裁状态,接收到读请求rd_req 跳转到读状态,读完成信号rd_end拉高后又进入到仲裁状态,循环往复。

【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计_第2张图片

程序设计

仲裁模块设计

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Engineer    : Linest-5                                                         
/* File        : ddr3_arbit.v                                                         
/* Create      : 2022-09-24 15:56:54
/* Revise      : 2022-09-24 15:56:54                                                  
/* Module Name : ddr3_arbit                                                  
/* Description : ddr3的读写仲裁模块,设定为写优先                                                                         
/* Editor : sublime text3, tab size (4)                                                                                
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

module ddr3_arbit(
	//时钟和复位
	input                 ui_clk,                 //用户时钟,由MIG提供
	input                 rst,                    //用户复位,高有效
	input                 wr_req,                 //写请求
	input                 rd_req,                 //读请求
	input                 wr_end,                 //写结束标志信号
	input                 rd_end,                 //读结束标志信号
	output  reg           wr_start,               //开始写操作标志信号
	output  reg           rd_start                //开始读操作标志信号
	);

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*       定义参数和信号                                                             */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
parameter     IDLE     =     4'b0001;
parameter     ARBIT    =     4'b0010;
parameter     WRITE    =     4'b0100;
parameter     READ     =     4'b1000;

reg   [3:0]       state;
reg   [3:0]       next_state;

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*       三段状态机设计                                                             */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge ui_clk or posedge rst) begin
	if (rst) begin
		state <= IDLE;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,组合逻辑阻塞赋值
always @(*) begin
	if (rst) begin
		next_state = state;
	end
	else begin
		case(state)
			IDLE: begin
				next_state = ARBIT;
			end
			ARBIT: begin
				if (wr_req) begin
					next_state = WRITE;
				end
				else if (rd_req) begin
					next_state = READ;
				end
				else begin
					next_state = ARBIT;
				end
			end
			WRITE: begin
				if (wr_end) begin
					next_state = ARBIT;
				end
				else begin
					next_state = WRITE;
				end
			end
			READ: begin
				if (rd_end) begin
					next_state = ARBIT;
				end
				else begin
					next_state = READ;
				end
			end
			default: begin
				next_state = IDLE;
			end
		endcase
	end
end

//状态机第三段,结果输出,时序逻辑非阻塞赋值
always @(posedge ui_clk or posedge rst) begin
	if (rst) begin
		wr_start <= 'd0;
		rd_start <= 'd0;
	end
	else begin
		case(state)
			IDLE: begin
				wr_start <= 'd0;
				rd_start <= 'd0;
			end
			ARBIT: begin
				if (wr_req) begin
					wr_start <= 'd1;
					rd_start <= 'd0;
				end
				else if (rd_req) begin
					wr_start <= 'd0;
					rd_start <= 'd1;
				end
				else begin
					wr_start <= 'd0;
					rd_start <= 'd0;	
				end		
			end
			WRITE: begin
				wr_start <= 'd0;
				rd_start <= 'd0;
			end
			READ: begin
				wr_start <= 'd0;
				rd_start <= 'd0;				
			end
			default: begin
				wr_start <= 'd0;
				rd_start <= 'd0;
			end
		endcase
	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                   wr_req;
wire                   rd_req;

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;

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
);

//DDR仲裁模块例化
ddr3_arbit inst_ddr3_arbit (
    .ui_clk   (ui_clk),
    .rst      (ui_clk_sync_rst || (~init_calib_complete)),
    .wr_req   (wr_req),
    .rd_req   (rd_req),
    .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

testbench 设计

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Engineer    : Linest-5                                                                                   
/* File        : tb_top_ddr3_init.v                                                                                  
/* Create      : 2022-09-15 10:10:36                                              
/* Revise      : 2022-09-24 19:48:54                                                                               
/* Module Name :                                                                                       
/* Description :                                                                                                                
/* Editor : sublime text3, tab size (4)                                                                                                                      
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
`timescale 1ns / 1ps

module tb_top_ddr3_init();

reg                    sys_clk;
reg                    rst_n;

wire  [15:0]           ddr3_dq;
wire  [1:0]            ddr3_dqs_n;
wire  [1:0]            ddr3_dqs_p;
wire  [14:0]           ddr3_addr;
wire  [2:0]            ddr3_ba;
wire                   ddr3_ras_n;
wire                   ddr3_cas_n;
wire                   ddr3_we_n;
wire                   ddr3_reset_n;
wire  [0:0]            ddr3_ck_p;
wire  [0:0]            ddr3_ck_n;
wire  [0:0]            ddr3_cke;
wire  [0:0]            ddr3_cs_n;
wire  [1:0]            ddr3_dm;
wire  [0:0]            ddr3_odt;

//wr_ddr
reg                    ui_clk;
reg                    wr_rst;
reg                    data_req;
reg    [127:0]         wr_data;
reg    [7:0]           wr_brust_len;
reg                    wr_start;
reg    [28:0]          wr_addr;
reg    [2:0]           wr_cmd;


//rd_ddr
reg                    rd_rst;
reg   [7:0]            rd_brust_len;
reg   [127:0]          rd_data;
reg                    rd_start;
reg   [28:0]           rd_addr;
reg   [2:0]            rd_cmd;
reg                    app_rdy;
reg   [127:0]          app_rd_data;
reg                    app_rd_data_end;
reg                    app_rd_data_valid;
reg   [2:0]            app_cmd;

reg                    wr_req;
reg                    rd_req;

initial begin
	sys_clk  = 'd1;
	rst_n   <= 'd0;
	#200
	rst_n   <= 'd1;
end

initial begin
	data_req       = 'd0;
    wr_data        = 'd0;
    wr_brust_len   = 'd64;
    wr_addr        = 'd0;
    wr_cmd         = 3'b000;
	force ui_clk   = inst_top_ddr3_init.inst_ddr3_wr_ctrl.ui_clk;
	force wr_rst   = inst_top_ddr3_init.inst_ddr3_wr_ctrl.rst;
	force data_req = inst_top_ddr3_init.inst_ddr3_wr_ctrl.data_req;
	force wr_start = inst_top_ddr3_init.inst_ddr3_wr_ctrl.wr_start;
    force inst_top_ddr3_init.wr_brust_len = wr_brust_len;
    force inst_top_ddr3_init.wr_addr      = wr_addr;
    force inst_top_ddr3_init.wr_cmd       = wr_cmd;
    force inst_top_ddr3_init.wr_data      = wr_data;

    force inst_top_ddr3_init.wr_req       = wr_req;
    force inst_top_ddr3_init.rd_req       = rd_req;

    rd_brust_len   = 'd64;
    rd_addr        = 'd0;
    rd_cmd         = 3'b001;
	force ui_clk   = inst_top_ddr3_init.inst_ddr3_rd.ui_clk;
	force rd_rst   = inst_top_ddr3_init.inst_ddr3_rd.rst;
    force rd_data  = inst_top_ddr3_init.inst_ddr3_rd.rd_data;
    force rd_start = inst_top_ddr3_init.inst_ddr3_rd.rd_start;
    force inst_top_ddr3_init.rd_brust_len = rd_brust_len;
    force inst_top_ddr3_init.rd_addr      = rd_addr;
    force inst_top_ddr3_init.rd_cmd       = rd_cmd;
end

initial begin
	#100
	gen_req();
end


always @(posedge ui_clk or posedge rd_rst) begin
	if (rd_rst) begin
		rd_req <= 'd0;
	end
	else if (wr_req) begin
		rd_req <= 'd1;
	end
	else if (rd_start) begin
		rd_req <= 'd0;
	end
	else begin
		rd_req <= rd_req;
	end
end

always @(posedge ui_clk or posedge rd_rst) begin
	if (rd_rst) begin
		wr_data <= 'd0;
	end
	else if (wr_data == 'd63) begin
		wr_data <= 'd0;
	end
	else if (data_req) begin
		wr_data <= wr_data + 'd1;
	end
	else begin
		wr_data <= wr_data;
	end
end

task gen_req;
	begin
		@ (negedge wr_rst);
		@ (posedge ui_clk);
		@ (posedge ui_clk);
		@ (posedge ui_clk);
		@ (posedge ui_clk);
		@ (posedge ui_clk);
		wr_req <= 'd1;
		#200
		wr_req <= 'd0;
	end
endtask

// task gen_data;
// 	integer i;
// 	begin
// 		@ (posedge data_req);
// 		for (i=0;i<64;i=i+1) begin
// 			wr_data = {96'd0,i[31:0]};
// 			@ (posedge ui_clk);
// 			if (data_req == 'd0) begin
// 				i = i - 1;
// 			end
// 		end
// 		wr_data = 'd0;
// 		@ (posedge ui_clk);
// 	end
// endtask

always #10 sys_clk = ~sys_clk;

top_ddr3_init inst_top_ddr3_init (
		.ddr3_dq      (ddr3_dq),
		.ddr3_dqs_n   (ddr3_dqs_n),
		.ddr3_dqs_p   (ddr3_dqs_p),
		.ddr3_addr    (ddr3_addr),
		.ddr3_ba      (ddr3_ba),
		.ddr3_ras_n   (ddr3_ras_n),
		.ddr3_cas_n   (ddr3_cas_n),
		.ddr3_we_n    (ddr3_we_n),
		.ddr3_reset_n (ddr3_reset_n),
		.ddr3_ck_p    (ddr3_ck_p),
		.ddr3_ck_n    (ddr3_ck_n),
		.ddr3_cke     (ddr3_cke),
		.ddr3_cs_n    (ddr3_cs_n),
		.ddr3_dm      (ddr3_dm),
		.ddr3_odt     (ddr3_odt),
		.sys_clk      (sys_clk),
		.rst_n        (rst_n)
	);

ddr3_model u_comp_ddr3 (
		.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],ddr3_dm[0]}),
		.ba      (ddr3_ba),
		.addr    (ddr3_addr),
		.dq      (ddr3_dq[15:0]),
		.dqs     ({ddr3_dqs_p[1],
		           ddr3_dqs_p[0]}),
		.dqs_n   ({ddr3_dqs_n[1],
		           ddr3_dqs_n[0]}),
		.tdqs_n  (),
		.odt     (ddr3_odt)
	);

endmodule

仿真波形

对信号进行分组,分别为初始化部分、写部分、读部分、仲裁部分、用户部分。

总体部分

可以看到下图的仿真波形中,首先进行了写操作,随后进行读操作,对具体的模块进行观察。

【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计_第3张图片

初始化部分

看到 init_calib_complete 信号拉高表示 DDR3 完成初始化,可以开始对其进行读写操作。其余信号暂时不管。

【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计_第4张图片

写操作部分

首先开始写操作标志信号拉高,表示开始进行写操作,指令部分:3'b000执行写操作、突发长度为64、初始写地址为0,wr_req 拉高获取数据,写入数据依次加1,wr_end 信号拉高表示写操作完成,写入数据0-63。 

【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计_第5张图片

将波形放大观察,可以看到当写请求拉高时,写入的数据依次加1,并且地址依次累加8,因为写入的数据为128bit,而DDR中地址每个位宽为16,每次写入填充8个地址。

【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计_第6张图片

读操作部分

当rd_start拉高标志着开始进行读操作,突发读长度64,初始地址为0,从下图可以看到当读使能拉高时,读地址依次加8,原因和写操作一样,但是读出的数据并不是立即呈现,而是要经过若干个时钟周期。

【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计_第7张图片

读出的数据为0-63,当最后一个数被读出后,同步的读操作完成信号 rd_end 拉高。

【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计_第8张图片

仲裁部分和用户部分

主要分为以下几个阶段:

  • 复位完成,状态跳转至 ARBIT 仲裁状态
  • wr_req 和 rd_req 同时拉高,但是仲裁器先执行写操作,写操作标志信号 wr_start 拉高,跳转至 WRITE 写状态
  • 当写完成信号 wr_end 拉高,此时 rd_req 仍然拉高,读操作标志信号 rd_start 拉高,跳转至 READ 写状态
  • 读完成信号 rd_end 拉高,依次写读操作完成,状态重新跳转至 ARBIT 仲裁状态

可以看到在用户端的信号也是和设计呈现的一致。

【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计_第9张图片

控制台部分

在控制台打印的信息,首先是写操作,从地址0开始写入数据,依次写入0-63。

最后一个数据为63,最后一个地址为511(16进制的1ff),也就是写入地址为0-511,符合设计要求。

读操作和写操作也是一样,读出数据0-63,读出地址0-511。

【DDR3 控制器设计】(5)DDR3 的仲裁读写操作设计_第10张图片

至此完成仲裁模块设计的验证!


汇总篇

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

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

你可能感兴趣的:(#,DDR,SDRAM,总线接口协议,fpga开发,Verilog,DDR3,xilinx,MIG)