• SDRAM控制器设计


    1.SDRAM芯片容量计算:

    2^(行地址线宽)*2^(列地址线宽)*2^(bank地址线宽)*数据位宽=xMbit

    2.初始化操作:

    首先明确控制信号有哪些,

     包括输入信号包括Clk时钟,Cke时钟使能,Cs_n片选,Ras_n行选通,Cas_n列选通,We_n写使能,Ba(bank地址),SA(地址总线),DQM数据掩码(一位控制8位);DQ(数据输入输出复用)

    对于SDRAM的操作,是通过命令来控制的,Command={Cs_n,Ras_n,Cas_n,We_n},同时地址总线Sa和DQM作辅助信号,来设置相应的模式寄存器,在设置模式寄存器命令的时候,地址总线提供了模式寄存器的值。

     

    在对SDRAM进行操作之前,SDRAM必须被初始化。初始化操作为:

    VDD和VDDQ上电,首先需要延时等待100us,在此期间执行空操作NOP,延时完成后首先执行一次预充电命令,所有BANK(A10为高电平)都必须被预充电,使得器件所有BANK处于空闲状态。

    进入空闲状态后执行两次自动刷新命令,之后就可以进行加载模式寄存器,在模式加载完成后的第二个时钟周期就可以执行激活命令了。

     使用一个线性序列机即可实现初始化操作

     再设置一个时钟的计数器

     之后用一个case对计数值判断,在相应时刻给出相应命令。

     可以设置一个初始化完成标识信号,方便其他模块调用

     至此,初始化操作完成。

    ------------------------------------------------------------------------------------------------------------------------------------------------------------

    控制器设计:

    行列地址输入进来后先进行寄存,防止操作过程中发生改变:

    主状态机

     可以看到刷新操作,读操作和写操作是有优先级的,刷新>写操作>读操作

    同时设置了一个标志位FF,只有当FF=0时才执行任务,执行完任务置1.(任务包括刷新任务,读数据,写数据)。

    下面对三个模块进行实现:

    一、

    对于自动刷新,首先要设置一个刷新定时器ref_time_cnt,保证<64ms刷新一次,此代码中设置1560个clk_period,复位时ref_tine_cnt计数器清零,否则计数到1560时置1,否则如果初始化完成或者计数值大于0,计数器自加1,其他时候保持。

    在设置一个刷新定时标志位ref_time_flag,当刷新定时到就置1.

    然后就可以写自动刷新操作任务了,用task实现

    对自动刷新过程时间设置计数器ref_cnt,复位时ref_cnt清零,否则如果计数到刷新结束清零,否则如果刷新请求来临或者刷新计数值>0,计数器自加1,其他时候保持

     二、一次突发写

    localparam  wr_ACT_TIME=1'b1,//激活时刻
                    wr_WRITE_TIME=1+SC_RCD,//+激活到读命令或写命令延时tRCD
                    wr_PRE_TIME=1+SC_RCD+SC_BL+WR_PRE,//+突发长度,写操作完成到预充电时间间隔
                    wr_END_TIME=SC_RCD+SC_BL+WR_PRE+REF_PRE;//+等待时间tRP
        reg [15:0]wr_cnt;
        reg wr_opt,wr_opt_done;
        reg Wr_data_vaild;
        wire Wdata_done;
        //突发写操作过程时间计数器
        always@(posedge clk or negedge rst_n)
            if(!rst_n)
                wr_cnt<=16'd0;
            else if(wr_cnt==wr_END_TIME)
                wr_cnt<=16'd0;
            else if(wr_req||wr_cnt>0)
                wr_cnt<=wr_cnt+16'd1;
            else
                wr_cnt<=wr_cnt;
        //突发写操作任务
        task write_data;
        begin
            case(wr_cnt)
                wr_ACT_TIME:begin
                    Command<=C_ACT;
                    Sa<=raddr_r;//激活行
                    Ba<=Baddr;
                end
                wr_WRITE_TIME:begin
                    Command<=C_WR;
                    Sa<={1'b0,caddr_r[8:0]};//激活列
                    Ba<=Baddr;
                end
                wr_PRE_TIME:begin
                    Command<=C_PRE;//预充电
                    Sa<=1'b1;
                end
                wr_END_TIME:begin
                    Command<=C_NOP;
                    FF<=1'b1;
                end
                default:Command<=C_NOP;
            endcase
        end    
        endtask
        //写操作完成标志位
        always@(posedge clk or negedge rst_n)
        begin
            if(!rst_n)
                wr_opt_done<=1'b0;
            else if(wr_cnt==wr_END_TIME)
                wr_opt_done<=1'b1;
            else
                wr_opt_done<=1'b0;
        end 
        //写操作过程标识
        always@(posedge clk or negedge rst_n)
        begin
            if(!rst_n)
                wr_opt<=1'b0;
            else if(wr_req)
                wr_opt<=1'b1;
            else if(wr_opt_done==1'b1)
                wr_opt<=1'b0;
            else
                wr_opt<=wr_opt;
        end
        //写数据操作,数据写入时刻有效区间
        always@(posedge clk or negedge rst_n)
        begin
            if(!rst_n)
                Wr_data_vaild<=1'b0;
            else if((wr_cnt>SC_RCD)&&(wr_cnt<=SC_RCD+SC_BL))
                Wr_data_vaild<=1'b1;
            else
                Wr_data_vaild<=1'b0;
        end   
        //写操作数据写完成标志位
        assign Wdata_done=(wr_cnt==SC_RCD+SC_BL)?1'b1:1'b0;
        //sDRAM数据线三态控制
        assign Dq=Wr_data_vaild?Wr_data:16'bz;

    三、一次突发读

    localparam  rd_ACT_TIME=1'b1,
                    rd_READ_TIME=1+SC_RCD,
                    rd_PRE_TIME=1+SC_RCD+SC_BL,
                    rd_END_TIME=SC_RCD+SC_BL+SC_CL;
        reg [15:0]rd_cnt;
        reg rd_opt,rd_opt_done;
        reg Rd_data_vaild;
        //突发读操作过程时间计数器
        always@(posedge clk or negedge rst_n)
        begin
            if(!rst_n)
                rd_cnt<=16'd0;
            else if(rd_cnt==rd_END_TIME)
                rd_cnt<=16'd0;
            else if(rd_req||rd_cnt>0)
                rd_cnt<=rd_cnt+16'd1;
            else
                rd_cnt<=rd_cnt;
        end
        //突发读任务
        task read_data;
        begin
            case(rd_cnt)
                rd_ACT_TIME:begin
                    Command<=C_ACT;
                    Sa<=raddr_r;
                    Ba<=Baddr;
                end
                rd_READ_TIME:begin
                    Command<=C_RD;
                    Sa<={1'b0,caddr_r[8:0]};//突发模式设置和突发长度设置
                    Ba<=Baddr;
                end
                rd_PRE_TIME:begin
                    Command<=C_PRE;
                    Sa[10]<=1'b1;
                end
                rd_END_TIME:begin
                    Command<=C_NOP;
                    FF<=1'b1;
                end
                default:Command<=C_NOP;
            endcase
        end
        endtask
        //突发读完成标志
        always@(posedge clk or negedge rst_n)
        begin
            if(!rst_n)
                rd_opt_done<=1'b0;
            else if(rd_cnt==rd_END_TIME)
                rd_opt_done<=1'b1;
            else
                rd_opt_done<=1'b0;
        end
        //突发读过程标志
        always@(posedge clk or negedge rst_n)
        begin
            if(!rst_n)
                rd_opt<=1'b0;
            else if(rd_req==1'b1)
                rd_opt<=1'b1;
            else if(rd_opt_done==1'b1)
                rd_opt<=1'b0;
            else
                rd_opt<=rd_opt;
        end
        //突发读过程数据读完标志位
        assign Rdata_done=(rd_cnt==rd_END_TIME)?1'b1:1'b0;
        //读数据操作,数据有效区
        always@(posedge clk or negedge rst_n)
        begin
            if(!rst_n)
                Rd_data_vaild<=1'b0;
            else if((rd_cnt>SC_RCD+SC_CL)&&(rd_cnt<=SC_RCD+SC_CL+SC_BL))
                Rd_data_vaild<=1'b1;
            else
                Rd_data_vaild<=1'b0;
        end
        //读数据
        assign Rd_data=Dq;

    四、还有一些穿插在主状态机

    //*****************************************************************//
        //写操作过程 刷新到 记住刷新信号//
        assign ref_break_wr=(ref_time_flag&&wr_opt)?1'b1:((!wr_opt)?1'b0:ref_break_wr);
        //读操作过程 刷新到 记住刷新信号//
        assign ref_break_rd=(ref_time_flag&&rd_opt)?1'b1:((!rd_opt)?1'b0:ref_break_rd);
        //刷新请求信号
        always@(*)
        begin
            case(main_state)
                AREF:begin
                    if(ref_time_flag)
                        ref_req=1'b1;
                    else
                        ref_req=1'b0;
                end
                WRITE:begin
                    if(ref_break_wr&&wr_opt_done)
                        ref_req=1'b1;
                    else
                        ref_req=1'b0;
                end
                READ:begin
                    if(ref_break_rd&&rd_opt_done)
                        ref_req=1'b1;
                    else
                        ref_req=1'b0;
                end
                default:ref_req=1'b0;
            endcase
        end
        //**************************************************************//
        //刷新过程 外部写使能到 记住写使能信号
        assign wr_break_ref=(Wr&&ref_opt)?1'b1:((!ref_opt)?1'b0:wr_break_ref);
        //写操作请求信号
        always@(*)
        begin
            case(main_state)
                AREF:begin
                    if(Wr&&(!wr_break_ref)&&!ref_time_flag)
                        wr_req=1'b1;
                    else if(wr_break_ref&&ref_opt_done)
                        wr_req=1'b1;
                    else
                        wr_req=1'b0;
                end
                WRITE:begin
                    if(wr_opt_done&&Wr&&!ref_break_wr)
                        wr_req=1'b1;
                    else
                        wr_req=1'b0;
                end
                READ:begin
                    if(rd_opt_done&&Wr&&!ref_break_rd)
                        wr_req=1'b1;
                    else
                        wr_req=1'b0;
                end
                default:wr_req=1'b0;
            endcase
        end
        //刷新过程 外部读使能到 记住读使能信号
        assign rd_break_ref=(Rd&&ref_opt)?1'b1:((!rd_opt)?1'b0:rd_break_ref);
        //读操作请求信号
        always@(*)
        begin
            case(main_state)
                AREF:begin
                    if(Rd&&(!rd_break_ref)&&(!wr_break_ref)&&(!ref_time_flag))
                        rd_req=1'b1;
                    else if(ref_opt_done&&(!wr_break_ref)&&rd_break_ref)
                        rd_req=1'b1;
                    else
                        rd_req=1'b0;
                end
                WRITE:begin
                    if(wr_opt_done&&(!ref_break_wr)&&!Wr&&Rd)
                        rd_req=1'b1;
                    else
                        rd_req=1'b0;
                end
                READ:begin
                    if(rd_opt_done&&(!ref_break_rd)&&!Wr&&Rd)
                        rd_req=1'b1;
                    else
                        rd_req=1'b0;
                end
                default:rd_req=1'b0;
            endcase
        end
    YKJIAO
  • 相关阅读:
    2020年北航OO助教工作总结
    OO第四单元——UML及其解析器——总结 暨 OO课程大总结
    OO第三单元——规格化设计与地铁系统——总结
    OO第二单元——电梯调度——总结
    OO第一单元——表达式求导——总结
    try_svg
    字体自适应
    网站使用微软雅黑需要版权吗
    body,td,th {
    input一定要在from里吗
  • 原文地址:https://www.cnblogs.com/ajiaoa/p/12977173.html
Copyright © 2020-2023  润新知