1. 背景
芯片设计中涉及资源的动态存储和修改,随着单芯片的规格、性能不断提升。 随之也产生了复杂的设计需求,为了降低后期出现读写mem 的时序问题风险。 在设计前,芯片架构师会约定mem的读延时(比正常的mem的延时要大)。同时开发mem_bypass 模块用于解决逻辑的读写冲突。
2. 概要
所谓的读写冲突,对于1rw的mem 不涉及。 因为其读写端口复用,不存在读写同拍/在读出数据前的写行为。其主要用于1r1w 和 2r1w 的mem 中。其可以保证逻辑在对同一个地址做读写操作时,保证读到的数据是最新值(当前新写入的值)。
读写冲突的后果就是: 读出的数据不是当前的最新值,使用旧数据做运算后回写数据错误等一些列问题。
3. 设计思想
如何保证读到的数据是最新值? 需要考虑在发起读操作~~~ 读数据返回这段时间是否存在该地址的写操作。
4. 设计实现
为了更好的描述读写冲突,下面根据时序图来做讲解。同时约定底层的cell的读写数据延时为0 ,外部wrapper 的读数据延时为4 cycle【将cell读出数据延时4 cycle】。
①对于在读发起--读数据返回期间,只有hazard0 有效。 在发起读的同时,逻辑wr 也操作了该地址。
cell无法处理同拍下读写相同地址的行为。有些fpga的ip 可以支持选择读数据使能使用老数据还是新数据(wr写的数据)
以此类推 hazard1/hazard2/hazard3/hazard4有效,其读地址的返回值就为在读数据返回前写数据的新值。
扩展: 在hazard0 状态,若cell 的读延时为1,写延时为0,且wr和rd 同拍。此时hazard0其的作用和rd_vld时rdata的结果就是一致的即hazard0 可以忽略不做处理。
② 基于①存在读发起--读数据返回期间每拍都存在wr 请求,所以设计的代码可以拆分为以下3段
always@(*)begin
if(hazard4)begin
rd_data = wr_data_hazard4
end
else if(hazard0 | hazard1 | hazard2 |hazard3 )begin
rd_data = wr_data_hazard0/wr_data_hazard1/wr_data_hazard2/wr_data_hazard3;
end
else
begin rd_data = mem_rdata
end
end
5.结论
mem_bypass 的就是将rd_rd----rd_vld间存在的写信号对应的写数据锁存起来,在rd_vld 时与mem返回的o_rdata 做mux选择。 如果期间存在写,则使用写数据(新数据),否则使用mem 自身返回的o_rdata。