SDRAM(5):读操作
读状态和写状态非常相似,可以说几乎一样。
一、SDRAM 读状态
1、SDRAM 内部状态机
粗线表示自动跳转,细线表示满足条件才跳转。经过前面的设计我们此时来到了 IDLE 状态,要完成读模块设计就要考虑两个问题:
(1)IDLE 状态到 READ 状态
① 在 IDLE 状态需要先给 ACT 命令激活某一行,此时处于 Row Active 状态。
② 在 Row Active 状态之后,给 READ 命令则会进入 READ 状态。
③ 在 READ 状态后,再给一次 READ 命令,就可以继续读出数据。
(2)READ 状态到 IDLE 状态 (经常需要进行刷新操作,必须从 IDLE 状态进入)
① 在 READ 状态给 PRE 命令,则 SDRAM 将跳出 READ 状态进入 Precharge 状态;
② 在 Precharge 状态后,会自动进入 IDLE 状态。
注:READA 状态不使用,因为当处于 READA 状态时,它会自动的进入到 Precharge 状态。想要继续进行读操作就要先再次激活读,也就是说 READA 比在 READ 状态的工作效率要低很多。
2、退出 READ 情况
在 READ 状态时,有 3 种情况是我们必须要退出 READ 状态的。
(1)本次设计的数据已经完全读完。都读完了肯定得退出 READ 状态啊,还折腾啥呢。
(2)SDRAM 需要进行自刷新操作。64ms内至少4096次的刷新操作是必须的,要刷新了就麻利的退出 READ 状态去刷新。
(3)数据未读完,但已经读完了 SDRAM 的一行,需要激活下一行。因为每次激活都是激活的一行,所以要换行时得退出 READ 进行下一行的激活。
二、读操作设计时序分析
1、READ 命令时序图
![](https://img2018.cnblogs.com/common/1536533/202002/1536533-20200202223109244-47024792.png)
由读命令时序图中我们可以得到如下信息:
① 其命令为 {CS_n,RAS_n,CAS_n,WE_n} = {4‘b0101}。
② A0-A9 提供 cow 列地址;
③ A11和A12不用管;
④ A10控制是否在突发读完成之后立即执行预充电,即关闭当前行操作。为0时不关闭当行,使其仍处于激活状态,方便紧接着对该行进行新的读写操作。为1时就是进入了 READA 状态,会立即执行预充电即关闭当前行,导致下次进行读又得重新激活该行。本次设计我们 A10 为 0。
⑤ BA0-BA1 提供 Bank 地址。
(这里没有提及 row 地址,是因为在 READ 前是 ROW ACTIVE,这就已经激活了行,因此不用再次激活。)
2、READ 总时序图
① 给出一个 ACT 命令,同时指明 Bank 和 row。然后等待时间 tRCD。
② tRCD 时间后,给出一个 READ 命令,同时指明 Bank 和 col,A10为低电平,然后等待4个时钟周期(突发长度为4)。
③ 不想读了就给一个 PRECHARGE 命令,跳出读状态。如果需要重新读,则要给一个 ACT 命令。
三、设计读模块
内部状态机如下所示:
![](https://img2018.cnblogs.com/common/1536533/202002/1536533-20200202231152087-1870020388.png)
具体代码就不贴了。
四、仿真验证
本次仿真只需要在 testbench 中设计一个 wr_trig 信号触发一下写,再设计一个 rd_trig 信号触发一下读,写数据则直接在写模块内部手动赋值,看看读数据有没有错即可。
![](https://img2018.cnblogs.com/common/1536533/202002/1536533-20200202232022008-6194695.png)
![](https://img2018.cnblogs.com/common/1536533/202002/1536533-20200202232054921-365256029.png)
有个细节需要注意,最后两个数据前有个 PRECHARGE 命令,为什么呢?这是因为我们前面设置的数据潜伏期为 3,时序分析图如下所示:
![](https://img2018.cnblogs.com/common/1536533/202002/1536533-20200202234046902-58465433.png)
参考资料:
[1]威三学院FPGA教程
[2]开源骚客FPGA教程