基于FPGA的SDRAM通用读写软IP

此IP简单易用,亲自测试可以跑到145M,读写控制信号只有wr和rd两个,其余(地址、数据、突发等)均根据个人需要配置,wr和rd一样时不操作,wr为1,rd为0时为写操作,反之为读操作,需要强调突发写时需要等待writeable为1后在时钟上升沿依此放置数据,读取时在readable为1时方可在上升沿读取数据。本人使用的sdram为HY57V641620E(L/S)T(P)-6
如有bug请一定告知,谢谢


RTL代码如下:



module  sdram_common(clk,rst,cke,cs,ba,a,ras,cas,we,udqm,ldqm,dq,wr,rd,burst_length,addr_row,addr_column,data_in,over,bank,readable,writeable);
input 			clk;//sdram输入
input 			rst;//sdram复位
input 			wr;//sdram写使能
input			rd;//sdram读使能,wr和rd一样时为无操作,当wr为1rd为0时为写反之为读
input  [11:0]	addr_row;//sdram行地址
input  [7:0]	addr_column;//sdram列地址
input  [15:0]   data_in;//数据输入
input  [2:0]    burst_length;//当为000时无突发,为001时突发为2,为010时突发为4,为011时突发为8,为100时为页突发(256)
input  [1:0]    bank;//选择四片中哪一片
inout  [15:0]   dq;//链接sdram的数据端口
output 			cke;//连接sdram的时钟使能端口
output 			cs;//连接sdram的片选端口
output [1:0] 	ba;//连接sdram的bank端口
output [11:0] 	a;//连接sdram的地址端口
output 			ras;//连接sdram的行地址选择端口
output 			cas;//连接sdram的列地址选择端口
output 			we;//连接sdram的写使能端口
output 			udqm;//
output   		ldqm;//数据掩码端口
output			over;//操作结束指示信号,上升沿或高电平有效
output			readable;//可读信号,高电平有效,高电平时在时钟上升沿获取读到的数据
output			writeable;//突发写时在这个信号高电平时上升沿开始放着数据,单写时无需此信号

reg [15:0]		dq_r;
reg [1:0]	ba_r;	
reg 			cke_r;
reg 			cs_r;
reg [11:0]		a_r;
reg 			ras_r;
reg				cas_r;
reg 			we_r;
reg [15:0]		data_out_r;
reg				over_r;
reg				writeable_r;//10160904

assign dq = wr?dq_r:16'bzzzzzzzzzzzzzzzz;
assign ba = ba_r;
assign cke = cke_r;
assign cs = cs_r;
assign a = a_r;
assign ras = ras_r;
assign cas = cas_r;
assign we = we_r;
assign over = over_r;
assign udqm = 0;
assign ldqm = 0;
assign readable = readable_r;
assign writeable = writeable_r;//10160904

reg [7:0] 		current_state;
reg [7:0]		next_state;
reg [8:0] 		burst_length_num;
wire [8:0]		burst_length_num_r;

parameter init 				= 8'b00000000;//初始化状态
parameter precharge 		= 8'b00000010;//预充电状态
parameter auto_reflash 		= 8'b00000100;//自动刷新状态
parameter mr_confige 		= 8'b00001000;//配置模式寄存器
parameter idel 				= 8'b00010000;//空闲状态
parameter start_active_row	= 8'b00100000;//行激活状态
parameter read 				= 8'b01000000;//读状态
parameter write 			= 8'b10000000;//写状态
parameter done				= 8'b00000001;//完成状态

assign burst_length_num_r = wr?burst_length_num:(burst_length_num + 3);

wire en;
assign en = wr ^ rd;

always@(posedge clk or negedge rst)
begin
	if(~rst)
		current_state <= idel;
	else
		current_state <= next_state;
end

always@(negedge clk)
begin
	case(current_state)
		init:
			begin
				cke_r <= 1;
				cs_r  <= 0;
				ras_r <= 1;
				cas_r <= 1;
				we_r  <= 1;
				over_r <= 0;
				writeable_r <= 0;
				if(init_ok)
					next_state <= precharge;
				else	
					next_state <= init;
			end
		precharge:
			begin
				cke_r <= 1;
				cs_r  <= 0;
				ras_r <= 0;
				cas_r <= 1;
				we_r  <= 0;
				a_r[10]   <= 1;
				writeable_r <= 0;
				if(precharge_done)
					next_state <= auto_reflash;
				else
					next_state <= precharge;
			end
		auto_reflash:
			begin
				cke_r <= 1;
				cs_r  <= 0;
				ras_r <= 0;
				cas_r <= 0;
				we_r  <= 1;
				over_r <= 0;
				writeable_r <= 0;
				if(en)
					next_state <= mr_confige;
				else 
					next_state <= idel;
			end
		mr_confige:
			begin
				cke_r <= 1;
				cs_r  <= 0;
				ras_r <= 0;
				cas_r <= 0;
				we_r  <= 0;
				ba_r  <= 2'b00;
				over_r <= 0;
				writeable_r <= 0;
				case(burst_length)//根据突发长度配着模式寄存器
					0:begin a_r <= 12'b000000110000; burst_length_num <= 0; end
					1:begin a_r <= 12'b000000110001; burst_length_num <= 1; end
					2:begin a_r <= 12'b000000110010; burst_length_num <= 3; end
					3:begin a_r <= 12'b000000110011; burst_length_num <= 7; end
					4:begin a_r <= 12'b000000110111; burst_length_num <= 255; end
					default:begin a_r <= 12'b000000110000; burst_length_num <= 0; end
				endcase
				if(en & mr_confige_done)
					next_state <= start_active_row;
				else if(mr_confige_done)
					next_state <= idel;
				else	
					next_state <= mr_confige;
			end
		idel:
			begin
				cke_r <= 1;
				cs_r  <= 0;
				ras_r <= 1;
				cas_r <= 1;
				we_r  <= 1;
				over_r <= 0;
				writeable_r <= 0;
				if(en)
					next_state <= mr_confige;
				else
					next_state <= auto_reflash;
			end
		start_active_row:
			begin
				cke_r <= 1;
				cs_r  <= 0;
				ras_r <= 0;
				cas_r <= 1;
				we_r  <= 1;
				ba_r  <= bank;
				a_r   <= addr_row;
				over_r <= 0;
				writeable_r <= 0;
				if(addr_row_done)
				begin
					if(en)
					begin
						if(wr)
						begin
							writeable_r <= 1;
							next_state <= write;
						end
						else
						begin
							writeable_r <= 0;
							next_state <= read;
						end
					end
					else
					begin
						writeable_r <= 0;
						next_state <= idel;
					end
				end
				else
				begin
					writeable_r <= 0;
					next_state <= start_active_row;
				end
			end
		read:
			begin
				cke_r <= 1;
				cs_r  <= 0;
				ras_r <= 1;
				cas_r <= 0;
				we_r  <= 1;
				ba_r  <= bank;
				a_r   <= {4'd0,addr_column};
				writeable_r <= 0;
				next_state <= done;
			end
		write:
			begin
				cke_r <= 1;
				cs_r  <= 0;
				ras_r <= 1;
				cas_r <= 0;
				we_r  <= 0;
				ba_r  <= bank;
				a_r   <= {4'd0,addr_column};
				dq_r <= data_in;
				if(burst_length_num_r == 1'd0)				
				begin
					over_r <= 1;
					writeable_r <= 0;
					next_state <= precharge;
				end
				else
					next_state <= done;
			end
		done://完成状态,因为有突发的读和写状态,突发时要把cas和ras拉低
			begin
				cke_r <= 1;
				cs_r  <= 0;
				ras_r <= 0;
				cas_r <= 0;
				if(wr)
				begin
					we_r  <= 0;
					dq_r <= data_in;
				end
				else
				begin
					data_out_r <= dq;
					we_r  <= 1;
				end
				if(burst_length_done || burst_length_num_r == 1'd0)//检测突发是否完成				
				begin
					over_r <= 1;
					writeable_r <= 0;
					next_state <= precharge;
				end
				else
				begin
					over_r <= 0;
					writeable_r <= writeable_r;
					next_state <= done;
				end
			end
		default:next_state <= idel;
	endcase
end  
  
  
//////////////////////////初始化计数器/////////////////////////////  
  
reg [13:0] 		init_counter;
reg 			init_ok;

always@(posedge clk)
begin
	if(init_counter < 15000)
	begin
		init_counter <= init_counter + 1;
		init_ok <= 0;
	end
	else	
	begin
		init_counter <= 15000;
		init_ok <= 1;
	end
end

////////////////////////////预充电计数器////////////////////////////

reg [2:0]		precharge_counter;
reg 			precharge_done;

always@(posedge clk or negedge rst)
begin
	if(~rst)
	begin
		precharge_counter <= 0;
		precharge_done <= 0;
	end
	else if(current_state == precharge)
	begin
		precharge_counter <= precharge_counter +1;
		if(precharge_counter == 7)
			precharge_done <= 1;
		else
			precharge_done <= 0;
	end
	else
	begin
		precharge_counter <= 0;
		precharge_done <= 0;
	end
end

///////////////////////////配着模式寄存器计数器////////////////////
reg [1:0] 		mr_confige_counter;
reg 			mr_confige_done;

always@(posedge clk or negedge rst)
begin
	if(~rst)
	begin
		mr_confige_counter <= 0;
		mr_confige_done <= 0;
	end
	else if(current_state == mr_confige)
	begin
		mr_confige_counter <= mr_confige_counter + 1;
		if(mr_confige_counter == 3)
			mr_confige_done <= 1;
		else
			mr_confige_done <= 0;
	end
	else 
	begin
		mr_confige_counter <=0;
		mr_confige_done <=0;
	end
end

/////////////////////////////行激活计数器//////////////////////////////
reg [1:0] 		addr_row_counter;
reg 			addr_row_done;

always@(posedge clk or negedge rst)
begin
	if(~rst)
	begin
		addr_row_counter <= 0;
		addr_row_done <=0;
	end
	else if(current_state == start_active_row)
	begin
		addr_row_counter <= addr_row_counter + 1;
		if(addr_row_counter == 3)
			addr_row_done <= 1;
		else
			addr_row_done <= 0;
	end
	else
	begin
		addr_row_counter <= 0;
		addr_row_done <= 0;
	end
end

////////////////////////////突发寄存器///////////////////////////////
reg [8:0] 		burst_length_counter;
reg 			burst_length_done;
reg			readable_r;

always@(posedge clk or negedge rst)
begin	
	if(~rst)
	begin
		burst_length_counter <= 0;
		burst_length_done <= 0;
		readable_r <= 0;
	end
	else if(current_state == read || current_state == write || current_state == done)
	begin
		burst_length_counter <= burst_length_counter + 1;
		if(burst_length_counter > 1 && burst_length_counter < burst_length_num_r && rd)
			readable_r <= 1;
		else
			readable_r <= 0;
		if(burst_length_counter == burst_length_num_r - 1 || burst_length_num_r == 1'd0)//20160904
			burst_length_done <= 1;
		else
			burst_length_done <= 0;
	end
	else
	begin
		burst_length_counter <= 0;
		burst_length_done <= 0;
		readable_r <= 0;
	end
end

endmodule


你可能感兴趣的:(FPGA,SDRAM)