再战SDRAM与资料整理。

       总之只要阅读操作手册,按照时序来,完全不难!

        器件记录: 

小梅哥AC620上SDRAM:M12L2561616A-6TG2T

        其的存储空间为16M*16=256MB,第二行的数字则与其速度等级有关;其分为:

        4bank*16bit*4M 即:8192*512 = 2^13 * 2^9 = 2^22 = 4M

        bank数目*数据位宽*存储深度

HY57V281620F,所以其具备的是

        4bank*16bits*2M 即 2^12 * 2^9 = 2^21 = 2M

SDRAM原理:

        SDRAM 存储数据是利用了电容能够保持电荷以及其充放电特性。一位数据的存取电路 如图 所示,该存储单元主要由行列选通三极管,存储电容,刷新放大器组成。对于这 一位的数据,首先需要打开行地址,然后打开列地址,则电容的电平状态就能呈现在数据线 (data_bit)上,即实现了读取。 或者,数据线上的电平值被送到电容上,从而实现写入数据。

再战SDRAM与资料整理。_第1张图片

        但是,打开行地址(激活行)是需要一定时间的,即从打开行地址到可以打开列地址进 行数据读/写,这之间有一定的时间间隔,这个间隔叫做 tRCD(ACTIVE-to-READ or WRITE delay),对于不同型号或不同速度等级的器件,这个值是不一样的。

        需要自行查阅产品手册获得这个速度等级,而M12L2561616A-6则对应的是速度等级6,其tRCD等于18ns。

        当列地址被打开后,数据并不是立即出现在最终的数据总线引脚上,而是有若干个时钟 的延迟,这个延迟叫做列选通潜伏期(CL,CL = CAS (READ) latency)。如图 32.3 为不同速 度等级的器件的列选通潜伏期值,速度等级不一样,其值也是不一样的。

用户手册原文:

        Bank activate 命令用于在空闲 Bank 中选择随机行。通过将 RAS 和 CS 以及所需的行和存储体地址置为低电平,即可启动行访问。从存储体激活时间起,经过 tRCD(min) 的时间延迟后,可以进行读或写操作。 tRCD是SDRAM的内部时序参数,因此它取决于工作时钟频率。

SDRAM命令

        不同的SDRAM命令是一样的,如果不一样说明可能使用的命令不是低有效吧。(或者有额外的命令控制)

再战SDRAM与资料整理。_第2张图片再战SDRAM与资料整理。_第3张图片

执行时间

        除了在指定的命令外,我们还需要关心执行命令所需的时间。

        例如:

M12L2561616A-6TG2T:

再战SDRAM与资料整理。_第4张图片

        初始化时序(小梅哥文档):

再战SDRAM与资料整理。_第5张图片

tRP :预充电需要时间;

tRFC:自刷新需要的周期

tRAS:激活行需要的时间

tRCD:激活到读或写命令的延迟(激活行到列操作的时间)

HY57V281620F:

再战SDRAM与资料整理。_第6张图片

Brust length

        对于SDRAM来说,区分于RAM和FIFO的读写方法,并不是连续地给出读写使能和地址,而是一次读写操作"Brust length"长度的数据。

        SDRAM的读指令都是默认突发的,但是写指令可以不突发,直接写一整行。

自动刷新:

        自动刷新(AUTO REFRESH)一般用于对 SDRAM 进行常规操作的 过程中。该命令是非持续性的,即每次需要时,都需要发送此命令。在执 行自动刷新命令之前,所有的 BANK 必须被预充电(关闭)。在自动刷新 和预充电命令之间,必须间隔最少 tRP 时间。自动刷新时,行地址由 SDRAM 芯片内部的刷新控制器自动更新,因此,在执行自动刷新命令时, 用户不需要关心地址总线上的值。不管器件的数据位宽是多少,对于 256Mbit 的 SDRAM,在商业和工业级的器件中,每 64ms 内需要执行 8192 次自动刷新操作,即每 7.813us 执行一次;在汽车级的器件中,每 16ms 内 执行 8192 次自动刷新操作,即每 1.953us 执行一次。另外,自动刷新操作 也可以采用突发的方式执行,即每 64ms(商业和工业级)/16ms(汽车级) 都连续不间断的执行 8192 次自动刷新命令,然后其他时间再执行读写或 者其他命令。如图 32.10 为刷新过程示意图。

        一些差别:

        M12L2561616A-6TG2T的自动刷新需要先发送预充电命令(ALL BANK),而且需要发送两次刷新指令,即需要一个tRP和两个tRFC的时间,而HY57V281620F却不需要,仅需要发送刷新指令然后等待刷新完成即可。

        后面的读写时序其实根据不同的器件来看还是有很多不一样的步骤的,请按照自己的芯片的操作手册来,应该不会有问题。

        比较重要的是仲裁器的写法,根据划定好的优先级来约束就好了。

        可参考:

参数配置:

//COMMAND  = {CS_N,RAS_N,CAS_N,WE_N};
parameter  COMMAND_MRS          = 4'b0000 ;
parameter  COMMAND_ARF          = 4'b0001 ;
parameter  COMMAND_PRE          = 4'b0010 ;
parameter  COMMAND_ACT          = 4'b0011 ;
parameter  COMMAND_WRITE        = 4'b0100 ;
parameter  COMMAND_READ         = 4'b0101 ;
parameter  COMMAND_interrupt    = 4'b0110 ;
parameter  COMMAND_NOP          = 4'b0111 ;

//time_wait
parameter  TIME_WAIT_ABOVE_100US = 10000 ;//wait_time > 100us set:200us Power up wait time
parameter  TIME_PRE_CHARGE       = 2     ;//tRP       > 18ns  set:40ns; Precharge cost time
parameter  TIME_Auto_refresh     = 5     ;//tRFC=TRRC > 60ns  set:100ns ARF cost time
parameter  TIME_MRS_done_wait    = 2     ;//During 2CLK following this command, the SDRAM cannot accept any other commands. 

//MRS_OPCODE
parameter  INIT_OPMODE_Brust_Mode   = 1'b0   ;//A9
parameter  INIT_OPMODE_STANDRD      = 2'b00  ;//A8 A7
parameter  INIT_CAS_Latency         = 3      ;//A6 A5 A4 ;CAS Latency ( 2 & 3 ) 
parameter  INIT_Burst_type          = 1'b0   ;//A3 0:Sequential 1:Interleave
parameter  INIT_Burst_length        = 4      ;//A2 A1 A0 ;Burst Length ( 1, 2, 4, 8 & full page )
parameter  INIT_OPMODE_Brust_Length = (INIT_Burst_length == 1)?(3'b000):
                                      (INIT_Burst_length == 2)?(3'b001):
                                      (INIT_Burst_length == 4)?(3'b010):
                                      (INIT_Burst_length == 8)?(3'b011):(3'b111);//( 1, 2, 4, 8 & full page )
parameter  INIT_OPMODE_CL           = (INIT_CAS_Latency  == 2)?(3'b010):(3'b011);//A6 A5 A4 ;

//auto refresh
parameter ARF_PERIOD = 750;// ARF_period = Row_nums/64ms 64ms = 64_000us = 64_000_000ns = 3_200_000 cycles (1 ARF/782 cycles)
//ACT
parameter TIME_RCD = 3;//tRCD > 20ns act RAS to CAS delay


主控制器和仲裁: 

        1.状态机的状态位宽要对齐。

module SDRAM_CTRL_TOP #(
    parameter SDRAM_DATA_WIDTH   = 16,
    parameter SDRAM_BANK_WIDTH   = 2 ,
    parameter SDRAM_ADDR_WIDTH   = 12
)(
    input   wire         Sys_clk,
    input   wire         Rst_n  ,
//SDRAM 
    //COMMAND
    output  wire            SDRAM_CS_N      ,
    output  wire            SDRAM_RAS_N     ,
    output  wire            SDRAM_CAS_N     ,
    output  wire            SDRAM_WE_N      ,
    output  wire            SDRAM_CKE       ,
    output  wire    [1:0]   SDRAM_DQM       ,
    output  wire            SDRAM_CLK       ,
    output  reg     [SDRAM_ADDR_WIDTH-1:0]  SDRAM_A_ADDR    ,
    output  reg     [SDRAM_BANK_WIDTH-1:0]  SDRAM_BANK_ADDR ,
    //DATA
    inout           [SDRAM_DATA_WIDTH-1:0]  SDRAM_DQ        
);
`include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h"
    localparam  STATE_IDLE = 6'b00_0001;
    localparam  STATE_INIT = 6'b00_0010;
    localparam  STATE_ARB  = 6'b00_0100;
    localparam  STATE_ARF  = 6'b00_1000;
    localparam  STATE_RD   = 6'b01_0000;
    localparam  STATE_WE   = 6'b10_0000;
    //Main
            reg  [3:0]                    SDRAM_COMMAND_SEND;
            reg  [5:0]                    STATE             ;
           wire  [SDRAM_DATA_WIDTH-1:0]   WR_SDRAM_DQ       ;
           wire                           WR_avai           ;
    //init
           wire                           INIT_DONE         ;
           wire  [3:0]                    COMMAND_INIT      ;       
           wire  [SDRAM_ADDR_WIDTH-1:0]   INIT_A_ADDR       ;
           wire  [SDRAM_BANK_WIDTH-1:0]   INIT_BANK_ADDR    ;
    //ARF
           wire                           ARF_access        ;
           wire  [3:0]                    COMMAND_REF       ;
           wire  [SDRAM_ADDR_WIDTH-1:0]   ARF_A_ADDR        ;
           wire  [SDRAM_BANK_WIDTH-1:0]   ARF_BANK_ADDR     ;
           wire                           REF_DONE          ;
           wire                           ARF_req           ;
    //WR
           wire                           WR_req            ;
           wire                           WR_access         ;
           wire  [3:0]                    COMMAND_WR        ;
           wire  [SDRAM_ADDR_WIDTH-1:0]   WR_A_ADDR         ;
           wire  [SDRAM_BANK_WIDTH-1:0]   WR_BANK_ADDR      ;
           wire                           WR_data_done      ;
           wire                           FIFO_WR_EN        ;
           wire  [7:0]                    FIFO_WR_data      ;
    //RD
           wire                           RD_req            ;
           wire                           RD_access         ;
           wire                           RD_data_done      ;
    //break
           wire                           Break_WR_to_ARF   ;
           wire                           Break_RD_to_ARF   ;
           wire                           Break_RD_to_WR    ;
    assign  WR_avai   = (STATE == STATE_WE)?1'b1:1'b0;
    assign  SDRAM_DQ  = (WR_avai == 1'b1)?WR_SDRAM_DQ :16'dz;
    assign  SDRAM_DQM = 2'b00  ;
    assign  SDRAM_CKE = 1'b1   ;
    assign  SDRAM_CLK = Sys_clk;
    assign  {SDRAM_CS_N,
             SDRAM_RAS_N,
             SDRAM_CAS_N,
             SDRAM_WE_N } = SDRAM_COMMAND_SEND;
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            SDRAM_COMMAND_SEND <= COMMAND_NOP;
        end else if(STATE == STATE_INIT) begin
            SDRAM_COMMAND_SEND <= COMMAND_INIT  ;
            SDRAM_A_ADDR       <= INIT_A_ADDR   ;
            SDRAM_BANK_ADDR    <= INIT_BANK_ADDR;
        end else if(STATE == STATE_ARF) begin
            SDRAM_COMMAND_SEND <= COMMAND_REF   ;
            SDRAM_A_ADDR       <= ARF_A_ADDR    ;
            SDRAM_BANK_ADDR    <= ARF_BANK_ADDR ;
        end else if(STATE == STATE_WE) begin
            SDRAM_COMMAND_SEND <= COMMAND_WR    ;
            SDRAM_A_ADDR       <= WR_A_ADDR     ;
            SDRAM_BANK_ADDR    <= WR_BANK_ADDR  ;
        end
    end
    //access
    assign ARF_access = (STATE == STATE_ARB) && (ARF_req == 1'b1);
    assign WR_access  = (STATE == STATE_ARB) && (WR_req  == 1'b1) 
                     && (ARF_req == 1'b0);
    assign RD_access  = (STATE == STATE_ARB) && (RD_req  == 1'b1) 
                     && (WR_req  == 1'b0   ) && (ARF_req == 1'b0);
//-------------------STATE MAIN-----------------------//
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            STATE <= STATE_IDLE;
        end else begin
            case (STATE) //ARG > WR > RD
                STATE_IDLE: begin
                    STATE <= STATE_INIT;
                end
                STATE_INIT: begin
                    if(INIT_DONE == 'd1) begin
                        STATE <= STATE_ARB;
                    end else begin
                        STATE <= STATE_INIT;
                    end
                end
                STATE_ARB: begin
                    if(ARF_req == 1'b1) begin
                        STATE <= STATE_ARF;
                    end else if(WR_req == 1'b1 && ARF_req == 1'b0) begin
                        STATE <= STATE_WE;
                    end else if(RD_req == 1'b1 && WR_req == 1'b0 && ARF_req == 1'b0) begin
                        STATE <= STATE_RD;
                    end else begin
                        STATE <= STATE_ARB;
                    end
                end
                STATE_ARF: begin
                    if(REF_DONE == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else begin
                        STATE <= STATE_ARF;
                    end
                end
                STATE_WE: begin
                    if(Break_WR_to_ARF == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else if(WR_data_done == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else begin
                        STATE <= STATE_WE;
                    end
                end
                STATE_RD: begin
                    if(RD_data_done == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else if(Break_RD_to_WR == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else if(Break_RD_to_ARF == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else begin
                        STATE <= STATE_RD;
                    end
                end
                default: begin
                    STATE <= STATE_IDLE;
                end
            endcase
        end
    end
/*-------------------instance begin---------------------------*/
SDRAM_INIT  INST0_SDRAM_INIT(
//input
    .Sys_clk                 ( Sys_clk         ),
    .Rst_n                   ( Rst_n           ),
//output
    .COMMAND_INIT            ( COMMAND_INIT    ),
    .INIT_A_ADDR             ( INIT_A_ADDR     ),
    .INIT_BANK_ADDR          ( INIT_BANK_ADDR  ),
    .INIT_DONE               ( INIT_DONE       )
);
SDRAM_ARF  INST0_SDRAM_ARF (
    .Sys_clk                 ( Sys_clk               ),
    .Rst_n                   ( Rst_n                 ),
    .INIT_DONE               ( INIT_DONE             ),
    .ARF_access              ( ARF_access            ),

    .COMMAND_REF             ( COMMAND_REF           ),
    .ARF_A_ADDR              ( ARF_A_ADDR            ),
    .ARF_BANK_ADDR           ( ARF_BANK_ADDR         ),
    .REF_DONE                ( REF_DONE              ),
    .ARF_req                 ( ARF_req               )
);
SDRAM_WR INST0_SDRAM_WR(
    .Sys_clk                 ( Sys_clk               ),
    .Rst_n                   ( Rst_n                 ),
    .FIFO_WR_EN              ( FIFO_WR_EN            ),
    .FIFO_WR_data            ( FIFO_WR_data          ),
    .INIT_DONE               ( INIT_DONE             ),
    .ARF_req                 ( ARF_req               ),
    .WR_access               ( WR_access             ),

    .COMMAND_WR              ( COMMAND_WR            ),
    .WR_A_ADDR               ( WR_A_ADDR             ),
    .WR_BANK_ADDR            ( WR_BANK_ADDR          ),
    .WR_data_done            ( WR_data_done          ),
    .WR_req                  ( WR_req                ),
    .Break_WR_to_ARF         ( Break_WR_to_ARF       ),
    .WRITE_SDRAM_DQ          ( WR_SDRAM_DQ           )
);
/*-------------------instance end-----------------------------*/
endmodule

初始化:

        1.初始化只需要进行一次。

module SDRAM_INIT(
    input   wire            Sys_clk       ,
    input   wire            Rst_n         ,
    output  reg     [ 3:0]  COMMAND_INIT  ,//COMMAND  = {CS_N,RAS_N,CAS_N,WE_N}
    output  reg     [11:0]  INIT_A_ADDR   ,
    output  reg     [ 1:0]  INIT_BANK_ADDR,
    output  reg             INIT_DONE
);
    `include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h"
    localparam TIME_TO_PRE   = TIME_WAIT_ABOVE_100US;
    localparam TIME_TO_ARF   = TIME_WAIT_ABOVE_100US + TIME_PRE_CHARGE;
    localparam TIME_TO_ARF_2 = TIME_WAIT_ABOVE_100US + TIME_PRE_CHARGE 
                             + TIME_Auto_refresh;
    localparam TIME_TO_MRS   = TIME_WAIT_ABOVE_100US + TIME_PRE_CHARGE 
                             + TIME_Auto_refresh + TIME_Auto_refresh;
    localparam INIT_END      = TIME_TO_MRS + TIME_MRS_done_wait     ;

            reg     [13:0]  INIT_CNT     ;
            reg             INIT_DONE_NOW;
            
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            INIT_DONE <= 'd0;
        end else if(INIT_CNT == INIT_END) begin
            INIT_DONE <= 'd1;
        end else begin
            INIT_DONE <= 'd0;
        end
    end
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            INIT_DONE_NOW <= 1'b0;
        end else if(INIT_CNT == INIT_END) begin
            INIT_DONE_NOW <= 1'b1;
        end else begin
            INIT_DONE_NOW <= INIT_DONE_NOW;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            INIT_CNT <= 'd0;
        end else if(INIT_DONE_NOW == 1'b0) begin
            if(INIT_CNT == INIT_END) begin
                INIT_CNT <= 'd0;
            end else begin
                INIT_CNT <= INIT_CNT + 1'b1;
            end
        end else begin
            INIT_CNT <= 'd0;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            COMMAND_INIT   <= COMMAND_NOP;
            INIT_A_ADDR    <= 12'd0      ;
            INIT_BANK_ADDR <= 2'b00      ;
        end else begin
            case (INIT_CNT)
                TIME_TO_PRE: begin
                    COMMAND_INIT      <= COMMAND_PRE;
                    INIT_A_ADDR[10]   <= 1'b1;
                end
                TIME_TO_ARF: begin
                    COMMAND_INIT <= COMMAND_ARF;
                end
                TIME_TO_ARF_2: begin
                    COMMAND_INIT <= COMMAND_ARF;
                end
                TIME_TO_MRS: begin
                    COMMAND_INIT <= COMMAND_MRS;
                    INIT_A_ADDR       <= {
                        2'b00                   ,//A11 A10
                        INIT_OPMODE_Brust_Mode  ,//A9
                        INIT_OPMODE_STANDRD     ,//A8 A7
                        INIT_OPMODE_CL          ,//A6 A5 A4 ;CAS Latency ( 2 & 3 ) 
                        INIT_Burst_type         ,//A3 0:Sequential 1:Interleave          
                        INIT_OPMODE_Brust_Length //A2 A1 A0 ;Burst Length ( 1, 2, 4, 8 & full page )
                    };
                end
                default:begin
                    COMMAND_INIT   <= COMMAND_NOP;
                    INIT_A_ADDR    <= 12'd0      ;
                    INIT_BANK_ADDR <= 2'b00		;
                end
            endcase
        end
	end
endmodule

刷新: 

module SDRAM_ARF #(

)(
    input   wire        Sys_clk,
    input   wire        Rst_n  ,
    //SDRAM
    input   wire            INIT_DONE     ,
    output  reg     [3:0]   COMMAND_REF   ,
    output  reg     [11:0]  ARF_A_ADDR    ,
    output  reg     [ 1:0]  ARF_BANK_ADDR ,
    output  reg             REF_DONE      ,
    output  reg             ARF_req       ,
    input   wire            ARF_access    
);
`include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h"
    localparam  TIME_ARF_BEGIN   = 1'b1                  ;
    // localparam  TIME_PRE_to_ARF  = 1'b1 + TIME_PRE_CHARGE;
    // localparam  TIME_ARF_to_done = 1'b1 + TIME_PRE_CHARGE + TIME_Auto_refresh;
    localparam  TIME_ARF_to_done = 'd9;
            reg  [9:0]  ARF_CNT    ;
            reg  [3:0]  COMMAND_CNT;
//ARF_CNT
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            ARF_req <= 'd0;
        end else if(ARF_access == 1'b1) begin
            ARF_req <= 1'b0;
        end else if(ARF_CNT == ARF_PERIOD) begin
            ARF_req <= 1'b1;
        end
    end
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            ARF_CNT <= 'd0;
        end else if(INIT_DONE == 1'b1) begin
            ARF_CNT <= 'd1;
        end else if(ARF_CNT == ARF_PERIOD) begin
            ARF_CNT <= 'd1;
        end else if(ARF_CNT > 'd0) begin
            ARF_CNT <= ARF_CNT + 1'd1;
        end else begin
            ARF_CNT <= ARF_CNT;
        end
    end
always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            REF_DONE <= 1'b0;
        end else if(COMMAND_CNT == TIME_ARF_to_done) begin
            REF_DONE <= 1'b1;
        end else begin
            REF_DONE <= 1'b0;
        end
    end
//COMMAND_CNT
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            COMMAND_CNT <= 'd0;
        end else if(ARF_access == 1'b1) begin
            COMMAND_CNT <= 'd1;
        end else if(COMMAND_CNT == TIME_ARF_to_done) begin
            COMMAND_CNT <= 'd0;
        end else if(COMMAND_CNT > 'd0) begin
            COMMAND_CNT <= COMMAND_CNT + 1'b1;
        end else begin
            COMMAND_CNT <= COMMAND_CNT;
        end
    end
//COMMAND
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            COMMAND_REF   <= COMMAND_NOP;
            ARF_A_ADDR    <= 12'd0      ;
            ARF_BANK_ADDR <= 2'b00      ;
        end else if(COMMAND_CNT == TIME_ARF_BEGIN) begin
            COMMAND_REF   <= COMMAND_ARF;
        end else begin
            COMMAND_REF   <= COMMAND_NOP;
            ARF_A_ADDR    <= 12'd0      ;
            ARF_BANK_ADDR <= 2'b00      ;
        end
    end
//COMMAND other SDRAM
    // always@(posedge Sys_clk or negedge Rst_n) begin
    //     if(Rst_n == 'd0) begin
    //         COMMAND_REF   <= COMMAND_NOP;
    //         ARF_A_ADDR    <= 12'd0      ;
    //         ARF_BANK_ADDR <= 2'b00      ;
    //     end else begin
    //         case (COMMAND_CNT)
    //             TIME_ARF_BEGIN:  begin
    //                 COMMAND_REF    <= COMMAND_PRE;
    //                 ARF_A_ADDR[10] <= 1'b1       ;
    //             end
    //             TIME_PRE_to_ARF: begin
    //                 COMMAND_REF   <= COMMAND_ARF;
    //             end
    //             default: begin
    //                 COMMAND_REF   <= COMMAND_NOP;
    //                 ARF_A_ADDR    <= 12'd0      ;
    //                 ARF_BANK_ADDR <= 2'b00      ;
    //             end
    //         endcase
    //     end
    // end
endmodule

写入:

        1.注意每一行结束以后要重新激活。

        2.写完了就不要继续req了。

//SDRAM SIZE = 8192X512X16
  //8192ROWS 512COLS 16BITS
module SDRAM_WR #(
    parameter SDRAM_COLS_MAX  = 128,
    parameter IMAGE_NEED_ROW  = 300, //300 = 640*480*8/16*512 
    parameter TIME_PRE_CHARGE_long = 8
)(
    input   wire        Sys_clk,
    input   wire        Rst_n  ,
    //FIFO
    input   wire            FIFO_WR_EN   ,//8bits
    input   wire    [ 7:0]  FIFO_WR_data ,
    //SDRAM
    input   wire            INIT_DONE    ,
    output  reg     [ 3:0]  COMMAND_WR   ,
    output  reg     [11:0]  WR_A_ADDR    ,
    output  reg     [ 1:0]  WR_BANK_ADDR ,
    output  wire            WR_data_done ,
    output  reg             WR_req       ,
    input   wire            ARF_req      ,
    output  reg             Break_WR_to_ARF,
    input   wire            WR_access    ,
    output  wire    [15:0]  WRITE_SDRAM_DQ    
);
`include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h"
            localparam  STATE_IDLE      = 5'b0_0001;
            localparam  STATE_WR_wait   = 5'b0_0010;
            localparam  STATE_ACT       = 5'b0_0100;
            localparam  STATE_WR_NOW    = 5'b0_1000;
            localparam  STATE_Precharge = 5'b1_0000;
            reg     [ 4:0]       STATE         ;
            reg     [ 1:0]       CNT_ACT       ;
            reg     [ 9:0]       CNT_SDRAM_COLS;
            reg     [12:0]       CNT_SDRAM_ROWS;
            wire                 ROWS_END_Flag ;
            reg     [ 1:0]       CNT_Brust     ;
            reg     [ 3:0]       CNT_Precharge ;
            reg                  Done_image    ;
    //FIFO
            wire                 FIFO_FULL     ;
            wire                 FIFO_EMPTY    ;
            wire    [ 9:0]       FIFO_RD_cnt   ;
            reg                  FIFO_RD_EN    ;
            wire    [15:0]       FIFO_RD_DATA  ;
    assign WRITE_SDRAM_DQ = FIFO_RD_DATA;
//FIFO_RD_EN
always @(posedge Sys_clk or negedge Rst_n) begin
    if(Rst_n == 'd0) begin
        FIFO_RD_EN <= 'd0;
    end else if(STATE == STATE_WR_NOW) begin
        FIFO_RD_EN <= 1'b1;
    end else begin
        FIFO_RD_EN <= 'd0;
    end
end
//WR_req
    always @(posedge Sys_clk or negedge Rst_n) begin
    if(Rst_n == 'd0) begin
        WR_req <= 'd0;
    end else if(FIFO_RD_cnt >= 512 && STATE == STATE_WR_wait && Done_image == 'd0) begin
        WR_req <= 1'b1;
    end else if(WR_access == 1'b1  && STATE == STATE_WR_wait) begin 
        WR_req <= 'd0;
    // end else if(Break_WR_to_ARF == 1'b1 && Done_image == 'd0) begin //通过uart写入FIFO的数据速度太慢了,SDRAM的写入速度非常快,这行会导致读出大量的重复数据写入SDRAM
    //     WR_req <= 1'b1;
    end else if(Done_image == 1'b1) begin
        WR_req <= 'd0;
    end else begin
        WR_req <= WR_req;
    end
end
//Done_image
    // always @(posedge Sys_clk or negedge Rst_n) begin
    //     if(Rst_n == 'd0) begin
    //         Done_image <= 'd0;
    //     end else if(STATE == STATE_WR_NOW
    //     && (CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 )
    //     && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1)    
    //     && (CNT_Brust == INIT_Burst_length -1'b1)) begin
    //         Done_image <= 1'b1;
    //     end else if(STATE == STATE_Precharge && CNT_Precharge == TIME_PRE_CHARGE_long) begin
    //         Done_image <= 'd0;
    //     end else begin
    //         Done_image <= Done_image;
    //     end
    // end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Done_image <= 'd0;
        end else if(STATE == STATE_WR_NOW
        && (CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 )
        && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1)    
        && (CNT_Brust == INIT_Burst_length -1'b1)) begin
            Done_image <= 1'b1;
        end else begin
            Done_image <= Done_image;
        end
    end
//WR_data_done
    assign WR_data_done = (STATE == STATE_Precharge 
        && CNT_Precharge == TIME_PRE_CHARGE_long 
        && Done_image == 1'b1);
    // always @(posedge Sys_clk or negedge Rst_n) begin
    //     if(Rst_n == 'd0) begin
    //         WR_data_done <= 'd0;
    //     end else if(STATE == STATE_Precharge 
    //     && CNT_Precharge == TIME_PRE_CHARGE_long 
    //     && Done_image == 1'b1) begin
    //         WR_data_done <= 1'b1;
    //     end else begin
    //         WR_data_done <= 'd0;
    //     end
    // end
//Break_WR_to_ARF
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Break_WR_to_ARF <= 'd0;
        end else if(STATE == STATE_Precharge 
        && CNT_Precharge == TIME_PRE_CHARGE_long 
        && Done_image == 1'b0) begin
            Break_WR_to_ARF <= 'd1;
        end else begin
            Break_WR_to_ARF <= 'd0;
        end
    end
//CNT_ACT
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_ACT <= 'd0;
        end else if(STATE == STATE_ACT) begin
            if(CNT_ACT == TIME_RCD) begin
                CNT_ACT <= 'd0; 
            end else begin
                CNT_ACT <= CNT_ACT + 1'b1;
            end
        end else begin
            CNT_ACT <= 'd0;
        end
    end
//CNT_Brust
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_Brust <= 'd0;
        end else if(STATE == STATE_WR_NOW) begin
            if(CNT_Brust == INIT_Burst_length -1'b1) begin
                CNT_Brust <= 'd0;
            end else begin
                CNT_Brust <= CNT_Brust + 1'b1;
            end
        end else begin
            CNT_Brust <= 'd0;
        end
    end
//CNT_SDRAM_ROWS
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_SDRAM_ROWS <= 'd0;
        end else if(STATE == STATE_WR_NOW) begin
            if (CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 
            && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1)
            && (CNT_Brust == INIT_Burst_length -1'b1)) begin
                CNT_SDRAM_ROWS <= 'd0;
            end else if((CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1)
            && (CNT_Brust == INIT_Burst_length -1'b1)) begin
                CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS + 1'b1;
            end else begin
                CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS;
            end
        end else begin
            CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS;
        end
    end
//CNT_SDRAM_COLS
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_SDRAM_COLS <= 'd0;
        end else if(STATE == STATE_WR_NOW) begin
            if((CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) 
            && (CNT_Brust == INIT_Burst_length -1'b1)) begin
                CNT_SDRAM_COLS <= 'd0;
            end else if(CNT_Brust == INIT_Burst_length -1'b1) begin
                CNT_SDRAM_COLS <= CNT_SDRAM_COLS + 1'b1;
            end else begin
                CNT_SDRAM_COLS <= CNT_SDRAM_COLS;
            end
        end else begin
            CNT_SDRAM_COLS <= CNT_SDRAM_COLS;
        end
    end
assign ROWS_END_Flag  = (STATE == STATE_WR_NOW) && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) && (CNT_Brust == INIT_Burst_length -1'b1);
//CNT_Precharge
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_Precharge <= 'd0;
        end else if(STATE == STATE_Precharge && CNT_Precharge == TIME_PRE_CHARGE_long) begin
            CNT_Precharge <= 'd0;
        end else if(STATE == STATE_Precharge) begin
            CNT_Precharge <= CNT_Precharge + 1'b1;
        end else begin
            CNT_Precharge <= CNT_Precharge;
        end
    end
//COMMAND
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            COMMAND_WR   <= COMMAND_NOP;
            WR_A_ADDR    <= 12'd0      ;
            WR_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_WR_wait && WR_access == 1'b1) begin
            COMMAND_WR   <= COMMAND_ACT;
            WR_A_ADDR    <= CNT_SDRAM_ROWS;//row_addr
            WR_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_WR_NOW  && CNT_Brust  == 'd0) begin
            COMMAND_WR   <= COMMAND_WRITE;
            WR_A_ADDR    <= CNT_SDRAM_COLS<<2'd2;
            WR_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_Precharge && CNT_Precharge == 'd0) begin
            COMMAND_WR <= COMMAND_PRE;
            WR_A_ADDR[10]<= 1'b1       ;
            WR_BANK_ADDR <= 2'b00      ;
        end else begin
            COMMAND_WR   <= COMMAND_NOP;
            WR_A_ADDR    <= 12'd0      ;
            WR_BANK_ADDR <= 2'b00      ;
        end
    end
//STATE
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            STATE <= STATE_IDLE;
        end else begin
            case (STATE)
                STATE_IDLE: begin
                    if(INIT_DONE == 1'b1) begin
                        STATE <= STATE_WR_wait;
                    end else begin
                        STATE <= STATE_IDLE;
                    end
                end
                STATE_WR_wait: begin
                    if(WR_access == 1'b1) begin
                        STATE <= STATE_ACT;
                    end else begin
                        STATE <= STATE_WR_wait;
                    end
                end
                STATE_ACT: begin
                    if(ARF_req == 1'b1 && CNT_ACT == TIME_RCD) begin
                        STATE <= STATE_Precharge;
                    end else if(CNT_ACT == TIME_RCD) begin
                        STATE <= STATE_WR_NOW;
                    end else begin
                        STATE <= STATE_ACT;
                    end
                end
                STATE_WR_NOW:begin
                    if(ARF_req == 1'b1 && CNT_Brust == INIT_Burst_length - 1'b1) begin
                        STATE <= STATE_Precharge;
                    end else if(ROWS_END_Flag == 1'b1) begin
                        STATE <= STATE_Precharge;
                    end else if(Done_image == 1'b1) begin
                        STATE <= STATE_Precharge;
                    end else begin
                        STATE <= STATE_WR_NOW;
                    end
                end
                STATE_Precharge: begin
                    if(CNT_Precharge == TIME_PRE_CHARGE_long) begin
                        STATE <= STATE_WR_wait;
                    end else begin
                        STATE <=  STATE_Precharge;
                    end
                end
                default: begin
                    STATE <= STATE_IDLE;
                end
            endcase
        end
    end
/*------------------------------------------------------------------------*/
AS_FIFO_w2048x8_r1024x16 INST0_AS_FIFO_w2048x8_r1024x16 (
  .wr_clk       ( Sys_clk       ), // input wr_clk
  .rd_clk       ( Sys_clk       ), // input rd_clk
  .din          ( FIFO_WR_data  ), // input [7 : 0] din
  .wr_en        ( FIFO_WR_EN    ), // input wr_en
  .rd_en        ( FIFO_RD_EN    ), // input rd_en
  .dout         ( FIFO_RD_DATA  ), // output [15 : 0] dout
  .full         ( FIFO_FULL     ), // output full
  .empty        ( FIFO_EMPTY    ), // output empty
  .rd_data_count( FIFO_RD_cnt   )  // output [9 : 0] rd_data_count
  /*------------------------------------------------------------------------*/
);
endmodule

你可能感兴趣的:(嵌入式硬件,fpga开发)