- FIFO有一个读口和一个写口,读写时钟一致是同步FIFO,时钟不一致就是异步FIFO
- IP设计中通常使用的是同步FIFO
- 异步FIFO通常使用在跨时钟域设计中
RAM(Random Access Memory)的设计
FIFO中的数据可以存储在寄存器中或者SRAM中,FIFO的容量比较小的时候,使用register,FIFO容量比较大的时候使用的是SRAM
- SRAM通常是Memory Compiler进行产生的
- SRAM不需要手动写仿真模型
- RAM在时钟的驱动下,可以从两个端口同时进行读写操作
- 写操作:写数据、写地址、写使能
- 读操作:读地址、读使能,读取完成之后,会返回读数据
双端口RAM的Verilog代码(仿真模型)
- 将RAM的位宽、深度进行参数化设计,方便后续进行修改
- 首先要定义一个存储空间,用于存储数据
- SRAM是已经综合好的block,其中布局布线已经完成
- 在进行DC综合的时候,会将定义的存储体综合为寄存器或者sram(如果有相应的库文件),使用sram,面效比会比较好;register作为存储体的时候,容量小的时候,面积比较小,并且在下一个周期读出其中的值
- 使用register作为存储体,使用组合逻辑在当拍就可以得到数据
//1.
always@ (posedge clk) begin
if(read_en)
read_data <= memory[read_addr];
end
//2.
// 当拍就可以得到memory的值
wire [DATA_WIDTH-1:0] read_data_next;
assign read_data_next = memory[read_addr];
always @(posedge clk) begin
if(read_en)
read_data <= read_data_next;
end
同步FIFO设计
- FIFO包含两部分,一部分是存储体,另一部分是fifo ctrl
- fifo是不会存在根据地址取值的,fifo - 先入先出,所以端口没有地址,地址通过其中的fifo ctrl进行控制
- 没有读地址和写地址
- fifo满了之后,不能写入数据,fifo为空的时候,不能向外读取数据,关键是full和empty信号的产生
- fifo上下游模块看到fifo的状态之后,满不写,空不读;在fifo内部也需要进行控制
方法1
- 需要维护读指针和写指针
- 产生一个写使能,需要给一个地址给到写使能,写指针加1;产生一个读使能,读指针加1
- 产生空满信号:用一个计数器,表示当前fifo中一共存有多少数据,写使能来的时候,计数器加1,读使能来的时候,计数器减1,写使能和读使能同时来的时候,计数器不变
- 当counter为容量减一的时候,来了一个写使能,会变为满
- 当counter为1的时候,来了一个读使能,会变为空
// 满信号产生
if((!write_allow) && (Fcounter == 9'b0))
empty <= 1;
else if((!write_allow) && (Fcounter == 9'b1 && (read_allow))
empty <=1;
else
empty <= 1'b0;
- counter的值要覆盖所有的RAM地址范围
parameter COUNTER_WIDTH = 9;
reg Fcounter [COUNTER_WDITH-1:0]; // 只能表示0-511,表示不了512这个数
reg Fcounter [COUNTER_WDITH:0]; // 9bit可以表示512这个数
方法2
方法1多例化了一个计数器,计数器需要占据一定的资源和面积
- 读写指针的空间扩大一倍,使用除最高位之外的其他位寻址sram