SDRAM及DDR3複習筆記及FPGA實作(二)
DDR與SDRAM的差別
記憶體可分為DRAM動态随機存取記憶體和SRAM靜态随機存取記憶體兩種。兩種存儲器都是揮發性的記憶體,SRAM的主要使用flip-flop正反器,通常用于快取(Cache),而DRAM則是使用電容器及半導體組成。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL5NmeNpXV61kMNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL1YzN0EzMzYTM4AjNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
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主要制器,初始化子產品,重新整理子產品,寫子產品,讀子產品
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
仿真結果
源碼位址