天天看點

SDRAM及DDR3複習筆記及FPGA實作(二)

SDRAM及DDR3複習筆記及FPGA實作(二)

DDR與SDRAM的差別

記憶體可分為DRAM動态随機存取記憶體和SRAM靜态随機存取記憶體兩種。兩種存儲器都是揮發性的記憶體,SRAM的主要使用flip-flop正反器,通常用于快取(Cache),而DRAM則是使用電容器及半導體組成。

SDRAM及DDR3複習筆記及FPGA實作(二)

DRAM中又以SDRAM同步動态随機存取記憶體在近幾年來最廣為使用,SDRAM最重要的就是能夠“同步”記憶體與處理器(CPU)的頻率,讓SDRAM頻率可超過100MHz使傳輸資料更能實時到位。SDRAM可稱為SDRSDRAM。

DDR其實指的是DDRSDRAM,SDRAM及DDR主要差異有三點整理如下:

SDRAM與DDR的主要差異

1.DDR使用了預取技術(Prefetch)。Prefetch為運作時1I0會預取的資料,也就會是DDR顆粒對外的IO寬度。

2.SDRAM隻能在頻率上升時傳輸資料,表示-一個頻率周期隻能做一次資料傳輸,但是DDR開始能夠在頻率上升及下降皆能夠傳輸資料,是以DDR一個頻率周期就可以進行兩次資料傳輸。

​3.DDR多了DQS(DataStrobe)有助于傳輸速率的提升,DQS為一個差分訊号且能雙向傳輸取(Read)時DQS由DDR傳往處理器,寫入(Write)時由處理器傳往DDR。

我們在後面筆記鐘進行詳細的描述

SDRAM控制器的FPGA實作

SDRAM(synchronous Dynamic Random )

同步動态随機存儲器,同步指記憶體工作需要同步時鐘,記憶體的指令的發送和資料的接收都以它為标準。動态是指需要不斷地重新整理來保證資料不丢失(電容存儲),随機指的是儲存位置可以随機指定,自由儲存。

SDRAM的表達方式

M*N M為多少個存儲單元 N為每個單元的存儲量

專有名詞總結

row 行

column 列

nop(no operation) 無操作

precharge 預充電

outorefresh 自動重新整理

RAS 行選通

CAS 列選通

CKE 時鐘使能

時序操作

sdram簡單來說可以分為三個過程:1.初始化操作。2.寫資料。3.讀資料。但是由于我們的sdram并不是時時刻刻都需要讀資料和寫資料的,是以當我們不讀資料或者不寫資料的時候,需要每隔一段時間去自動重新整理一下,防止資料丢失。(當然官方手冊給出了的是先預充電,然後延時20ns,然後重新整理)。間隔的重新整理時間由資料手冊決定。

詳細時序見上一篇筆記

項目整體結構

SDRAM及DDR3複習筆記及FPGA實作(二)

包括仿真檔案頂層子產品,SDRAM主要制器,初始化子產品,重新整理子產品,寫子產品,讀子產品

1.初始化操作

自己寫沒有這個人寫的好大家可以看看這個人寫的非常詳細

初始化操作

本人自己寫的初始化例程

/*=============================================================================
#
# Author: 田澤禮 [email protected]
#
# QQ : 1069273936
#
# Last modified: 2020-07-16 19:14
#
# Filename: top_sdram.v
#
# Description: SDRAM控制器的頂層子產品,時鐘生成,例化
#
=============================================================================*/

/*----------------------------------------------------------------------------------------------------
sdram初始化
cmd真值表		cs_n	ras_n	cas_n	we_n	ba[1:0]	addr[12:11]	  addr[10]    addr[9:0]
	NOP			0		1		1		1		X		  X			    X		     X
	PALL		0		0		1		0		X		  x			    1		     X
	REF			0		0		0		1		X		  X			    X		     X
    ACT         0       0       1       1       v         v             v            v
    RD          0       1       0       1       v         v             0            v
    WR          0       1       0       0       v         v             0            v

MR模式寄存器     {ba[1:0],addr[12:0]}    =   {00,000,000,011,0,010}
突發長度為4,順序突發,潛伏期為3,busrt read and burst write mode
		
-----------------------------------------------------------------------------------------------------*/


module	sdram_init(
			input	wire		clk,	//50MHZ
			input	wire		rst,
			
			output	reg			init_done,
			output	reg[18:0]	init_cmd
			);
	


//==================================================
//paranmeter define
//==================================================

parameter	TRP		=	2,
		    TRC		=	4,
		    TMRD	=	2;

parameter	DEY_200US	    =	34333 - 1;
parameter   PRE_MAX =   8-1     ;
parameter   REF_MAX =   128 - 1  ;
parameter   MODE_MAX=   24 -1    ;
			
parameter   REF     =   19'h08000;//18'b00_0100_0000_0000_0000
parameter   NOP     =   19'h38000;//18'b01_1100_0000_0000_0000
parameter   PALL    =   19'h10400;//18'b00_1000_0100_0000_0000
parameter   ACT     =   4'b0011  ;//when give command to sdram{ACT,ba,addr}
parameter   WR      =   4'b0100  ;//when give command to sdram{WR,ba,addr}
parameter   RD      =   4'b0101  ;//when give command to sdram{RD,ba,addr}
parameter   MR      =   19'h00032;          //19'b00_0000_0000_0011_0010

parameter   IDLE    =   5'b0_0001;
parameter   WAIT    =   5'b0_0010;
parameter   PRE     =   5'b0_0100;
parameter   REFRESH =   5'b0_1000;
parameter   MODE    =   5'b1_0000;
			
//==================================================
//internal signals
//==================================================

reg     [15:0]  	  cnt_init    ;
wire                add_cnt_init;
wire                end_cnt_init;

reg     [3:0]       cnt_pre     ;
wire                add_cnt_pre ;
wire                end_cnt_pre ;

reg     [8:0]       cnt_ref     ;
wire                add_cnt_ref ;
wire                end_cnt_ref ;

reg     [5:0]       cnt_mode    ;
wire                add_cnt_mode;
wire                end_cnt_mode;

reg     [4:0]       state       ;

//--------------------state machine define--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        state <= IDLE;
    end
    else begin
        case(state)
            IDLE:begin
                state <= WAIT;
            end

            WAIT:begin
                if(end_cnt_init)
                    state <= PRE;
                else
                    state <= WAIT;
            end

            PRE:begin
                if(end_cnt_pre)
                    state <= REFRESH;
                else
                    state <= PRE;
            end

            REFRESH:begin
                if(end_cnt_ref)
                    state <= MODE;
                else
                    state <= REFRESH;
            end

            MODE:begin
                if(end_cnt_mode)
                    state <= IDLE;
                else
                    state <= MODE;
            end

            default:begin
                state <= IDLE;
            end
        endcase
    end
end

//--------------------cnt_init--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_init <= 'd0;
    end
    else if(add_cnt_init)begin
        if(end_cnt_init)
            cnt_init <= 'd0;
        else
            cnt_init <= cnt_init + 1'b1;
    end
    else begin
        cnt_init <= 'd0;
    end
end

assign add_cnt_init = state==WAIT;       
assign end_cnt_init = add_cnt_init && cnt_init== DEY_200US;

//--------------------cnt_pre--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_pre <= 0;
    end
    else if(add_cnt_pre)begin
        if(end_cnt_pre)
            cnt_pre <= 0;
        else
            cnt_pre <= cnt_pre + 1'b1;
    end
    else begin
        cnt_pre <= 'd0;
    end
end

assign add_cnt_pre = state==PRE;       
assign end_cnt_pre = add_cnt_pre && cnt_pre== PRE_MAX; 

//--------------------cnt_ref--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_ref <= 0;
    end
    else if(add_cnt_ref)begin
        if(end_cnt_ref)
            cnt_ref <= 0;
        else
            cnt_ref <= cnt_ref + 1'b1;
    end
    else begin
        cnt_ref <= 'd0;
    end
end

assign add_cnt_ref = state==REFRESH;       
assign end_cnt_ref = add_cnt_ref && cnt_ref== REF_MAX; 

//--------------------cnt_mode--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_mode <= 0;
    end
    else if(add_cnt_mode)begin
        if(end_cnt_mode)
            cnt_mode <= 0;
        else
            cnt_mode <= cnt_mode + 1'b1;
    end
    else begin
        cnt_mode <= 'd0;
    end
end

assign add_cnt_mode = state==MODE;       
assign end_cnt_mode = add_cnt_mode && cnt_mode== MODE_MAX;

//--------------------init_done--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        init_done <= 1'b0;
    end
    else if(end_cnt_mode)begin
        init_done <= 1'b1;
    end
    else begin
        init_done <= init_done;
    end
end

//--------------------init_cmd--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        init_cmd <= NOP;
    end
    else if(end_cnt_init) begin
        init_cmd <= PALL;
    end
	 else if(state==REFRESH && cnt_ref[3:0]==4'b0000)begin
		  init_cmd <= REF;
	 end
    else if(end_cnt_ref)begin
        init_cmd <= MR;
    end
    else begin
        init_cmd <= NOP;
    end
end
endmodule		

           

2.讀操作

/*=============================================================================
#
# Author: 田澤禮 [email protected]
#
# QQ : 1069273936
#
# Last modified: 2020-07-16 19:14
#
# Filename: top_sdram.v
#
# Description: SDRAM控制器的頂層子產品,時鐘生成,例化
#
=============================================================================*/

/*----------------------------------------------------------------------------------------------------
sdram初始化
cmd真值表		cs_n	ras_n	cas_n	we_n	ba[1:0]	addr[12:11]	  addr[10]    addr[9:0]
	NOP			0		1		1		1		X		  X			    X		     X
	PALL		0		0		1		0		X		  x			    1		     X
	REF			0		0		0		1		X		  X			    X		     X
    ACT         0       0       1       1       v         v             v            v
    RD          0       1       0       1       v         v             0            v
    WR          0       1       0       0       v         v             0            v

MR模式寄存器     {ba[1:0],addr[12:0]}    =   {00,000,000,011,0,010}
突發長度為4,順序突發,潛伏期為3,busrt read and burst write mode
		
-----------------------------------------------------------------------------------------------------*/
module  sdram_rd(
    input   wire            clk     ,
    input   wire            rst     ,
    input   wire            ref_req , 
    input   wire            rd_en   ,
    input   wire    [15:0]  rd_dq   ,
	 input	wire				 init_done,

    output  wire            rd_req  ,
    output  reg             rd_flag ,//indicate read sdram
    output  reg             rd_done ,
    output  reg             rd_ref_break,
    output  reg     [18:0]  rd_cmd  ,
    output  wire    [15:0]  rd_data    
);

//==================================================
//parameter define
//==================================================
parameter   IDLE        = 5'b0_0001;
parameter   RD_REQ      = 5'b0_0010;
parameter   ACTIVE      = 5'b0_0100;
parameter   READ        = 5'b0_1000;
parameter   PRECHARGE   = 5'b1_0000;

parameter   REF		=	19'h08000;//18'b00_0100_0000_0000_0000
parameter   NOP		=	19'h38000;//18'b01_1100_0000_0000_0000
parameter 	PALL	=	19'h10400;//18'b00_1000_0100_0000_0000
parameter 	ACT 	=	4'b0011  ;//when give command to sdram{ACT,ba,addr}
parameter   WR      =   4'b0100  ;//when give command to sdram{WR,ba,addr}
parameter   RD      =   4'b0101  ;//when give command to sdram{RD,ba,addr}

parameter   ACT_DELAY   = 10 - 1;
parameter   BURST_LENGTH= 4 - 1;
parameter   COL_MAX     = 512-1;//sdram 1 row has 512 col
parameter   ROW_MAX     = 8192 -1;
parameter   PRE_MAX     = 10 -1;//precharge max time

//==================================================
//internal signals
//==================================================
reg     [4:0]   state       ;//state register

reg     [4:0]   cnt_act     ;//row active counter
wire            add_cnt_act ;
wire            end_cnt_act ;

reg     [3:0]   cnt_pre     ;//after precharge count 
wire            add_cnt_pre ;
wire            end_cnt_pre ;

reg     [1:0]   cnt_burst   ;//burst count
wire            add_cnt_burst;
wire            end_cnt_burst;

reg     [8:0]   cnt_col     ;//col address count
wire            add_cnt_col ;
wire            end_cnt_col ;
    
reg     [12:0]  cnt_row     ;//row address count
wire            add_cnt_row ;
wire            end_cnt_row ;

reg             rd_start    ;//start to read flag
reg             rd_done_flag;//read is finished flag
reg             rd_break_flag;//read state is broken flag

wire    [1:0]   bank        ;//bank addr
wire    [12:0]  row_addr    ;//row addr
wire    [8:0]   col_addr    ;//col addr

reg     [4:0]   rd_delay    ;//read data from sdram delay to keep data stable
wire            wr_fifo_en  ;//write fifo enable
reg     [79:0]  wr_data     ;//data will be writen into fifo

wire            rd_fifo_en  ;
wire            empty       ;
wire            full        ;
wire		[8:0]	 rd_data_count;
wire		[8:0]	 wr_data_count ;

assign  bank    = 2'd0;
assign  row_addr = cnt_row;
assign  col_addr = cnt_col;
    



//--------------------state machine describe--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        state <= IDLE;
    end
    else begin
        case(state)
            IDLE:begin
                if(rd_start && init_done)begin
                    state <= RD_REQ;
                end
                else begin
                    state <= IDLE;
                end
            end

            RD_REQ:begin
                if(rd_en)begin
                    state <= ACTIVE;
                end
                else begin
                    state <= RD_REQ;
                end
            end

            ACTIVE:begin
                if(end_cnt_act && ref_req==1'b0)begin
                    state <= READ;
                end
                else if(end_cnt_act && ref_req==1'b1)begin
                    state <= PRECHARGE;
                end
                else begin
                    state <= ACTIVE;
                end
            end

            READ:begin
                if(end_cnt_col)begin
                    state <= PRECHARGE;
                end
                else if(end_cnt_burst && ref_req==1'b1)begin
                    state <= PRECHARGE;
                end
                else begin
                    state <= READ;
                end
            end

            PRECHARGE:begin
                if(rd_done_flag && end_cnt_pre)begin
                    state <= IDLE;
                end
                else if(rd_break_flag && end_cnt_pre)begin
                    state <= RD_REQ;
                end
                else begin
                    state <= PRECHARGE;
                end
            end

            default:begin
                state <= IDLE;
            end
        endcase
    end
end

//--------------------rd_start--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        rd_start <= 1'b0;
    end
    else if(state==IDLE && rd_data_count <= 'd510 )begin
        rd_start <= 1'b1;
    end
    else begin
        rd_start <= 1'b0;
    end
end

//--------------------rd_req--------------------
assign  rd_req = (state==RD_REQ)?1'b1:1'b0;

//--------------------cnt_act--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_act <= 'd0;
    end
    else if(add_cnt_act)begin
        if(end_cnt_act)
            cnt_act <= 'd0;
        else
            cnt_act <= cnt_act + 1'b1;
    end
    else begin
        cnt_act <= 'd0;
    end
end

assign add_cnt_act = state==ACTIVE;       
assign end_cnt_act = add_cnt_act && cnt_act== ACT_DELAY; 

//--------------------cnt_col--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_col <= 0;
    end
    else if(add_cnt_col)begin
        if(end_cnt_col)
            cnt_col <= 0;
        else
            cnt_col <= cnt_col + 1'b1;
    end
    else begin
        cnt_col <= cnt_col;
    end
end

assign add_cnt_col = state==READ;       
assign end_cnt_col = add_cnt_col && cnt_col== COL_MAX;

//--------------------cnt_burst--------------------
always @(posedge  clk)begin
    if(rst==1'b1)begin
        cnt_burst <= 'd0;
    end
    else if(add_cnt_burst)begin
        if(end_cnt_burst)
            cnt_burst <= 'd0;
        else
            cnt_burst <= cnt_burst + 1'b1;
    end
    else begin
        cnt_burst <= 'd0;
    end 
end

assign add_cnt_burst = state==READ;       
assign end_cnt_burst = add_cnt_burst && cnt_burst== BURST_LENGTH;   



//--------------------cnt_row--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_row <= 0;
    end
    else if(add_cnt_row)begin
        if(end_cnt_row)
            cnt_row <= 0;
        else
            cnt_row <= cnt_row + 1'b1;
    end
    else begin
        cnt_row <= cnt_row;
    end
end

assign add_cnt_row = end_cnt_col;       
assign end_cnt_row = add_cnt_row && cnt_row== ROW_MAX; 


//--------------------rd_done_flag--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        rd_done_flag <= 1'b0;
    end
    else if(end_cnt_col)begin
        rd_done_flag <= 1'b1;
    end
    else if(rd_done_flag==1'b1 && end_cnt_pre)begin
        rd_done_flag <= 1'b0;
    end
    else begin
        rd_done_flag <= rd_done_flag;
    end
end

//--------------------rd_break_flag--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        rd_break_flag <= 1'b0;
    end
    else if(end_cnt_burst && ref_req==1'b1)begin
        rd_break_flag <= 1'b1;
    end
	 else if(end_cnt_act && ref_req==1'b1)begin
        rd_break_flag <= 1'b1;
    end
    else if(rd_break_flag==1'b1 && end_cnt_pre)begin
        rd_break_flag <= 1'b0;
    end
    else begin
        rd_break_flag <= rd_break_flag;
    end
end

//--------------------rd_done--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        rd_done <= 1'b0;
    end
    else if(end_cnt_pre && rd_done_flag)begin
        rd_done <= 1'b1;
    end
    else begin
        rd_done <= 1'b0;
    end
end

//--------------------rd_ref_break-------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        rd_ref_break <= 1'b0;
    end
    else if(end_cnt_pre && rd_break_flag)begin
        rd_ref_break <= 1'b1;
    end
    else begin
        rd_ref_break <= 1'b0;
    end
end

//--------------------cnt_pre--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_pre <= 0;
    end
    else if(add_cnt_pre)begin
        if(end_cnt_pre)
            cnt_pre <= 0;
        else
            cnt_pre <= cnt_pre + 1'b1;
    end
    else begin
        cnt_pre <= 'd0;
    end
end

assign add_cnt_pre = state==PRECHARGE;       
assign end_cnt_pre = add_cnt_pre && cnt_pre== PRE_MAX; 

//--------------------cmd--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        rd_cmd <= NOP;
    end
    else if(end_cnt_col || (end_cnt_burst && ref_req==1'b1) || (end_cnt_act && ref_req==1'b1))begin
        rd_cmd <= PALL;
    end
    else if(rd_en)begin
        rd_cmd <= {ACT,bank,row_addr};
    end
    else if(end_cnt_act && ref_req==1'b0)begin
        rd_cmd <= {RD,bank,{4'b0000,col_addr}};
    end
    else if(end_cnt_burst==1'b1 && end_cnt_col==1'b0)begin
        rd_cmd <= {RD,bank,{4'b0000,col_addr+1'b1}};
    end
    else begin
        rd_cmd <= NOP;
    end
end

//--------------------rd_delay--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        rd_delay <= 'd0;
    end
    else begin
        rd_delay <= {rd_delay[3:0],(state==READ)};
    end
end

//--------------------wr_fifo_en--------------------
assign  wr_fifo_en = rd_delay[4];

//--------------------wr_data--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        wr_data <= 'd0;
    end
    else begin
        wr_data <= {wr_data[79:16],rd_dq};
    end
end

always @(posedge clk)begin
    if(rst == 1'b1)begin
        rd_flag <= 'd0;
    end
    else if(state==READ)begin
        rd_flag <= 1'b1;            
    end
    else begin
        rd_flag <= 1'b0;
    end
end



//==================================================
//this part is creat to verify function
//==================================================
assign  rd_fifo_en = ~empty;


asfifo_wr256x16_rd256x16 wr_fifo_inst (
  .wr_clk(clk), // input wr_clk
  .rd_clk(clk), // input rd_clk
  .din(wr_data[79:64]), // input [15 : 0] din
  .wr_en(wr_fifo_en), // input wr_en
  .rd_en(rd_fifo_en), // input rd_en
  .dout(rd_data), // output [15 : 0] dout
  .full(full), // output full
  .empty(empty), // output empty
  .rd_data_count(rd_data_count), // output [8 : 0] rd_data_count
  .wr_data_count(wr_data_count) // output [8 : 0] wr_data_count
);




endmodule

           

3.寫操作

/*=============================================================================
#
# Author: 田澤禮 [email protected]
#
# QQ : 1069273936
#
# Last modified: 2020-07-16 19:14
#
# Filename: top_sdram.v
#
# Description: SDRAM控制器的頂層子產品,時鐘生成,例化
#
=============================================================================*/

/*----------------------------------------------------------------------------------------------------
sdram初始化
cmd真值表		cs_n	ras_n	cas_n	we_n	ba[1:0]	addr[12:11]	  addr[10]    addr[9:0]
	NOP			0		1		1		1		X		  X			    X		     X
	PALL		0		0		1		0		X		  x			    1		     X
	REF			0		0		0		1		X		  X			    X		     X
    ACT         0       0       1       1       v         v             v            v
    RD          0       1       0       1       v         v             0            v
    WR          0       1       0       0       v         v             0            v

MR模式寄存器     {ba[1:0],addr[12:0]}    =   {00,000,000,011,0,010}
突發長度為4,順序突發,潛伏期為3,busrt read and burst write mode
		
-----------------------------------------------------------------------------------------------------*/

module  sdram_wr(
    input   wire            clk         ,
    input   wire            rst         ,
    input   wire            wr_en       ,//write module enable signal
    input   wire            ref_req     ,//refresh request signal
    input   wire            init_done   ,//initialize is finished

    output  wire            wr_req      ,//write sdram request
    output  reg             wr_flag     ,//indicate writing sdram
    output  reg             wr_ref_break,//write state is stopped by ref_req signal
    output  reg             wr_done     ,//write sdram a row complete signanl
    output  reg    [18:0]   wr_cmd      ,//command to sdram
    output  reg    [15:0]   wr_dq       
);

//==================================================
// parameter define
//==================================================

//--------------------state define--------------------
parameter   IDLE        = 5'b0_0001;
parameter   WR_REQ      = 5'b0_0010;
parameter   ACTIVE      = 5'b0_0100;
parameter   WRITE       = 5'b0_1000;
parameter   PRECHARGE   = 5'b1_0000;

//--------------------cmd--------------------
parameter   REF     =   19'h08000;//19'b0001_000_0000_0000_0000
parameter   NOP     =   19'h38000;//19'b0111_000_0000_0000_0000
parameter   PALL    =   19'h10400;//19'b0010_000_0100_0000_0000
parameter   ACT     =   4'b0011  ;//when give command to sdram{ACT,ba,addr}
parameter   WR      =   4'b0100  ;//when give command to sdram{WR,ba,addr}
parameter   RD      =   4'b0101  ;//when give command to sdram{RD,ba,addr}

//--------------------time parameter--------------------
parameter   ACT_DELAY   = 10 - 1     ;
parameter   BURST_LENGTH= 4 - 1     ;
parameter   COL_MAX     = 512 - 1   ;//sdram 1 row has 512 col
parameter   ROW_MAX     = 8192 - 1  ;
parameter   PRE_MAX     = 10 - 1    ;//precharge max time


//==================================================
//internal signals
//==================================================

reg     [4:0]   state           ;//state register
reg             wr_start_flag   ;//write sdram start flag
reg             wr_end_flag     ;// write a row finished
reg             wr_ref_break_flag;//write is stopped by refresh

reg     [3:0]   cnt_act         ;//counter in active state
wire            add_cnt_act     ;
wire            end_cnt_act     ;

reg     [1:0]   cnt_burst       ;//counter to count how many words have been writen into sdaram
wire            add_cnt_burst   ;
wire            end_cnt_burst   ;

reg     [8:0]   cnt_col         ;//counter for how many words have been writen into sdram in a row
wire            add_cnt_col     ;
wire            end_cnt_col     ;

reg     [12:0]  cnt_row         ;//counter for row address
wire            add_cnt_row     ;
wire            end_cnt_row     ;

reg     [3:0]   cnt_pre         ;//counter for precharge state
wire            add_cnt_pre     ;
wire            end_cnt_pre     ;

wire    [1:0]   bank            ;//bank address
wire    [12:0]  row_addr        ;//row address
wire    [8:0]   col_addr        ;//col address

wire    [8:0]   rd_data_cnt     ;
reg             rd_en           ;
wire    [15:0]  dout            ;

wire     [15:0] wr_fifo_data    ;//data will be writen into fifo
reg             wr_fifo_en      ;//write fifo enable
wire            full            ;
wire            empty           ;

reg     [15:0]  data_up         ;
wire	[8:0]	wr_data_cnt		;
    
assign  bank = 2'b00            ;
assign  col_addr = cnt_col      ;
assign  row_addr = cnt_row      ;

//--------------------state machine describe--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        state <= IDLE;
    end
    else begin
        case(state)
            IDLE:begin
                if(wr_start_flag && init_done)//inside fifo have enough data
                    state <= WR_REQ;
                else 
                    state <= IDLE;
            end

            WR_REQ:begin
                if(wr_en)begin //recive a write sdram enable signal
                    state <= ACTIVE;
                end
                else begin
                    state <= WR_REQ;
                end
            end

            ACTIVE:begin //active is done and refresh request don't show
                if(end_cnt_act && ref_req==1'b0)begin//active command is finished
                    state <= WRITE;
                end
                else if(end_cnt_act && ref_req==1'b1)begin// active command is done and ref_req shows
                    state <= PRECHARGE;
                end
                else begin
                    state <= ACTIVE;
                end
            end

            WRITE:begin
                if(end_cnt_col)begin//write sdram a row
                    state <= PRECHARGE;
                end
                else if(cnt_burst=='d3 && ref_req==1'b1)begin//break by ref_req
                    state <= PRECHARGE;
                end
                else begin
                    state <= WRITE;
                end
            end

            PRECHARGE:begin
                if(end_cnt_pre)begin
                    if(wr_end_flag)begin//write a sdram row 
                        state <= IDLE;
                    end
                    else if(wr_ref_break_flag)begin// break by ref_req
                        state <= WR_REQ;
                    end
                    else begin
                        state <= IDLE;
                    end
                end
                else begin
                    state <= PRECHARGE;
                end
            end

            default:begin
                state <= IDLE;
            end
        endcase
    end
end

//--------------------wr_start_flag--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        wr_start_flag <= 1'b0;
    end
    else if(wr_data_cnt >= 'd509)begin  // inside fifo has enough datas
        wr_start_flag <= 1'b1;
    end
    else begin
        wr_start_flag <= 1'b0;
    end
end

//--------------------wr_req--------------------
assign wr_req = (state==WR_REQ)?1'b1:1'b0;

//--------------------during active state-------------------
//--------------------cnt_act--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_act <= 'd0;
    end
    else if(add_cnt_act)begin
        if(end_cnt_act)
            cnt_act <= 'd0;
        else
            cnt_act <= cnt_act + 1'b1;
    end
    else begin
        cnt_act <= 'd0;
    end 
end

assign add_cnt_act = state==ACTIVE;       
assign end_cnt_act = add_cnt_act && cnt_act== ACT_DELAY;   

//--------------------during write state--------------------
//--------------------cnt_burst--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_burst <= 'd0;
    end
    else if(add_cnt_burst)begin
        if(end_cnt_burst)
            cnt_burst <= 'd0;
        else
            cnt_burst <= cnt_burst + 1'b1;
    end
    else begin
        cnt_burst <= 'd0;
    end 
end

assign add_cnt_burst = state==WRITE;       
assign end_cnt_burst = add_cnt_burst && cnt_burst== BURST_LENGTH;

//--------------------cnt_col--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_col <= 'd0;
    end
    else if(add_cnt_col)begin
        if(end_cnt_col)
            cnt_col <= 'd0;
        else
            cnt_col <= cnt_col + 1'b1;
    end
    else begin
        cnt_col <= cnt_col;
    end 
end

assign add_cnt_col = state==WRITE;       
assign end_cnt_col = add_cnt_col && cnt_col== COL_MAX;   

//--------------------cnt_row--------------------
always @(posedge clk or posedge rst)begin
    if(rst==1'b1)begin
        cnt_row <= 'd0;
    end
    else if(add_cnt_row)begin
        if(end_cnt_row)
            cnt_row <= 'd0;
        else
            cnt_row <= cnt_row + 1'b1;
    end
    else begin
        cnt_row <= cnt_row;
    end 
end

assign add_cnt_row = end_cnt_col;       
assign end_cnt_row = add_cnt_row && cnt_row== ROW_MAX;   


//--------------------wr_end_flag--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
       wr_end_flag <= 1'b0; 
    end
    else if(end_cnt_col)begin
        wr_end_flag <= 1'b1;
    end
    else if(end_cnt_pre)begin
        wr_end_flag <= 1'b0;
    end
    else begin
        wr_end_flag <= wr_end_flag;
    end
end

//--------------------wr_ref_break_flag--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        wr_ref_break_flag <= 1'b0;
    end
    else if(end_cnt_burst && ref_req==1'b1 && end_cnt_col==1'b0)begin
        wr_ref_break_flag <= 1'b1;
    end
    else if(end_cnt_act && ref_req==1'b1)begin
        wr_ref_break_flag <= 1'b1;
    end
	 else if(end_cnt_pre)begin
        wr_ref_break_flag <= 1'b0;
    end
    else begin
        wr_ref_break_flag <= wr_ref_break_flag;
    end
end

//--------------------rd_en--------------------
always  @(*)begin
    if(state == WRITE)
        rd_en = 1'b1;
    else 
        rd_en = 1'b0;
end

//--------------------wr_dq--------------------
always  @(*)begin
    if(state==WRITE)
        wr_dq = dout;
    else 
        wr_dq = 'd0;
end




//--------------------during precharge state--------------------
//--------------------cnt_pre--------------------
always @(posedge clk)begin
    if(rst==1'b1)begin
        cnt_pre <= 'd0;
    end
    else if(add_cnt_pre)begin
        if(end_cnt_pre)
            cnt_pre <= 'd0;
        else
            cnt_pre <= cnt_pre + 1'b1;
    end
    else begin
        cnt_pre <= 'd0;
    end 
end

assign add_cnt_pre = state==PRECHARGE;       
assign end_cnt_pre = add_cnt_pre && cnt_pre== PRE_MAX;   

//--------------------wr_done--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        wr_done <= 1'b0;
    end
    else if(wr_end_flag && end_cnt_pre)begin
        wr_done <= 1'b1;
    end
    else begin
        wr_done <= 1'b0;
    end
end

//--------------------wr_ref_break--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        wr_ref_break <= 1'b0;
    end
    else if(wr_ref_break_flag && end_cnt_pre)begin
        wr_ref_break <= 1'b1;
    end
    else begin
        wr_ref_break <= 1'b0;
    end
end

//--------------------wr_cmd--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        wr_cmd <= NOP;
    end
    else if((end_cnt_act==1'b1&&ref_req==1'b1)||(end_cnt_burst==1'b1&&ref_req==1'b1)||end_cnt_col==1'b1)begin
        wr_cmd <= PALL;
    end
    else if(wr_en==1'b1)begin
        wr_cmd <= {ACT,bank,row_addr};
    end
    else if((end_cnt_act==1'b1 && ref_req==1'b0))begin
        wr_cmd <= {WR,bank,{4'b0000,col_addr}};
    end
    else if(end_cnt_burst==1'b1 && end_cnt_col==1'b0)begin
        wr_cmd <= {WR,bank,{4'b0000,col_addr+1'b1}};
    end
    else begin
        wr_cmd <= NOP;
    end
end


always @(posedge clk) begin
    if (rst==1'b1) begin
        data_up <= 'd0;
    end
    else if (state==IDLE && init_done) begin
        if(data_up == COL_MAX)
            data_up <= data_up;
        else
            data_up <= data_up + 1'b1;
    end
    else
        data_up <= 'd0;
end

assign wr_fifo_data = data_up;

always @(posedge clk) begin
	 if(rst==1'b1)
		wr_fifo_en <= 1'b0;
    else if (state==IDLE && (data_up<COL_MAX) && init_done) begin
        wr_fifo_en <= 1'b1;
    end
    else begin
        wr_fifo_en <= 1'b0;
    end
end

always @(posedge clk) begin
    if (rst==1'b1) begin
        wr_flag <= 'd0;
    end
    else if (state==WRITE) begin
        wr_flag <= 1'b1;
    end
    else begin
        wr_flag <= 1'b0;
    end
end





asfifo_wr256x16_rd256x16 wr_fifo_inst (
  .wr_clk(clk), // input wr_clk
  .rd_clk(clk), // input rd_clk
  .din(wr_fifo_data), // input [15 : 0] din
  .wr_en(wr_fifo_en), // input wr_en
  .rd_en(rd_en), // input rd_en
  .dout(dout), // output [15 : 0] dout
  .full(full), // output full
  .empty(empty), // output empty
  .rd_data_count(rd_data_cnt), // output [8 : 0] rd_data_count
  .wr_data_count(wr_data_cnt) // output [8 : 0] wr_data_count
);

//
//wire	[35:0]	CONTROL;	
//wire	[52:0]	triger;
//	 chipscope_icon icon0 (
//    .CONTROL0(CONTROL) // INOUT BUS [35:0]
//);
//chipscope_ila ila0 (
//    .CONTROL(CONTROL), // INOUT BUS [35:0]
//    .CLK(clk), // IN
//    .TRIG0(triger) // IN BUS [39:0]
//); 
//assign	triger[18:0] = wr_cmd;
//assign	triger[19] = wr_flag;
//assign	triger[20] = init_done;
//assign	triger[36:21]= wr_dq;
//assign	triger[52:37] = dout;
//
//


endmodule

           

4.重新整理子產品

詳細時序

/*=============================================================================
#
# Author: 田澤禮 [email protected]
#
# QQ : 1069273936
#
# Last modified: 2020-07-16 19:14
#
# Filename: top_sdram.v
#
# Description: SDRAM控制器的頂層子產品,時鐘生成,例化
#
=============================================================================*/

/*----------------------------------------------------------------------------------------------------
sdram初始化
cmd真值表		cs_n	ras_n	cas_n	we_n	ba[1:0]	addr[12:11]	  addr[10]    addr[9:0]
	NOP			0		1		1		1		X		  X			    X		     X
	PALL		0		0		1		0		X		  x			    1		     X
	REF			0		0		0		1		X		  X			    X		     X
    ACT         0       0       1       1       v         v             v            v
    RD          0       1       0       1       v         v             0            v
    WR          0       1       0       0       v         v             0            v

MR模式寄存器     {ba[1:0],addr[12:0]}    =   {00,000,000,011,0,010}
突發長度為4,順序突發,潛伏期為3,busrt read and burst write mode
		
-----------------------------------------------------------------------------------------------------*/
module  sdram_ref(
    inout   wire            clk         ,
    input   wire            rst         ,
    input   wire            init_done   ,//initialize state is finished
    input   wire            ref_en      ,//refresh enable

    output  reg             ref_req     ,//refresh request
    output  reg             ref_done    ,//refresh done
    output  reg     [18:0]  ref_cmd      //ref_cmd{cs_n,ras_n,cas_n,we_n,bank[1:0],addr[11:0]}
);

//==================================================
//parameter define
//==================================================
parameter   REF     =   19'h08000;//19'b0001_000_0000_0000_0000
parameter   NOP     =   19'h38000;//19'b0111_000_0000_0000_0000
parameter   PALL    =   19'h10400;//19'b0010_000_0100_0000_0000
parameter   ACT     =   4'b0011  ;//when give command to sdram{ACT,ba,addr}
parameter   WR      =   4'b0100  ;//when give command to sdram{WR,ba,addr}
parameter   RD      =   4'b0101  ;//when give command to sdram{RD,ba,addr}
parameter	MR		=   19'h00022; //19'b00_0000_0000_0011_0010

parameter       REF_MAX     = 976 - 1;//refresh time
parameter       DELAY_MAX   = 20 - 1 ;//delay a few time after refresh


//==================================================
//internal signals
//==================================================
reg     [9:0]   cnt_ref     ;//counter to gen refresh request
wire            add_cnt_ref ;
wire            end_cnt_ref ;

reg             delay_flag  ;//delay a few time after refresh
reg     [5:0]   cnt_delay   ;//count delay time
wire            add_cnt_delay;
wire            end_cnt_delay;


//--------------------cnt_ref--------------------
always @(posedge clk or posedge rst)begin
    if(rst==1'b1)begin
        cnt_ref <= 'd0;
    end
    else if(add_cnt_ref)begin
        if(end_cnt_ref)
            cnt_ref <= 'd0;
        else
            cnt_ref <= cnt_ref + 1'b1;
    end
    else begin
        cnt_ref <= 'd0;
    end 
end

assign add_cnt_ref = init_done==1'b1;       
assign end_cnt_ref = add_cnt_ref && cnt_ref== REF_MAX;

//--------------------ref_req--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        ref_req <= 1'b0;
    end
    else if(end_cnt_ref == 1'b1)begin
        ref_req <= 1'b1;
    end
    else if(ref_en ==1'b1)begin
        ref_req <= 1'b0;
    end
    else begin
        ref_req <= ref_req;
    end
end

//--------------------ref_cmd--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        ref_cmd <= NOP;
    end
    else if(ref_en)begin
        ref_cmd <= REF;
    end
    else begin
        ref_cmd <= NOP;
    end
end

//--------------------delay_flag--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        delay_flag <= 1'b0;
    end
    else if(ref_en)begin
        delay_flag <= 1'b1;
    end
    else if(end_cnt_delay)begin
        delay_flag <= 1'b0;
    end
    else begin
        delay_flag <= delay_flag;
    end
end

//--------------------cnt_delay--------------------
always @(posedge clk or posedge rst)begin
    if(rst==1'b1)begin
        cnt_delay <= 'd0;
    end
    else if(add_cnt_delay)begin
        if(end_cnt_delay)
            cnt_delay <= 'd0;
        else
            cnt_delay <= cnt_delay + 1'b1;
    end
    else begin
        cnt_delay <= 'd0;
    end 
end

assign add_cnt_delay = delay_flag;       
assign end_cnt_delay = add_cnt_delay && cnt_delay== DELAY_MAX;

//--------------------ref_done--------------------
always @(posedge clk)begin
    if(rst == 1'b1)begin
        ref_done <= 1'b0;
    end
    else if(end_cnt_delay)begin
        ref_done <= 1'b1;
    end
    else begin
        ref_done <= 1'b0;
    end
end

endmodule

           

5.控制器子產品

/*=============================================================================
#
# Author: 田澤禮 [email protected]
#
# QQ : 1069273936
#
# Last modified: 2020-07-16 19:14
#
# Filename: top_sdram.v
#
# Description: SDRAM控制器的頂層子產品,時鐘生成,例化
#
=============================================================================*/


/*----------------------------------------------------------------------------------------------------
sdram初始化
cmd真值表		cs_n	ras_n	cas_n	we_n	ba[1:0]	addr[12:11]	  addr[10]    addr[9:0]
	NOP			0		1		1		1		X		  X			    X		     X
	PALL		0		0		1		0		X		  x			    1		     X
	REF			0		0		0		1		X		  X			    X		     X
    ACT         0       0       1       1       v         v             v            v
    RD          0       1       0       1       v         v             0            v
    WR          0       1       0       0       v         v             0            v

MR模式寄存器     {ba[1:0],addr[12:0]}    =   {00,000,000,011,0,010}
突發長度為4,順序突發,潛伏期為3,busrt read and burst write mode
		
-----------------------------------------------------------------------------------------------------*/

module  sdram_main_state(
    input   wire            clk     	,
    input   wire            rst     	,

    output  reg     [18:0]  cmd     	, //command{cs_n,ras_n,cas_n,we_n,ba,addr}
    inout   wire    [15:0]  dq      	,
	 output	wire				 wr_flag		,
	 output	wire				 rd_flag		,
	 output	wire				 init_done
);


//==================================================
//parameter define
//==================================================
parameter       IDLE    = 6'b00_0001;
parameter       INIT    = 6'b00_0010;//initial state
parameter       SW      = 6'b00_0100;//arbit state
parameter       REF     = 6'b00_1000;// refresh state
parameter       WRITE   = 6'b01_0000;// write state
parameter       READ    = 6'b10_0000;//read state

parameter       NOP         = {4'b0111,15'd0};      //no opreation ref_cmd



//==================================================
//internal signals
//==================================================
reg     [5:0]   state       ;//state register
//wire            init_done   ;//initialize state is done from init_module
wire    [18:0]  init_cmd    ;//initialize command

wire            ref_req     ;//refresh request from ref_module
wire            ref_en      ;//refresh enable from arbit to ref_module
wire            ref_done    ;//refresh state is finished
wire    [18:0]  ref_cmd     ;//refresh command

wire            wr_req      ;//write request from write_module
wire            wr_en       ;//write enable from arbit to write_module
wire            wr_done     ;//write state is finished
wire            wr_ref_break_flag;//write state is stopped by ref_req
wire    [18:0]  wr_cmd      ;
wire    [15:0]  wr_dq       ;

wire            rd_req      ;//read request from read_module
wire            rd_en       ;//read enable from arbit to read_module
wire            rd_done     ;//read state is finished
wire            rd_ref_break_flag;//read state is stopped by ref_req
wire    [18:0]  rd_cmd      ;//read command
wire    [15:0]  rd_dq       ;//sdram bus data
wire 	  [15:0]	 data_out	;//read data from sdram


always @(posedge clk)begin
    if(rst == 1'b1)begin
        state <= IDLE;
    end
    else begin
        case (state)
            IDLE:begin
                state <= INIT;//after reset,start to initialize 
            end

            INIT:begin
                if(init_done)begin//initialize is finished
                    state <= SW;
                end
                else begin
                    state <= state;
                end
            end

            SW:begin
                if(ref_req==1'b1)begin
                    state <= REF;
                end
                else if(wr_req==1'b1 && ref_req==1'b0 && rd_flag==1'b0)begin
                    state <= WRITE;
                end
                else if(rd_req==1'b1 && wr_req==1'b0 && ref_req==1'b0 && wr_flag==1'b0)begin
                    state <= READ;
                end
                else begin
                    state <= state;
                end
            end

            REF:begin
                if(ref_done)begin
                    state <= SW;
                end
                else begin
                    state <= state;
                end
            end

            WRITE:begin
                if(wr_done || wr_ref_break_flag)begin
                    state <= SW;
                end
                else begin
                    state <= state;
                end
            end

            READ:begin
                if(rd_done || rd_ref_break_flag)begin
                    state <= SW;
                end
                else begin
                    state <= state;
                end
            end

            default:begin
                state <= IDLE;
            end
        endcase
    end
end

assign  ref_en  = (state==SW) && (ref_req==1'b1);//when state is arbit and recive a ref_req
assign  wr_en   = (state==SW) && (ref_req==1'b0) && (wr_req==1'b1) && (rd_flag==1'b0);
assign  rd_en   = (state==SW) && (ref_req==1'b0) && (wr_req==1'b0) && (rd_req==1'b1) && (wr_flag==1'b0);

always  @(*)begin
    case(state)
        INIT:begin
            cmd = init_cmd;
        end

        REF:begin
            cmd = ref_cmd;
        end

        WRITE:begin
            cmd = wr_cmd;
        end

        READ:begin
            cmd = rd_cmd;
        end

        default:begin
            cmd = NOP;
        end
    endcase
end

assign  dq =(state==WRITE)?wr_dq:16'hz;
assign  rd_dq = dq;



sdram_init sdram_init_inst(
	.clk            (clk		),	//50MHZ
	.rst            (rst 		),
	
	.init_done  	(init_done 	),
	.init_cmd       (init_cmd 	)
);
	

sdram_ref sdram_ref_inst(
    .clk         	(clk 			),
    .rst         	(rst	),
    .init_done   	(init_done  ),//initialize state is finished
    .ref_en      	(ref_en 		),//refresh enable
    .ref_req     	(ref_req 	),//refresh request
    .ref_done    	(ref_done   ),//refresh done
    .ref_cmd     	(ref_cmd 	) //ref_cmd{cs_n,ras_n,cas_n,we_n,bank[1:0],addr[11:0]}
);

sdram_wr sdram_wr_inst (
    .clk 			(clk			), 
    .rst 			(rst			), 
    .wr_en 			(wr_en 		), 
    .ref_req 		(ref_req 	), 
	 .init_done 	(init_done 	),
    .wr_req 		(wr_req 		), 
    .wr_ref_break (wr_ref_break_flag), 
    .wr_done 		(wr_done 	), 
    .wr_cmd 		(wr_cmd		), 
    .wr_dq 			(wr_dq 		),
	 .wr_flag		(wr_flag		)
    );

sdram_rd sdram_rd_inst (
    .clk				(clk			), 
    .rst 			(rst	), 
    .ref_req 		(ref_req 	), 
    .rd_en 			(rd_en 		), 
    .rd_dq 			(rd_dq 		), 
	 .init_done		(init_done	),
    .rd_req 		(rd_req 		), 
    .rd_done 		(rd_done		), 
    .rd_ref_break (rd_ref_break_flag), 
    .rd_cmd 		(rd_cmd 		), 
    .rd_data 		(data_out 	),
	 .rd_flag		(rd_flag		)
    );
	 


endmodule

           

仿真結果

SDRAM及DDR3複習筆記及FPGA實作(二)

源碼位址

繼續閱讀