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
原文地址:https://www.cnblogs.com/ajiaoa/p/12977173.html