FPGA SDRAM读写控制器

感谢邓堪文大佬 !

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拥有四个命令控制线,分别为CSRASCASWE。组成的命令表如下:

        在写入数据时,有时会出现不想对某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文库 获取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/10878.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Node.js基础:从入门到实战

初识 Node.js 与内置模块 &#xff08;初识&#xff09; 1、知道什么是node.js 2、知道node.js可以做什么 3、node.js 中js的组成部分 &#xff08;内置模块&#xff09; 4、用 fs 模块读写操作文件 5、使用 path 模块处理路径 6、使用http 模块写一个基本的web服务器 初识 N…

设计模式——模板设计模式(Template Method)

模板设计-base 什么是模板&#xff1f; 举个简单的例子&#xff0c;以AABB的格式&#xff0c;写出一个词语&#xff0c;你可能会想到&#xff0c;明明白白&#xff0c;干干净净等&#xff0c; 这个AABB就是一个模板&#xff0c;对模板心中有了一个清晰的概念之后&#xff0c;…

环境变量(全)

概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪里&#xff0c;但是照样可以链接成功&#xff0c;生成可执…

今日arXiv最热NLP大模型论文:揭露大语言模型短板,北京大学提出事件推理测试基准

人工智能领域又一里程碑时刻&#xff01;北京大学、北京智源人工智能研究院等机构联合推出大型事件推理评测基准 。这是首个同时在知识和推理层面全面评估大模型事件推理能力的数据集。 总所周知&#xff0c;事件推理需要丰富的事件知识和强大的推理能力&#xff0c;涉及多种推…

consul启动Error_server_rejoin_age_max (168h0m0s) - consider wiping your data dir

consul 启动报错&#xff1a; consul[11880]: 2024-05-12T08:37:51.095-0400 [ERROR] agent: startup error: error"refusing to rejoin cluster because server has been offline for more than the configured server_rejoin_age_max (168h0m0s) - consider wiping you…

【GD32】02-ADC模拟数字转换器

ADC 在电子和通信技术中&#xff0c;ADC&#xff08;模拟数字转换器&#xff09;是一种将模拟信号转换为数字信号的电子设备。这种转换是电子系统中非常关键的一个环节&#xff0c;因为数字信号更易于处理、存储和传输。ADC的工作原理通常包括采样、保持、量化和编码等步骤。采…

http协议 tomcat如何访问资源 servlet理论介绍

tomcat介绍 bin是启动命令&#xff1b; conf是配置&#xff0c;可以修改端口号&#xff1b; lib是依赖的jar包&#xff1b; logs是日志 webapps是重点&#xff0c;在这里新建我们自己的javaWeb项目 tomcat如何访问资源 tomcat通过统一资源定位符&#xff08;URL&#xff09;来…

乡村振兴与农村基础设施建设:加大农村基础设施建设投入,提升农村公共服务水平,改善农民生产生活条件,构建宜居宜业的美丽乡村

一、引言 乡村振兴是我国现代化进程中的重要战略&#xff0c;而农村基础设施建设则是乡村振兴的基石。随着城市化进程的加快&#xff0c;农村基础设施建设滞后的问题日益凸显&#xff0c;成为制约乡村发展的瓶颈。因此&#xff0c;加大农村基础设施建设投入&#xff0c;提升农…

AI大模型探索之路-训练篇21:Llama2微调实战-LoRA技术微调步骤详解

系列篇章&#x1f4a5; AI大模型探索之路-训练篇1&#xff1a;大语言模型微调基础认知 AI大模型探索之路-训练篇2&#xff1a;大语言模型预训练基础认知 AI大模型探索之路-训练篇3&#xff1a;大语言模型全景解读 AI大模型探索之路-训练篇4&#xff1a;大语言模型训练数据集概…

华为OD机试 - 执行任务赚积分 - 动态规划(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷+B卷+C卷)》。 刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。 一、题目描述 现有 N 个任…

Gradle基础学习(六) 认识任务Task

理解Gradle中的任务 Gradle的构建过程基于任务&#xff08;Task&#xff09;的概念&#xff0c;而每个任务都可以包含一个或多个动作&#xff08;Action&#xff09;。 任务是构建中执行的一些独立的工作单元&#xff0c;例如编译类、创建JAR、生成Javadoc或将存档发布到仓库…

4.5网安学习第四阶段第五周回顾(个人学习记录使用)

本周重点 ①部署域环境&#xff08;Win2008&#xff09; ②域组策略 ③域内信息收集 ④(重点)哈希传递攻击PTH ⑤MS14-068 提权漏洞 ⑥黄金票据伪造 ⑦白银票据伪造 ⑧ZeroLogon (CVE-2020-1472) 漏洞复现 本周主要内容 ①部署域环境&#xff08;Win2008&#xff09;…

【算法】滑动窗口——串联所有单词的子串

今天来以“滑动窗口”的思想来详解一道比较困难的题目——串联所有单词的子串&#xff0c;有需要借鉴即可。 目录 1.题目2.下面是示例代码3.总结 1.题目 题目链接&#xff1a;LINK 这道题如果把每个字符串看成一个字母&#xff0c;就是另外一道中等难度的题目&#xff0c;即&…

不同路径| 和 不同路径||

不同路径| 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xf…

大学生体质测试|基于Springboot+vue的大学生体质测试管理系统设计与实现(源码+数据库+文档)

大学生体质测试管理系统 目录 基于Springboot&#xff0b;vue的大学生体质测试管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3用户功能模块 4教师功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算…

C++笔试强训day20

目录 1.经此一役小红所向无敌 2.连续子数组最大和 3.非对称之美 1.经此一役小红所向无敌 链接 简单模拟即可。 需要注意的是&#xff1a; 除完之后有无余数&#xff0c;若有&#xff0c;则还可以再挨一次打。 #include <iostream> using namespace std; #define in…

设计模式——结构型模式——代理模式(静态代理、动态代理:JDK、CGLIB)

目录 代理模式 代理模式简介 代理模式的分类 代理模式组成 代理模式的优缺点 静态代理 背景前置 编写代码 JDK动态代理 编写代码 使用Arthas分析JDK动态代理底层原理 CGLIB动态代理 编写代码 三种代理的对比 代理模式使用场景 代理模式 代理模式简介 代理模式属…

Mybatis操作数据库的两种方式:Mapper代理模式

1.Mapper代理模式的特点 程序员没有写接口的子实现——直接获取数据库的数据 因为Mybatis定义了一套规则&#xff0c;对方法进行了实现&#xff0c;程序员只要遵循这套方法就可以直接使用 2.如何实现Mapper代理模式 步骤&#xff1a; 1.创建一个dao接口&#xff0c;在接口…

java项目之英语知识应用网站源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的英语知识应用网站。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 英语知识应用网站的主要…

【免费】AME最新Adobe Media Encoder电脑软件安装包2024-2018支持WIN和MAC

Adobe MediaEncoder「Me」2024是一款功能强大的转码和媒体处理软件&#xff0c;它不仅能轻松应对各种媒体文件的编码和导出需求&#xff0c;还支持多种视频格式和分辨率&#xff0c;让你的视频处理变得更加高效。此外&#xff0c;该软件界面简洁明了&#xff0c;操作简便&#…