SDRAM学习(三)——主状态机设计

之前设计完成了SDRAM的各个命令输入和状态的设计,这一部分开始将其进行一个整合,根据命令和需要进行状态的选择和变换。

请添加图片描述

整个流程的设计是:主状态机—task任务线性序列机–状态执行,即根据命令来切换task。步骤是:上电–执行初始化命令–三态根据命令转换(状态的优先级为刷新》》写操作》》读操作,当读操作时默认!刷新!写操作)

 //主状态机,优先级:刷新》写》读
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)begin
			main_state <= IDLE;
			FF <= 1'b1;     //刷新操作、写操作和读操作 3 种不同的任务的执行是通过标志位 FF 来控制的,只有在标志位为 0 时,指定的操作任务才能执行,执行完后将 FF 置 1 退出任务。
		end
		else begin
			case(main_state)
				IDLE:begin   //空闲
					Command <= init_cmd;    //SDRAM初始化模块进行命令输出
					Sa <= init_addr;     //SDRAM初始化地址输出
					if(init_done)       // init_done SDRAM初始化完成标志位
						main_state <= AREF;
					else
						main_state <= IDLE;
				end

				AREF:begin				//自动刷新
					if(FF == 1'b0)
						auto_ref;       //自动刷新任务task
					else begin
						if(ref_req)begin   //ref_req刷新请求操作时
							main_state <= AREF;
							FF <= 1'b0;
						end
						else if(wr_req)begin     //读请求,读状态
							main_state <= WRITE;
							FF <= 1'b0;
						end
						else if(rd_req)begin    //写请求,写状态
							main_state <= READ;
							FF <= 1'b0;
						end
						else
							main_state <= AREF;
					end
				end

				WRITE:begin
					if(FF == 1'b0)
						write_data;   //write_data task
					else begin
						if(ref_req == 1'b1)begin   //ref_req刷新请求操作时
							main_state <= AREF;
							FF <= 1'b0;
						end
						else if(wr_opt_done & wr_req)begin       // 写完成 & 写请求
							main_state <= WRITE;
							FF <= 1'b0;
						end
						else if(wr_opt_done & rd_req)begin      //写完成 &!写请求&读请求(因为优先级没有写请求已经是前提不用写)
							main_state <= READ;
							FF <= 1'b0;
						end
						else if(wr_opt_done&!wr_req&!rd_req)       //(写完成 & !写请求 & !读请求)完成写后没指令就进入自动刷新等待
							main_state <= AREF;
						else
							main_state <= WRITE;
					end
				end

				READ:begin
					if(FF == 1'b0)
						read_data;   	//read_data task
					else begin
						if(ref_req == 1'b1)begin
							main_state <= AREF;
							FF <= 1'b0;
						end
						else if(rd_opt_done & wr_req)begin
							main_state <= WRITE;
							FF <= 1'b0;
						end
						else if(rd_opt_done & rd_req)begin
							main_state <= READ;
							FF <= 1'b0;
						end
						else if( rd_opt_done&!wr_req&!rd_req)
							main_state <= AREF;
						else
							main_state <= READ;
					end
				end
			endcase
		end
	end

一、刷新状态自动刷新
长时间没有命令要自动刷新保持上电,因此设计时序的自动刷新计数器。

//刷新定时计数器,每隔一段时间进行自动刷新,保持数据
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)
			ref_time_cnt <= 0;
		else if(ref_time_cnt == AUTO_REF)             //到达开发板上使用的 SDRAM 芯片64Ms刷新4096次时间
			ref_time_cnt <= 1;
		else if(init_done || ref_time_cnt > 0)      //SDRAM初始化完成或者已经开始刷新计数定时
			ref_time_cnt <= ref_time_cnt + 10'd1;
		else
			ref_time_cnt <= ref_time_cnt;
	end

	//刷新定时时间标志位,定时到达时置1
	assign ref_time_flag = (ref_time_cnt == AUTO_REF);			//循环计数,自动隔段刷新	

二、自动刷新请求信号的产生(读写请求同理)

//刷新请求信号
	always@(*)
	begin
		case(main_state)
			AREF:begin           //刷新状态时
				if(ref_time_flag)    //刷新指令,刷新
					ref_req = 1'b1;
				else
					ref_req = 1'b0;
			end
			WRITE:           //写状态时
			begin
				if(ref_break_wr && wr_opt_done)      //写状态收到刷新指令且写状态完成
					ref_req = 1'b1;
				else
					ref_req = 1'b0;
			end
			READ:
			begin
				if(ref_break_rd && rd_opt_done)
					ref_req = 1'b1;
				else
					ref_req = 1'b0;
			end

			default:
				ref_req = 1'b0;
		endcase	
	
	end

三、命令的保持
此处主要有两个点:
1.当SDRAM进行一个操作时,到来新的命令,将新命令进行寄存,待当前操作完成后执行
2.读写操作寄存器,在读写时对地址进行寄存防止操作过程中地址变化,处理方法也是寄存后执行

//写操作时接收到刷新信号,记住此信号为ref_break_wr
	assign ref_break_wr = (ref_time_flag && wr_opt)?1'b1:((!wr_opt)?1'b0:ref_break_wr);
                                                             //	刷新定时时间标志位且写操作中拉高;没有在写状态中拉低;否则维持原状态
读写操作寄存器,在读写时对地址进行寄存防止操作过程中地址变化
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)
		begin
			raddr_r <= 0;
			caddr_r <= 0;
			baddr_r <= 0;
		end
		else if(rd_req || wr_req)		//读写请求中
		begin
			raddr_r <= Raddr;          //Raddr_r是输入SDRAM的行地址,raddr_r将其寄存
			caddr_r <= Caddr;     	 //读写列地址
			baddr_r <= Baddr;  		 //读写bank地址
		end
		else
			;
	end	

四、主状态机仿真
主状态机已经设计完毕,仍然带入镁光SDRAM模型进行仿真

	//SDRAM控制器模块例化
	initial Clk = 1'b1;
	always #(`clk100m_period/2) Clk = ~Clk;	
				
	initial
		begin
			Rst_n   = 0;
			Wr      = 0;
			Rd      = 0;
			Caddr   = 0;
			Raddr   = 0;
			Baddr   = 0;
			Wr_data = 0;
			#(`clk100m_period*200+1);
			Rst_n   = 1;
			
			@(posedge sdram_control.sdram_init.init_done)    //关注控制模块中的初始化完成信号
			#2000;   //等待2000ns,初始化完成
			
			repeat(100)                 //写入100组数据
			begin
				Wr    = 1;
				Baddr = 2;
				#`clk100m_period;
				Wr    = 0;
		/*****这一块的读行列的手法学习******/		
				if(Caddr == 512-SC_BL)begin                //因为时序,512列减列突发长度后重新开始,其实整个512列已经读完了
					Caddr = 0; 
					Raddr = Raddr + 1;   //1行的所有列写满,行加1
				end
				else
					Caddr = Caddr + SC_BL;

				#5000;                  //延时5us
			end

			Caddr = 0;
			Raddr = 0;
			#5000;
			repeat(100)                //读出100组数据
			begin
				Rd = 1'b1;
				#`clk100m_period;
				Rd = 1'b0;

				if(Caddr == 512-SC_BL)begin
					Caddr = 0;
					Raddr = Raddr + 1;   //1行读完,行加1
				end
				else
					Caddr = Caddr + SC_BL;
					
				#5000;                  //延时5us
			end

			#5000;
			$stop;
		end
	
	initial         //两个initial是并行的,即每写入一个数据,被写入的数据加一
	begin
		forever begin
			@(posedge Wr_data_vaild);
			repeat(SC_BL)            //改变待写入的数据
			begin
				#`clk100m_period;
				Wr_data = Wr_data + 1;
			end		
		end
	end		

仿真结果:
请添加图片描述
镁光模型进行信息打印
可以看到数据可以被写入,然后读出
请添加图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值