基于 A7 的 DDR3 SDRAM IP 读和仲裁实现

发布于:2022-11-05 ⋅ 阅读:(648) ⋅ 点赞:(0)

设计任务:

设计 DDR3 SDRAM 的 IP 核的读时序,做出对应的波形图,用 Verilog HDL 实现具体的功能。

DDR3 Sdram IP 读时序:

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

上节课已经对命令总线做了介绍,由于读命令总线和写命令总线复用一组总线,因此对命令总线不做过多的介绍,但是我们需要知道 app_cmd==3’b001 代表读命令。 读命令的时序同写命令时序相同,均需要 app_en 和 app_rdy 有效时,对应的 app_cmd 和 app_addr 才会被 IP 核接收,如图 1 所示,指令③和地址 A3 会被 IP核接收。

 下面给出 app 端读数据总线中的每一根信号作用,此处的 input 和 output 均现对于 IP 核而言。

 根据上表所描述,我们可以对 app 端读时序所用到的每一根信号有一点的了解,下面给出读时序的波形。图 2 中所示的①、②、④处的读数据均无效,只有③处的读数据才有效。

 app_rd_data_end 同 app_wdf_end 信号相同,在 DDR3 的物理层端与用户端存在两种速率比值不同的情况下,也会存在不同的状态,具体可以参考 DDR3 IP 核写控制章节。

2、读命令和读数据间关系讲解

根据 Xilinx UG586手册我们可知,读数据是在给出读命令之后一段时间后开始出现的,具体的波形可以参考图 3 所示。

 

3、读控制模块框图

在了解了读命令和读数据的时序及相应关系之后,我们给出读控制模块的框图,示例如图 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 可以告知外界模块,本次突发读结束。

4、读控制模块波形图

下面给出示例波形。其中底 色为绿色的是输入信号,黄色为输出信号,白色为内部信号。

 

5、读控制模块代码实现

module rd_ctrl(
    input          wire            clk,
    input          wire            rst_n,
    input          wire            rd_cmd_start,
    input          wire   [2:0]    rd_cmd_intr,
    input          wire   [27:0]   rd_cmd_addr,
    input          wire   [10:0]   rd_cmd_bl,
    input          wire            app_rdy,
    input          wire   [127:0]  app_rd_data,
    input          wire            app_rd_data_end,
    input          wire            app_rd_data_valid,
    output         reg             app_cmd,
    output         reg             app_en,
    output         reg    [27:0]   app_addr,
    output         reg             rd_end,
    output         reg   [127:0]  rd_data,
    output         reg            rd_data_valid
    );

reg   [10:0]      cmd_cnt;
reg   [10:0]      data_cnt;
reg   [10:0]      cmd_bl;

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        app_cmd<='d0;
    end
    else if (rd_cmd_start==1'b1) begin
        app_cmd<=rd_cmd_intr;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        cmd_bl<='d0;
    end
    else if (rd_cmd_start==1'b1) begin
        cmd_bl<=rd_cmd_bl;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        cmd_cnt<='d0;
    end
    else if(app_en==1'b1 && app_rdy==1'b1 && cmd_cnt==cmd_bl-1) begin
        cmd_cnt<='d0;
    end
    else if (app_en==1'b1 && app_rdy==1'b1) begin
        cmd_cnt<=cmd_cnt+1'b1;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        app_en<=1'b0;
    end
    else if(app_en==1'b1 && app_rdy==1'b1 && cmd_cnt==cmd_bl-1) begin
        app_en<=1'b0;
    end
    else if (rd_cmd_start==1'b1) begin
        app_en<=1'b1;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        data_cnt<='d0;
    end
    else if (app_rd_data_valid==1'b1 && data_cnt==cmd_bl-1) begin
        data_cnt<='d0;
    end
    else if (app_rd_data_valid==1'b1) begin
        data_cnt<=data_cnt+1'b1;
    end
end


always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        rd_data_valid<=1'b0;
    end
    else if (app_rd_data_valid==1'b1) begin
        rd_data_valid<=1'b1;
    end
    else begin
        rd_data_valid<=1'b0;
    end
end


always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        rd_data<='d0;
    end
    else if (rd_cmd_start==1'b1) begin
        rd_data<=app_rd_data;
    end
end


always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        rd_end<=1'b0;
    end
    else if (app_rd_data_valid==1'b1 && data_cnt==cmd_bl-1) begin
        rd_end<=1'b1;
    end
    else begin
        rd_end<=1'b0;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        app_addr<='d0;
    end
    else if (rd_cmd_start==1'b1) begin
        app_addr<=rd_cmd_addr;
    end
    else if(rd_end==1'b1) begin
        app_addr<='d0;
    end
    else if(app_en==1'b1 && app_rdy==1'b1) begin
        app_addr<=app_addr+'d8;
    end
end

endmodule


网站公告

今日签到

点亮在社区的每一天
去签到