我用Verilog HDL设计了一个简单的SDRAM驱动模块。该模块定义了一个简单的有限状态机。它在前几个状态中执行SDRAM(Winbond的W9825G6KH 4M * 4Banks * 16bits)的初始化,然后进入正常模式状态以等待微处理器发送的读/写请求。它根据SDRAM数据表中定义的时序图响应每个请求,然后返回正常模式状态。我在 Intel Altera FPGA 上测试了该模块,它似乎按预期工作。数据可以正确写入和读取。然而,我注意到SDRAM似乎能够永远保留存储的数据而无需刷新!目前,该模块没有显式实现任何刷新(至少我是这么认为的)。附件是 FSM。任何人都可以帮助诊断我的代码并提供一些指导吗?代码中是否包含一些隐藏的看不见的逻辑,可以在我不注意的情况下自动刷新 SDRAM?非常感谢。
/////////////////////////////////////////
/////////////////////////////////////////
/////////////////////////////////////////
/* normal operation loop */
5'b01000: //normal operation starts here
begin
if((wbRPtr==wbWPtr)&&(rbRPtr==rbWPtr)) //if no CPU request for data (write/read)
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01000; //stay on the same state
counterEnable <= 0;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
else if(wbRPtr!=wbWPtr) //CPU has sent a data item to write to the DRAM
begin
cs_ <= 0;
ras_ <= 0;
cas_ <= 1;
we_ <= 0;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01001; //go to precharge waiting
counterEnable <= 1;
rst2 <= 1;
addr <= 0;
bs <= waddrBuffer[wbRPtr][23:22]; //highest two bits of the buffered address are bank selection
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
else //CPU has sent a read request
begin
cs_ <= 0;
ras_ <= 0;
cas_ <= 1;
we_ <= 0;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01110; //go to precharge waiting
counterEnable <= 1;
rst2 <= 1;
addr <= 0;
bs <= raddrBuffer[rbWPtr][23:22]; //highest two bits of the buffered address are bank selection
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
end
/////////////////////////////////
/////////////////////////////////
/////////////////////////////////
/*write request handling states*/
5'b01001:
begin
if(counter<2)
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01001; //stay on precharge waiting
counterEnable <= 1;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
else
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01010; //go to activate
counterEnable <= 0;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
end
5'b01010:
begin
cs_ <= 0;
ras_ <= 0;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01011; //go to activate waiting
counterEnable <= 1;
rst2 <= 1;
addr <= waddrBuffer[wbRPtr][21:9]; //row address extracted from write address buffer
bs <= waddrBuffer[wbRPtr][23:22]; //bank address extracted from write address buffer
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
5'b01011:
begin
if(counter<2)
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01011; //stay on activate waiting
counterEnable <= 1;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
else
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01100; //go to write
counterEnable <= 0;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
end
5'b01100:
begin
cs_ <= 0;
ras_ <= 1;
cas_ <= 0;
we_ <= 0;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01101; //go to write waiting
counterEnable <= 1;
rst2 <= 1;
addr <= {4'b0000, waddrBuffer[wbRPtr][8:0]}; //column address extracted from write address buffer
bs <= waddrBuffer[wbRPtr][23:22]; //bank address extracted from write address buffer
dq_out <= writeBuffer[wbRPtr];
inc <= 0;
wbRPtrUpdate <= 1;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
5'b01101:
begin
if(counter<2)
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01101; //stay on write waiting
counterEnable <= 1;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
else
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01000; //go back to normal
counterEnable <= 0;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
end
//////////////////////////////////
//////////////////////////////////
//////////////////////////////////
/* read request handling states */
5'b01110:
begin
if(counter<2)
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01110; //stay on precharge waiting
counterEnable <= 1;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
else
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01111; //go to activate
counterEnable <= 0;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
end
5'b01111:
begin
cs_ <= 0;
ras_ <= 0;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b10000; //go to activate waiting
counterEnable <= 1;
rst2 <= 1;
addr <= raddrBuffer[rbWPtr][21:9]; //row address extracted from read address buffer
bs <= raddrBuffer[rbWPtr][23:22]; //bank address extracted from read address buffer
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
5'b10000:
begin
if(counter<2)
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b10000; //stay on activate waiting
counterEnable <= 1;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
else
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b10001; //go to read
counterEnable <= 0;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
end
5'b10001:
begin
cs_ <= 0;
ras_ <= 1;
cas_ <= 0;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 1; //must turn on dq input now
next_state <= 5'b10010; //go to read waiting
counterEnable <= 1;
rst2 <= 1;
addr <= {4'b0000, raddrBuffer[rbWPtr][8:0]}; //column address extracted from read address buffer
bs <= raddrBuffer[rbWPtr][23:22]; //bank address extracted from write address buffer
dq_out <= 0; //read command cycle don't care dq bus value
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
5'b10010:
begin
if(counter<2)
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 1;
next_state <= 5'b10010; //stay on read waiting
counterEnable <= 1;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
else
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 1;
next_state <= 5'b10011; //go to finishing the read
counterEnable <= 0;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 1;
rtEnable <= 1;
end
end
5'b10011:
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 1;
next_state <= 5'b01000; //go back to normal
counterEnable <= 0;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 1;
rbWEn <= 0;
rtEnable <= 1;
end
default:
begin
cs_ <= 1;
ras_ <= 1;
cas_ <= 1;
we_ <= 1;
ldqm <= 0;
udqm <= 0;
cke <= 1;
dqInEn <= 0;
next_state <= 5'b01000; //stay on the same state
counterEnable <= 0;
rst2 <= 0;
addr <= 0;
bs <= 0;
dq_out <= 0;
inc <= 0;
wbRPtrUpdate <= 0;
rbWPtrUpdate <= 0;
rbWEn <= 0;
rtEnable <= 1;
end
endcase
结束
我尝试禁用初始化部分所需的 8 个自动刷新周期,但 SDRAM 仍然不知何故自行刷新。我也尝试更换PCB板(我有多个),所有这些都显示出同样的问题。这是 SDRAM pdf 的链接
您没有解释您正在做的测试,特别是访问模式。请记住,访问相关数据本身就会使这些行保持刷新,您不需要专门使用 the 刷新命令来保持所需数据的活动。
要查看数据降级,您必须在相当长的一段时间内不访问这些行。 IE。写入该行特有的内容,对其进行预充电,并且访问时间不要超过 64 毫秒,最好更长。编写一些独特的内容,以避免将别名地址(在出现错误的情况下)误解为不同的,因为频繁访问同一行将使其保持活动状态。