Verilog实现异步FIFO

空满标志产生:
满标志:“写时钟阈写指针格雷码” 与 “同步到写时钟阈的读指针格雷码” 高两位不同,其余低位相同即为满。其中高两位中已经包含了折返标志位。
空标志:“读时钟阈读指针格雷码” 与 “同步到读时钟阈的写指针格雷码” 全等即为空。

直接上源码

module FIFO #(
    parameter data_width = 16, 
    parameter data_depth = 8,
    parameter addr_width = 4
)
(
    input clk_write,
    input clk_read,
    input rst_n,
    input write_a, //write avalible
    input read_a,  //read avalible
    input [data_width : 0] data_in,

    output reg [data_width : 0] data_out,
    output reg full,
    output reg empty
);

reg  [addr_width-1 : 0] write_addr;
wire [addr_width-1 : 0] write_addr_gray;
reg  [addr_width-1 : 0] w2r_addr_gray1;
reg  [addr_width-1 : 0] w2r_addr_gray2;

reg  [addr_width-1 : 0] read_addr;
wire [addr_width-1 : 0] read_addr_gray;
reg  [addr_width-1 : 0] r2w_addr_gray1;
reg  [addr_width-1 : 0] r2w_addr_gray2;

reg  [data_width-1 : 0] FIFO [data_depth-1 : 0];

//写时钟阈
always@(posedge clk_write or negedge rst_n) begin
    if(!rst_n)
       write_addr <= 0;
    else if(write_a & !full) begin      //写使能和非满时才可向FIFO写入数据
        write_addr <= write_addr + 1;
        FIFO[write_addr[addr_width-2 : 0]] <= data_in;
    end
    else begin
        write_addr <= write_addr;
        FIFO[write_addr[addr_width-2 : 0]] <= FIFO[write_addr[addr_width-2 : 0]];  //注意此处写FIFO的地址是除去折返标志位(最高位)的地址
    end
end

//读时钟阈
always @(posedge clk_read or negedge rst_n) begin
    if(!rst_n)
       read_addr <= 0;
    else if(read_a & !empty ) begin    //读使能和非空时才可从FIFO读出数据
        read_addr <= read_addr + 1;
        data_out <= FIFO[read_addr[addr_width-2 : 0]];
    end
    else begin
        read_addr <= read_addr;
    end
end

//写指针同步到读时钟阈
assign write_addr_gray = (write_addr >> 1) ^ write_addr;
always @(posedge clk_read ) begin
    w2r_addr_gray1 <= write_addr_gray;
    w2r_addr_gray2 <= w2r_addr_gray1;       //两级寄存器减少亚稳态 
end

//读指针同步带写时钟阈
assign read_addr_gray = (read_addr >> 1) ^ read_addr;
always @(posedge clk_write ) begin
    r2w_addr_gray1 <= read_addr_gray;
    r2w_addr_gray2 <= r2w_addr_gray1;       //两级寄存器减少亚稳态 
end

//FIFO空信号产生,在读时钟阈判断
always@(*) begin
    if (w2r_addr_gray2 == read_addr_gray) begin
        empty = 'b1;
    end
    else begin
        empty = 'b0;
    end
end

//FIFO满信号产生,在写时钟阈判断,高两位不同,其余低位相同
always @(*) begin
    if({~r2w_addr_gray2[addr_width-1 : addr_width-2],r2w_addr_gray2[addr_width-3 : 0]} ==  write_addr_gray) begin
        full = 'b1;
    end
    else begin
        full = 'b0;
    end
end

endmodule
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
异步FIFO是一种用于在两个异步时钟域之间传输数据的解决方案。在Verilog实现异步FIFO可以采用以下步骤: 1. 定义FIFO的输入和输出接口:包括读写时钟、读写使能信号、读写数据和读写指针等。 2. 使用两个时钟域的寄存器同步输入信号:由于读写时钟不同,需要使用两级寄存器级联来同步输入信号,以消除亚稳态。 3. 实现FIFO的读写逻辑:根据读写使能信号和读写指针,确定读写操作的时机和数据。 4. 实现FIFO的存储器:可以使用RAM或者其他存储结构来存储数据。 5. 实现FIFO的读写指针逻辑:根据读写操作的完成情况,更新读写指针的值。 6. 添加互斥逻辑:为了避免读写冲突,可以使用互斥逻辑来控制读写操作的互斥性。 需要注意的是,在实现异步FIFO时,需要考虑跨时钟域的问题。可以使用两级寄存器同步和格雷码等方法来解决跨时钟域的问题,确保读写指针的比较正确。 总之,通过定义接口、同步输入信号、实现读写逻辑和存储器、更新读写指针以及添加互斥逻辑等步骤,可以在Verilog实现异步FIFO。 #### 引用[.reference_title] - *1* *3* [异步FIFO---Verilog实现](https://blog.csdn.net/alangaixiaoxiao/article/details/81432144)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [基于Verilog实现异步FIFO](https://blog.csdn.net/ZHOUJIAN1997/article/details/121597269)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值