XILINX DDR3 VIVADO(三)读模块

三、DDR3 Sdram IP 读时序:

1、读命令和读数据总线介绍

上节课已经对命令总线做了介绍,由于读命令总线和写命令总线复用一组总
线,因此对命令总线不做过多的介绍,但是我们需要知道 app_cmd==3’b001 代表读命令。
读命令的时序同写命令时序相同,均需要 app_en 和 app_rdy 有效时,对应的app_cmd 和 app_addr 才会被 IP 核接收,如图 1 所示,指令③和地址 A3 会被 IP核接收。
在这里插入图片描述
下面给出 app 端读数据总线中的每一根信号作用,此处的 input 和 output 均
现对于 IP 核而言。
在这里插入图片描述
显然,从ddr读出的数据不是一给读命令就出来的,而是得过一阵子,反正只有在app_rd_data_valid为高时数据有效。(所以我们要在valid为高时进行数据的突发计数和有效数据采集)。
在这里插入图片描述
app_rd_data_end 同 app_wdf_end 信号相同,在 DDR3 的物理层端与用户端存在两种速率比值不同的情况下,也会存在不同的状态,具体可以参考 DDR3 IP核写控制章节。

2、读控制模块框图及波形

在了解了读命令和读数据的时序及相应关系之后,我们给出读控制模块的框
图,示例如图 4 所示,其中 A7_rd_ctrl 模块即为我们需要完成的模块。
在这里插入图片描述
从图 4 中可以得知 A7_rd_ctrl 模块与 DDR3 IP 核是通过 app 接口进行通信,另外 A7_rd_ctrl 模块预留了一些接口,下面给出这些接口的具体描述。
在这里插入图片描述
在这里插入图片描述
当 rd_cmd_start 有效时,启动本次的读突发,根据由外部输入的 rd_cmd_bl
可以确定本次突发需要读出多少数据;rd_cmd_start 有效时,rd_cmd_addr 代表本次突发读的起始地址,由于 128bit = 8x16bit,因此每个 128bit 数据需要读出 8 个DDR3 SDRAM 的地址内数据,因此每发送一次 rd_cmd_start,rd_cmd_addr 需要加 8;由于该模块只实现读控制,因此 rd_cmd_instr 可以一直保持为读状态;可以由 rd_end 可以告知外界模块,本次突发读结束。下面给出示例波形。其中底色为绿色的是输入信号,黄色为输出信号,白色为内部信号。***(个人建议地址突发等等的最好与start同步发出,至于为什么在以后就知道了)***
在这里插入图片描述

3.代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/07/17 21:51:41
// Design Name: 
// Module Name: rd_ctrl
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module rd_ctrl(
// for top
input       wire  [10:0]        rd_cmd_bl,
input       wire                rd_cmd_start,
input       wire  [27:0]        rd_cmd_addr,
output      reg                 rd_data_valid,
output      reg                 rd_end,
output      reg   [127:0]       rd_data_128bit,

//for ip
input       wire                ui_clk,
input       wire                rst_n,
input       wire                app_rdy,
input       wire  [127:0]       app_rd_data,
input       wire                app_rd_data_end,
input       wire                app_rd_data_valid,
output      wire   [2:0]         app_cmd,
output      reg                 app_en,
output      reg   [27:0]        app_addr               

    );

reg    [10:0]     data_cnt;

reg    [10:0]     reg_cmd_bl;

reg    [10:0]     cmd_cnt;

assign app_cmd = 3'b001;

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 reg_cmd_bl <= 11'd0;
else if(rd_cmd_start == 1'b1)
 reg_cmd_bl <= rd_cmd_bl;
end

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 app_en <= 1'b0;
else if(cmd_cnt == reg_cmd_bl - 1'b1&&app_rdy == 1'b1&&app_en == 1'b1)
 app_en <= 1'b0;
else if(rd_cmd_start == 1'b1)
 app_en <= 1'b1;
end 
 
always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 cmd_cnt <= 11'd0;
else if(cmd_cnt == reg_cmd_bl - 1'b1&&app_rdy == 1'b1&&app_en == 1'b1)
 cmd_cnt <= 11'd0;
else if(app_rdy == 1'b1&&app_en == 1'b1) 
 cmd_cnt <= cmd_cnt + 1'd1;
end 

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 app_addr <= 28'd0;
else if(cmd_cnt == reg_cmd_bl - 1'b1&&app_rdy == 1'b1&&app_en == 1'b1)
 app_addr <= 28'd0;
else if(rd_cmd_start == 1'b1)
 app_addr <= rd_cmd_addr;
else if(app_rdy == 1'b1&&app_en == 1'b1)
 app_addr <= app_addr + 4'd8;
end 

always@(posedge ui_clk)begin
if(rst_n == 1'b0)	
 rd_data_valid <= 1'b0;
else
 rd_data_valid <= app_rd_data_valid;
end 

always@(posedge ui_clk)begin
if(rst_n == 1'b0)	
 rd_data_128bit <= 128'd0;
else 
 rd_data_128bit <= app_rd_data;
end 

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 data_cnt <= 11'd0;
else if(data_cnt == reg_cmd_bl - 1'b1&&app_rd_data_valid == 1'b1)
 data_cnt <= 11'd0;
else if(app_rd_data_valid == 1'b1)
 data_cnt <= data_cnt + 1'd1;
end 

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 rd_end <= 1'b0;
else if(data_cnt == reg_cmd_bl - 1'b1&&app_rd_data_valid == 1'b1)
 rd_end <= 1'b1;
else 
 rd_end <= 1'b0;
end 
 
	
	
	
	
endmodule

猜你喜欢

转载自blog.csdn.net/weixin_44716774/article/details/118961523
今日推荐