简易SDRAM控制器的verilog代码实现

简易SDRAM控制器的verilog代码实现SDRAM是每隔15us进行刷新一次,但是如果当SDRAM需要进行刷新时,而SDRAM正在写数据,这两个操作之间怎么进行协调呢?需要保证写的数据不能丢失,所以,如果刷新的时间到了,先让写操作把正在写的4个数据(突发长度为4)写完,然后再去进行刷新操作;而如果在执行读操作也遇到需要刷新的情况,也可以先让数据读完,再去执行刷新操作。思路:SDRAM控制器包括初始化、读操作、写操作…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

SDRAM是每隔15us进行刷新一次,但是如果当SDRAM需要进行刷新时,而SDRAM正在写数据,这两个操作之间怎么进行协调呢?

需要保证写的数据不能丢失,所以,如果刷新的时间到了,先让写操作把正在写的4个数据(突发长度为4)写完,然后再去进行刷新操作;

而如果在执行读操作也遇到需要刷新的情况,也可以先让数据读完,再去执行刷新操作。

思路:SDRAM控制器包括初始化、读操作、写操作及自动刷新这些操作,给每一个操作写上一个模块独立开来,也便于我们每个模块的调试,显然这种思路是正确的;

虽然都是独立的模块,但很显然这几个模块之间又是相互关联的。如果SDRAM需要刷新了,而SDRAM却正在执行写操作,为了控制各个模块之间的工作关系,引入仲裁机制。


仲裁状态机 ↓

简易SDRAM控制器的verilog代码实现

仲裁机工作原理框图 ↓

简易SDRAM控制器的verilog代码实现

在仲裁模块中,初始化操作完成之后便进入到了“ARBIT”仲裁状态,只有处于仲裁状态的时候,仲裁机才能向其他模块发送命令。

当状态机处于“WRITE”写状态时,如果SDRAM刷新的时间到了,刷新模块同时向写模块和仲裁模块发送刷新请求ref_req信号,当写模块接受到ref_req之后,写模块在写完当前4个数据(突发长度为4)之后,写模块的写结束标志flag_wr_end拉高,然后状态机进入“ARBIT”仲裁状态;

处于仲裁状态之后,此时有刷新请求ref_req,然后状态机跳转到“AREF”状态并且仲裁模块发送ref_en刷新使能,然后刷新模块将刷新请求信号ref_req拉低并给sdram发送刷新的命令。

等刷新完毕之后,刷新模块给仲裁模块发送flag_ref_end刷新结束标志,状态机跳转到“ARBIT”仲裁状态。

当刷新完跳转到“ARBIT”仲裁状态之后,如果之前全部数据仍然没有写完(指的是全部数据,并不是一个突发长度的4个数据),那么此时仍然要给仲裁模块写请求“wr_req”,然后仲裁模块经过一系列判断之后,如果符合写操作的时机,那就给写模块一个写使能信号“wr_en”,然后跳转到“WRITE”写状态并且写模块开始工作。


 

 仲裁模块中状态机定义 ↓

//state
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            state    <=    IDLE;
        else case(state)
            IDLE:
                if(key[0] == 1'b1)
                    state    <=    INIT;
                else
                    state    <=    IDLE;
            INIT:
                if(flag_init_end == 1'b1)    //初始化结束标志
                    state    <=    ARBIT;
                else
                    state    <=    INIT;
            ARBIT:
                if(ref_req == 1'b1)    //刷新请求到来且已经写完
                    state    <=    AREF;
                else if(ref_req == 1'b0 && rd_en == 1'b1)    //默认读操作优先于写操作
                    state    <=    READ;            
                else if(ref_req == 1'b0 && wr_en == 1'b1)    //无刷新请求且写请求到来
                    state    <=    WRITE;
                else
                    state    <=    ARBIT;
            AREF:
                if(flag_ref_end == 1'b1)
                    state    <=    ARBIT;
                else
                    state    <=    AREF;
            WRITE:
                if(flag_wr_end == 1'b1)
                    state    <=    ARBIT;
                else
                    state    <=    WRITE;
            READ:
                if(flag_rd_end == 1'b1)
                    state    <=    ARBIT;
                else
                    state    <=    READ;
            default:
                state    <=    IDLE;            
        endcase    

key[0]作为我们初始化的一个使能信号,如果是实际下板子的时候,我们还需要给按键加一个按键消抖模块。当按键0按下之后,代表我们的SDRAM的初始化使能信号来了;

所以状态机从“IDLE”跳转到了“INIT”状态。在初始化状态,如果我们的初始化模块传来了初始化结束标志“flag_init_end”,那状态机跳转到“ARBIT”仲裁状态;

在仲裁状态中,第一个“if”是判断刷新请求的,这也就说明了我们刷新的优先级最高。

之后,如果处于仲裁状态,来了读使能信号或者写使能信号并且没有刷新请求,那状态机就跳转到对应的状态。

如果处于读或写的状态,当读结束标志或者写结束标志来临的时候(这里的写结束标志和读结束标志都是指突发读或突发写的结束标志),那么就会跳转到仲裁状态。


初始化模块 ↓

module    sdram_init(
        input    wire        sclk,        //系统时钟为50M,即T=20ns
        input    wire        s_rst_n,
        
        output    reg    [3:0]    cmd_reg,    //sdram命令寄存器
        output    reg    [11:0]    sdram_addr,    //地址线
        output    reg    [1:0]    sdram_bank,    //bank地址
        output    reg        flag_init_end    //sdram初始化结束标志    
        );
        
    parameter    CMD_END        =    4'd11,        //初始化结束时的命令计数器的值
            CNT_200US    =    14'd1_0000,    
            NOP        =    4'b0111,    //空操作命令
            PRECHARGE    =    4'b0010,    //预充电命令
            AUTO_REF    =    4'b0001,    //自刷新命令
            MRSET        =    4'b0000;    //模式寄存器设置命令
 
    reg    [13:0]    cnt_200us;        //200us计数器
    reg        flag_200us;        //200us结束标志(200us结束后,一直拉高)
    reg    [3:0]    cnt_cmd;        //命令计数器,便于控制在某个时候发送特定指令
    reg        flag_init;        //初始化标志:初始化结束后,该标志拉低
//flag_init 
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_init    <=    1'b1;
        else if(cnt_cmd == CMD_END)
            flag_init    <=    1'b0;    
//cnt_200us    
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            cnt_200us    <=    14'd0;
        else if(cnt_200us == CNT_200US)
            cnt_200us    <=    14'd0;
        else if(flag_200us == 1'b0)
            cnt_200us    <=    cnt_200us + 1'b1;
//flag_200us
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_200us    <=    1'b0;
        else if(cnt_200us == CNT_200US)
            flag_200us    <=    1'b1;
//cnt_cmd
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            cnt_cmd    <=    4'd0;
        else if(flag_200us == 1'b1 && flag_init == 1'b1)
            cnt_cmd    <=    cnt_cmd + 1'b1;
//flag_init_end
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_init_end    <=    1'b0;
        else if(cnt_cmd == CMD_END)
            flag_init_end    <=    1'b1;
        else
            flag_init_end    <=    1'b0;
//cmd_reg
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            cmd_reg    <=    NOP;
        else if(cnt_200us == CNT_200US)
            cmd_reg    <=    PRECHARGE;
        else if(flag_200us)
            case(cnt_cmd)
                4'd0:
                    cmd_reg    <=    AUTO_REF;    //预充电命令
                4'd6:
                    cmd_reg    <=    AUTO_REF;
                4'd10:
                    cmd_reg    <=    MRSET;        //模式寄存器设置
                default:
                    cmd_reg    <=    NOP;
            endcase
//sdram_addr
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_addr    <=    12'd0;
        else case(cnt_cmd)
            4'd0:
                sdram_addr    <=    12'b0100_0000_0000;    //预充电时,A10拉高,对所有Bank操作
            4'd10:
                sdram_addr    <=    12'b0000_0011_0010;    //模式寄存器设置时的指令:CAS=2,Burst Length=4;
            default:
                sdram_addr    <=    12'd0;
        endcase
//sdram_bank
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_bank    <=    2'd0;    //这里仅仅只是初始化,在模式寄存器设置时才会用到且其值为全零,故不赋值
 
//sdram_clk
    assign    sdram_clk    =    ~sclk;
            
endmodule

首先,我们需要有200us的稳定期,所以我们便有了一个200us的计数器cnt_200us,而这个计数器是根据flag_200us的低电平来工作的。

falg_200us在200us计时之后一直拉高。在200us计满,即flag_200us拉高之后,我们就需要先给一个“NOP”命令,然后给两次“Precharge”命令,同时选中ALL Banks。


写操作模块 ↓

module    sdram_write(
        input    wire        sclk,
        input    wire        s_rst_n,
        input    wire        key_wr,
        input    wire        wr_en,        //来自仲裁模块的写使能
        input    wire        ref_req,    //来自刷新模块的刷新请求
        input    wire    [5:0]    state,        //顶层模块的状态
        
        output    reg    [15:0]    sdram_dq,    //sdram输入/输出端口
        //output    reg    [3:0]    sdram_dqm,    //输入/输出掩码
        output    reg    [11:0]    sdram_addr,    //sdram地址线
        output    reg    [1:0]    sdram_bank,    //sdram的bank地址线
        output    reg    [3:0]    sdram_cmd,    //sdram的命令寄存器
        output    reg        wr_req,        //写请求(不在写状态时向仲裁进行写请求)
        output    reg        flag_wr_end    //写结束标志(有刷新请求来时,向仲裁输出写结束)
        );
        
    parameter    NOP    =    4'b0111,    //NOP命令
            ACT    =    4'b0011,    //ACT命令
            WR    =    4'b0100,    //写命令(需要将A10拉高)
            PRE    =    4'b0010,    //precharge命令
            CMD_END    =    4'd8,
            COL_END    =    9'd508,        //最后四个列地址的第一个地址
            ROW_END    =    12'd4095,    //行地址结束
            AREF    =    6'b10_0000,    //自动刷新状态
            WRITE    =    6'b00_1000;    //状态机的写状态
            
    reg        flag_act;            //需要发送ACT的标志            
    reg    [3:0]    cmd_cnt;            //命令计数器
    reg    [11:0]    row_addr;            //行地址
    reg    [11:0]    row_addr_reg;            //行地址寄存器
    reg    [8:0]    col_addr;            //列地址
    reg        flag_pre;            //在sdram内部为写状态时需要给precharge命令的标志
 
//flag_pre
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_pre    <=    1'b0;
        else if(col_addr == 9'd0 && flag_wr_end == 1'b1)
            flag_pre    <=    1'b1;
        else if(flag_wr_end == 1'b1)
            flag_pre    <=    1'b0;
    
//flag_act
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_act    <=    1'b0;
        else if(flag_wr_end)
            flag_act    <=    1'b0;
        else if(ref_req == 1'b1 && state == AREF)
            flag_act    <=    1'b1;
//wr_req
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            wr_req    <=    1'b0;
        else if(wr_en == 1'b1)
            wr_req    <=    1'b0;
        else if(state != WRITE && key_wr == 1'b1)
            wr_req    <=    1'b1;
//flag_wr_end
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_wr_end    <=    1'b0;
        else if(cmd_cnt == CMD_END)
            flag_wr_end    <=    1'b1;
        else
            flag_wr_end    <=    1'b0;
//cmd_cnt
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            cmd_cnt    <=    4'd0;
        else if(state == WRITE)
            cmd_cnt    <=    cmd_cnt + 1'b1;
        else 
            cmd_cnt    <=    4'd0;
        
//sdram_cmd
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_cmd    <=    4'd0;
        else case(cmd_cnt)
            3'd1:
                if(flag_pre == 1'b1)
                    sdram_cmd    <=    PRE;
                else
                    sdram_cmd    <=    NOP;
            3'd2:
                if(flag_act == 1'b1 || col_addr == 9'd0)
                    sdram_cmd    <=    ACT;
                else
                    sdram_cmd    <=    NOP;
            3'd3:         
                sdram_cmd    <=    WR;
 
            default:
                sdram_cmd    <=    NOP;        
        endcase
//sdram_dq
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_dq    <=    16'd0;
        else case(cmd_cnt)
            3'd3:
                sdram_dq    <=    16'h0012;
            3'd4:
                sdram_dq    <=    16'h1203;
            3'd5:
                sdram_dq    <=    16'h562f;
            3'd6:
                sdram_dq    <=    16'hfe12;
            default:
                sdram_dq    <=    16'd0;
        endcase
/* //sdram_dq_m
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_dqm    <=    4'd0; */
//row_addr_reg
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            row_addr_reg    <=    12'd0;
        else if(row_addr_reg == ROW_END && col_addr == COL_END && cmd_cnt == CMD_END)
            row_addr_reg    <=    12'd0;
        else if(col_addr == COL_END && flag_wr_end == 1'b1)
            row_addr_reg    <=    row_addr_reg + 1'b1;
        
//row_addr
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            row_addr    <=    12'd0;
        else case(cmd_cnt)
        //因为下边的命令是通过行、列地址分开再给addr赋值,所以需要提前一个周期赋值,以保证在命令到来时能读到正确的地址
            3'd2:
                row_addr    <=    12'b0000_0000_0000;    //在写命令时,不允许auto-precharge    
            default:
                row_addr    <=    row_addr_reg;
        endcase
//col_addr
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            col_addr    <=    9'd0;
        else if(col_addr == COL_END && cmd_cnt == CMD_END)
            col_addr    <=    9'd0;
        else if(cmd_cnt == CMD_END)
            col_addr    <=    col_addr + 3'd4;
//sdram_addr
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_addr    <=    12'd0;
        else case(cmd_cnt)
            3'd2:
                sdram_addr    <=    row_addr;
            3'd3:
                sdram_addr    <=    col_addr;
            
            default:
                sdram_addr    <=    row_addr;
        endcase
//sdram_bank
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_bank    <=    2'b00;
endmodule

在模块端口列表中,用key_wr来接收写请求信号,这个写请求信号,是在没有写完之前一直拉高的,在写完了全部数据之后才拉低的。

在写模块中,让SDRAM循环着写16’h0012,16’h1203,16’h562f,16’hfe12这四个数据。

另外一点,在这个写模块中,每写完4个数据,也就是突发结束后,有一个写完标志,从而使状态机跳转到仲裁状态,然后如果数据没写完,由于写请求是拉高的,所以如果此时没有刷新请求,那状态机还是会跳转到写状态继续写的。


读操作模块 ↓

module    sdram_read(
        input    wire        sclk,
        input    wire        s_rst_n,
        input    wire        rd_en,
        input    wire    [5:0]    state,
        input    wire        ref_req,        //自动刷新请求
        input    wire        key_rd,            //来自外部的读请求信号
        input    wire    [15:0]    rd_dq,        //sdram的数据端口
        
        output    reg    [3:0]    sdram_cmd,
        output    reg    [11:0]    sdram_addr,
        output    reg    [1:0]    sdram_bank,
        output    reg        rd_req,            //读请求
        output    reg        flag_rd_end        //突发读结束标志
        );
 
    parameter    NOP    =    4'b0111,
            PRE    =    4'b0010,
            ACT    =    4'b0011,
            RD    =    4'b0101,        //SDRAM的读命令(给读命令时需要给A10拉低)
            CMD_END    =    4'd12,            //
            COL_END    =    9'd508,            //最后四个列地址的第一个地址
            ROW_END    =    12'd4095,        //行地址结束
            AREF    =    6'b10_0000,        //自动刷新状态
            READ    =    6'b01_0000;        //状态机的读状态
        
    reg    [11:0]    row_addr;
    reg    [8:0]    col_addr;
    reg    [3:0]    cmd_cnt;
    reg        flag_act;                //发送ACT命令标志(单独设立标志,便于跑高速)
 
//flag_act
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_act    <=    1'b0;
        else if(flag_rd_end == 1'b1 && ref_req == 1'b1)
            flag_act    <=    1'b1;
        else if(flag_rd_end == 1'b1)
            flag_act    <=    1'b0;
//rd_req
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            rd_req    <=    1'b0;
        else if(rd_en == 1'b1)
            rd_req    <=    1'b0;
        else if(key_rd == 1'b1 && state != READ)
            rd_req    <=    1'b1;
//cmd_cnt
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            cmd_cnt    <=    4'd0;
        else if(state == READ)
            cmd_cnt    <=    cmd_cnt + 1'b1;
        else
            cmd_cnt    <=    4'd0;
//flag_rd_end
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_rd_end    <=    1'b0;
        else if(cmd_cnt == CMD_END)
            flag_rd_end    <=    1'b1;
        else
            flag_rd_end    <=    1'b0;
//row_addr
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            row_addr    <=    12'd0;
        else if(row_addr == ROW_END && col_addr == COL_END && flag_rd_end == 1'b1)
            row_addr    <=    12'd0;
        else if(col_addr == COL_END && flag_rd_end == 1'b1)
            row_addr    <=    row_addr + 1'b1;
//col_addr
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            col_addr    <=    9'd0;
        else if(col_addr == COL_END && flag_rd_end == 1'b1)
            col_addr    <=    9'd0;
        else if(flag_rd_end == 1'b1)
            col_addr    <=    col_addr + 3'd4;
//cmd_cnt
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            cmd_cnt    <=    4'd0;
        else if(state == READ)
            cmd_cnt    <=    cmd_cnt + 1'b1;
        else
            cmd_cnt    <=    4'd0;
//sdram_cmd
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_cmd    <=    NOP;
        else case(cmd_cnt)
            4'd2:
                if(col_addr == 9'd0)
                    sdram_cmd    <=    PRE;
                else
                    sdram_cmd    <=    NOP;
            4'd3:    
                if(flag_act == 1'b1 || col_addr == 9'd0)
                    sdram_cmd    <=    ACT;
                else
                    sdram_cmd    <=    NOP;
            4'd4:
                sdram_cmd    <=    RD;
            default:
                sdram_cmd    <=    NOP;
        endcase
//sdram_addr
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_addr    <=    12'd0;
        else case(cmd_cnt)
            4'd4:
                sdram_addr    <=    {
   
   3'd0, col_addr};
            default:
                sdram_addr    <=    row_addr;
        endcase
//sdram_bank
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_bank    <=    2'd0;
endmodule


自动刷新模块 ↓

module    auto_refresh(
        input    wire        sclk,
        input    wire        s_rst_n,
        input    wire        ref_en,
        input    wire        flag_init_end,    //初始化结束标志(初始化结束后,启动自刷新标志)
        
        output    reg    [11:0]    sdram_addr,
        output    reg    [1:0]    sdram_bank,
        output    reg        ref_req,
        output    reg    [3:0]    cmd_reg,
        output    reg        flag_ref_end
        );
 
    parameter    BANK    =    12'd0100_0000_0000,    //自动刷新是对所有bank刷新
            CMD_END    =    4'd10,
            CNT_END    =    10'd749,    //15us计时结束
            NOP    =    4'b0111,    //
            PRE    =    4'b0010,    //precharge命令
            AREF    =    4'b0001;    //auto-refresh命令
            
            
    reg    [9:0]    cnt_15ms;    //15ms计数器
    reg        flag_ref;    //处于自刷新阶段标志
    reg        flag_start;    //自动刷新启动标志
    reg    [3:0]    cnt_cmd;    //指令计数器
//flag_start
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_start    <=    1'b0;
        else if(flag_init_end == 1'b1)
            flag_start    <=    1'b1;
//cnt_15ms
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            cnt_15ms    <=    10'd0;
        else if(cnt_15ms == CNT_END)
            cnt_15ms    <=    10'd0;
        else if(flag_start == 1'b1)
            cnt_15ms    <=    cnt_15ms + 1'b1;
//flag_ref
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_ref    <=    1'b0;
        else if(cnt_cmd == CMD_END)
            flag_ref    <=    1'b0;
        else if(ref_en == 1'b1)
            flag_ref    <=    1'b1;
//cnt_cmd
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            cnt_cmd    <=    4'd0;
        else if(flag_ref == 1'b1)
            cnt_cmd    <=    cnt_cmd + 1'b1;
        else
            cnt_cmd    <=    4'd0;
//flag_ref_end
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_ref_end    <=    1'b0;
        else if(cnt_cmd == CMD_END)
            flag_ref_end    <=    1'b1;
        else
            flag_ref_end    <=    1'b0;
//cmd_reg
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            cmd_reg    <=    NOP;
        else case(cnt_cmd)
            3'd0:
                if(flag_ref == 1'b1)
                    cmd_reg    <=    PRE;
                else
                    cmd_reg    <=    NOP;
            3'd1:
                cmd_reg    <=    AREF;
            3'd5:
                cmd_reg    <=    AREF;
            default:
                cmd_reg    <=    NOP;
        endcase
//sdram_addr
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_addr    <=    12'd0;
        else case(cnt_cmd)
            4'd0:
                sdram_addr    <=    BANK;    //bank进行刷新时指定allbank or signle bank
            default:
                sdram_addr    <=    12'd0;
        endcase
//sdram_bank
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            sdram_bank    <=    2'd0;        //刷新指定的bank
//ref_req
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            ref_req    <=    1'b0;
        else if(ref_en == 1'b1)
            ref_req    <=    1'b0;
        else if(cnt_15ms == CNT_END)
            ref_req    <=    1'b1;
//flag_ref_end
    always    @(posedge sclk or negedge s_rst_n)
        if(s_rst_n == 1'b0)
            flag_ref_end    <=    1'b0;
        else if(cnt_cmd == CMD_END)
            flag_ref_end    <=    1'b1;
        else
            flag_ref_end    <=    1'b0;
 
endmodule


。。。。。。。。。。。。。。。待续。。。2017-06-05。。。


 

转载于:https://www.cnblogs.com/JissXbon/p/6947279.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160094.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 移动端HTML5开发心得「建议收藏」

    移动端HTML5开发心得「建议收藏」1,iOS里固定中有输入或者textarea,用户在里面输入文字,触发键盘,固定容器会客显示,而不是是连续悬浮   解决办法:http: //dwz.cn/CrwNz2,移动端点击时间300ms的延迟   解决办法:zepto.js或者百度touch.js或者是fastclick.js3,zepto的触摸问题:swipe事件在小米1等低端手机不支持基本不用zepto…

  • JAVA保留两位小数(四舍五入)「建议收藏」

    JAVA保留两位小数(四舍五入)「建议收藏」importjava.math.BigDecimal;importjava.text.DecimalFormat;importjava.text.NumberFormat;publicclasstestNumber{ publicstaticdoublenum=3.1015926; publicstaticdoublezero=0.00000;

  • echarts 自定义 markPoint 的 symbol 样式

    echarts 自定义 markPoint 的 symbol 样式

    2021年11月22日
  • JS闭包的作用与优缺点[通俗易懂]

    JS闭包的作用与优缺点[通俗易懂]一、什么是闭包闭包是指一个函数和对其周围状态(lexicalenvironment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。简单来说就是指有权访问另一个函数作用域中变量的函数。举个例子:functionfn(){varnum=10;functionfun(){console.log(num);}fun();}fn();这就是一个闭…

    2022年10月30日
  • 第一、二、三范式

    第一、二、三范式范式(NormalForm)是范式是符合某一种级别的关系模式的集合。通俗一点就是对数据库中表的属性的约束条件。第一范式1NF第一范式的条件:元组中的每一个分量都必须是不可分割的数据项。反例:应该修改为:第二范式2NF第二范式的条件:在第一范式的基础上,所有的非主属性完全依赖于主键。完全依赖意味着不能依赖于主键的一部分属性。反例:对于该表,学号和课程号组合在一起是主键,但…

  • 织梦dedecms中arclist标签下无法嵌套图片

    织梦dedecms中arclist标签下无法嵌套图片

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号