SDRAM学习(二)——自动刷新,读写操作

一、自动刷新
自动刷新由控制器对SDRAM正常操作,需要时钟信号,时序图

自动刷新步骤:
上电即开始–预充电–A10拉高选择all bank–等待tRP后,自动刷新命令–等待tRFc后,第二次自动刷新命令–等待tRFc,自动刷新结束,空操作命令

///自动刷新操作任务,采用线性序列机方法
	
	localparam  ref_PRE_TIME = 1'b1,    //预充电时刻
					ref_REF1_TIME = REF_PRE + 1,    //第一次自动刷新时刻,充电时刻加REF_PRE(tRP选通潜伏期) 
					ref_REF2_TIME = REF_PRE + REF_REF + 1,   //第二次自动刷新时刻,每次刷新后等待tRFc
					ref_END = REF_PRE + REF_REF *2;     //自动刷新结束时刻
	
	//自动刷新过程时间计数器
	always@(posedge clk or negedge rst_n)
	begin 
		if(!rst_n)
			ref_cnt <= 16'd0;
		else if(ref_cnt == ref_END)
			ref_cnt <= 16'd0;
		else if(ref_req || ref_cnt>1'b0)
			ref_cnt <= ref_cnt +16'd1;
		else
			ref_cnt <= ref_cnt;
	end
	
	//一次刷新操作完成标志位ref_opt_done
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			ref_opt_done <= 1'b0;
		else if(ref_cnt ==ref_END)
			ref_opt_done <= 1'b1;
		else 
			ref_opt_done <= 1'b0;
	end
	
	//一次突发写操作过程状态标识信号。ref_req刷新操作时,ref_opt_done拉高,自动刷新操作完成后拉低
	reg ref_opt;
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			ref_opt <= 1'b0;
		else if(ref_req ==1'b1)
			ref_opt <= 1'b1;
		else if(ref_opt_done == 1'b1)
			ref_opt <= 1'b0;
		else 
			ref_opt <= ref_opt;
	end
	
	//自动刷新操作,线性序列机,根据时序图,是在下降沿后发生改变,上升沿时正好能读取到
	task auto_ref;
	begin
		case(ref_cnt)
			ref_PRE_TIME:begin
				command <= C_PRE;			//预充电
				sa[10] <= 1'b1;         //SDRAM地址总线A0-A10,其中的A10拉高选择all bank
			end
			
			ref_REF1_TIME:begin
				command <= C_AREF;    //自动刷新
			end
				
			ref_REF2_TIME:begin
				command <= C_AREF;    //自动刷新
			end
			
			ref_END:begin				//结束,空操作命令
				FF <= 1'b1;				//标记寄存器,拉高
				command <= C_NOP;
			end
			
			default:
				command <= C_NOP;
		endcase
	end
	endtask

二、不带自动预充电写操作
时序图:
在这里插入图片描述
写操作步骤:
上电–激活行时刻,写操作开始立刻激活命令,激活行、bank–激活后tRCD,写命令,激活列、bank–写命令后经突发长度SC_BL写数据、写数据完成到预充电时间间隔后预充电–预充电后tRP后结束,写操作结束时刻

//
	
	//一次突发写操作任务,线性序列机方法
	localparam 
		wr_ACT_TIME = 1'b1;                  //激活行时刻,写操作开始立刻激活
		wr_WRITE_TIME = SC_RCD +1,                 //写命令时刻,激活到读命令或写命令延时tRCD后写命令
		wr_PRE_TIME = SC_RCD + SC_BL + WR_PRE + 1,     //预充电时刻,写命令后经突发长度SC_BL写数据、写数据完成到预充电时间间隔后预充电
		wr_END_TIME = SC_RCD + SC_BL + WR_PRE +REF_PRE;//写操作结束时刻,预充电后tRP后结束
	
	//一次突发写操作过程时间计数器
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			wr_cnt <= 16'd0;
		else if(wr_cnt == wr_END_TIME)     
			wr_cnt <= 16'd0;
		else if(wr_req || wr_cnt>1'b0)		 //写操作请求或读书开始后读数
			wr_cnt <= wr_cnt + 16'd1;
		else
			wr_cnt <= 16'd0;
	end
	
	//一次写操作过程完成标志位
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			wr_opt_done <= 1'b0;
		else if(wr_cnt == wr_END_TIME)
			wr_opt_done <= 1'b1;
		else
			wr_opt_done <= 1'b0;
	end
	
	//一次突发写操作过程状态标识信号wr_opt,写操作时拉高,写完拉低
	reg wr_opt;
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			wr_opt <= 1'b0;
		else if(wr_req == 1'b1)
			wr_opt <= 1'b1;
		else if(wr_opt_done == 1'b1)
			wr_opt <= 1'b0;
		else
			wr_opt <= wr_opt;
	end
	
	//写数据操作,数据写入(改变)时刻有效区间,激活到读命令或写命令延时tRCD后到突发长度8这一段时序数据写入
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			wr_data_vaild <= 1'b0;
		else if((wr_cnt > SC_RCD)&& (wr_cnt <= SC_RCD + SC_BL))
			wr_data_vaild <= 1'b1;
		else
			wr_data_vaild <= 1'b0;
	end
	
	//一次突发写操作数据写完成标志位,写完拉高
	assign wdata_done = (wr_cnt == SC_RCD+SC_BL+1)?1'b1:1'b0;
	
	//一次突发写操作任务,类似线性序列机方法
	task write_data;
	begin
		case(wr_cnt)
			wr_ACT_TIME:begin					//激活行时刻
				command <= C_ACT;				//激活命令
				sa <= raddr_r;             //激活行,SDRAM地址总线读写行地址寄存器	
				ba <= baddr_r;					//激活bank,SDRAMBank地址读写bank地址寄存器
			end

			wr_WRITE_TIME:begin				//写命令时刻
				command <= C_WR;				//写命令
				sa <= {1'b0,caddr_r[8:0]}; //激活列,读写列地址寄存器A0-A9
				ba <= baddr_r;
			end

			wr_PRE_TIME:begin				//预充电时刻
				command <= C_PRE;          //预充电命令
				sa[10] <= 1'b1;         //所有bank
			end

			wr_END_TIME:begin				//写操作结束时刻
				command <= C_NOP;       //空命令
				FF <= 1'b1;					标记寄存器拉高
			end

			default:
				command <= C_NOP;
		endcase
	end
	endtask
	
	
	//一次突发读操作任务,线性序列机方法	
	localparam
		rd_ACT_TIME  = 1'b1,              //激活行时刻
		rd_READ_TIME = SC_RCD+1,          //读命令时刻
		rd_PRE_TIME  = SC_RCD+SC_BL+1,    //预充电时刻
		rd_END_TIME  = SC_RCD+SC_CL+SC_BL;//读操作结束时刻
	
	//一次突发读操作过程时间计数器
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			rd_cnt <= 16'd0;
		else if(rd_cnt == rd_END_TIME)
			rd_cnt <= 16'd0;
		else if(rd_req ||rd_cnt>1'b0)
			rd_cnt <= rd_cnt + 16'd1;
		else
			rd_cnt <= 16'd0;
	end
	
	//一次突发读操作过程完成标志位	
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			rd_opt_done <= 1'b0;
		else if(rd_cnt == rd_END_TIME)
			rd_opt_done <= 1'b1;
		else
			rd_opt_done <= 1'b0;
	end

	//一次突发读操作过程状态标识信号
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			rd_opt <= 1'b0;
		else if(rd_req == 1'b1)
			rd_opt <= 1'b1;
		else if(rd_opt_done == 1'b1)
			rd_opt <= 1'b0;
		else
			rd_opt <= rd_opt;
	end

   //一次突发读操作过程中数据读完标志位
	assign rdata_done = (rd_cnt == rd_END_TIME)?1'b1:1'b0;
	
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			rd_data_vaild <= 1'b0;
		else if((rd_cnt > SC_RCD+SC_CL)
		        &&(rd_cnt <= SC_RCD+SC_CL+SC_BL))
			rd_data_vaild <= 1'b1;
		else
			rd_data_vaild <= 1'b0;
	end

	//读数据
	assign rd_data = dq;
	
	//一次突发读操作任务,类似线性序列机方法
	task read_data;
	begin
		case(rd_cnt)
			rd_ACT_TIME:begin			     //激活命令
				Command <= C_ACT;
				Sa <= raddr_r; 
				Ba <= baddr_r;
			end

			rd_READ_TIME:begin			  //读命令
				Command <= C_RD;
				Sa <= {1'b0,caddr_r[8:0]};
				Ba <= baddr_r;
			end

			rd_PRE_TIME:begin
				Command <= C_PRE;         //预充电
				Sa[10] <= 1'b1;
			end
			
			rd_END_TIME:begin
				FF <= 1'b1;
				Command <= C_NOP;
			end
			
			default:
				Command <= C_NOP;
		endcase
	end
	endtask

三、不带自动预充电读操作
与写操作类似

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值