无论是用XPM_MEMORY还是IP Core的方式调用各种类型的RAM(单端口、简单双端口或真双端口),都会遇到这样一个参数:Write Mode。该参数有三个可选值,分别为write_first、read_first和no_change。那么这三个值到底有什么区别呢?应用场景又如何?本质上,这个参数是用来解决读写冲突即同时对同一地址进行读写操作时,写入该地址的数据是什么,读出该地址的数据是什么。
write_first
首先看write_first(又称为Read after Write,即先写后读或写优先),如图1所示,相应的读写时序如图2所示。不难看出,当写使能WEA有效时(高有效),此时读依然有效,故该模式下从地址bb和cc读出的是新写入的数据1111和2222,也意味着写入地址bb和cc的数据分别为1111和2222。
read_first
再看read_first(又称为Read before Write,即先读后写或读优先),如图3所示,相应的读写时序如图4所示。此时,从时序图中可以看出读出的是该地址上的原有数据,同时会把新数据写入该地址。
no_change
最后我们看看no_change(No Read on Write,保持模式),如图5所示,相应的读写时序如图6所示。可以看出,一旦写操作有效,读操作即无效,此时输出端口保持写操作之前读出的数据不变。
三种模式让很多初学者觉得困惑。实际上,这并没有什么神秘感,我们可以通过RTL代码实现这三种功能,如图7~图9所示。可以看到write_first由if else语句完成,we有效时写入新数据,同时输出等于输入,无效时输出等于该地址原有数据。read_first由if语句完成,写法类似于移位寄存器,这就是为什么写有效时读出的是该地址上的原有数据。no_change由if else语句完成,dout在if分支上没有被赋值,故保持不变,这是实现no_change的关键点。
write_fisrt Verilog代码:
read_fisrt Verilog代码:
no_change Verilog代码:
从代码风格的角度而言,实现这三种功能是非常容易的。这也进一步验证了RTL代码风格对设计的影响。因此,对于初学者而言,可以多花些时间研究代码风格,很可能会有事半功倍的效果。
思考一下:
对于一个单端口RAM,采用RTL代码描述,如何在同一个模块中实现如下功能:
(1)宽度可配置
(2)深度可配置
(3)写模式可配置