1、前言
Vivado在生成memory的时候,有个Operating Mode选项。
本篇将专门分析这些工作模式的含义。
2、具体含义
官方解释如下:
“WRITE_FIRST” 模式,写操作时,输出端口会将当前写的数据输出。(ASIC中又称“write through”,或AWT,Async)
“READ_FIRST” 模式,写操作时,输出端口会将当前写地址的原数据输出。
“NO_CHANGE”模式,写操作时,输出端口会保持原值不变。只有在读操作的过程中输出端口才会变化。
不好理解没关系,下面列出图示和时序波形:
- “WRITE_FIRST” 模式(ASIC中又称“write through”)
- 写入的数据一边写到RAM内核,一边输出到端口。
- “READ_FIRST” 模式
- 写入的数据写到RAM内核,写地址指向的RAM数据输出到端口。
- “READ_FIRST” 模式
- 写入的数据写到RAM内核。输出端口的数据(实际上有个寄存器)保持不变。
下面列出对应的代码,有人习惯从RTL代码上理解。此代码是可以被Vivado工具直接识别的。
- “WRITE_FIRST”代码,可综合
-
//write port
-
always @(posedge clk)
begin
-
if(en && we)
-
RAM[addr] <= di;
-
end
-
-
//read port
-
always @(posedge clk)
begin
-
if(en)
-
if(we)
-
dout <= di;
-
else
-
dout <= RAM[addr];
-
end
- “READ_FIRST”代码,可综合
-
//write port
-
always @(posedge clk)
begin
-
if(en && we)
-
RAM[addr] <= di;
-
end
-
-
//
read port
-
always @(posedge clk)
begin
-
if(en)
-
dout <= RAM[addr];
-
end
- “NO_CHANGE”代码,可综合
-
//write port
-
always @(posedge clk)
begin
-
if(en && we)
-
RAM[addr] <= di;
-
end
-
-
//
read port
-
always @(posedge clk)
begin
-
if(en && !we)
-
dout <= RAM[addr];
-
end
其实,RTL还是更好理解一些的。
注意,http://www.elecfans.com/d/887964.html这篇文章的RTL部分“READ_FIRST” 代码和“NO_CHANGE”代码写的有问题。
3、应用和背景
在IC设计领域,FPGA主要用来做AISC的原型验证,即在FPGA上要实现一个与ASIC完全一致的设计,以此加速仿真,方便快速找到AISC设计的问题。
分享两个故事:
一个故事发生在前东家,有次生成FPGA的ram时,错把Operation Mode选成了“READ_FIRST” ,而恰好暴露出来一个之前没验证到的bug。为什么会这样呢?
Bug是这样的,这位designer把当前cycle写入ram的值,下一cycle直接在读接口上采样并使用了,这实际是利用了“WRITE_FIRST”(ASIC中叫“write through”)的特性。
在设计中,这样的操作是不允许的,虽然这样可以省掉一个read cycle,但这种设计的通用性很差,一旦更换ram,就会出问题。当时的项目就是迁移到新工艺节点,ram由原来的“write through”(对应FPGA的“WRITE_FIRST”)更新到了“no write through”(对应FPGA的“NO_CHANGE”),这样此designer的设计出问题了。
为什么ASIC仿真没有发现这个问题呢?
IC公司在ASIC仿真时为了加速,一般都是用自己写的ram sim model来做仿真模型的。工艺节点升级了,ram行为也由write through变成了no write through模式,而ram sim model却没有更新。因此,ASIC仿真并没有暴露出来这个问题。
幸亏这个bug在RTL freeze前暴露出来了,若是没有检查出来而流片了,那后果不堪设想。
另一个故事发生在现公司,遇到的问题也是类似原因。
Bug是这样的,一位designer设计时没有考虑好读写端口的配合,导致某种场景下会出现读的数据没来及取走,就已经向这个地址覆盖了新的数据的情况,且这种情况只会冲刷一个cycle。
若ram是write through模式,则会丢失一个数据;若是no write through模式,则恰好利用了读端口的保持特性规避了丢数据的问题。
本质上讲,这样的设计也是错误的,肯定要改设计,只不过项目已经进展到RTL freeze阶段,只能靠这种方式来规避了。
4、总结
上述提到的两处bug,都是因为设计者(包括写ram model的验证者)不了解ram的特性导致的。
- 建议要用脚本语言来生成FPGA、ASIC的ram,用GUI生成则很容易出错,且不好检查。
- 建议要用FPGA、ASIC的ram工具生成的ram model来做仿真,不要手写ram model。
- 设计者要用标准的读写时序进行设计,必须避免“利用端口特性的不规则设计”,