FPGA学习记录——大话SDRAM读写控制模块

参考书目:《FPGA Verilog开发实战指南——基于Xilinx Artix7》、《FPGA Verilog开发实战指南——基于Altera EP4CE10》。

SDRAM的读写给我一种CPU指令的感觉,感觉在完成了一个单周期CPU后,SDRAM的读写控制模块的理解也更加容易。

参考野火的第53章,开始功利的学习:

1、按我的理解sdram读写控制模块可以分成四个类似于cpu的指令和一个仲裁模块:初始化、自刷新、读、写。

2、各个模块会经过仲裁后会发送一些指令到sdram,做出相应的读写操作。同时sdram中也有一些操作码。

先发这么多,以后再添。

初始化模块:

 


module  sdram_init
(
    input   wire            sys_clk     ,   //系统时钟,频率100MHz
    input   wire            sys_rst_n   ,   //复位信号,低电平有效

    output  reg     [3:0]   init_cmd    ,   //初始化阶段写入sdram的指令,{cs_n,ras_n,cas_n,we_n}
    output  reg     [1:0]   init_ba     ,   //初始化阶段Bank地址
    output  reg     [12:0]  init_addr   ,   //初始化阶段地址数据,辅助预充电操作
                                            //和配置模式寄存器操作,A12-A0,共13位
    output  wire            init_end        //初始化结束信号
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

// parameter    define
parameter   T_POWER     =   15'd20_000  ;   //上电后等待时钟数(200us)
//SDRAM初始化用到的控制信号命令
parameter   P_CHARGE    =   4'b0010     ,   //预充电指令
            AUTO_REF    =   4'b0001     ,   //自动刷新指令
            NOP         =   4'b0111     ,   //空操作指令
            M_REG_SET   =   4'b0000     ;   //模式寄存器设置指令
//SDRAM初始化过程各个状态
parameter   INIT_IDLE   =   3'b000      ,   //初始状态
            INIT_PRE    =   3'b001      ,   //预充电状态
            INIT_TRP    =   3'b011      ,   //预充电等待          tRP
            INIT_AR     =   3'b010      ,   //自动刷新
            INIT_TRF    =   3'b100      ,   //自动刷新等待        tRC
            INIT_MRS    =   3'b101      ,   //模式寄存器设置
            INIT_TMRD   =   3'b111      ,   //模式寄存器设置等待  tMRD
            INIT_END    =   3'b110      ;   //初始化完成
parameter   TRP_CLK     =   3'd2        ,   //预充电等待周期,20ns
            TRC_CLK     =   3'd7        ,   //自动刷新等待,70ns
            TMRD_CLK    =   3'd3        ;   //模式寄存器设置等待周期,30ns

// wire define
wire            wait_end        ;   //上电后200us等待结束标志
wire            trp_end         ;   //预充电等待结束标志
wire            trc_end         ;   //自动刷新等待结束标志
wire            tmrd_end        ;   //模式寄存器设置等待结束标志

// reg  define
reg     [14:0]  cnt_200us       ;   //SDRAM上电后200us稳定期计数器
reg     [2:0]   init_state      ;   //SDRAM初始化状态
reg     [2:0]   cnt_clk         ;   //时钟周期计数,记录初始化各状态等待周期数
reg             cnt_clk_rst     ;   //时钟周期计数复位标志
reg     [3:0]   cnt_init_aref   ;   //初始化过程自动刷新次数计数器

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//cnt_200us:SDRAM上电后200us稳定期计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_200us   <=  15'd0;
    else    if(cnt_200us == T_POWER)
        cnt_200us   <=  T_POWER;
    else
        cnt_200us   <=  cnt_200us + 1'b1;

//wait_end:上电后200us等待结束标志
assign  wait_end = (cnt_200us == (T_POWER - 1'b1)) ? 1'b1 : 1'b0;

//init_end:SDRAM初始化完毕信号
assign  init_end = (init_state == INIT_END) ? 1'b1 : 1'b0;

//cnt_clk:时钟周期计数,记录初始化各状态等待时间
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk <=  3'd0;
    else    if(cnt_clk_rst == 1'b1)
        cnt_clk <=  3'd0;
    else
        cnt_clk <=  cnt_clk + 1'b1;

//cnt_init_aref:初始化过程自动刷新次数计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_init_aref   <=  4'd0;
    else    if(init_state == INIT_IDLE)
        cnt_init_aref   <=  4'd0;
    else    if(init_state == INIT_AR)
        cnt_init_aref   <=  cnt_init_aref + 1'b1;
    else
        cnt_init_aref   <=  cnt_init_aref;

//trp_end,trc_end,tmrd_end:等待结束标志
assign  trp_end     =   ((init_state == INIT_TRP )
                        && (cnt_clk == TRP_CLK )) ? 1'b1 : 1'b0;
assign  trc_end     =   ((init_state == INIT_TRF )
                        && (cnt_clk == TRC_CLK )) ? 1'b1 : 1'b0;
assign  tmrd_end    =   ((init_state == INIT_TMRD)
                        && (cnt_clk == TMRD_CLK)) ? 1'b1 : 1'b0;

//SDRAM的初始化状态机
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        init_state  <=  INIT_IDLE;
    else
        case(init_state)
            INIT_IDLE:  //系统上电后,在初始状态等待200us跳转到预充电状态
                if(wait_end == 1'b1)
                    init_state  <=  INIT_PRE;
                else
                    init_state  <=  init_state;
            INIT_PRE:   //预充电状态,直接跳转到预充电等待状态
                init_state  <=  INIT_TRP;
            INIT_TRP:   //预充电等待状态,等待结束,跳转到自动刷新状态
                if(trp_end == 1'b1)
                    init_state  <=  INIT_AR;
                else
                    init_state  <=  init_state;
            INIT_AR :   //自动刷新状态,直接跳转到自动刷新等待状态
                init_state  <=  INIT_TRF;
            INIT_TRF:   //自动刷新等待状态,等待结束,自动跳转到模式寄存器设置状态
                if(trc_end == 1'b1)
                    if(cnt_init_aref == 4'd8)
                        init_state  <=  INIT_MRS;
                    else
                        init_state  <=  INIT_AR;
                else
                    init_state  <=  init_state;
            INIT_MRS:   //模式寄存器设置状态,直接跳转到模式寄存器设置等待状态
                init_state  <=  INIT_TMRD;
            INIT_TMRD:  //模式寄存器设置等待状态,等待结束,跳到初始化完成状态
                if(tmrd_end == 1'b1)
                    init_state  <=  INIT_END;
                else
                    init_state  <=  init_state;
            INIT_END:   //初始化完成状态,保持此状态
                init_state  <=  INIT_END;
            default:    init_state  <=  INIT_IDLE;
        endcase

//cnt_clk_rst:时钟周期计数复位标志
always@(*)
    begin
        case (init_state)
            INIT_IDLE:  cnt_clk_rst <=  1'b1;   //时钟周期计数复位信号,高有效,时钟周期计数清零
            INIT_TRP:   cnt_clk_rst <= (trp_end == 1'b1) ? 1'b1 : 1'b0;
                                                //等待结束标志有效,计数器清零
            INIT_TRF:   cnt_clk_rst <=  (trc_end == 1'b1) ? 1'b1 : 1'b0; 
                                                //等待结束标志有效,计数器清零
            INIT_TMRD:  cnt_clk_rst <=  (tmrd_end == 1'b1) ? 1'b1 : 1'b0;
                                                //等待结束标志有效,计数器清零
            INIT_END:   cnt_clk_rst <=  1'b1;   //初始化完成,计数器清零
            default:    cnt_clk_rst <=  1'b0;
        endcase
    end

//SDRAM操作指令控制
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            init_cmd    <=  NOP;
            init_ba     <=  2'b11;
            init_addr   <=  13'h1fff;
        end
    else
        case(init_state)
            INIT_IDLE,INIT_TRP,INIT_TRF,INIT_TMRD:  //执行空操作指令
                begin
                    init_cmd    <=  NOP;
                    init_ba     <=  2'b11;
                    init_addr   <=  13'h1fff;
                end
            INIT_PRE:   //预充电指令
                begin
                    init_cmd    <=  P_CHARGE;
                    init_ba     <=  2'b11;
                    init_addr   <=  13'h1fff;
                end 
            INIT_AR:    //自动刷新指令
                begin
                    init_cmd    <=  AUTO_REF;
                    init_ba     <=  2'b11;
                    init_addr   <=  13'h1fff;
                end
            INIT_MRS:   //模式寄存器设置指令
                begin
                    init_cmd    <=  M_REG_SET;
                    init_ba     <=  2'b00;
                    init_addr   <=
                    {    //地址辅助配置模式寄存器,参数不同,配置的模式不同
                        3'b000,     //A12-A10:预留
                        1'b0,       //A9=0:读写方式,0:突发读&突发写,1:突发读&单写
                        2'b00,      //{A8,A7}=00:标准模式,默认
                        3'b011,     //{A6,A5,A4}=011:CAS潜伏期,010:2,011:3,其他:保留
                        1'b0,       //A3=0:突发传输方式,0:顺序,1:隔行
                        3'b111      //{A2,A1,A0}=111:突发长度,000:单字节,001:2字节
                                    //010:4字节,011:8字节,111:整页,其他:保留
                    };
                end 
            INIT_END:   //SDRAM初始化完成
                begin
                    init_cmd    <=  NOP;
                    init_ba     <=  2'b11;
                    init_addr   <=  13'h1fff;
                end
            default:
                begin
                    init_cmd    <=  NOP;
                    init_ba     <=  2'b11;
                    init_addr   <=  13'h1fff;
                end    
        endcase

endmodule

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值