异步FIFO设计verilog代码

直接上代码;参考Clifford E. Cummings大师的style1设计。
给出其英文原文链接:
Simulation and Synthesis Techniques for Asynchronous
FIFO Design

`timescale 1ns / 1ps
//
// Company: 
// Engineer: lhf
// 
// Create Date: 2022/05/20 19:00:24
// Design Name: 
// Module Name: asyn_FIFO
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description:    FIFO 深度为8;   数据位宽为16
// 格雷码指针作用:(1)用于跨时钟域(保证在时钟边沿时只有单bit变化)  (2)用来比较空满
// 二进制指针作用:(1)低三位0-7-7-0循环,可以用来产生读写地址       (2)整体0-16-16-0循环,用于产生格雷码
// 打拍的作用?(跨时钟域同步)
// 写“满”判断是在写时钟域,当wclk更快时,可能发生多采,但多采不是问题;当rclk更快时,可能发生漏采,漏采只会造成假“满”,不会造成功能错误。
// 读“空”信号是在读时钟域,当wclk更快时,可能发生漏采,漏采只会造成假“空”,不会有功能问题;当rclk更快时,可能发生多采,但多采不是问题。
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module asyn_FIFO (
    
    //write signal
    input wclk,
    input wrst_n,
    input [15:0] wr_data,
    input wr_en,  
    
    //read signal
    input rclk,
    input rrst_n,
    output reg [15:0] rd_data,
    input rd_en,
    
    //flag
    output full,
    output empty
);


reg [15:0] RAM[7:0];         //RAM

reg [3:0] wptr;              //二进制写指针
reg [3:0] rptr;              //二进制读指针

wire [2:0] waddr;            //写地址
wire [2:0] raddr;            //读地址

wire [3:0] g_wptr;           //格雷码写指针
wire [3:0] g_rptr;           //格雷码读指针

reg [3:0] g_rptr_r, g_rptr_r1;    //打拍
reg [3:0] g_wptr_r, g_wptr_r1;    //打拍

//binary to gray
assign g_wptr = (wptr>>1) ^ wptr;
assign g_rptr = (rptr>>1) ^ rptr;


//低三位为地址
assign waddr = wptr[2:0];
assign raddr = rptr[2:0];



//读写指针递增
always @(posedge wclk or negedge wrst_n) begin
    if(!wrst_n) begin
        wptr <= 0;
    end
    else if(wr_en && !full)
        wptr <= wptr + 1'b1;
end

always @(posedge rclk or negedge rrst_n) begin
    if(!rrst_n) begin
        rptr <= 0;
    end
    else if(rd_en && !empty)
        rptr <= rptr + 1'b1;
end

//数据读写                         
always @(posedge wclk) begin           //可以不用初始化RAM
    if(wr_en && !full) begin
        RAM[waddr] <= wr_data;
    end
end

always @(posedge rclk) begin
    if(rd_en && !empty)
        rd_data <= RAM[raddr];
end

//打两拍(作同步)(适用于单bit变化)
always @(posedge wclk or negedge wrst_n) begin          //将读gray指针同步到写时钟域,以便于 写满判断
    if(!wrst_n) begin
        g_rptr_r  <= 0;
        g_rptr_r1 <= 0;
    end
    else begin
        g_rptr_r  <=  g_rptr;
        g_rptr_r1 <= g_rptr_r;
    end
        
end

always @(posedge rclk or negedge rrst_n) begin          //将写gray指针同步到读时钟域,以便于 读空判断
    if(!rrst_n) begin
        g_wptr_r  <= 0;
        g_wptr_r1 <= 0;
    end
    else begin
        g_wptr_r  <=  g_wptr;
        g_wptr_r1 <= g_wptr_r;
    end
        
end

//空满判断
    assign empty = (g_rptr == g_wptr_r1);         //每一位都相同
//assign full = ( (g_wptr[3:2] != g_rptr_r1[3:2]) && (g_wptr[1:0] == g_rptr_r1[1:0]) );  
// (g_wptr[3:2] != g_rptr_r1[3:2])逻辑错了,有一位不同这个表达式就成立,这不正确;要特别注意
assign full  = (g_wptr == ({~g_rptr_r1[3:2],g_rptr_r1[1:0]}));            //高两位不同,低两位相同
    
    
endmodule
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值