⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdram_ctrl.v

📁 sdram读写
💻 V
字号:
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company		: 
// Engineer		: 
// Create Date	: 
// Design Name	: 
// Module Name	: sdram_top
// Project Name	: 
// Target Device: Cyclone EP1C3T144C8 
// Tool versions: Quartus II 8.1
// Description	: SDRAM状态控制模块
//							SDRAM初始化以及定时刷新、读写控制
//				
// Revision		: V1.0
// Additional Comments	:  
// 
////////////////////////////////////////////////////////////////////////////////
module sdram_ctrl(
				clk,rst_n,
				/*sdram_udqm,sdram_ldqm,*/
				sdwr_byte,sdrd_byte,sys_r_wn,
				sys_en,sdram_wr_ack,sdram_rd_ack,
				sdram_busy,sys_dout_rdy,
				init_state,work_state,cnt_clk
			);
	//系统信号接口
input clk;				//系统时钟,50MHz
input rst_n;			//复位信号,低电平有效
	// SDRAM硬件接口
//output sdram_udqm;	// SDRAM高字节屏蔽
//output sdram_ldqm;	// SDRAM低字节屏蔽
	// SDRAM封装接口
//input sdram_wr_req;			//系统写SDRAM请求信号
//input sdram_rd_req;			//系统读SDRAM请求信号
input sys_en;
input sys_r_wn;
output sdram_wr_ack;		//系统写SDRAM响应信号,作为wrFIFO的输出有效信号
output sdram_rd_ack;		//系统读SDRAM响应信号	
//output sdram_ref_w;		// SDRAM自刷新请求信号
output sdram_busy;		// SDRAM忙标志位,高表示忙
output sys_dout_rdy;	// SDRAM数据输出完成标志
input[8:0] sdwr_byte;
input[8:0] sdrd_byte;
	// SDRAM内部接口
output[4:0] init_state;	// SDRAM初始化寄存器
output[3:0] work_state;	// SDRAM工作状态寄存器
output[8:0] cnt_clk;	//时钟计数


wire done_200us;		//上电后200us输入稳定期结束标志位
wire sdram_init_done;	// SDRAM初始化完成标志,高表示完成
wire sdram_busy;		// SDRAM忙标志,高表示SDRAM处于工作中
reg sdram_ref_req;		// SDRAM自刷新请求信号
wire sdram_ref_ack;		// SDRAM自刷新请求应答信号

`include "sdr_para.v"		// 包含SDRAM参数定义模块

	// SDRAM时序延时参数
parameter		TRP_CLK		= 9'd4,//1,	//TRP=18ns预充电有效周期
				TRFC_CLK	= 9'd6,//3,	//TRC=60ns自动预刷新周期
				TMRD_CLK	= 9'd6,//2,	//模式寄存器设置等待时钟周期
				TRCD_CLK	= 9'd2,//1,	//TRCD=18ns行选通周期
				TCL_CLK		= 9'd3,		//潜伏期TCL_CLK=3个CLK,在初始化模式寄存器中可设置
				TREAD_CLK	= 9'd256,	//突发读数据周期256CLK
				TWRITE_CLK	= 9'd256,  	//突发写数据256CLK
				TDAL_CLK	= 9'd3;	//写入等待

//------------------------------------------------------------------------------
//assign sdram_udqm = 1'b0;	// SDRAM数据高字节有效
//assign sdram_ldqm = 1'b0;	// SDRAM数据低字节有效

//------------------------------------------------------------------------------
//上电后200us计时,计时时间到,则done_200us=1          50MHZ
//------------------------------------------------------------------------------
reg[14:0] cnt_200us; 
always @ (posedge clk or negedge rst_n) 
	if(!rst_n) cnt_200us <= 15'd0;
	else if(cnt_200us < 15'd20_000) cnt_200us <= cnt_200us+1'b1;	//计数

assign done_200us = (cnt_200us == 15'd20_000);	//条件满足则done_200us=1

//------------------------------------------------------------------------------
//SDRAM的初始化操作状态机
//------------------------------------------------------------------------------
reg[4:0] init_state_r;	// SDRAM初始化状态

always @ (posedge clk or negedge rst_n)
	if(!rst_n) init_state_r <= `I_NOP;
	else //初始化阶段
		case (init_state_r)
				`I_NOP: 	init_state_r <= done_200us ? `I_PRE:`I_NOP;		//上电复位后200us结束则进入下一状态
				`I_PRE: 	init_state_r <= (TRP_CLK == 0) ? `I_AR1:`I_TRP;	//预充电状态
				`I_TRP: 	init_state_r <= (`end_trp) ? `I_AR1:`I_TRP;			//预充电等待TRP_CLK个时钟周期
				`I_AR1: 	init_state_r <= (TRFC_CLK == 0) ? `I_AR2:`I_TRF1;	//第1次自刷新
				`I_TRF1:	init_state_r <= (`end_trfc) ? `I_AR2:`I_TRF1;			//等待第1次自刷新结束,TRFC_CLK个时钟周期
				`I_AR2: 	init_state_r <= (TRFC_CLK == 0) ? `I_AR3:`I_TRF2; //第2次自刷新	
				`I_TRF2:	init_state_r <= (`end_trfc) ? `I_AR3:`I_TRF2; 		//等待第2次自刷新结束,TRFC_CLK个时钟周期
				`I_AR3: 	init_state_r <= (TRFC_CLK == 0) ? `I_AR4:`I_TRF3; //第3次自刷新	
				`I_TRF3:	init_state_r <= (`end_trfc) ? `I_AR4:`I_TRF3;			//等待第3次自刷新结束,TRFC_CLK个时钟周期
				`I_AR4: 	init_state_r <= (TRFC_CLK == 0) ? `I_AR5:`I_TRF4; //第4次自刷新
				`I_TRF4:	init_state_r <= (`end_trfc) ? `I_AR5:`I_TRF4; 		//等待第4次自刷新结束,TRFC_CLK个时钟周期
				`I_AR5: 	init_state_r <= (TRFC_CLK == 0) ? `I_AR6:`I_TRF5; //第5次自刷新
				`I_TRF5:	init_state_r <= (`end_trfc) ? `I_AR6:`I_TRF5;			//等待第5次自刷新结束,TRFC_CLK个时钟周期
				`I_AR6: 	init_state_r <= (TRFC_CLK == 0) ? `I_AR7:`I_TRF6; //第6次自刷新
				`I_TRF6:	init_state_r <= (`end_trfc) ? `I_AR7:`I_TRF6;			//等待第6次自刷新结束,TRFC_CLK个时钟周期
				`I_AR7: 	init_state_r <= (TRFC_CLK == 0) ? `I_AR8:`I_TRF7; //第7次自刷新	
				`I_TRF7: 	init_state_r <= (`end_trfc) ? `I_AR8:`I_TRF7;			//等待第7次自刷新结束,TRFC_CLK个时钟周期
				`I_AR8: 	init_state_r <= (TRFC_CLK == 0) ? `I_MRS:`I_TRF8;	//第8次自刷新
				`I_TRF8:	init_state_r <= (`end_trfc) ? `I_MRS:`I_TRF8;			//等待第8次自刷新结束,TRFC_CLK个时钟周期
				`I_MRS:		init_state_r <= (TMRD_CLK == 0) ? `I_DONE:`I_TMRD;//模式寄存器设置(MRS)	
				`I_TMRD:	init_state_r <= (`end_tmrd) ? `I_DONE:`I_TMRD;		//等待模式寄存器设置完成,TMRD_CLK个时钟周期
				`I_DONE:	init_state_r <= `I_DONE;		// SDRAM的初始化设置完成标志
				default: init_state_r <= `I_NOP;
				endcase


assign init_state = init_state_r;
assign sdram_init_done = (init_state_r == `I_DONE);		// SDRAM初始化完成标志
//------------------------------------------------------------------------------
//15us计时,每60ms全部4096行存储区进行一次自刷新
// ( 存储体中电容的数据有效保存期上限是64ms )
//------------------------------------------------------------------------------	 
reg[10:0] cnt_15us;	//计数寄存器

always @ (posedge clk or negedge rst_n)
	if(!rst_n) cnt_15us <= 11'd0;
	else if(cnt_15us < 11'd1499) cnt_15us <= cnt_15us+1'b1;	// 60ms(64ms)/4096=15us循环计数
	else cnt_15us <= 11'd0;	

always @ (posedge clk or negedge rst_n)
	if(!rst_n) sdram_ref_req <= 1'b0;
	else if(cnt_15us == 11'd1498) sdram_ref_req <= 1'b1;	//产生自刷新请求
	else if(sdram_ref_ack) sdram_ref_req <= 1'b0;		//已响应自刷新 

//------------------------------------------------------------------------------
//SDRAM的读写以及自刷新操作状态机
//------------------------------------------------------------------------------
reg[3:0] work_state_r;	// SDRAM读写状态

always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) work_state_r <= `W_IDLE;
	else 
		case (work_state_r)
			//SDRAM空闲,初始化完成并且产生自刷新请求
 			`W_IDLE:	if(sdram_ref_req && sdram_init_done && !sdram_busy) 
								work_state_r <= `W_AR; 		//定时自刷新请求		
						else if(sys_en & sdram_init_done) 
							work_state_r <= `W_ACTIVE;//读SDRAM
						else 	work_state_r <= `W_IDLE;

						//行有效状态  判断TRCD=18ns行选通延时是否结束
			`W_ACTIVE: 	if(TRCD_CLK == 0) //时间到行有效
							 if(sys_r_wn) work_state_r <= `W_READ;
							 else work_state_r <= `W_WRITE;
						else work_state_r <= `W_TRCD; //行有效等待
						//行有效等待
			`W_TRCD:	 if(`end_trcd)
						 	 if(sys_r_wn) work_state_r <= `W_READ;
						 	 else work_state_r <= `W_WRITE;
						else work_state_r <= `W_TRCD;
						// SDRAM读数据状态
			`W_READ:	work_state_r <= `W_CL;	//等待潜伏期
			`W_CL:		work_state_r <= (`end_tcl) ? `W_RD:`W_CL;	
			`W_RD:		work_state_r <= (`end_tread) ? `W_RBST:`W_RD;	//突发读模式停止
			`W_RWAIT:	work_state_r <= (`end_trwait) ? `W_IDLE:`W_RWAIT;
						// SDRAM写数据状态
			`W_WRITE:	work_state_r <= `W_WD;		
			`W_WD:		work_state_r <= (`end_twrite) ? `W_WBST:`W_WD;//`W_TDAL
			`W_TDAL:		work_state_r <= (`end_tdal) ? `W_IDLE:`W_TDAL;
						// SDRAM自动刷新状态
			`W_AR:		work_state_r <= (TRFC_CLK == 0) ? `W_IDLE:`W_TRFC; 
			`W_TRFC:	work_state_r <= (`end_trfc) ? `W_IDLE:`W_TRFC;
			
			`W_RBST:	work_state_r <= `W_RWAIT;//读突发停止
			`W_WBST:	work_state_r <= `W_TDAL; //写突发停止	
			
			default: 	work_state_r <= `W_IDLE;
			endcase
end

assign work_state = work_state_r;		// SDRAM工作状态寄存器
assign sdram_busy = (sdram_init_done && work_state_r == `W_IDLE) ? 1'b0:1'b1;	// SDRAM忙标志位
assign sdram_ref_ack = (work_state_r == `W_AR);		// SDRAM自刷新应答信号

assign sdram_wr_ack = ((work_state == `W_TRCD) & ~sys_r_wn) | (work_state == `W_WRITE) | 
						((work_state == `W_WD) & (cnt_clk_r < sdwr_byte-2'd2));		//写SDRAM响应信号,作为wrFIFO的输出有效信号??
assign sdram_rd_ack = (work_state_r == `W_RD) & (cnt_clk_r > 9'd1) & (cnt_clk_r < sdrd_byte+2'd2);		//读SDRAM响应信号
assign sys_dout_rdy = (work_state_r == `W_RD && `end_tread);		// SDRAM数据输出完成标志
//------------------------------------------------------------------------------
//产生SDRAM时序操作的延时
//------------------------------------------------------------------------------
reg[8:0] cnt_clk_r;	//时钟计数
reg cnt_rst_n;		//时钟计数复位信号	

always @ (posedge clk or negedge rst_n) 
	if(!rst_n) cnt_clk_r <= 9'd0;			//计数寄存器复位
	else if(!cnt_rst_n) cnt_clk_r <= 9'd0;	//计数寄存器清零
	else cnt_clk_r <= cnt_clk_r+1'b1;		//启动计数延时
	
assign cnt_clk = cnt_clk_r;			//计数寄存器引出,内部`define中使用 

	//计数器控制逻辑
always @ (*) begin
	case (init_state_r)
	    	`I_NOP:	cnt_rst_n <= 1'b0;
	   		`I_PRE:	cnt_rst_n <= (TRP_CLK != 0);//预充电延时计数启动	
	   		`I_TRP:	cnt_rst_n <= (`end_trp) ? 1'b0:1'b1;	//等待预充电延时计数结束后,清零计数器
	    	`I_AR1,`I_AR2,`I_AR3,`I_AR4,`I_AR5,`I_AR6,`I_AR7,`I_AR8:
	         		cnt_rst_n <= (TRFC_CLK != 0);			//自刷新延时计数启动
	    	`I_TRF1,`I_TRF2,`I_TRF3,`I_TRF4,`I_TRF5,`I_TRF6,`I_TRF7,`I_TRF8:
	         		cnt_rst_n <= (`end_trfc) ? 1'b0:1'b1;	//等待自刷新延时计数结束后,清零计数器
			`I_MRS:	cnt_rst_n <= (TMRD_CLK != 0);			//模式寄存器设置延时计数启动
			`I_TMRD:	cnt_rst_n <= (`end_tmrd) ? 1'b0:1'b1;	//等待自刷新延时计数结束后,清零计数器
		   	`I_DONE:
	      		case (work_state_r)
						`W_IDLE:	cnt_rst_n <= 1'b0;
						`W_ACTIVE: 	cnt_rst_n <= (TRCD_CLK == 0) ? 1'b0:1'b1;
						`W_TRCD:	cnt_rst_n <= (`end_trcd) ? 1'b0:1'b1;
						`W_CL:		cnt_rst_n <= (`end_tcl) ? 1'b0:1'b1;
						`W_RD:		cnt_rst_n <= (`end_tread) ? 1'b0:1'b1;
						`W_RWAIT:	cnt_rst_n <= (`end_trwait) ? 1'b0:1'b1;
						`W_WD:		cnt_rst_n <= (`end_twrite) ? 1'b0:1'b1;
						`W_TDAL:	cnt_rst_n <= (`end_tdal) ? 1'b0:1'b1;
						`W_TRFC:	cnt_rst_n <= (`end_trfc) ? 1'b0:1'b1;
					default: cnt_rst_n <= 1'b0;
		         	endcase
		default: cnt_rst_n <= 1'b0;
		endcase
end

endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -