簡易SDRAM控制器的verilog代碼實現


SDRAM是每隔15us進行刷新一次,但是如果當SDRAM需要進行刷新時,而SDRAM正在寫數據,這兩個操作之間怎么進行協調呢?

需要保證寫的數據不能丟失,所以,如果刷新的時間到了,先讓寫操作把正在寫的4個數據(突發長度為4)寫完,然后再去進行刷新操作;

而如果在執行讀操作也遇到需要刷新的情況,也可以先讓數據讀完,再去執行刷新操作。

思路:SDRAM控制器包括初始化、讀操作、寫操作及自動刷新這些操作,給每一個操作寫上一個模塊獨立開來,也便於我們每個模塊的調試,顯然這種思路是正確的;

雖然都是獨立的模塊,但很顯然這幾個模塊之間又是相互關聯的。如果SDRAM需要刷新了,而SDRAM卻正在執行寫操作,為了控制各個模塊之間的工作關系,引入仲裁機制。


仲裁狀態機 ↓

仲裁機工作原理框圖 ↓

在仲裁模塊中,初始化操作完成之后便進入到了“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。。。


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM