感谢邓堪文大佬 !
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 Commandlocalparam 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) begincnt_200us <= 0;end else if(~flag_200us) begincnt_200us <= cnt_200us +1 ;endendalways @(posedge clk) begin if(~reset_n) begincnt_cmd <= 0;end else if(flag_200us && ~flag_init_end )begincnt_cmd <= cnt_cmd + 1;endendalways @(posedge clk or negedge reset_n) beginif(~reset_n) begincmd_reg <= NOP;end else if(flag_200us) begincase (cnt_cmd)0 : cmd_reg <= PRE ;1 : cmd_reg <= AREF ;5 : cmd_reg <= AREF ;9 : cmd_reg <= MSET ; default : cmd_reg <= PRE ;endcaseendendassign 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 ) beginif(~reset_n) beginref_cnt <= 0;end else if(ref_cnt == DELAY_15US) beginref_cnt <= 0;endelse if(flag_init_end)ref_cnt <= ref_cnt + 1'b1;endalways @(posedge clk ) beginif(~reset_n) beginflag_ref <= 0;end else if (flag_ref_end)flag_ref <= 0;else if(ref_en)beginflag_ref <= 1;endendalways @(posedge clk ) beginif(~reset_n) begincmd_cnt <= 0;end else if(flag_ref ) begincmd_cnt <= cmd_cnt + 1'b1;endelsecmd_cnt <= 0;endalways @(posedge clk ) beginif(~reset_n) beginaref_cmd <= CMD_NOP;end else if(cmd_cnt == 2)aref_cmd <= CMD_AREF;elsearef_cmd <= CMD_NOP;endalways @(posedge clk) beginif(~reset_n) beginref_req <= 0;end else if(ref_en)ref_req <= 0;else if(ref_cnt >= DELAY_15US)beginref_req <= 1;end// else// ref_req <= 0;endassign 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 ; //1localparam S_REQ = 5'b00010 ; //2localparam S_ACT = 5'b00100 ; //4localparam S_WR = 5'b01000 ; //8localparam S_PRE = 5'b10000 ; //16//SDRAM Commendlocalparam 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_wralways @(posedge clk) begin if(~reset_n) beginflag_wr <= 0;end else if(wr_trig && ~flag_wr)beginflag_wr <= 1;endelse if(wr_data_end)flag_wr <= 0;end//burst_cntalways @(posedge clk ) begin if(~reset_n) beginburst_cnt <= 0;end else if(state == S_WR)beginburst_cnt <= burst_cnt + 1;endelseburst_cnt <= 0;end//burst_cnt_talways @(posedge clk) beginburst_cnt_t <= burst_cnt;end//-----------------------------STATE-------------------------always @(posedge clk ) beginif(~reset_n) beginstate <= S_IDLE;end else begincase (state)S_IDLE : if(wr_trig)state <= S_REQ;elsestate <= S_IDLE;S_REQ :if(wr_en)state <= S_ACT;elsestate <= S_REQ;S_ACT :if(flag_act_end)state <= S_WR;elsestate <= 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;endcaseendend//wr_cmdalways @(posedge clk ) begin if(~reset_n) beginwr_cmd <= CMD_NOP;end else begincase (state)S_ACT : if(act_cnt == 0)wr_cmd <= CMD_ACT;elsewr_cmd <= CMD_NOP;S_WR :if(burst_cnt ==0)wr_cmd <= CMD_WR;elsewr_cmd <= CMD_NOP;S_PRE :if(break_cnt ==0)wr_cmd <= CMD_PRE;else wr_cmd <= CMD_NOP;default : wr_cmd <= CMD_NOP;endcaseendend//wr_addralways @(*) beginbegincase (state)S_ACT :if(act_cnt == 0)wr_addr <= row_addr;elsewr_addr <= wr_addr;S_WR :wr_addr <= {3'b000,col_addr};S_PRE :if(break_cnt == 0)wr_addr <= {12'b0100_0000_0000};elsewr_addr <= 0;default : wr_addr <= 0;endcaseendend//--------------------------------------------------------------//flag_act_endalways @(posedge clk ) begin if(~reset_n) beginflag_act_end <= 0;end else if(act_cnt == 'd3)beginflag_act_end <= 1;endelseflag_act_end <= 0;end//act_cntalways @(posedge clk ) begin if(~reset_n) beginact_cnt <= 0;end else if(state == S_ACT)beginact_cnt <= act_cnt + 1;endelseact_cnt <= 0;endalways @(posedge clk or negedge reset_n) begin if(~reset_n) beginflag_wr_end <= 0;end else if((state == S_PRE && ref_req) || (state == S_PRE && ~flag_wr))beginflag_wr_end <= 1;endelseflag_wr_end <= 0;end//flag_pre_endalways @(posedge clk ) begin if(~reset_n) beginflag_pre_end <= 0;end else if(break_cnt == 'd3)beginflag_pre_end <= 1;endelseflag_pre_end <= 0;end//break_cntalways @(posedge clk ) begin if(~reset_n) beginbreak_cnt <= 0;end else if(state == S_PRE)beginbreak_cnt <= break_cnt + 1;endelsebreak_cnt <= 0;end//wr_data_endalways @(posedge clk ) begin if(~reset_n) beginwr_data_end <= 0;end else if(row_addr == 1 && col_addr == 510) beginwr_data_end <= 1;endelsewr_data_end <= 0;end//col_cntalways @(posedge clk ) beginif(~reset_n) begincol_cnt <= 0;end else if(col_addr == 511 )col_cnt <= 0;else if(burst_cnt == 3 ) begincol_cnt <= col_cnt + 1;endend//row_addralways @(posedge clk) begin if(~reset_n) beginrow_addr <= 0;end else if(sd_row_end) beginrow_addr <= row_addr + 1;endendalways @(posedge clk ) begin if(~reset_n) beginsd_row_end <= 0;end else if(col_addr == 'd509) beginsd_row_end <= 1;endelsesd_row_end <= 0;endalways @(posedge clk ) begin col_cnt_t <= col_cnt;end//col_addrassign 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;endcaseendendmodule
读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 ; //1localparam S_REQ = 5'b00010 ; //2localparam S_ACT = 5'b00100 ; //4localparam S_RD = 5'b01000 ; //8localparam S_PRE = 5'b10000 ; //16//SDRAM Commendlocalparam 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_rdalways @(posedge clk) begin if(~reset_n) beginflag_rd <= 0;end else if(rd_trig && ~flag_rd)beginflag_rd <= 1;endelse if(rd_data_end)flag_rd <= 0;end//burst_cntalways @(posedge clk ) begin if(~reset_n) beginburst_cnt <= 0;end else if(state == S_RD)beginburst_cnt <= burst_cnt + 1;endelseburst_cnt <= 0;end//burst_cnt_talways @(posedge clk) beginburst_cnt_t <= burst_cnt;end//-----------------------------STATE-------------------------always @(posedge clk ) beginif(~reset_n) beginstate <= S_IDLE;end else begincase (state)S_IDLE : if(rd_trig)state <= S_REQ;elsestate <= S_IDLE;S_REQ :if(rd_en)state <= S_ACT;elsestate <= S_REQ;S_ACT :if(flag_act_end)state <= S_RD;elsestate <= 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;endcaseendend//rd_cmdalways @(posedge clk ) begin if(~reset_n) beginrd_cmd <= CMD_NOP;end else begincase (state)S_ACT : if(act_cnt == 0)rd_cmd <= CMD_ACT;elserd_cmd <= CMD_NOP;S_RD :if(burst_cnt ==0)rd_cmd <= CMD_RD;elserd_cmd <= CMD_NOP;S_PRE :if(break_cnt ==0)rd_cmd <= CMD_PRE;else rd_cmd <= CMD_NOP;default : rd_cmd <= CMD_NOP;endcaseendend//rd_addralways @(*) beginbegincase (state)S_ACT :if(act_cnt == 0)rd_addr <= row_addr;elserd_addr <= rd_addr;S_RD :rd_addr <= {3'b000,col_addr};S_PRE :if(break_cnt == 0)rd_addr <= {12'b0100_0000_0000};elserd_addr <= 0;default : rd_addr <= 0;endcaseendend//--------------------------------------------------------------//flag_act_endalways @(posedge clk ) begin if(~reset_n) beginflag_act_end <= 0;end else if(act_cnt == 'd3)beginflag_act_end <= 1;endelseflag_act_end <= 0;end//act_cntalways @(posedge clk ) begin if(~reset_n) beginact_cnt <= 0;end else if(state == S_ACT)beginact_cnt <= act_cnt + 1;endelseact_cnt <= 0;endalways @(posedge clk or negedge reset_n) begin if(~reset_n) beginflag_rd_end <= 0;end else if((state == S_PRE && ref_req) || (state == S_PRE && ~flag_rd))beginflag_rd_end <= 1;endelseflag_rd_end <= 0;end//flag_pre_endalways @(posedge clk ) begin if(~reset_n) beginflag_pre_end <= 0;end else if(break_cnt == 'd3)beginflag_pre_end <= 1;endelseflag_pre_end <= 0;end//break_cntalways @(posedge clk ) begin if(~reset_n) beginbreak_cnt <= 0;end else if(state == S_PRE)beginbreak_cnt <= break_cnt + 1;endelsebreak_cnt <= 0;end//rd_data_endalways @(posedge clk ) begin if(~reset_n) beginrd_data_end <= 0;end else if(row_addr == 1 && col_addr == 510) beginrd_data_end <= 1;endelserd_data_end <= 0;end//col_cntalways @(posedge clk ) beginif(~reset_n) begincol_cnt <= 0;end else if(col_addr == 511 )col_cnt <= 0;else if(burst_cnt == 3 ) begincol_cnt <= col_cnt + 1;endend//row_addralways @(posedge clk) begin if(~reset_n) beginrow_addr <= 0;end else if(sd_row_end) beginrow_addr <= row_addr + 1;endendalways @(posedge clk ) begin if(~reset_n) beginsd_row_end <= 0;end else if(col_addr == 'd509) beginsd_row_end <= 1;endelsesd_row_end <= 0;endalways @(posedge clk ) begin col_cnt_t <= col_cnt;end//col_addrassign 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 ,//otherinput 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 modulewire ref_req ;reg ref_en ;wire flag_ref_end ;wire [3 :0] ref_cmd ;wire [11:0] ref_addr ;//write modulewire [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) beginstate <= IDLE;end else begincase (state)IDLE :if(flag_init_end)state <= ARBIT;elsestate <= 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;elsestate <= AREF;WRITE :if(flag_wr_end)state <= ARBIT;elsestate <= WRITE;READ :if(flag_rd_end)state <= ARBIT;elsestate <= READ;default : state <= IDLE;endcaseendend//ref_enalways @(posedge clk) begin if(~reset_n) beginref_en <= 0;end else if(state == ARBIT && ref_req)beginref_en <= 1;endelseref_en <= 0;end//wr_enalways @(posedge clk) begin if(~reset_n) beginwr_en <= 0;end else if(state == ARBIT && wr_req && ~ref_req)beginwr_en <= 1;endelsewr_en <= 0;end//rd_enalways @(posedge clk ) beginif(~reset_n) beginrd_en <= 0;end else if(state == ARBIT && ~wr_req && ~ref_req && rd_req)beginrd_en <= 1;endelse rd_en <= 0;endalways @(*) begin case (state)IDLE : begin sd_cmd <= init_cmd ; sdram_addr <= init_addr; endAREF : begin sd_cmd <= ref_cmd ; sdram_addr <= ref_addr; endWRITE : 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 ; //NOPsdram_addr <= 'd0 ;endendcaseend// 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 ; //2minitial begin wr_trig <= 0;rd_trig <= 0;#205000;wr_trig <= 1;#20;wr_trig <= 0;#226500;rd_trig <= 1;#20;rd_trig <= 0;endinitial beginclk = 1;reset_n = 0;#100;reset_n = 1;endalways #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文库 获取。