感谢邓堪文大佬 !
SDRAM
同步动态随机存取内存(synchronousdynamic randon-access menory,简称SDRAM)是有一个同步接口的动态随机存取内存(DRAM)。通常DRAM是有一个异步接口的,这样它可以随时响应控制输入的变化。而SDRAM有一个同步接口,在响应控制输入前会等待一个时钟信号,这样就能和计算机的系统总线同步。时钟被用来驱动一个有限状态机,对进入的指令进行管线操作。这使得SDRAM与没有同步接口的异步DRAM相比,可以有一个更复杂的操作模式。
管线意味着芯片可以在处理完之前的指令前,接受一个新的指令。在一个写入的管线中,写入命令在另一个指令执行完之后可以立刻执行,而不需要等到数据写入存储队列的时间。在一个读取的流水线中,需要的数据在读取指令发出之后固定数量的时钟频率后到达,而这个等待的过程可以发出其他附加指令。这种延迟被称为等待时间(Latency),在为计算机购买内存时是一个很重要的参数。
SDRAM之所以称为DRAM就是因为他要不断进行刷新才能保留住数据,因为刷新是DRAM最重要的操作。那么要隔多长时间重复一次刷新,目前公认的标准是,存储体中电容的数据有效保存期上限是64ms,也就是每一行刷新的循环周期是64ms。 SDRAM是多Bank结构,例如在一个具有两个Bank的SDRAM模组中,其中一个Bank在进行预充电期间,另一个Bank却马上可以被读取,这样当进行一次读取后,又马上读取已经预充电Bank的数据时,就无需等待而是可以直接读取了,这也就大大提高了存储器的访问速度。
随机访问存储器(RAM)分为静态RAM(SRAM)和动态RAM(DRAM)。由于动态存储器存储单元的结构非常简单,所以它能达到的集成度远高于静态存储器。但是动态存储器的存取速度不如静态存储器快。
RAM的动态存储单元是利用电容可以存储电荷的原理制成的。由于存储单元的机构能够做得很简单,所以在大容量、高集成度的RAM中得到了普遍的应用。但是由于电容的容量很小,而漏电流又不可能绝对等于零,所以电荷保存的时间有限。为了及时补充漏掉的电荷以避免存储的信号丢失,必须定时地给电容补充电荷,通常将这种操作称为刷新。
行列地址线被选中后,数据线(data_bit)直接和电容相连接。当写入时,数据线给电容充放电;读取时,电容将数据线拉高或者置低。
SDRAM 的全称即同步动态随机存储器(Synchronous Dynamic Random Access Memory);这里的同步是指其时钟频率与对应控制器的系统时钟频率相同,并且内部命令的发送与数据传输都是以该时钟为基准;动态是指存储阵列需要不断的刷新来保证数据不丢失。
SDR SDRAM中的SDR是指单数据速率,即每一根数据线上,每个时钟只传输一个bit的数据。SDR SDRAM的时钟频率可以达到100MHz以上,按照100MHz的速率计算,一片16位数据宽度的SDR SDRAM的读写数据带宽可以达到1.6Gbit/s。
SDR SDRAM需要时钟端和时钟使能端。SDR SDRAM所有的操作都依靠于此时钟;当时钟使能端无效时,SDR SDRAM自动忽略时钟上升沿。
SDR SDRAM拥有四个命令控制线,分别为CS、RAS、CAS、WE。组成的命令表如下:
在写入数据时,有时会出现不想对某8bit进行写入,就可以采用DQM进行控制。
SDR SDRAM的内部机构为:
由于SDR SDRAM为DRAM,内部的存储都是靠电容进行保存数据,电容的保持数据的时间为64ms,SDR SDRAM每次只能够刷新一行,为了不丢失任何数据,所以要保证64ms内,将所有的行都要刷新一遍。
在SDR SDRAM正常使用之前,需要进行初始化。初始化的时序图如下:
在PRECHARGE时,A10为高,表示选中所有的bank;A10为低,表示选中BA0、BA1所指定的bank。初始化中,A10置高。
在LOAD MOOE REGISTER中,采用地址线进行配置模式寄存器。说明如下:
在模式配置中,利用CL(CAS Latency)表示列选通潜伏期,利用BL(Burst Length)表示突发长度。
SDR SDRAM中有内部的刷新控制器和刷新的行计数器,外部控制器只需要保证在64ms之内进行8192次刷新即可。
在进行PRECHARGE时,A10要为高电平。
自动刷新时序:
SDR SDRAM中,可以在任意位置进行写入。写入的时序图如下:
SDR SDRAM中,可以在任意位置进行读出。读出的时序图如下:
在各个时序中的时序参数如下:
设计分析
该控制器共有四部分功能,初始化、刷新、写和读。四部分的执行控制采用一个模块来控制。
SDR SDRAM必须要进行初始化,初始化只用执行一次。然后启动一个计时器,等计时器达到后,进行刷新。在刷新的间隔中,根据读写的要求进行读写。
四个模块都会对SDR SDRAM的命令线和地址线进行控制,所以输出时,采用多路选择器对齐进行选择输出。
四个模块按照对应的时序图进行编写代码即可。
初始化sdram_init模块
// -----------------------------------------------------------------------------
// Author : RLG
// File : sdram_init.v
`timescale 1ns / 1ps
module sdram_init(
input clk ,
input reset_n ,
output reg [3 :0] cmd_reg ,
output wire [11:0] sdram_addr ,
output wire flag_init_end
);
/*-------------------------------------------------------------*\
********* Define Parameter and Internal Signals **********
\*-------------------------------------------------------------*/
localparam DELAY_200US = 10000 ;
//SDRAM Command
localparam NOP = 4'b0111 ;
localparam PRE = 4'b0010 ;
localparam AREF = 4'b0001 ;
localparam MSET = 4'b0000 ;
reg [13:0] cnt_200us ;
wire flag_200us ;
reg [3 :0] cnt_cmd ;
/*-------------------------------------------------------------*\
********* main code **********
\*-------------------------------------------------------------*/
always @(posedge clk ) begin
if(~reset_n) begin
cnt_200us <= 0;
end else if(~flag_200us) begin
cnt_200us <= cnt_200us +1 ;
end
end
always @(posedge clk) begin
if(~reset_n) begin
cnt_cmd <= 0;
end
else if(flag_200us && ~flag_init_end )begin
cnt_cmd <= cnt_cmd + 1;
end
end
always @(posedge clk or negedge reset_n) begin
if(~reset_n) begin
cmd_reg <= NOP;
end else if(flag_200us) begin
case (cnt_cmd)
0 : cmd_reg <= PRE ;
1 : cmd_reg <= AREF ;
5 : cmd_reg <= AREF ;
9 : cmd_reg <= MSET ;
default : cmd_reg <= PRE ;
endcase
end
end
assign flag_init_end = (cnt_cmd >= 4'd10) ? 1'b1 : 1'b0;
assign sdram_addr = (cmd_reg == MSET) ? 12'b0000_0011_0010 : 12'b0100_0000_0000;
assign flag_200us = (cnt_200us >= DELAY_200US) ? 1'b1 : 1'b0;
endmodule
刷新sdram_aref模块
`timescale 1ns / 1ps
module sdram_aref(
input clk ,
input reset_n ,
input ref_en ,
output reg ref_req ,
output flag_ref_end ,
output reg [3 :0] aref_cmd ,
output [11:0] sdram_addr ,
input flag_init_end
);
/*-------------------------------------------------------------*\
********* Define Parameter and Internal Signals **********
\*-------------------------------------------------------------*/
localparam DELAY_15US = 749 ;
localparam CMD_AREF = 4'b0001 ;
localparam CMD_NOP = 4'b0111 ;
localparam CMD_PRE = 4'b0010 ;
reg [3:0] cmd_cnt ;
reg [9:0] ref_cnt;
reg flag_ref ;
/*-------------------------------------------------------------*\
********* main code **********
\*-------------------------------------------------------------*/
always @(posedge clk ) begin
if(~reset_n) begin
ref_cnt <= 0;
end else if(ref_cnt == DELAY_15US) begin
ref_cnt <= 0;
end
else if(flag_init_end)
ref_cnt <= ref_cnt + 1'b1;
end
always @(posedge clk ) begin
if(~reset_n) begin
flag_ref <= 0;
end
else if (flag_ref_end)
flag_ref <= 0;
else if(ref_en)begin
flag_ref <= 1;
end
end
always @(posedge clk ) begin
if(~reset_n) begin
cmd_cnt <= 0;
end else if(flag_ref ) begin
cmd_cnt <= cmd_cnt + 1'b1;
end
else
cmd_cnt <= 0;
end
always @(posedge clk ) begin
if(~reset_n) begin
aref_cmd <= CMD_NOP;
end else if(cmd_cnt == 2)
aref_cmd <= CMD_AREF;
else
aref_cmd <= CMD_NOP;
end
always @(posedge clk) begin
if(~reset_n) begin
ref_req <= 0;
end
else if(ref_en)
ref_req <= 0;
else if(ref_cnt >= DELAY_15US)begin
ref_req <= 1;
end
// else
// ref_req <= 0;
end
assign flag_ref_end = (cmd_cnt >= 4'd3) ? 1'b1 : 1'b0;
assign sdram_addr = 12'b0100_0000_0000;
endmodule
写sdram_write模块
`timescale 1ns / 1ps
module sdram_write(
input clk ,
input reset_n ,
input wr_en ,
output wr_req ,
output reg flag_wr_end ,
output reg [3 :0] wr_cmd ,
output reg [11:0] wr_addr ,
output wire [1 :0] bank_addr ,
input ref_req ,
input wr_trig ,
output reg [15:0] wr_data
);
/*-------------------------------------------------------------*\
********* Define Parameter and Internal Signals **********
\*-------------------------------------------------------------*/
localparam S_IDLE = 5'b00001 ; //1
localparam S_REQ = 5'b00010 ; //2
localparam S_ACT = 5'b00100 ; //4
localparam S_WR = 5'b01000 ; //8
localparam S_PRE = 5'b10000 ; //16
//SDRAM Commend
localparam CMD_NOP = 4'b0111 ;
localparam CMD_PRE = 4'b0010 ;
localparam CMD_AREF = 4'b0001 ;
localparam CMD_ACT = 4'b0011 ;
localparam CMD_WR = 4'b0100 ;
reg flag_wr ;
reg [4:0] state ;
//--------------------------------------------------------------
reg flag_act_end ;
reg flag_pre_end ;
reg sd_row_end ;
reg [1 :0] burst_cnt ;
reg [1 :0] burst_cnt_t ;
reg wr_data_end ;
//--------------------------------------------------------------
reg [3 :0] act_cnt ;
reg [3 :0] break_cnt ;
reg [6 :0] col_cnt ;
reg [6 :0] col_cnt_t ;
//--------------------------------------------------------------
reg [11:0] row_addr ;
wire [8 :0] col_addr ;
/*-------------------------------------------------------------*\
********* main code **********
\*-------------------------------------------------------------*/
//flag_wr
always @(posedge clk) begin
if(~reset_n) begin
flag_wr <= 0;
end
else if(wr_trig && ~flag_wr)begin
flag_wr <= 1;
end
else if(wr_data_end)
flag_wr <= 0;
end
//burst_cnt
always @(posedge clk ) begin
if(~reset_n) begin
burst_cnt <= 0;
end else if(state == S_WR)begin
burst_cnt <= burst_cnt + 1;
end
else
burst_cnt <= 0;
end
//burst_cnt_t
always @(posedge clk) begin
burst_cnt_t <= burst_cnt;
end
//-----------------------------STATE-------------------------
always @(posedge clk ) begin
if(~reset_n) begin
state <= S_IDLE;
end else begin
case (state)
S_IDLE :
if(wr_trig)
state <= S_REQ;
else
state <= S_IDLE;
S_REQ :
if(wr_en)
state <= S_ACT;
else
state <= S_REQ;
S_ACT :
if(flag_act_end)
state <= S_WR;
else
state <= S_ACT;
S_WR :
if(wr_data_end)
state <= S_PRE;
else if(ref_req && burst_cnt_t == 2 && flag_wr)
state <= S_PRE;
else if(sd_row_end && flag_wr)
state <= S_PRE;
S_PRE :
if(ref_req && flag_wr)
state <= S_REQ;
else if(flag_pre_end && flag_wr)
state <= S_ACT;
else if(~flag_wr)
state <= S_IDLE;
// S_PRE:
// if(ref_req == 1'b1 && flag_wr == 1'b1)
// state <= S_REQ;
// else if(flag_pre_end == 1'b1 && flag_wr == 1'b1)
// state <= S_ACT;
// else if(flag_wr == 1'b0)
// state <= S_IDLE;
default : state <= S_IDLE;
endcase
end
end
//wr_cmd
always @(posedge clk ) begin
if(~reset_n) begin
wr_cmd <= CMD_NOP;
end else begin
case (state)
S_ACT :
if(act_cnt == 0)
wr_cmd <= CMD_ACT;
else
wr_cmd <= CMD_NOP;
S_WR :
if(burst_cnt ==0)
wr_cmd <= CMD_WR;
else
wr_cmd <= CMD_NOP;
S_PRE :
if(break_cnt ==0)
wr_cmd <= CMD_PRE;
else
wr_cmd <= CMD_NOP;
default : wr_cmd <= CMD_NOP;
endcase
end
end
//wr_addr
always @(*) begin
begin
case (state)
S_ACT :
if(act_cnt == 0)
wr_addr <= row_addr;
else
wr_addr <= wr_addr;
S_WR :
wr_addr <= {3'b000,col_addr};
S_PRE :
if(break_cnt == 0)
wr_addr <= {12'b0100_0000_0000};
else
wr_addr <= 0;
default : wr_addr <= 0;
endcase
end
end
//--------------------------------------------------------------
//flag_act_end
always @(posedge clk ) begin
if(~reset_n) begin
flag_act_end <= 0;
end else if(act_cnt == 'd3)begin
flag_act_end <= 1;
end
else
flag_act_end <= 0;
end
//act_cnt
always @(posedge clk ) begin
if(~reset_n) begin
act_cnt <= 0;
end else if(state == S_ACT)begin
act_cnt <= act_cnt + 1;
end
else
act_cnt <= 0;
end
always @(posedge clk or negedge reset_n) begin
if(~reset_n) begin
flag_wr_end <= 0;
end
else if((state == S_PRE && ref_req) || (state == S_PRE && ~flag_wr))begin
flag_wr_end <= 1;
end
else
flag_wr_end <= 0;
end
//flag_pre_end
always @(posedge clk ) begin
if(~reset_n) begin
flag_pre_end <= 0;
end else if(break_cnt == 'd3)begin
flag_pre_end <= 1;
end
else
flag_pre_end <= 0;
end
//break_cnt
always @(posedge clk ) begin
if(~reset_n) begin
break_cnt <= 0;
end else if(state == S_PRE)begin
break_cnt <= break_cnt + 1;
end
else
break_cnt <= 0;
end
//wr_data_end
always @(posedge clk ) begin
if(~reset_n) begin
wr_data_end <= 0;
end else if(row_addr == 1 && col_addr == 510) begin
wr_data_end <= 1;
end
else
wr_data_end <= 0;
end
//col_cnt
always @(posedge clk ) begin
if(~reset_n) begin
col_cnt <= 0;
end
else if(col_addr == 511 )
col_cnt <= 0;
else if(burst_cnt == 3 ) begin
col_cnt <= col_cnt + 1;
end
end
//row_addr
always @(posedge clk) begin
if(~reset_n) begin
row_addr <= 0;
end else if(sd_row_end) begin
row_addr <= row_addr + 1;
end
end
always @(posedge clk ) begin
if(~reset_n) begin
sd_row_end <= 0;
end
else if(col_addr == 'd509) begin
sd_row_end <= 1;
end
else
sd_row_end <= 0;
end
always @(posedge clk ) begin
col_cnt_t <= col_cnt;
end
//col_addr
assign col_addr = {col_cnt_t,burst_cnt_t};
assign bank_addr = 2'b00;
assign wr_req = state[1];
always @(*) begin
case (burst_cnt_t)
0 : wr_data <= 'd3;
1 : wr_data <= 'd5;
2 : wr_data <= 'd7;
3 : wr_data <= 'd9;
endcase
end
endmodule
读sdram_read模块
`timescale 1ns / 1ps
module sdram_read(
input clk ,
input reset_n ,
input rd_en ,
output rd_req ,
output reg flag_rd_end ,
output reg [3 :0] rd_cmd ,
output reg [11:0] rd_addr ,
output wire [1 :0] bank_addr ,
input ref_req ,
input rd_trig
// output reg [15:0] wr_data
);
/*-------------------------------------------------------------*\
********* Define Parameter and Internal Signals **********
\*-------------------------------------------------------------*/
localparam S_IDLE = 5'b00001 ; //1
localparam S_REQ = 5'b00010 ; //2
localparam S_ACT = 5'b00100 ; //4
localparam S_RD = 5'b01000 ; //8
localparam S_PRE = 5'b10000 ; //16
//SDRAM Commend
localparam CMD_NOP = 4'b0111 ;
localparam CMD_PRE = 4'b0010 ;
localparam CMD_AREF = 4'b0001 ;
localparam CMD_ACT = 4'b0011 ;
localparam CMD_RD = 4'b0101 ;
reg flag_rd ;
reg [4:0] state ;
//--------------------------------------------------------------
reg flag_act_end ;
reg flag_pre_end ;
reg sd_row_end ;
reg [1 :0] burst_cnt ;
reg [1 :0] burst_cnt_t ;
reg rd_data_end ;
//--------------------------------------------------------------
reg [3 :0] act_cnt ;
reg [3 :0] break_cnt ;
reg [6 :0] col_cnt ;
reg [6 :0] col_cnt_t ;
//--------------------------------------------------------------
reg [11:0] row_addr ;
wire [8 :0] col_addr ;
/*-------------------------------------------------------------*\
********* main code **********
\*-------------------------------------------------------------*/
//flag_rd
always @(posedge clk) begin
if(~reset_n) begin
flag_rd <= 0;
end
else if(rd_trig && ~flag_rd)begin
flag_rd <= 1;
end
else if(rd_data_end)
flag_rd <= 0;
end
//burst_cnt
always @(posedge clk ) begin
if(~reset_n) begin
burst_cnt <= 0;
end else if(state == S_RD)begin
burst_cnt <= burst_cnt + 1;
end
else
burst_cnt <= 0;
end
//burst_cnt_t
always @(posedge clk) begin
burst_cnt_t <= burst_cnt;
end
//-----------------------------STATE-------------------------
always @(posedge clk ) begin
if(~reset_n) begin
state <= S_IDLE;
end else begin
case (state)
S_IDLE :
if(rd_trig)
state <= S_REQ;
else
state <= S_IDLE;
S_REQ :
if(rd_en)
state <= S_ACT;
else
state <= S_REQ;
S_ACT :
if(flag_act_end)
state <= S_RD;
else
state <= S_ACT;
S_RD :
if(rd_data_end)
state <= S_PRE;
else if(ref_req && burst_cnt_t == 2 && flag_rd)
state <= S_PRE;
else if(sd_row_end && flag_rd)
state <= S_PRE;
S_PRE :
if(ref_req && flag_rd)
state <= S_REQ;
else if(flag_pre_end && flag_rd)
state <= S_ACT;
else if(~flag_rd)
state <= S_IDLE;
// S_PRE:
// if(ref_req == 1'b1 && flag_rd == 1'b1)
// state <= S_REQ;
// else if(flag_pre_end == 1'b1 && flag_rd == 1'b1)
// state <= S_ACT;
// else if(flag_rd == 1'b0)
// state <= S_IDLE;
default : state <= S_IDLE;
endcase
end
end
//rd_cmd
always @(posedge clk ) begin
if(~reset_n) begin
rd_cmd <= CMD_NOP;
end else begin
case (state)
S_ACT :
if(act_cnt == 0)
rd_cmd <= CMD_ACT;
else
rd_cmd <= CMD_NOP;
S_RD :
if(burst_cnt ==0)
rd_cmd <= CMD_RD;
else
rd_cmd <= CMD_NOP;
S_PRE :
if(break_cnt ==0)
rd_cmd <= CMD_PRE;
else
rd_cmd <= CMD_NOP;
default : rd_cmd <= CMD_NOP;
endcase
end
end
//rd_addr
always @(*) begin
begin
case (state)
S_ACT :
if(act_cnt == 0)
rd_addr <= row_addr;
else
rd_addr <= rd_addr;
S_RD :
rd_addr <= {3'b000,col_addr};
S_PRE :
if(break_cnt == 0)
rd_addr <= {12'b0100_0000_0000};
else
rd_addr <= 0;
default : rd_addr <= 0;
endcase
end
end
//--------------------------------------------------------------
//flag_act_end
always @(posedge clk ) begin
if(~reset_n) begin
flag_act_end <= 0;
end else if(act_cnt == 'd3)begin
flag_act_end <= 1;
end
else
flag_act_end <= 0;
end
//act_cnt
always @(posedge clk ) begin
if(~reset_n) begin
act_cnt <= 0;
end else if(state == S_ACT)begin
act_cnt <= act_cnt + 1;
end
else
act_cnt <= 0;
end
always @(posedge clk or negedge reset_n) begin
if(~reset_n) begin
flag_rd_end <= 0;
end
else if((state == S_PRE && ref_req) || (state == S_PRE && ~flag_rd))begin
flag_rd_end <= 1;
end
else
flag_rd_end <= 0;
end
//flag_pre_end
always @(posedge clk ) begin
if(~reset_n) begin
flag_pre_end <= 0;
end else if(break_cnt == 'd3)begin
flag_pre_end <= 1;
end
else
flag_pre_end <= 0;
end
//break_cnt
always @(posedge clk ) begin
if(~reset_n) begin
break_cnt <= 0;
end else if(state == S_PRE)begin
break_cnt <= break_cnt + 1;
end
else
break_cnt <= 0;
end
//rd_data_end
always @(posedge clk ) begin
if(~reset_n) begin
rd_data_end <= 0;
end else if(row_addr == 1 && col_addr == 510) begin
rd_data_end <= 1;
end
else
rd_data_end <= 0;
end
//col_cnt
always @(posedge clk ) begin
if(~reset_n) begin
col_cnt <= 0;
end
else if(col_addr == 511 )
col_cnt <= 0;
else if(burst_cnt == 3 ) begin
col_cnt <= col_cnt + 1;
end
end
//row_addr
always @(posedge clk) begin
if(~reset_n) begin
row_addr <= 0;
end else if(sd_row_end) begin
row_addr <= row_addr + 1;
end
end
always @(posedge clk ) begin
if(~reset_n) begin
sd_row_end <= 0;
end
else if(col_addr == 'd509) begin
sd_row_end <= 1;
end
else
sd_row_end <= 0;
end
always @(posedge clk ) begin
col_cnt_t <= col_cnt;
end
//col_addr
assign col_addr = {col_cnt_t,burst_cnt_t};
assign bank_addr = 2'b00;
assign rd_req = state[1];
endmodule
顶层sdram_top模块
`timescale 1ns / 1ps
module sdram_top(
input clk ,
input reset_n ,
output wire sdram_clk ,
output wire sdram_cke ,
output wire sdram_cs_n ,
output wire sdram_cas_n ,
output wire sdram_ras_n ,
output wire sdram_we_n ,
output wire [ 1:0] sdram_bank ,
output reg [11:0] sdram_addr ,
output wire [ 1:0] sdram_dqm ,
inout [15:0] sdram_dq ,
//other
input wr_trig ,
input rd_trig
);
localparam IDLE = 5'b0_0001;
localparam ARBIT = 5'b0_0010;
localparam AREF = 5'b0_0100;
localparam WRITE = 5'b0_1000;
localparam READ = 5'b1_0000;
// localparam IDLE = 5'B0_1000;
// localparam IDLE = 5'B1_0000;
reg [3 :0] sd_cmd ;
wire [3 :0] init_cmd ;
wire flag_init_end ;
wire [11:0] init_addr ;
reg [4 :0] state ;
//Refresh module
wire ref_req ;
reg ref_en ;
wire flag_ref_end ;
wire [3 :0] ref_cmd ;
wire [11:0] ref_addr ;
//write module
wire [11:0] wr_addr ;
wire [1 :0] wr_bank_addr ;
wire [3 :0] wr_cmd ;
reg wr_en ;
wire wr_req ;
wire flag_wr_end ;
wire [15:0] wr_data ;
reg rd_en ;
wire rd_req ;
wire flag_rd_end ;
wire [3 :0] rd_cmd ;
wire [11:0] rd_addr ;
wire [1 :0] rd_bank_addr ;
always @(posedge clk ) begin
if(~reset_n) begin
state <= IDLE;
end else begin
case (state)
IDLE :
if(flag_init_end)
state <= ARBIT;
else
state <= IDLE;
ARBIT :
if(ref_en)
state <= AREF;
else if(wr_en)
state <= WRITE;
else if(rd_en)
state <= READ;
else
state <= ARBIT;
AREF :
if(flag_ref_end)
state <= ARBIT;
else
state <= AREF;
WRITE :
if(flag_wr_end)
state <= ARBIT;
else
state <= WRITE;
READ :
if(flag_rd_end)
state <= ARBIT;
else
state <= READ;
default :
state <= IDLE;
endcase
end
end
//ref_en
always @(posedge clk) begin
if(~reset_n) begin
ref_en <= 0;
end else if(state == ARBIT && ref_req)begin
ref_en <= 1;
end
else
ref_en <= 0;
end
//wr_en
always @(posedge clk) begin
if(~reset_n) begin
wr_en <= 0;
end else if(state == ARBIT && wr_req && ~ref_req)begin
wr_en <= 1;
end
else
wr_en <= 0;
end
//rd_en
always @(posedge clk ) begin
if(~reset_n) begin
rd_en <= 0;
end
else if(state == ARBIT && ~wr_req && ~ref_req && rd_req)begin
rd_en <= 1;
end
else
rd_en <= 0;
end
always @(*) begin
case (state)
IDLE : begin
sd_cmd <= init_cmd ;
sdram_addr <= init_addr;
end
AREF : begin
sd_cmd <= ref_cmd ;
sdram_addr <= ref_addr;
end
WRITE : begin
sd_cmd <= wr_cmd;
sdram_addr <= wr_addr;
end
READ :begin
sd_cmd <= rd_cmd;
sdram_addr <= rd_addr;
end
default :begin
sd_cmd <= 4'b0111 ; //NOP
sdram_addr <= 'd0 ;
end
endcase
end
// assign sdram_addr = (state == IDLE) ? init_addr : ref_addr;
assign sdram_dqm = 2'b00 ;
assign sdram_cke = 1 ;
assign sdram_clk = ~clk ;
assign {sdram_cs_n ,sdram_ras_n ,sdram_cas_n,sdram_we_n} = sd_cmd;
// (state == IDLE) ? init_cmd : ref_cmd;
assign sdram_dq = (state == WRITE) ? wr_data : {16{1'bz}};
assign sdram_bank = (state == WRITE) ? wr_bank_addr : rd_bank_addr;
sdram_init sdram_init
(
.clk (clk ),
.reset_n (reset_n ),
.cmd_reg (init_cmd ),
.sdram_addr (init_addr ),
.flag_init_end (flag_init_end )
);
sdram_aref sdram_aref
(
.clk (clk ),
.reset_n (reset_n ),
.ref_en (ref_en ),
.ref_req (ref_req ),
.flag_ref_end (flag_ref_end ),
.aref_cmd (ref_cmd ),
.sdram_addr (ref_addr ),
.flag_init_end (flag_init_end )
);
sdram_write sdram_write
(
.clk (clk ),
.reset_n (reset_n ),
.wr_en (wr_en ),
.wr_req (wr_req ),
.flag_wr_end (flag_wr_end ),
.wr_cmd (wr_cmd ),
.wr_addr (wr_addr ),
.bank_addr (wr_bank_addr ),
.ref_req (ref_req ),
.wr_trig (wr_trig ),
.wr_data (wr_data )
);
sdram_read sdram_read
(
.clk (clk ),
.reset_n (reset_n ),
.rd_en (rd_en ),
.rd_req (rd_req ),
.flag_rd_end (flag_rd_end ),
.rd_cmd (rd_cmd ),
.rd_addr (rd_addr ),
.bank_addr (rd_bank_addr ),
.ref_req (ref_req ),
.rd_trig (rd_trig )
);
endmodule
测试模块
测试顶层:
// -----------------------------------------------------------------------------
// Author : RLG
// File : tb_sdram_top.v
`timescale 1ns / 1ps
module tb_sdram_top;
reg clk;
reg reset_n;
wire sdram_clk;
wire sdram_cke;
wire sdram_cs_n;
wire sdram_cas_n;
wire sdram_ras_n;
wire sdram_we_n;
wire [ 1:0] sdram_bank;
wire [11:0] sdram_addr;
wire [ 1:0] sdram_dqm;
wire [15:0] sdram_dq;
reg wr_trig ;
reg rd_trig;
defparam sdram_model_plus_inst.addr_bits = 12 ;
defparam sdram_model_plus_inst.data_bits = 16 ;
defparam sdram_model_plus_inst.col_bits = 9 ;
defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024 ; //2m
initial begin
wr_trig <= 0;
rd_trig <= 0;
#205000;
wr_trig <= 1;
#20;
wr_trig <= 0;
#226500;
rd_trig <= 1;
#20;
rd_trig <= 0;
end
initial begin
clk = 1;
reset_n = 0;
#100;
reset_n = 1;
end
always #10 clk = ~clk;
sdram_top sdram_top
(
.clk (clk),
.reset_n (reset_n),
.sdram_clk (sdram_clk),
.sdram_cke (sdram_cke),
.sdram_cs_n (sdram_cs_n),
.sdram_cas_n (sdram_cas_n),
.sdram_ras_n (sdram_ras_n),
.sdram_we_n (sdram_we_n),
.sdram_bank (sdram_bank),
.sdram_addr (sdram_addr),
.sdram_dqm (sdram_dqm),
.sdram_dq (sdram_dq),
.wr_trig (wr_trig ),
.rd_trig (rd_trig)
);
sdram_model_plus sdram_model_plus_inst (
.Dq (sdram_dq ),
.Addr (sdram_addr ),
.Ba (sdram_bank ),
.Clk (sdram_clk ),
.Cke (sdram_cke ),
.Cs_n (sdram_cs_n ),
.Ras_n (sdram_ras_n ),
.Cas_n (sdram_cas_n ),
.We_n (sdram_we_n ),
.Dqm (sdram_dqm ),
.Debug ( 1 )
);
endmodule
其中sdram_model_plus在这---> 【免费】SDRAM读写控制仿真模型资源-CSDN文库 获取。
以及SDRAM数据手册在这---> 【免费】SDRAM手册资源-CSDN文库 获取。