AX7A200教程(3): DDR3突发读写

news2024/9/25 11:21:00

上一个章节我们新建工程,然后进行基本的初始化操作,这个章节将在上个工程的基础上进行突发读写

因ddr3读写部分控制信号比较多,所以ddr3读写控制模块比较复杂,本章节着重于一个256位数据的突发读写,ddr读写控制模块暂不引出行复位部分,简化了ddr读写控制模块也让各种童鞋理解更清晰。

因本章的工程是在上一篇博客的基础上进行改进的,加入了ddr读写控制模块,和突发读写模块,所以务必按照我博客的顺序来看

ddr3突发读写工程顶层

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/01/20 20:24:41
// Design Name: 
// Module Name: ddr3_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module ddr3_top(
    //clock
    input               sys_clk_i,//200M
    //reset
    input               sys_rst,
   // Inouts
   inout [31:0]         ddr3_dq,
   inout [3:0]          ddr3_dqs_n,
   inout [3: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 [3:0]         ddr3_dm,
   output [0:0]         ddr3_odt
   
    );

  ddr_test ddr_test_inst (
    // 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 [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
    .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
    // System Clock Ports
    .sys_clk_i                      (sys_clk_i),
    .sys_rst                        (sys_rst) // input sys_rst

    );     
 
endmodule

ddr3测试模块(测试模块包含:mig控制器,ddr3读写控制模块,ddr3突发读写模块)

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/01/21 18:58:16
// Design Name: 
// Module Name: ddr_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module ddr_test(
   input                sys_clk_i,//200M
   //reset
   input                sys_rst,
   // Inouts
   inout [31:0]         ddr3_dq,
   inout [3:0]          ddr3_dqs_n,
   inout [3: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 [3:0]         ddr3_dm,
   output [0:0]         ddr3_odt
   
    );
    
  wire [28:0]                           app_addr;               //DDR3地址
  wire [2:0]                            app_cmd;                //MIG IP核操作命令,读或者写
  wire                                  app_en;                 //MIG IP发送命令使能
  wire                                  app_rdy;                //MIG 命令接收准备好标志
  wire [255:0]                          app_rd_data;            //用户读数据
  wire                                  app_rd_data_end;        //突发读当前时钟最后一个数据
  wire                                  app_rd_data_valid;      //读数据有效
  wire [255:0]                          app_wdf_data;           //用户写数据
  wire                                  app_wdf_end;            //突发写当前时钟最后一个数据
  wire [31:0]                           app_wdf_mask;
  wire                                  app_wdf_rdy;            //MIG数据接收准备好
  wire                                  app_sr_active;
  wire                                  app_ref_ack;
  wire                                  app_zq_ack;
  wire                                  app_wdf_wren;    
  wire                                  ui_clk;                //用户时钟
  wire                                  ui_clk_sync_rst;       //复位,高有效
  wire [24:0]                           ddr_addr_max;
  
  //mig控制器  
  mig_7series_0 u_mig_7series_0 (
    // 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 [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 [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 [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                     (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                   (32'd0),  // input [31:0]        app_wdf_mask
    // System Clock Ports
    .sys_clk_i                      (sys_clk_i),
    .sys_rst                        (sys_rst) // input sys_rst

    ); 
    
  assign ddr_addr_max = 32-8;   
 //读写控制模块   
 ddr3_rw_control  ddr3_rw_control_inst (              
    .ui_clk                         (ui_clk),   //用户时钟
    .ui_clk_sync_rst                (ui_clk_sync_rst),   //复位,高有效
    .init_calib_complete            (init_calib_complete),   //DDR3初始化完成
    .app_rdy                        (app_rdy),   //MIG 命令接收准备好标致
    .app_wdf_rdy                    (app_wdf_rdy),   //MIG数据接收准备好
    .app_rd_data_valid              (app_rd_data_valid),   //读数据有效
    .app_addr                       (app_addr),   //DDR3地址                      
    .app_en                         (app_en),   //MIG IP发送命令使能
    .app_wdf_wren                   (app_wdf_wren),   //用户写数据使能
    .app_wdf_end                    (app_wdf_end),   //突发写当前时钟最后一个数据 
    .app_cmd                        (app_cmd),   //MIG IP核操作命令,读或者写
    //用户接口
    .ddr_addr_max                   (ddr_addr_max),
    .wr_len_en                      (wr_len_en),
    .rd_len_en                      (rd_len_en),
    .wr_len_done                    (wr_len_done),
    .rd_len_done                    (rd_len_done),
    .ddr_wr_end                     (ddr_wr_end),
    .ddr_rd_end                     (ddr_rd_end)

     );     

//突发读写
 burst_rw    burst_rw_inst(
    .ui_clk                         (ui_clk),
    .i_rst_n                        (!ui_clk_sync_rst),
    .init_calib_complete            (init_calib_complete),
    //突发读写控制信号
    .wr_len_en                      (wr_len_en),//突发写使能
    .rd_len_en                      (rd_len_en),//突发读使能
    .wr_len_done                    (wr_len_done),//突发写完成
    .rd_len_done                    (rd_len_done),//突发读完成
    .ddr_wr_end                     (ddr_wr_end),//ddr写结束
    .ddr_rd_end                     (ddr_rd_end),//ddr读结束
    //读写数据接口
    .app_wdf_wren                   (app_wdf_wren),//ddr写有效
    .app_wdf_data                   (app_wdf_data),//ddr写入的数据
    .app_rd_data_valid              (app_rd_data_valid),//ddr读有效
    .app_rd_data                    (app_rd_data)//ddr读出的数据
    
    );    
        
endmodule

ddr3读写控制模块

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/01/22 08:27:58
// Design Name: 
// Module Name: ddr3_rw_control
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


 module ddr3_rw_control (              
     input                    ui_clk,                //用户时钟
     input                    ui_clk_sync_rst,       //复位,高有效
     input                    init_calib_complete,   //DDR3初始化完成
     input                    app_rdy,               //MIG 命令接收准备好标致
     input                    app_wdf_rdy,           //MIG数据接收准备好
     input                    app_rd_data_valid,     //读数据有效
     output         [27:0]    app_addr,              //DDR3地址                      
     output                   app_en,                //MIG IP发送命令使能
     output                   app_wdf_wren,          //用户写数据使能
     output                   app_wdf_end,           //突发写当前时钟最后一个数据 
     output          [2:0]    app_cmd,               //MIG IP核操作命令,读或者写
     output reg     [2 :0]    state,                 //读写状态
     output reg     [23:0]    rd_addr_cnt,           //用户读地址计数
     output reg     [23:0]    wr_addr_cnt,           //用户写地址计数
     input          [24:0]    ddr_addr_max,
     input                     wr_len_en,
     input                     rd_len_en,
     output                    wr_len_done,
     output                    rd_len_done,
     output reg               ddr_wr_end,
     output reg               ddr_rd_end,
     input                     vin_vs,
     input                     vout_vs,
     output  reg               wr_reset, 
     output  reg               rd_reset
     );
 
 //parameter define
 parameter  WRITE_LENGTH = 4;
 parameter  READ_LENGTH = 4;
 parameter  IDLE        = 3'd0;            //空闲状态
 parameter  WRITE       = 3'd1;            //写状态
 parameter  WRITE_DONE  = 3'd2;            //读到写过度等待
 parameter  READ        = 3'd3;            //读状态
 parameter  READ_DONE   = 3'd4;
 
 wire         rst_n;     //复位,低有效
 
 reg   [27:0]   app_addr_wr;
 reg   [27:0]   app_addr_rd;
 reg  [2:0]     wr_page;
 reg  [2:0]     rd_page;
 reg   [15:0]   wr_load_r;
 reg   [15:0]   rd_load_r;



  //*****************************************************
 //**                    main code
 //***************************************************** 
 
 assign rst_n = ~ui_clk_sync_rst;
 
 //在写状态MIG IP 命令接收和数据接收都准备好,或者在读状态命令接收准备好,此时拉高使能信号,
 assign app_en = ((state == WRITE && (app_rdy && app_wdf_rdy))
                 ||(state == READ && app_rdy)) ? 1'b1:1'b0;
                 
 //在写状态,命令接收和数据接收都准备好,此时拉高写使能
 assign app_wdf_wren = (state == WRITE && (app_rdy && app_wdf_rdy)) ? 1'b1:1'b0;
 
 //由于DDR3芯片时钟和用户时钟的分频选择4:1,突发长度为8,故两个信号相同
 assign app_wdf_end = app_wdf_wren; 
 
 //处于读的时候命令值为1,其他时候命令值为0
 assign app_cmd = (state == READ) ? 3'd1 :3'd0;  
 
 assign app_addr = (state == WRITE && (app_rdy && app_wdf_rdy))? {wr_page,app_addr_wr[24:0]}:{rd_page,app_addr_rd[24:0]};  
  
 assign wr_len_done =  ((state == WRITE_DONE) && wr_len_en)? 1'b1:1'b0;
 
 assign rd_len_done =  ((state == READ_DONE) && rd_len_en)? 1'b1:1'b0;
 

always @(posedge ui_clk or negedge rst_n) begin
        if(!rst_n)
            ddr_wr_end    <=  1'b0;
        else if(wr_reset)
            ddr_wr_end    <=  1'b0;    
        else if((state == WRITE_DONE) && app_addr_wr == ddr_addr_max)
            ddr_wr_end    <=  1'b1;
end

always @(posedge ui_clk or negedge rst_n) begin
        if(!rst_n)
            ddr_rd_end    <=  1'b0;
        else if(rd_reset)
            ddr_rd_end    <=  1'b0;    
        else if((state == READ_DONE) && app_addr_rd == ddr_addr_max)
            ddr_rd_end    <=  1'b1;
end


always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)
            wr_load_r   <=  1'd0;
        else 
            wr_load_r   <=  {wr_load_r[14:0],vin_vs};
end 

always @(posedge ui_clk or negedge rst_n) begin
         if(!rst_n)
             wr_page    <=  3'd0;
         else if(wr_load_r[0] && !wr_load_r[14])
             wr_page    <=  wr_page + 1'b1;
end
      
always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)
            wr_reset   <=  1'd0;
        else if(wr_load_r[0] && !wr_load_r[14])
            wr_reset   <=  1'd1;
        else if(app_addr_wr == 0 && !(wr_load_r[0] && !wr_load_r[14]))    
            wr_reset   <=  1'd0;
end



always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)
            rd_load_r   <=  1'd0;
        else 
            rd_load_r   <=  {rd_load_r[14:0],vout_vs};
end

always @(posedge ui_clk or negedge rst_n) begin
         if(!rst_n)
             rd_page    <=  3'd0;
         else if(rd_load_r[0] && !rd_load_r[14])
             rd_page    <=  wr_page - 1'b1;
end 
       
always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)
            rd_reset   <=  1'd0;
        else if(rd_load_r[0] && !rd_load_r[14])
            rd_reset   <=  1'd1;
        else if(app_addr_rd == 0 && !(rd_load_r[0] && !rd_load_r[14]))    
            rd_reset   <=  1'd0;
end 
                       

              
 //DDR3读写逻辑实现
 always @(posedge ui_clk or negedge rst_n) begin
     if(!rst_n) begin 
         state    <= IDLE;             
         wr_addr_cnt  <= 24'd0;      
         rd_addr_cnt  <= 24'd0;       
         app_addr_wr <= 25'd0;
         app_addr_rd <= 25'd0;         
     end
     else if(init_calib_complete)begin               //MIG IP核初始化完成
         case(state)
             IDLE:
                 if(rd_reset)begin
                        rd_addr_cnt  <= 24'd0;                        
                        app_addr_rd  <= 25'd0;
                        end
                 else if(wr_reset)begin
                        wr_addr_cnt  <= 24'd0;
                        app_addr_wr  <= 25'd0;
                        end
                 else if(rd_len_en)begin
                        state       <= READ;      
                        rd_addr_cnt <= 24'd0;
                        end              
                 else if(wr_len_en)begin
                        state       <= WRITE; 
                        wr_addr_cnt <= 24'd0;                 
                        end
                 else
                        state    <= IDLE;                         
             WRITE:begin
                 if(wr_addr_cnt == WRITE_LENGTH - 1 &&(app_rdy && app_wdf_rdy))
                     state    <= WRITE_DONE;                  //写到设定的长度跳到等待状态
                 else if(app_rdy && app_wdf_rdy)begin   //写条件满足
                     wr_addr_cnt  <= wr_addr_cnt + 1;   //写地址自加
                     app_addr_wr     <= app_addr_wr + 8;      //DDR3 地址加8
                 end
                 else begin                             //写条件不满足,保持当前值
                     wr_addr_cnt  <= wr_addr_cnt;
                     app_addr_wr  <= app_addr_wr; 
                 end
               end
             WRITE_DONE:begin   
                if(app_addr_wr == ddr_addr_max)begin               
                        app_addr_wr <=  25'd0;
                        wr_addr_cnt  <= 24'd0;  
                        state   <= IDLE;       
                        end
                else begin
                       app_addr_wr <=  app_addr_wr + 8;
                       wr_addr_cnt  <= 24'd0;
                       state   <= IDLE;
                       end                                                 
               end
             READ:begin                               //读到设定的地址长度    
                 if(rd_addr_cnt == READ_LENGTH - 1 && app_rdy)begin
                     state   <= READ_DONE; 
                     end                  //则跳到空闲状态 
                 else if(app_rdy)begin                  //若MIG已经准备好,则开始读
                     rd_addr_cnt <= rd_addr_cnt + 1'd1; //用户地址每次加一
                     app_addr_rd    <= app_addr_rd + 8;       //DDR3地址加8
                 end
                 else begin                             //若MIG没准备好,则保持原值
                     rd_addr_cnt <= rd_addr_cnt;
                     app_addr_rd <= app_addr_rd; 
                 end
               end
             READ_DONE:begin
                  if(app_addr_rd == ddr_addr_max)begin
                       app_addr_rd <=  25'd0;
                       rd_addr_cnt  <= 24'd0;
                       state   <= IDLE;   
                       end
                  else begin
                       app_addr_rd <=  app_addr_rd + 8;
                       rd_addr_cnt  <= 24'd0;
                       state   <= IDLE;
                       end 
               end                 
             default:begin
                 state    <= IDLE;
                 wr_addr_cnt  <= 24'd0;
                 rd_addr_cnt  <= 24'd0;
                 app_addr_wr  <= 25'd0;
                 app_addr_rd  <= 25'd0;
             end
         endcase
     end
 end   
                          
 
 endmodule

ddr3突发读写模块

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/01/21 20:00:10
// Design Name: 
// Module Name: burst_rw
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module burst_rw(
input               ui_clk,
input               i_rst_n,
input               init_calib_complete,
output reg         wr_len_en,//突发写使能
output reg         rd_len_en,//突发读使能
input               wr_len_done,//突发写完成
input               rd_len_done,//突发读完成
input               ddr_wr_end,//ddr写结束
input               ddr_rd_end,//ddr读结束
input               app_wdf_wren,//ddr写有效
output  [255:0]     app_wdf_data,//ddr写入的数据
input               app_rd_data_valid,//ddr读有效
input   [255:0]     app_rd_data//ddr读出的数据

    );
    reg     [5:0]       count;
    reg     [255:0]     ddr3_w_data;
    wire    [255:0]     ddr3_read_in;
        
    
    assign app_wdf_data = ddr3_w_data;//ddr3写入的数据
    assign ddr3_read_in = (app_rd_data_valid)? app_rd_data:256'd0;//ddr3读出的数据
    
    //通过计数器产生突发读写使能信号
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)    
                count   <=  6'd0;
            else if(count == 6'd32)
                count   <=  count;
            else if(init_calib_complete)
                count   <=  count + 1'b1;
    end 
    
    //ddr写入的数据
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)    
                ddr3_w_data   <=  256'd0;
            else if(init_calib_complete && app_wdf_wren)
                ddr3_w_data   <=  ddr3_w_data + 1'b1;
            else
                ddr3_w_data   <=  256'd0;    
    end 
                        
    //突发写使能
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                wr_len_en    <=  1'd0;    
            else if(ddr_wr_end)
                wr_len_en    <=  1'd0;    
            else if(rd_len_en)
                wr_len_en    <=  1'd0;    
            else if(wr_len_done)
                wr_len_en    <=  1'd0;                             
            else if(count == 6'd16)
                wr_len_en    <=  1'd1;                        
    end  
    
    //突发读使能
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                rd_len_en    <=  1'd0;
            else if(ddr_rd_end)
                rd_len_en    <=  1'd0;            
            else if(wr_len_en)
                rd_len_en    <=  1'd0;     
            else if(rd_len_done)
                rd_len_en    <=  1'd0;                 
            else if(count == 6'd32)
                rd_len_en    <=  1'd1;                     
    end        
    
    
endmodule

从硬件上看两片16位ddr加在一起是32位的

可以看到读写的数据位宽都是[255:0]也就是256位,那是因为ddr3突发读写一般都是8位,ddr的数据位宽是32位,也就是32*8=256位,所以突发读或者突发写一次就是256位

因突发一次相当于写8个32位数据,也就是256位宽数据,所以ddr控制模块读写地址每次都是加8位

ddr型号为MT41J256M16,可以看出行为[14:0],列为[9:0]

从下图可以看出ddr一共有8个bank,也就是bank0~bank7,而且每个bank的存储空间都一样

行为[14:0],列为[9:0],那么一个bank的最大寻址空间为

2^15*2^10 = 32768*1024= 33554432=2^25
数据位宽相当于[24:0]

从下图可以看出bank选择,由BA0,BA1,BA2这三个管脚组成,也就是2^3=8(bank0~bank7)

再来看8个bank的寻址空间计算

bank0
33554432*1-1 = 33554431([24:0]),加上BA0,BA1,BA2,也就是[27:0],将33554431化为二进制
‭‭0   0   0     1111111111111111111111111‬‬
ba2 ba1  ba0    ([24:0])
所以[ba2,ba1,ba0] = 000

同样bank1为
33554432*2-1 = 67108863
‭‭0   0   1     1111111111111111111111111‬‬
ba2 ba1  ba0    ([24:0])
所以[ba2,ba1,ba0] = 001

同样bank2为
33554432*3-1 = 100663295
‭‭0   1   0     1111111111111111111111111‬‬
ba2 ba1  ba0    ([24:0])
所以[ba2,ba1,ba0] = 010

同样bank3为
33554432*4-1 = 134217727
‭‭0   1   1     1111111111111111111111111‬‬
ba2 ba1  ba0    ([24:0])
所以[ba2,ba1,ba0] = 011

同样bank4为
33554432*5-1 = 167772159
‭‭1   0   0     1111111111111111111111111‬‬
ba2 ba1  ba0    ([24:0])
所以[ba2,ba1,ba0] = 100

同样bank5为
33554432*6-1 = 201326591‬
‭‭1   0   1     1111111111111111111111111‬‬
ba2 ba1  ba0    ([24:0])
所以[ba2,ba1,ba0] = 101

同样bank6为
33554432*7-1 = 234881023
1   1   0     1111111111111111111111111‬‬
ba2 ba1  ba0    ([24:0])
所以[ba2,ba1,ba0] = 110

同样bank7为
33554432*8-1 = 268435455
‭‭1   1   1     1111111111111111111111111‬‬
ba2 ba1  ba0    ([24:0])
所以[ba2,ba1,ba0] = 111

从上面可以看出,ddr寻址范围[24:0]为每个bank的寻址空间,而高三位[27:25]为ba2,ba1,ba0为bank选择

所以ddr控制模块里面读写寻址空间为[27:0],后[24:0]为寻址空间,前面三位为bank选择,因本ddr一共有8个bank,所以可以缓存8页数据

 assign app_addr = (state == WRITE && (app_rdy && app_wdf_rdy))? {wr_page,app_addr_wr[24:0]}:{rd_page,app_addr_rd[24:0]}; 

再来看工程仿真波形

当count计数器计数到32时产生一次wr_len_en突发写使能

    //突发写使能
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                wr_len_en    <=  1'd0;    
            else if(ddr_wr_end)
                wr_len_en    <=  1'd0;    
            else if(rd_len_en)
                wr_len_en    <=  1'd0;    
            else if(wr_len_done)
                wr_len_en    <=  1'd0;                             
            else if(count == 8'd32)
                wr_len_en    <=  1'd1;                        
    end 

当发出wr_len_en写突发使能后,可以看到app_rdy和app_wdf_rdy都为1,表示可以写数据,app_cmd为0表示写命令,这里一共进行四次突发写,所以地址为0,8,10,18(所以ddr地址为32-8),wr_addr_cnt为突发写的次数,这个次数是可以设置的,但我们这里设置为4,截图中可以看到进行了四次计数分别是000000,000001,000002,000003。

当wr_len_en为1时,app_wdf_wren为高写有效,可以看到app_wdf_data写入了四个256位宽度的数据,分别为0,1,2,3这四个数据,写完成后产生一个wr_len_done突发写完成信号,因前面我们设置了写四个数据,数据写完成后会产生一个ddr_wr_end写结束信号。

    //ddr写入的数据
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)    
                ddr3_w_data   <=  256'd0;
            else if(init_calib_complete && app_wdf_wren)
                ddr3_w_data   <=  ddr3_w_data + 1'b1;
            else
                ddr3_w_data   <=  256'd0;    
    end 

当count计数器计数到64时产生一次rd_len_en突发读使能

    //突发读使能
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                rd_len_en    <=  1'd0;
            else if(ddr_rd_end)
                rd_len_en    <=  1'd0;            
            else if(wr_len_en)
                rd_len_en    <=  1'd0;     
            else if(rd_len_done)
                rd_len_en    <=  1'd0;                 
            else if(count == 8'd64)
                rd_len_en    <=  1'd1;                     
    end

突发读时,当app_rdy和app_wdf_rdy为高时,app_en使能为高,写入需要读数据的地址,也就是0,8,10,18这四个地址,而且此时的app_cmd为1表示进行ddr读命令,rd_addr_cnt为突发读次数,可以看到进行了四次突发读分别是000000,000001,000002,000003,并产生ddr_rd_end读突发结束信号。

读出数据,可以看到app_rd_data_valid为高表示读出数据有效,app_rd_data读出0,1,2,3四个数据和写入的数据一致(一般读出数据是有延迟的,并不是写完控制命令后,立即就能读出数据,具体需要多少个周期,可以参考ddr3数据手册)

因怕很多人对突发读写不理解,所以将ddr读写控制和突发读写模块简化了很多,本来想将突发读写,写一篇博客的,但感觉涉及的东西太多了,写到这里还没有将ddr复位信号加入进去,之后使用hdmi显示再加入场信号复位,如果写的有问题欢迎各位指正。

如若转载,请注明出处

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

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

相关文章

【JavaWeb】前端开发三剑客之CSS(下)

✨哈喽&#xff0c;进来的小伙伴们&#xff0c;你们好耶&#xff01;✨ &#x1f6f0;️&#x1f6f0;️系列专栏:【JavaWeb】 ✈️✈️本篇内容:CSS的深度学习&#xff01; &#x1f680;&#x1f680;代码托管平台github&#xff1a;JavaWeb代码存放仓库&#xff01; ⛵⛵作者…

(考研湖科大教书匠计算机网络)第二章物理层-第一、二节:物理层基本概念和传输媒体

文章目录一&#xff1a;物理层概念二&#xff1a;物理层传输媒体&#xff08;1&#xff09;导引型传输媒体A&#xff1a;同轴电缆B&#xff1a; 双绞线C&#xff1a;光纤①&#xff1a;光纤通信②&#xff1a;光纤D&#xff1a;电力线&#xff08;2&#xff09;非导引型传输媒体…

day22 多线程02

1.线程池 1.1 线程状态介绍 当线程被创建并启动以后&#xff0c;它既不是一启动就进入了执行状态&#xff0c;也不是一直处于执行状态。线程对象在不同的时期有不同的状态。那么Java中的线程存在哪几种状态呢&#xff1f;Java中的线程 状态被定义在了java.lang.Thread.State…

[ESP][驱动]ST7701S RGB屏幕驱动

ST7701SForESP ST7701S ESP系列驱动&#xff0c;基于ESP-IDF5.0&#xff0c;ESP32S3编写。 本库只负责SPI的配置&#xff0c;SPI设置屏幕两方面。由于RGB库和图形库的配置无法解耦&#xff0c;具体使用的RGB库&#xff0c;图形库需要自行配置添加。 SPI的指令&#xff0c;地…

操作系统真相还原_第5章第2节:内存分页机制

文章目录分段机制分页机制一级页表二级页表启用分页机制的过程启用分页机制(二级页表)详解程序include.incmbr.sloader.s写入硬盘启动bochs执行分段机制 分页机制 一级页表 二级页表 启用分页机制的过程 1、准备好页目录项及页表 2、将页表地址写入控制寄存器cr3 3、寄存器cr0…

【ArcGIS微课1000例】0059:三种底图影像调色技巧案例教程

三种调整影像底图效果的技术,让你的图纸清新脱俗,做出的图更美观! 文章目录 方法一:影像源类型调整方法二:符号拉伸类型设置方法三:影像分析模块设置方法一:影像源类型调整 这种方法是最基础、最简单的一种方法,可以调整的内容有限。当大家发现导入了影像,然后影像图…

Spring Batch 基本概念和运行示例

基本概念 Spring Batch是批处理框架。 作业(Job)是状态以及状态之间转换的集合。 作业里包含步骤&#xff08;Spring Bean&#xff09;&#xff0c;每一个步骤解耦到独立的处理器中&#xff0c;并负责自己的数据&#xff0c;把所需的业务逻辑应用到数据上&#xff0c;然后把数…

【React】组件的创建与事件绑定

&#x1f4d8;前言 &#x1f6a9;&#x1f6a9;&#x1f6a9; &#x1f48e;个人主页: 阿选不出来 &#x1f4a8;&#x1f4a8;&#x1f4a8; &#x1f48e;个人简介: 一名大二在校生,学习方向前端,不定时更新自己学习道路上的一些笔记. &#x1f4a8;&#x1f4a8;&#x1f4a…

C规范编辑笔记(十三)

往期文章&#xff1a; C规范编辑笔记(一) C规范编辑笔记(二) C规范编辑笔记(三) C规范编辑笔记(四) C规范编辑笔记(五) C规范编辑笔记(六) C规范编辑笔记(七) C规范编辑笔记(八) C规范编辑笔记(九) C规则编辑笔记(十) C规范编辑笔记(十一) C规范编辑笔记(十二) 正文&#xff…

CSS背景:背景色/背景图像/背景重复/背景附着/简写背景属性(一文搞懂)

目录 CSS背景 CSS 背景色 实例 其他元素 实例 不透明度 / 透明度 实例 使用 RGBA 的透明度 实例 CSS 背景图像 实例 实例 实例 CSS 背景重复 实例 实例 CSS background-repeat: no-repeat 实例 CSS background-position 实例 CSS 背景附着 实例 实例 C…

linux系统中利用QT实现视频监控的基本方法

大家好&#xff0c;今天主要和大家分享一下&#xff0c;如何利用QT实现视频监控的基本操作。 目录 第一&#xff1a;视频监控基本简介 第二&#xff1a;实验流程图 第三&#xff1a;视频监控之服务器 第四&#xff1a;视频监控之客户端实现 第一&#xff1a;视频监控基本简…

Java基础之《netty(30)—RPC调用流程分析》

一、RPC基本介绍 1、RPC&#xff08;Remote Procedure Call&#xff09;—远程过程调用&#xff0c;是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序&#xff0c;而程序无需额外的为这个交互作用编程。 2、两个或多个应用程序都分布在不同的…

Kettle(4):excel数据抽取到mysql

1 准备工作 1.1 准备Excel文件 我这边直接使用上一篇导出的excel:file_user.xls 1.2 创建数据库 在mysql中创建数据库 1.3 在kettle中加载MySQL驱动 Kettle要想连接到MySQL&#xff0c;必须要安装一个MySQL的驱动&#xff0c;就好比我们装完操作系统要安装显卡驱动一样。加…

CMMI之工程类

工程类过程域涵盖了工程学科所共有的开发与维护活动。工程类过程域的书写使用了通用的工程术语&#xff0c;这样&#xff0c;涉及产品开发过程&#xff08;如软件工程、机械工程等&#xff09;的任何技术学科都能够将其用于过程改进。工程类过程域还将不同工程学科的关联过程整…

分享111个ASP源码,总有一款适合您

ASP源码 分享111个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 111个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1Afx8CxZIGwcGWB6aUOssZg?pwdr81w 提取码&#x…

CPU缓存架构缓存一致性协议详解

一、CPU高速缓存&#xff08;Cache Memory&#xff09;1.1 CPU高速缓存CPU缓存即高速缓冲存储器&#xff0c;是位于CPU与主内存间的一种容量较小但速度很高的存储器。由于CPU的速度远高于主内存&#xff0c;CPU直接从内存中存取数据要等待一定时间周期&#xff0c;Cache中保存着…

《你当像鸟飞往你的山》教育让你内心的山更高,更广

《你当像鸟飞往你的山》教育让你内心的山更高&#xff0c;更广 塔拉韦斯特弗&#xff0c;美国作家、历史学家。1986年生于美国爱达荷州的山区。自学考取杨百翰大学&#xff0c;2009年获得剑桥大学哲学硕士学位&#xff0c;2014年获剑桥大学历史学博士学位。2018年出版处女座《你…

2023 年8个ChatGPT 的替代品

OpenAI 于 2022 年 11 月下旬推出的 ChatGPT 在网络世界引起了不小的轰动。它不仅引起了社交媒体用户的关注&#xff0c;也引起了各大媒体的关注。 这种先进的 AI 技术不仅可以根据命令生成、重写和汇总文本&#xff0c;还可以与用户进行交互。它会记住以前的对话&#xff0c;…

[论文翻译] Improving Knowledge Tracing via Pre-training Question Embeddings

摘要 知识追踪 (KT) 定义了根据学生的历史反应预测他们是否能正确回答问题的任务。尽管许多研究致力于利用问题信息&#xff0c;但问题和技能中的大量高级信息尚未被很好地提取&#xff0c;这使得以前的工作难以充分执行。在本文中&#xff0c;我们证明了通过在丰富的边信息上…

通过属性配置文件编写JDBC程序

package com.bjpowernode.jdbc;import java.sql.*; import java.util.ResourceBundle; /* 编程思想&#xff1a;将连接数据库时可变化的4条信息都写到配置文件中&#xff0c;以后需要连接其他数据库的时候&#xff0c;可直接修改配置文件&#xff0c;不用修改java程序。这4个信…