欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-02-25 11:28:10
...

SDRAM控制器接口简述

完整的SDRAM控制器的模块框图如下:
基于FPGA的SDRAM控制器设计(4)
前面的三篇文章,我们已经简述了基本的SDRAM的基本操作。这里总结一下SDRAM的几个模块,SDRAM的上电初始化,自刷新、读写模块、顶层仲裁控制。了解了上面的操作,我们已经可以完成SDRAM控制器的代码完成,接下来我们便完善SDRAM控制器的接口,简化该SDRAM控制器设计,使得该SDRAM控制器可以很容易的使用。下面的接口定义如下:
基于FPGA的SDRAM控制器设计(4)
顶层模块的接口主要时上面的接口,我们把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的描述相同。

自动读写模块的框图

这里为了方便同学们理解,我们给出自动读写模块的框图,也是仿照开源骚客的文章设计:
基于FPGA的SDRAM控制器设计(4)
基于FPGA的SDRAM控制器设计(4)

SDRAM控制器完整代码

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

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : aaa@qq.com
// 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        : aaa@qq.com
// 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        : aaa@qq.com
// 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        : aaa@qq.com
// 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        : aaa@qq.com
// 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        : aaa@qq.com
// 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        : aaa@qq.com
// 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

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

仿真结果

基于FPGA的SDRAM控制器设计(4)
细看我们的测试模块,我们编写的是循环测试的代码,运行了一段时间后,err_cnt依旧是0,证明了我们模块设计的正确性。

总结

创作不易,认为文章有帮助的同学们可以关注点赞支持。(工程也都在群中)对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
基于FPGA的SDRAM控制器设计(4)