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

本文详细介绍了一个基于FPGA的SDRAM控制器设计,包括SDRAM控制器的模块划分、接口定义、自动读写模块的设计,以及完整的代码实现。此外,还提供了SDRAM控制器的测试代码和仿真结果,验证了设计的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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        : nnzhang1996@foxmail.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                  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值