FPGA之SDRAM控制器设计(三)

FPGA之SDRAM控制器设计(三):写

由于已经涉及了上电刷新,写三个大的状态转移,先把状态转移图给出。主控状态转移图是基于手册上描述来的。在代码注释中会给出每个状态的意义解释。

 

写时序图

写状态转移图:

主控设计(含读模块):

`include	"head.v"

module mainref_fsm(
		init_done,ref_done,clk,soft_rst_n,wr_en,rd_en,init_en,ref_en,rt_en,
		rt_flag,sel_mux,local_wdata,local_rdata,local_write,local_read,local_addr,
		local_ready,local_rddatavalid,wr_done,rd_done,row,col,ba,wdata,rdata
);//刷新的主控状态机,TOP
		input				init_done;
		input				ref_done;
		input				clk;
		input				soft_rst_n;
		input				rt_flag;
		output	reg			init_en;
		output	reg			ref_en;
		output	reg			rt_en;
		output	reg	[1:0]	sel_mux;
		output	reg			wr_en;
		output	reg			rd_en;
		input	[31:0]		local_wdata;
		output	reg	[31:0]	local_rdata;
		input				local_write;
		input				local_read;
		input	[24:0]		local_addr;
		output	reg			local_ready;
		output	reg			local_rddatavalid;
		input				wr_done,rd_done;
		output	reg	[12:0]	row;
		output	reg	[9:0]	col;
		output	reg	[1:0]	ba;
		output	reg	[31:0]	wdata;
		input	[31:0]		rdata;
		
		reg		[2:0]	state;
		localparam	s0 = 3'b000;
		localparam	s1 = 3'b001;
		localparam	s2 = 3'b010;
		localparam	s3 = 3'b011;
		localparam	s4 = 3'b100;
		localparam	s51 = 3'b101;
		localparam	s52 = 3'b110;
		
always @(posedge clk)begin
		if(soft_rst_n == 1'b0)
			begin
				ref_en <= 1'b0;
				rt_en <= 1'b0;
				init_en <= 1'b0;
				sel_mux <= `MUX_INIT;
				rd_en <= 1'b0;
				wr_en <= 1'b0;
				wdata <= 'd0;
				col	<= 'd0;
				row <= 'd0;
				ba <= 2'b00;
				local_ready <= 1'b0;
				local_rddatavalid <= 1'b0;
				local_rdata <= 'd0;
				state <= s0;				
			end
		else
			case(state)
				s0 : begin
						init_en <= 1'b1;
						state <= s1;
					 end					//初始化,发出初始化使能信号
					 
				s1 : if(init_done == 1'b0)
					 begin
					 	init_en <= 1'b0;
					 	state <= s1;
					 end				//对应s0和s1的这部分对应ini_fsm.v模块
					 else if(init_done == 1'b1)
					 	begin
					 		//ref_en <= 1'b1;
					 		rt_en <= 1'b1;
					 		local_ready <= 1'b1;
					 		sel_mux <= `MUX_REF;
					 		state <= s2;
					 	end					//上电初始化完成,
					 	
				s2 : begin
					 	ref_en <= 1'b1;
					 	state <= s3;
					 end
					 
				s3 : if(ref_done == 1'b0)
						begin
							ref_en <= 1'b0;
							state <= s3;
						end					//s2,s3对应ref_fsm刷新状态机模块				
					 else
					 state <=s4;
										 
				s4 : if(rt_flag == 1'b0)
						begin	//只有在7810ns时间内才执行读写操作
							if(local_write == 1'b0 && local_read ==  1'b0)																
									state <= s4;						
							 else if(local_write ==  1'b1)			
							 	begin
							 		wr_en <= 1'b1;
							 		row <= local_addr[22:10];
							 		col	<= local_addr[9:0];
							 		ba	<= local_addr[24:23];
							 		local_ready <= 1'b0;
							 		wdata <= local_wdata;
							 		sel_mux <= `MUX_WR;							 		
							 		state <= s51;
							 	end														
							else if(local_read == 1'b1)
								begin
									rd_en <= 1'b1;
									row <= local_addr[22:10];
							 		col	<= local_addr[9:0];
							 		ba	<= local_addr[24:23];
							 		local_ready <= 1'b0;
							 		local_rddatavalid <= 1'b0;
							 		sel_mux <= `MUX_RD;	
							 		state <= s52;
								end
						end
				 	else	//rt_flag == 1 ————> 这一次7810ns时间到了,要刷新:拉高ref_en,转到刷新状态机,进行几次操作。
					 	begin
					 		ref_en <= 1'b1;
					 		state <= s3;
					 	end				 	
				
				s51 : if(wr_done == 1'b0)
						begin
							wr_en <= 1'b0;
							state <= s51;
						end
					 else
					 	begin
					 		sel_mux <= `MUX_REF;
					 		local_ready <= 1'b1;
					 		state <= s4;
					 		
					 	end
					 	
				s52 : if(rd_done == 1'b0)
						begin
							rd_en <= 1'b0;
							state <= s52;
						end
					 else
					 	begin
					 		sel_mux <= `MUX_REF;
					 		local_ready <= 1'b1;
					 		local_rddatavalid <= 1'b1;
					 		local_rdata <= rdata;
					 		state <= s4;
					 	end
			endcase
		
		end
endmodule

写模块:

`include	"head.v"

module	write(
		clk,soft_rst_n,wr_en,wr_done,wdata,
		wr_bus,row,col,ba,dq_out,out_en
);//不需要中断的写模式:在输入列线时将a[10]拉高,自动中断
		input				clk;
		input				soft_rst_n;
		input				wr_en;
		input	[31:0]		wdata;
		input	[12:0]		row;
		input	[9:0]		col;
		input	[1:0]		ba;		
		output	[19:0]		wr_bus;
		output	reg			wr_done;
		output	reg	[15:0]	dq_out;
		output	reg			out_en;
		
		reg		[12:0]		wr_a;
		reg		[1:0]		wr_ba;
		reg		[3:0]		wr_cmd;
		reg		[3:0]		cnt;
		reg					wr_cke;
		reg		[2:0]		state;	
		
		localparam	s0 = 3'b000;
		localparam	s1 = 3'b001;
		localparam	s2 = 3'b010;
		localparam	s3 = 3'b011;
		localparam	s4 = 3'b100;
		
		assign	wr_bus = {wr_cmd,wr_a,wr_ba,wr_cke};
		
always @(posedge clk)
		if(soft_rst_n == 1'b0)
			begin
				wr_done <= 1'b0;
				wr_a <= 'd0;
				wr_ba <= 'd0;
				cnt <= 'd0;
				wr_cke <= 1'b1;
				dq_out <= 'd0;
				out_en <= 1'b0;
				wr_cmd <= `NOP;
				state <= s0;
			end
		else case(state)
				s0	:	if(wr_en == 1'b0)	
							state <= s0;
						 else
					 		begin
					 			wr_cmd <= `ACT;
					 			wr_a <= row;//加载行
					 			wr_ba <= ba;//选择bank:0,1,2,3其中一个
					 			wr_done <= 1'b0;
					 			state <= s1;
					 		end
					 	
				s1	:	if(cnt < `tWCD - 1)
							begin
								cnt <= cnt + 1'b1;
								wr_cmd <= `NOP;
								state <= s1;
							end
						else
							begin
								wr_cmd <= `WR;
								wr_a[9:0] <= col;//输入列地址
								wr_a[10] <= 1'b1;//不用外部输入中断信号,写完一个突发长度自己断掉
								dq_out <= wdata[15:0];//数据线分两次输入到SDRAM中,第一次低16位
								out_en <= 1'b1;
								cnt	<= 'd0;
								state <= s2;
							end
				
				s2	:	begin
							wr_cmd <= `NOP;
							dq_out <= wdata[31:16];//输入高16位数据
							state <= s3;
						end
				
				s3	: 	begin
							wr_done <= 1'b1;//一次写的过程完成
							out_en <= 1'b0;
							state <= s4;
						end
				s4 : begin
						wr_done <= 1'b0;
						state <= s0;
					 end
						
			endcase
				
endmodule

仿真报告:

猜你喜欢

转载自blog.csdn.net/qq_41754003/article/details/107937860