基于FPGA的SDRAM控制器设计(4)

SDRAM控制器接口简述

完整的SDRAM控制器的模块框图如下:
在这里插入图片描述
前面的三篇文章,我们已经简述了基本的SDRAM的基本操作。这里总结一下SDRAM的几个模块,SDRAM的上电初始化,自刷新、读写模块、顶层仲裁控制。了解了上面的操作,我们已经可以完成SDRAM控制器的代码完成,接下来我们便完善SDRAM控制器的接口,简化该SDRAM控制器设计,使得该SDRAM控制器可以很容易的使用。下面的接口定义如下:
在这里插入图片描述
顶层模块的接口主要时上面的接口,我们把SDRAM做成了FIFO类型的接口。
其中1时系统接口:
sclk:是100MHz的时钟,
rst_n:是系统复位信号,
2是SDRAM硬件的接口信号,连接到SDRAM硬件上。
3是SDRAM写FIFO的信号
4是SDRAM读FIFO的信号
5是SDRAM最大的读地址信号,
RROW_ADDR_END是SDRAM的FIFO接口最大的行地址,
RCOL_MADDR_END是SDRAM最大的列地址,超过上面的信号便会清零,注意RCOL_MADDR_END信号必须是4的倍数,因为我们SDRAM中是4突发的。
6是SDRAM最大FIFO接口最大的写地址信号,与5的描述相同。

自动读写模块的框图

这里为了方便同学们理解,我们给出自动读写模块的框图,也是仿照开源骚客的文章设计:
在这里插入图片描述
在这里插入图片描述

SDRAM控制器完整代码

经过前面三篇文章的学习,我们这里不在给出原理,直接给出使用的SDRAM的代码:
sdram_top模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : sdram_top.v
// Create Time  : 2020-02-09 17:22:24
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module sdram_top(
    //System Interfaces
    input                   sclk            ,
    input                   rst_n           ,
    //SDRAM Interfaces
    output  wire            sdram_clk       ,
    output  wire            sdram_cke       ,
    output  reg             sdram_cs_n      ,
    output  reg             sdram_cas_n     ,
    output  reg             sdram_ras_n     ,
    output  reg             sdram_we_n      ,
    output  reg     [ 1:0]  sdram_bank      ,
    output  reg     [11:0]  sdram_addr      ,
    output  wire    [ 1:0]  sdram_dqm       ,
    inout           [15:0]  sdram_dq        ,
    //User Interfaces
    input                   wfifo_wclk      ,
    input                   wfifo_wr_en     ,
    input           [15:0]  wfifo_wr_data   ,
    input                   rfifo_rclk      ,
    input                   rfifo_rd_en     ,
    output  wire    [15:0]  rfifo_rd_data   ,
    output  wire            rfifo_rd_ready            
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
parameter  RROW_ADDR_END    =   937         ;
parameter  RCOL_MADDR_END   =   256         ;
parameter  WROW_ADDR_END    =   937         ;
parameter  WCOL_MADDR_END   =   256         ;

localparam      NOP     =   4'b0111         ;

localparam      IDLE    =   5'b0_0001       ;
localparam      ARBIT   =   5'b0_0010       ;
localparam      AREF    =   5'b0_0100       ;
localparam      WRITE   =   5'b0_1000       ;
localparam      READ    =   5'b1_0000       ;
//sdram_init
wire                [ 3:0]  init_cmd        ;
wire                [11:0]  init_addr       ;
wire                        init_done       ;
//AREF
wire                        aref_req        ;
reg                         aref_en         ;
wire                        aref_end        ;
wire                [ 3:0]  aref_cmd        ;
wire                [11:0]  aref_addr       ;
//WRITE
wire                [ 3:0]  wr_cmd          ;
wire                [11:0]  wr_addr         ;
wire                [ 1:0]  wr_bank_addr    ;
wire                [15:0]  wr_data         ;    
reg                         wr_en           ;
wire                        wr_end          ;
wire                        wr_req          ;
wire                        wr_trig         ;
//READ
wire                [ 3:0]  rd_cmd          ;
wire                [11:0]  rd_addr         ;
wire                [ 1:0]  rd_bank_addr    ;
reg                         rd_en           ;
wire                        rd_end          ;
wire                        rd_req          ;
wire                        rd_trig         ;
//sdram_auto_write_read
wire                        wfifo_rd_en     ;       
wire                [15:0]  wfifo_rd_data   ;
wire                        rfifo_wr_en     ;      
wire                [15:0]  rfifo_wr_data   ;

//ARBIT
reg                 [ 4:0]  state           ;

//Others
reg                 [15:0]  sdram_dq1       ;
reg                         sdram_dq_en     ;
 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
assign      sdram_dqm       =       2'b00;
assign      sdram_clk       =       ~sclk;
assign      sdram_cke       =       1'b1;
assign      sdram_dq        =       sdram_dq_en == 1'b1 ? sdram_dq1 : 16'hzzzz;
assign      rfifo_wr_data   =       sdram_dq;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        state       <=      IDLE;
    else case(state)
        IDLE    :   if(init_done == 1'b1)
                        state           <=      ARBIT;
                    else 
                        state           <=      state;
        ARBIT   :   if(aref_req == 1'b1)
                        state           <=      AREF;
                    else if(wr_req == 1'b1)
                        state           <=      WRITE;
                    else if(rd_req == 1'b1)
                        state           <=      READ;
                    else
                        state           <=      state;
        AREF    :   if(aref_end == 1'b1)
                        state           <=      ARBIT;
                    else
                        state           <=      state;
        WRITE   :   if(wr_end == 1'b1)
                        state           <=      ARBIT;
                    else 
                        state           <=      state;
        READ    :   if(rd_end == 1'b1)
                        state           <=      ARBIT;
                    else
                        state           <=      state;                        
        default :   state           <=      IDLE;
    endcase

always @(*)
    case(state)
        IDLE    :   begin
                        sdram_addr      =      init_addr;
                        {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n}      =       init_cmd;
                        sdram_dq_en     =       1'b0;
                    end
        AREF    :   begin
                        sdram_addr      =      aref_addr;
                        {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n}      =       aref_cmd;
                    end
        WRITE   :   begin
                        sdram_addr      =      wr_addr;
                        {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n}      =       wr_cmd;
                        sdram_dq1       =      wr_data;
                        sdram_bank      =      wr_bank_addr;
                        sdram_dq_en     =      1'b1;
                    end
        READ    :   begin
                        sdram_addr      =      rd_addr;
                        {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n}      =       rd_cmd;
                        sdram_bank      =      rd_bank_addr;
                        sdram_dq_en     =      1'b0;  
                    end
        default :   begin
                        sdram_addr      =      12'd0;
                        {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n}      =       NOP;
                        sdram_dq1       =      16'd0;
                        sdram_bank      =      2'b00;
                        sdram_dq_en     =      1'b0;
                    end
    endcase

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        aref_en             <=      1'b0;
    else if(state == ARBIT && aref_req == 1'b1) 
        aref_en             <=      1'b1;
    else
        aref_en             <=      1'b0;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        wr_en               <=      1'b0;
    else if(state == ARBIT && aref_req == 1'b1) 
        wr_en               <=      1'b0;
    else if(state == ARBIT && wr_req == 1'b1) 
        wr_en               <=      1'b1;
    else
        wr_en               <=      1'b0;
        
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_en               <=      1'b0;
    else if(state == ARBIT && aref_req == 1'b1) 
        rd_en               <=      1'b0;
    else if(state == ARBIT && wr_req == 1'b1)
        rd_en               <=      1'b0;
    else if(state == ARBIT && rd_req == 1'b1)
        rd_en               <=      1'b1;
    else
        rd_en               <=      1'b0;

sdram_init sdram_init_inst(
    //System Interfaces
    .sclk                   (sclk                   ),
    .rst_n                  (rst_n                  ),
    //SDRAM Interfaces
    .sdram_cmd              (init_cmd               ),
    .sdram_addr             (init_addr              ),
    //Others
    .init_done              (init_done              )
);

sdram_aref sdram_aref_inst(
    //Sysytem Interfaces
    .sclk                   (sclk                   ),
    .rst_n                  (rst_n                  ),
    //SDRAM Interfaces
    .aref_cmd               (aref_cmd               ),
    .aref_addr              (aref_addr              ),
    //Others
    .aref_req               (aref_req               ),
    .aref_end               (aref_end               ),
    .aref_en                (aref_en                ),
    .init_done              (init_done              )
);

sdram_auto_write_read sdram_auto_write_read_inst(
    // system signals
    .rst_n                  (rst_n                  ),       
    // wfifo
    .wfifo_wclk             (wfifo_wclk             ),
    .wfifo_wr_en            (wfifo_wr_en            ),       
    .wfifo_wr_data          (wfifo_wr_data          ),
    .wfifo_rclk             (sclk                   ),
    .wfifo_rd_en            (wfifo_rd_en            ),       
    .wfifo_rd_data          (wfifo_rd_data          ),
    .wr_trig                (wr_trig                ),
    // rfifo
    .rfifo_wclk             (~sclk                  ),       // 100MHz
    .rfifo_wr_en            (rfifo_wr_en            ),       
    .rfifo_wr_data          (rfifo_wr_data          ),
    .rfifo_rclk             (rfifo_rclk             ),
    .rfifo_rd_en            (rfifo_rd_en            ),       
    .rfifo_rd_data          (rfifo_rd_data          ),
    .rd_trig                (rd_trig                ),
    // user interfaces
    .rfifo_rd_ready         (rfifo_rd_ready         )
);

sdram_write #(
    .WROW_ADDR_END          (WROW_ADDR_END          ),
    .WCOL_MADDR_END         (WCOL_MADDR_END         )
    ) sdram_write_inst(
    //System Interfaces
    .sclk                   (sclk                   ),
    .rst_n                  (rst_n                  ),
    //SDRAM Interfaces
    .wr_cmd                 (wr_cmd                 ),
    .wr_addr                (wr_addr                ),
    .bank_addr              (wr_bank_addr           ),
    .wr_data                (wr_data                ), 
    //Communication Interfaces
    .wr_trig                (wr_trig                ),
    .wr_en                  (wr_en                  ),
    .wr_end                 (wr_end                 ),
    .wr_req                 (wr_req                 ),
    .aref_req               (aref_req               ),
    .wfifo_rd_en            (wfifo_rd_en            ),
    .wfifo_rd_data          (wfifo_rd_data          )    
);

sdram_read #(
    .RROW_ADDR_END          (RROW_ADDR_END          ),
    .RCOL_MADDR_END         (RCOL_MADDR_END         )
    ) sdram_read_inst(
    //System Interfaces
    .sclk                   (sclk                   ),
    .rst_n                  (rst_n                  ),
    //SDRAM Interfaces
    .rd_cmd                 (rd_cmd                 ),
    .rd_addr                (rd_addr                ),
    .bank_addr              (rd_bank_addr           ),    
    //Communication Interfaces
    .rd_trig                (rd_trig                ),
    .rd_en                  (rd_en                  ),
    .rd_end                 (rd_end                 ),
    .rd_req                 (rd_req                 ),
    .aref_req               (aref_req               ),
    .rd_data_en             (rfifo_wr_en            )
);

 
endmodule

sdram_init模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : sdram_init.v
// Create Time  : 2020-02-09 16:20:31
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module sdram_init(
    //System Interfaces
    input                   sclk            ,
    input                   rst_n           ,
    //SDRAM Interfaces
    output  reg     [ 3:0]  sdram_cmd       ,
    output  reg     [11:0]  sdram_addr      ,
    //Others
    output  reg             init_done  
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
localparam  DELAY_200US =  20000           ;
//SDRAM Command
localparam  NOP         =  4'b0111          ;
localparam  PRE         =  4'b0010          ;
localparam  AREF        =  4'b0001          ;
localparam  MSET        =  4'b0000          ;

reg                 [14:0]  cnt_200us       ;
reg                         flag_200us      ;
reg                 [ 4:0]  cnt_cmd         ;
 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_200us       <=      11'd0;
    else if(flag_200us == 1'b0)
        cnt_200us       <=      cnt_200us + 1'b1;
    else
        cnt_200us       <=      cnt_200us;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        flag_200us      <=      1'b0;
    else if(cnt_200us >= DELAY_200US) 
        flag_200us      <=      1'b1;
    else
        flag_200us      <=      flag_200us;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_cmd         <=      5'd0;
    else if(flag_200us == 1'b1 && cnt_cmd <= 5'd19)
        cnt_cmd         <=      cnt_cmd + 1'b1;
    else 
        cnt_cmd         <=      cnt_cmd;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        sdram_cmd       <=      NOP;
    else case(cnt_cmd)
        1       :   sdram_cmd       <=      PRE;
        3       :   sdram_cmd       <=      AREF;
        11      :   sdram_cmd       <=      AREF;
        19      :   sdram_cmd       <=      MSET;
        default :   sdram_cmd       <=      NOP;
    endcase

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        sdram_addr      <=      12'b0100_0000_0000;
    else if(cnt_cmd == 5'd19) 
        sdram_addr      <=      12'b0000_0011_0010;
    else
        sdram_addr      <=      12'b0100_0000_0000;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        init_done       <=      1'b0; 
    else if(cnt_cmd > 5'd19) 
        init_done       <=      1'b1;
    else
        init_done       <=      init_done;
        
endmodule

sdram_aref模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : sdram_aref.v
// Create Time  : 2020-02-10 13:34:03
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module sdram_aref(
    //Sysytem Interfaces
    input                   sclk            ,
    input                   rst_n           ,
    //SDRAM Interfaces
    output  reg     [ 3:0]  aref_cmd        ,
    output  wire    [11:0]  aref_addr       ,
    //Others
    input                   init_done       ,
    output  reg             aref_req        ,
    output  reg             aref_end        ,
    input                   aref_en         
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
localparam  NOP         =   4'b0111         ;
localparam  PRE         =   4'b0010         ;
localparam  AREF        =   4'b0001         ;
localparam  DELAY_15US  =   11'd1500        ;

reg                         aref_flag       ;
reg             [ 2:0]      cnt_cmd         ;
reg             [10:0]      cnt_15ms        ;

 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
assign  aref_addr           =       12'b0100_0000_0000;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        aref_flag           <=      1'b0; 
    else if(cnt_cmd >= 3'd7)
        aref_flag           <=      1'b0;
    else if(aref_en == 1'b1)
        aref_flag           <=      1'b1;
    else
        aref_flag           <=      aref_flag;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_cmd             <=      3'd0;
    else if(cnt_cmd >= 3'd7)
        cnt_cmd             <=      3'd0;
    else if(aref_flag == 1'b1)
        cnt_cmd             <=      cnt_cmd + 1'b1; 
    
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        aref_cmd            <=      NOP;    
    else case(cnt_cmd)
        1       :   aref_cmd            <=      PRE;
        4       :   aref_cmd            <=      AREF;
        default :   aref_cmd            <=      NOP;
    endcase
   
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        aref_end            <=      1'b0;
    else if(cnt_cmd >= 3'd7)
        aref_end            <=      1'b1;
    else
        aref_end            <=      1'b0;   
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_15ms            <=      20'd0;
    else if(cnt_15ms == DELAY_15US)
        cnt_15ms            <=      20'd0;
    else if(init_done == 1'b1) 
        cnt_15ms            <=      cnt_15ms + 1'b1;
    else
        cnt_15ms            <=      20'd0;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        aref_req            <=      1'b0; 
    else if(cnt_15ms == DELAY_15US)
        aref_req            <=      1'b1;
    else if(aref_en == 1'b1)
        aref_req            <=      1'b0;
    else
        aref_req            <=      aref_req;
            

endmodule

sdram_auto_write_read模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : sdram_auto_write_read.v
// Create Time  : 2020-02-15 11:26:21
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module sdram_auto_write_read(
    // system signals
    input                   rst_n                   ,       
    // wfifo
    input                   wfifo_wclk              ,
    input                   wfifo_wr_en             ,       
    input           [15:0]  wfifo_wr_data           ,
    input                   wfifo_rclk              ,
    input                   wfifo_rd_en             ,       
    output  wire    [15:0]  wfifo_rd_data           ,
    output  reg             wr_trig                 ,
    // rfifo
    input                   rfifo_wclk              ,       // 100MHz
    input                   rfifo_wr_en             ,       
    input           [15:0]  rfifo_wr_data           ,
    input                   rfifo_rclk              ,
    input                   rfifo_rd_en             ,       
    output  wire    [15:0]  rfifo_rd_data           ,
    output  reg             rd_trig                 ,
    // user interfaces
    output  reg             rfifo_rd_ready      
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
parameter   WFIFO_RD_CNT    =       256             ;
parameter   RFIFO_WR_CNT    =       250             ;



wire                [10:0]  wfifo_rd_count          ;
wire                [10:0]  rfifo_wr_count          ;
reg                         flag_rd                 ;   

 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
always @(posedge rfifo_wclk or negedge rst_n)
    if(rst_n == 1'b0)
        rfifo_rd_ready      <=      1'b0;
    else if(rfifo_wr_count >= RFIFO_WR_CNT)
        rfifo_rd_ready      <=      1'b1;
    else
        rfifo_rd_ready      <=      rfifo_rd_ready;
          
always @(posedge wfifo_rclk or negedge rst_n)
     if(rst_n == 1'b0)
        flag_rd             <=      1'b0; 
     else if(wfifo_rd_count >= WFIFO_RD_CNT)
        flag_rd             <=      1'b1;
    else
        flag_rd             <=      flag_rd;

always @(posedge rfifo_wclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_trig             <=      1'b0;
    else if(rfifo_wr_count < RFIFO_WR_CNT && flag_rd == 1'b1)
        rd_trig             <=      1'b1;
    else
        rd_trig             <=      1'b0; 
    
always @(posedge wfifo_rclk or negedge rst_n)
    if(rst_n == 1'b0)
        wr_trig             <=      1'b0;
    else if(wfifo_rd_count >= WFIFO_RD_CNT)
        wr_trig             <=      1'b1;
    else
        wr_trig             <=      1'b0;

//wfifo
fifo_generator_0 wfifo_inst(
  .rst                      (~rst_n                     ),                      // input wire rst
  .wr_clk                   (wfifo_wclk                 ),                // input wire wr_clk
  .rd_clk                   (wfifo_rclk                 ),                // input wire rd_clk
  .din                      (wfifo_wr_data              ),                      // input wire [15 : 0] din
  .wr_en                    (wfifo_wr_en                ),                  // input wire wr_en
  .rd_en                    (wfifo_rd_en                ),                  // input wire rd_en
  .dout                     (wfifo_rd_data              ),                    // output wire [15 : 0] dout
  .full                     (                           ),                    // output wire full
  .empty                    (                           ),                  // output wire empty
  .rd_data_count            (wfifo_rd_count             ),  // output wire [10 : 0] rd_data_count
  .wr_data_count            (                           )  // output wire [10 : 0] wr_data_count
);
//rfifo
fifo_generator_0 rfifo_inst(
  .rst                      (~rst_n                     ),                      // input wire rst
  .wr_clk                   (rfifo_wclk                 ),                // input wire wr_clk
  .rd_clk                   (rfifo_rclk                 ),                // input wire rd_clk
  .din                      (rfifo_wr_data              ),                      // input wire [15 : 0] din
  .wr_en                    (rfifo_wr_en                ),                  // input wire wr_en
  .rd_en                    (rfifo_rd_en                ),                  // input wire rd_en
  .dout                     (rfifo_rd_data              ),                    // output wire [15 : 0] dout
  .full                     (                           ),                    // output wire full
  .empty                    (                           ),                  // output wire empty
  .rd_data_count            (                           ),  // output wire [10 : 0] rd_data_count
  .wr_data_count            (rfifo_wr_count             )  // output wire [10 : 0] wr_data_count
);

endmodule

sdram_write模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : sdram_write.v
// Create Time  : 2020-02-10 20:05:26
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module sdram_write(
    //System Interfaces
    input                   sclk            ,
    input                   rst_n           ,
    //SDRAM Interfaces
    output  reg     [ 3:0]  wr_cmd          ,
    output  reg     [11:0]  wr_addr         ,
    output  wire    [ 1:0]  bank_addr       ,
    output  wire    [15:0]  wr_data         ,     
    //Communication Interfaces
    input                   wr_trig         ,
    input                   wr_en           ,
    output  reg             wr_end          ,
    output  reg             wr_req          ,
    input                   aref_req        ,
    output  reg             wfifo_rd_en     ,
    input           [15:0]  wfifo_rd_data      
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
parameter  WROW_ADDR_END    =   937         ;
parameter  WCOL_MADDR_END   =   256         ;
parameter  WCOL_FADDR_END   =   512         ;
// Define State
localparam  S_IDLE      =   5'b0_0001       ;
localparam  S_REQ       =   5'b0_0010       ;
localparam  S_ACT       =   5'b0_0100       ;
localparam  S_WR        =   5'b0_1000       ;
localparam  S_PRE       =   5'b1_0000       ;
// SDRAM Command
localparam  CMD_NOP     =   4'b0111         ;
localparam  CMD_PRE     =   4'b0010         ;
localparam  CMD_AREF    =   4'b0001         ;
localparam  CMD_ACT     =   4'b0011         ;
localparam  CMD_WR      =   4'b0100         ;

reg                 [ 4:0]  state           ;
reg                         flag_act_end    ;
reg                         row_end         ;
reg                 [ 1:0]  burst_cnt       ;
reg                         data_end        ;
reg                         flag_row_end    ;
reg                         flag_data_end   ;
reg                         flag_aref_req   ;
reg                 [ 8:0]  col_addr        ;
reg                 [ 1:0]  burst_cnt_r     ;
reg                 [11:0]  row_addr        ;
reg                         data_end_r      ;
reg                         data_end_r2     ;
reg                         row_end_r       ;
reg                         row_end_r2      ; 


//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
assign      bank_addr       =       2'b00;
assign      wr_data         =       wfifo_rd_data;


always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        state           <=      S_IDLE;
    else case(state)
        S_IDLE    :   if(wr_trig == 1'b1)
                        state           <=      S_REQ;
                    else
                        state           <=      state;                        
        S_REQ   :   if(wr_en == 1'b1)
                        state           <=      S_ACT;
                    else
                        state           <=      state;                        
        S_ACT   :   if(flag_act_end == 1'b1)
                        state           <=      S_WR;
                    else
                        state           <=      state;                        
        S_WR    :   if(data_end_r == 1'b1 || row_end_r == 1'b1)
                        state           <=      S_PRE;
                    else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)
                        state           <=      S_PRE;
                    else
                        state           <=      state;                        
        S_PRE   :   if(flag_data_end == 1'b1)
                        state           <=      S_IDLE;
                    else if(flag_aref_req == 1'b1)
                        state           <=      S_REQ;
                    else if(flag_row_end == 1'b1)
                        state           <=      S_ACT;
                    else 
                        state           <=      state;
        default :   state           <=      S_IDLE;
    endcase
  
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        flag_aref_req       <=      1'b0;
    else if(state == S_PRE && aref_req == 1'b1)
        flag_aref_req       <=      1'b1;
    else
        flag_aref_req       <=      1'b0; 

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        flag_act_end    <=      1'b0;    
    else if(state == S_ACT && wr_cmd == CMD_ACT)
        flag_act_end    <=      1'b1;
    else 
        flag_act_end    <=      1'b0; 

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        row_end         <=      1'b0;
    else if(col_addr == 9'd508 && burst_cnt == 2'd1)
        row_end         <=      1'b1;
    else
        row_end         <=      1'b0;

always @(posedge sclk)begin
    row_end_r   <=      row_end;
    row_end_r2  <=      row_end_r;
end
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        burst_cnt       <=      2'd0;
    else if(state == S_WR)
        burst_cnt       <=      burst_cnt + 1'b1;
    else
        burst_cnt       <=      2'd0;

always @(posedge sclk)
    burst_cnt_r     <=      burst_cnt;

 always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        data_end    <=      1'b0;     
    else if(state == S_WR && wr_cmd == CMD_WR && col_addr == WCOL_MADDR_END - 4 && row_addr == WROW_ADDR_END)
        data_end    <=      1'b1;
    else if((col_addr == 'd252 || col_addr == 508) && burst_cnt == 2'd1)
        data_end    <=      1'b1;
    else
        data_end    <=      1'b0;
            
always @(posedge sclk)begin
    data_end_r      <=      data_end;
    data_end_r2     <=      data_end_r;  
end  

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        flag_row_end    <=      1'b0;   
    else if(state == S_PRE && row_end_r2 == 1'b1)
        flag_row_end    <=      1'b1;
    else 
        flag_row_end    <=      1'b0;
         
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        flag_data_end   <=      1'b0;  
    else if(state == S_PRE && data_end_r2 == 1'b1) 
        flag_data_end   <=      1'b1;
    else
        flag_data_end   <=      1'b0;
        
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        col_addr        <=      9'd0;
    else if(state == S_WR && wr_cmd == CMD_WR && col_addr == WCOL_MADDR_END - 4 && row_addr == WROW_ADDR_END)
        col_addr        <=      9'd0;
    else if(state == S_WR && wr_cmd == CMD_WR && col_addr == 'd508)
        col_addr        <=      9'd0;   
    else if(state == S_WR && wr_cmd == CMD_WR)
        col_addr        <=      col_addr + 3'd4;
    else
        col_addr        <=      col_addr;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        row_addr        <=      12'd0;  
    else if(state == S_WR && wr_cmd == CMD_WR && col_addr == WCOL_MADDR_END - 4 && row_addr == WROW_ADDR_END)
        row_addr        <=      12'd0;
    else if(state == S_WR && wr_cmd == CMD_WR && col_addr == 'd508)
        row_addr        <=      row_addr + 1'b1;
    else
        row_addr        <=      row_addr;
             
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        wr_cmd          <=      CMD_NOP;    
    else case(state)
        S_ACT   :   if(wr_cmd != CMD_ACT && flag_act_end == 1'b0)
                        wr_cmd          <=      CMD_ACT;
                    else
                        wr_cmd          <=      CMD_NOP;
        S_WR    :   if(data_end == 1'b1 || row_end == 1'b1)
                        wr_cmd          <=      CMD_NOP;
                    else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)
                        wr_cmd          <=      CMD_NOP;
                    else if(burst_cnt == 2'd0)
                        wr_cmd          <=      CMD_WR;
                    else
                        wr_cmd          <=      CMD_NOP; 
        S_PRE   :   if(wr_cmd != CMD_PRE)
                        wr_cmd          <=      CMD_PRE;
                    else 
                        wr_cmd          <=      CMD_NOP;
                
        default :   wr_cmd          <=      CMD_NOP;
    endcase

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        wr_addr         <=      12'd0;    
    else case(state)
        S_ACT   :   if(wr_cmd != CMD_ACT)
                        wr_addr         <=      row_addr;
                    else
                        wr_addr         <=      12'd0;
        S_WR    :   if(data_end == 1'b1 || row_end == 1'b1)
                        wr_addr         <=      12'd0;
                    else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)
                        wr_addr         <=      12'd0;
                    else if(burst_cnt == 2'd0)
                        wr_addr         <=      {3'b000,col_addr};
                    else
                        wr_addr         <=      12'd0; 
        S_PRE   :   wr_addr         <=      12'b0100_0000_0000;
        default :   wr_addr         <=      12'd0;
    endcase

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        wfifo_rd_en     <=      1'b0;    
    else if(state == S_WR)
        wfifo_rd_en     <=      1'b1;
    else
        wfifo_rd_en     <=      1'b0;    

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        wr_end          <=      1'b0;   
    else if(flag_data_end == 1'b1)
        wr_end          <=      1'b1;
    else if(state != S_IDLE && flag_aref_req == 1'b1 && wr_end == 1'b0)
        wr_end          <=      1'b1;
    else
        wr_end          <=      1'b0;
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        wr_req          <=      1'b0;  
    else if(wr_en == 1'b1)
        wr_req          <=      1'b0;
    else if(state == S_REQ)
        wr_req          <=      1'b1;
    else
        wr_req          <=      wr_req;
          
endmodule

sdram_read模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : sdram_read.v
// Create Time  : 2020-02-11 20:48:41
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module sdram_read(
    //System Interfaces
    input                   sclk            ,
    input                   rst_n           ,
    //SDRAM Interfaces
    output  reg     [ 3:0]  rd_cmd          ,
    output  reg     [11:0]  rd_addr         ,
    output  wire    [ 1:0]  bank_addr       ,    
    //Communication Interfaces
    input                   rd_trig         ,
    input                   rd_en           ,
    output  reg             rd_end          ,
    output  reg             rd_req          ,
    input                   aref_req        ,
    output  reg             rd_data_en      
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
parameter  RROW_ADDR_END    =   937         ;
parameter  RCOL_MADDR_END   =   256         ;
// Define State
localparam  S_IDLE      =   5'b0_0001       ;
localparam  S_REQ       =   5'b0_0010       ;
localparam  S_ACT       =   5'b0_0100       ;
localparam  S_RD        =   5'b0_1000       ;
localparam  S_PRE       =   5'b1_0000       ;
// SDRAM Command
localparam  CMD_NOP     =   4'b0111         ;
localparam  CMD_PRE     =   4'b0010         ;
localparam  CMD_AREF    =   4'b0001         ;
localparam  CMD_ACT     =   4'b0011         ;
localparam  CMD_RD      =   4'b0101         ;

reg                 [ 4:0]  state           ;
reg                         flag_act_end    ;
reg                         row_end         ;
reg                 [ 1:0]  burst_cnt       ;
reg                         data_end        ;
reg                         flag_row_end    ;
reg                         flag_data_end   ;
reg                         flag_aref_req   ;
reg                 [ 8:0]  col_addr        ;
reg                 [ 1:0]  burst_cnt_r     ;
reg                 [11:0]  row_addr        ;
reg                         data_end_r      ;
reg                         data_end_r2     ;
reg                         row_end_r       ;
reg                         row_end_r2      ; 
reg                         rfifo_wd_en_r1  ;
reg                         rfifo_wd_en_r2  ;
reg                         rfifo_wd_en_r3  ;



//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
assign      bank_addr       =       2'b00;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        state           <=      S_IDLE;
    else case(state)
        S_IDLE    :   if(rd_trig == 1'b1)
                        state           <=      S_REQ;
                    else
                        state           <=      state;                        
        S_REQ   :   if(rd_en == 1'b1)
                        state           <=      S_ACT;
                    else
                        state           <=      state;                        
        S_ACT   :   if(flag_act_end == 1'b1)
                        state           <=      S_RD;
                    else
                        state           <=      state;                        
        S_RD    :   if(data_end_r == 1'b1 || row_end_r == 1'b1)
                        state           <=      S_PRE;
                    else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)
                        state           <=      S_PRE;
                    else
                        state           <=      state;                        
        S_PRE   :   if(flag_data_end == 1'b1)
                        state           <=      S_IDLE;
                    else if(flag_aref_req == 1'b1)
                        state           <=      S_REQ;
                    else if(flag_row_end == 1'b1)
                        state           <=      S_ACT;
                    else 
                        state           <=      state;
        default :   state           <=      S_IDLE;
    endcase
  
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        flag_aref_req       <=      1'b0;
    else if(state == S_PRE && aref_req == 1'b1)
        flag_aref_req       <=      1'b1;
    else
        flag_aref_req       <=      1'b0; 

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        flag_act_end    <=      1'b0;    
    else if(state == S_ACT && rd_cmd == CMD_ACT)
        flag_act_end    <=      1'b1;
    else 
        flag_act_end    <=      1'b0; 

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        row_end         <=      1'b0;
    else if(col_addr == 9'd508 && burst_cnt == 2'd1)
        row_end         <=      1'b1;
    else
        row_end         <=      1'b0;

always @(posedge sclk)begin
    row_end_r   <=      row_end;
    row_end_r2  <=      row_end_r;
end
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        burst_cnt       <=      2'd0;
    else if(state == S_RD)
        burst_cnt       <=      burst_cnt + 1'b1;
    else
        burst_cnt       <=      2'd0;

always @(posedge sclk)
    burst_cnt_r     <=      burst_cnt;

 always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        data_end    <=      1'b0; 
    else if(state == S_RD && rd_cmd == CMD_RD && col_addr == RCOL_MADDR_END - 4 && row_addr == RROW_ADDR_END)
        data_end    <=      1'b1;    
    else if((col_addr == 'd252 || col_addr == 508) && burst_cnt == 2'd1)
        data_end    <=      1'b1;
    else
        data_end    <=      1'b0;
            
always @(posedge sclk)begin
    data_end_r      <=      data_end;
    data_end_r2     <=      data_end_r;  
end  

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        flag_row_end    <=      1'b0;   
    else if(state == S_PRE && row_end_r2 == 1'b1)
        flag_row_end    <=      1'b1;
    else 
        flag_row_end    <=      1'b0;
         
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        flag_data_end   <=      1'b0;  
    else if(state == S_PRE && data_end_r2 == 1'b1) 
        flag_data_end   <=      1'b1;
    else
        flag_data_end   <=      1'b0;
        
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        col_addr        <=      12'd0;
    else if(state == S_RD && rd_cmd == CMD_RD && col_addr == RCOL_MADDR_END - 4 && row_addr == RROW_ADDR_END)
        col_addr        <=      9'd0;
    else if(state == S_RD && rd_cmd == CMD_RD && col_addr == 'd508)
        col_addr        <=      12'd0;   
    else if(state == S_RD && rd_cmd == CMD_RD)
        col_addr        <=      col_addr + 3'd4;
    else
        col_addr        <=      col_addr;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        row_addr        <=      12'd0;  
    else if(state == S_RD && rd_cmd == CMD_RD && col_addr == RCOL_MADDR_END - 4 && row_addr == RROW_ADDR_END)
        row_addr        <=      12'd0;
    else if(state == S_RD && rd_cmd == CMD_RD && col_addr == 'd508)
        row_addr        <=      row_addr + 1'b1;
    else
        row_addr        <=      row_addr;
          
    
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_cmd          <=      CMD_NOP;    
    else case(state)
        S_ACT   :   if(rd_cmd != CMD_ACT && flag_act_end == 1'b0)
                        rd_cmd          <=      CMD_ACT;
                    else
                        rd_cmd          <=      CMD_NOP;
        S_RD    :   if(data_end == 1'b1 || row_end == 1'b1)
                        rd_cmd          <=      CMD_NOP;
                    else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)
                        rd_cmd          <=      CMD_NOP;
                    else if(burst_cnt == 2'd0)
                        rd_cmd          <=      CMD_RD;
                    else
                        rd_cmd          <=      CMD_NOP; 
        S_PRE   :   if(rd_cmd != CMD_PRE)
                        rd_cmd          <=      CMD_PRE;
                    else 
                        rd_cmd          <=      CMD_NOP;
                
        default :   rd_cmd          <=      CMD_NOP;
    endcase

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_addr         <=      12'd0;    
    else case(state)
        S_ACT   :   if(rd_cmd != CMD_ACT)
                        rd_addr         <=      row_addr;
                    else
                        rd_addr         <=      12'd0;
        S_RD    :   if(data_end == 1'b1 || row_end == 1'b1)
                        rd_addr         <=      12'd0;
                    else if(burst_cnt_r == 2'd2 && aref_req == 1'b1)
                        rd_addr         <=      12'd0;
                    else if(burst_cnt == 2'd0)
                        rd_addr         <=      {3'b000,col_addr};
                    else
                        rd_addr         <=      12'd0; 
        S_PRE   :   rd_addr         <=      12'b0100_0000_0000;
        default :   rd_addr         <=      12'd0;
    endcase

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_end          <=      1'b0;   
    else if(flag_data_end == 1'b1)
        rd_end          <=      1'b1;
    else if(state != S_IDLE && flag_aref_req == 1'b1 && rd_end == 1'b0)
        rd_end          <=      1'b1;
    else
        rd_end          <=      1'b0;
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_req          <=      1'b0;  
    else if(rd_en == 1'b1)
        rd_req          <=      1'b0;
    else if(state == S_REQ)
        rd_req          <=      1'b1;
    else
        rd_req          <=      rd_req;
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rfifo_wd_en_r1  <=      1'b0;    
    else if(state == S_RD)
        rfifo_wd_en_r1  <=      1'b1;
    else
        rfifo_wd_en_r1  <=      1'b0;  

always @(posedge sclk)begin
    rfifo_wd_en_r2      <=      rfifo_wd_en_r1;
    rfifo_wd_en_r3      <=      rfifo_wd_en_r2;
end

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_data_en      <=      1'b0;
    else 
        rd_data_en      <=      rfifo_wd_en_r3;


endmodule

SDRAM控制器完整的模块代码如上,一共五个模块,其中SDRAM上电初始化、自刷新与前面的模块一摸一样,SDRAM读写模块只是更改了一小部分内容,又在前面基础上添加了sdram_auto_write_read自动读写模块。

SDRAM控制器的测试代码

这里我们给出顶层测试模块的代码,如下:

`timescale 1ns / 1ps
`define CLOCK    10
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : sdram_init_tb.v
// Create Time  : 2020-02-09 17:10:08
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module sdram_init_tb;
reg                         sclk            ;
reg                         clk_50m         ;
reg                         rst_n           ;
wire                        sdram_clk       ;
wire                        sdram_cke       ;
wire                        sdram_cs_n      ;
wire                        sdram_cas_n     ;
wire                        sdram_ras_n     ;
wire                        sdram_we_n      ;
wire    [ 1:0]              sdram_bank      ;
wire    [11:0]              sdram_addr      ;
wire    [ 1:0]              sdram_dqm       ;
wire    [15:0]              sdram_dq        ;

reg                         wfifo_wr_en     ;
reg    [15:0]               wfifo_wr_data   ;
wire   [15:0]               rfifo_rd_data   ;
wire                        rfifo_rd_ready  ;
reg    [15:0]               rfifo_test_data ; 
reg    [20:0]               err_cnt         ;
reg                         rfifo_rd_en     ;

initial begin
    sclk        =       1'b0;
    rst_n       <=      1'b0;
    #(200*`CLOCK)
    rst_n       <=      1'b1;
end
always  #(`CLOCK/2)     sclk        =       ~sclk; 

initial begin
    clk_50m     =       1'b0;
    wfifo_wr_en <=      1'b0;
    rfifo_rd_en <=      1'b0;
    #(250_000)
    wfifo_wr_en <=      1'b1;
    #(5_000_000)
    rfifo_rd_en <=      1'b1;
    #(459_852_690-250_000);
    wfifo_wr_en <=      1'b0;
    rfifo_rd_en <=      1'b0;
    // #(9_863_860-250_000);
    // wfifo_wr_en <=      1'b0;
    // rfifo_rd_en <=      1'b1;
end
always  #(`CLOCK*5)       clk_50m      =       ~clk_50m; 


always @(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
        wfifo_wr_data       <=      16'd0;
    else if(wfifo_wr_en == 1'b1)
        wfifo_wr_data       <=      wfifo_wr_data + 1'b1;
    else
        wfifo_wr_data       <=      wfifo_wr_data;

always @(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
       rfifo_test_data      <=      16'd0; 
    else if(rfifo_rd_en == 1'b1)
        rfifo_test_data     <=      rfifo_test_data + 1'b1;
    else
        rfifo_test_data     <=      rfifo_test_data;

always @(posedge clk_50m or negedge rst_n)
    if(rst_n == 1'b0)
        err_cnt             <=      21'd0;
    else if(rfifo_rd_en == 1'b1 && rfifo_test_data != rfifo_rd_data) 
        err_cnt             <=      err_cnt + 1'b1;
    else
        err_cnt             <=      err_cnt;         
    

sdram_top sdram_top_inst(
    //System Interfaces
    .sclk                   (sclk                   ),
    .rst_n                  (rst_n                  ),
    //SDRAM Interfaces
    .sdram_clk              (sdram_clk              ),
    .sdram_cke              (sdram_cke              ),
    .sdram_cs_n             (sdram_cs_n             ),
    .sdram_cas_n            (sdram_cas_n            ),
    .sdram_ras_n            (sdram_ras_n            ),
    .sdram_we_n             (sdram_we_n             ),
    .sdram_bank             (sdram_bank             ),
    .sdram_addr             (sdram_addr             ),
    .sdram_dqm              (sdram_dqm              ),
    .sdram_dq               (sdram_dq               ),
    //User Interfaces
    .wfifo_wclk             (clk_50m                ),
    .wfifo_wr_en            (wfifo_wr_en            ),
    .wfifo_wr_data          (wfifo_wr_data          ),
    .rfifo_rclk             (clk_50m                ),
    .rfifo_rd_en            (rfifo_rd_en            ),
    .rfifo_rd_data          (rfifo_rd_data          ),
    .rfifo_rd_ready         (rfifo_rd_ready         )
);

defparam        sdram_model_plus_inst.addr_bits =       12;
defparam        sdram_model_plus_inst.data_bits =       16;
defparam        sdram_model_plus_inst.col_bits  =       9;
defparam        sdram_model_plus_inst.mem_sizes =       2*1024*1024;            // 2M

sdram_model_plus sdram_model_plus_inst(
    .Dq                     (sdram_dq               ), 
    .Addr                   (sdram_addr             ), 
    .Ba                     (sdram_bank             ), 
    .Clk                    (sdram_clk              ), 
    .Cke                    (sdram_cke              ), 
    .Cs_n                   (sdram_cs_n             ), 
    .Ras_n                  (sdram_ras_n            ), 
    .Cas_n                  (sdram_cas_n            ), 
    .We_n                   (sdram_we_n             ), 
    .Dqm                    (sdram_dqm              ),
    .Debug                  (1'b1                   )
);

endmodule

测试模型的代码,我们为了简单起见不再给出,有需要的同学可以去前面的文章中自取。

仿真结果

在这里插入图片描述
细看我们的测试模块,我们编写的是循环测试的代码,运行了一段时间后,err_cnt依旧是0,证明了我们模块设计的正确性。

总结

创作不易,认为文章有帮助的同学们可以关注点赞支持。(工程也都在群中)对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
在这里插入图片描述

发布了34 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/zhangningning1996/article/details/104334625