原理参照这个第7部分:各种FIFO硬件设计(FIFO概念、异步、同步、非2次幂深度FIFO)_fifo设计-优快云博客
我发现大家的异步fifo或多或少存在一些问题,我在上面这个老哥的基础上修改了一些地方:
1.去除了判断时候的偏移
2.二进制计数器的范围大小,以及到ram的地址映射
3.bram修改为不是ip,方便移植
4.testbench的值的提供不用延时,采用always模块根据full和empty状态提供输入,而且我的是边写边读验证,一般人都是先写后读验证;
5.修改tb文件的 FIFO_DEPTH_COMPLE为0,可以实现2次幂整数的异步fifo,也就是这个代码是兼容的
代码如下:
顶层代码
module Asyn_no2power#(
//BLOCK RAM address width
parameter integer RAM_ADDR_WIDTH = 5,
//FIFO true depth
parameter integer FIFO_DATA_DEPTH = 6,
//FIFO compensate depth,(FIFO_DATA_DEPTH+FIFO_DEPTH_COMPLE) must be the data of power 2
parameter integer FIFO_DEPTH_COMPLE = 2,
parameter integer FIFO_ADDR_WIDTH = $clog2(FIFO_DATA_DEPTH+FIFO_DEPTH_COMPLE),
parameter integer FIFO_DATA_WIDTH = 8
)(
input wire nrst,
input wire clk_w,
input wire wr_en,
input wire [FIFO_DATA_WIDTH-1:0] wrdata,
output reg fifo_full,
input wire clk_r,
input wire rd_en,
output wire [FIFO_DATA_WIDTH-1:0] rddata,
output reg fifo_empty
);
/*
w_ptr : the write data pointer (RAM Write address)
r_ptr : the read data pointer (RAM Read address)
*/
wire fifo_full_wire;
wire fifo_empty_wire;
reg [FIFO_ADDR_WIDTH:0] w_ptr;
reg [FIFO_ADDR_WIDTH:0] r_ptr;
wire [RAM_ADDR_WIDTH-1:0] ram_wr_addr;
wire [RAM_ADDR_WIDTH-1:0] ram_rd_addr;
wire [FIFO_ADDR_WIDTH:0] w_ptr_shift;
wire [FIFO_ADDR_WIDTH:0] r_ptr_shift;
assign w_ptr_shift = (w_ptr>=2**FIFO_ADDR_WIDTH)?w_ptr:w_ptr-FIFO_DEPTH_COMPLE;
assign r_ptr_shift = (r_ptr>=2**FIFO_ADDR_WIDTH)?r_ptr:r_ptr-FIFO_DEPTH_COMPLE;
assign ram_wr_addr = {
{(RAM_ADDR_WIDTH-FIFO_ADDR_WIDTH){1'b0}},w_ptr_shift[FIFO_ADDR_WIDTH-1:0]};
assign ram_rd_addr = {
{(RAM_ADDR_WIDTH-FIFO_ADDR_WIDTH){1'b0}},r_ptr_shift[FIFO_ADDR_WIDTH-1:0]};
wire fifo_wr;
wire fifo_rd;
/*
fifo_wr : (RAM Write enable). valid only when fifo is not full and fifo data wr