verilog实现异步FIFO

异步时钟的空、满信号生成:通过读、写时钟域的读、写指针比较生成

异步信号的比较问题:同步,通过二级寄存器实现,

这里的同步还存在两个问题:1)二进制指针的多位信号转变的异步同步,存在采样错的可能(无法保证同时刻电频反转),2)快到慢存在的漏采现象。

对问题1)采用格雷码编码再同步,再解码,实现多bit信号的异步同步

对问题2)漏采现象只会产生未满报满,未空报空的更保守操作,不影响正确性。

补充:异步信号需要从寄存器输出而不是逻辑输出;

 总流程如下:

二进制转化格雷码:

 module binary2gray_wireout #(
    PTR=4)
 (
    input  [PTR-1:0]  binary_in,
    output [PTR-1:0]  gary_out
);

generate
    genvar i;
    for(i=0;i<(PTR-1);i=i+1)begin
        gary_out[i] = binary_in[i]^binary_in[i+1];
    end
endgenerate

assign gary_out[PTR-1] = binary_in[PTR-1];

endmodule

格雷码转换二进制:

 module gray2binary_wireout #(
    PTR=4)
 (
    input  [PTR-1:0]  gray_in,
    output [PTR-1:0]  binary_out
);

generate
    genvar i;
    for(i=0;i<(PTR-1);i=i+1)begin
        binary_out[i] = gray_in[i]^binary_out[i+1];
    end
endgenerate

assign binary_out[PTR-1] = gray_in[PTR-1];

endmodule

通过双端口RAM实现异步FIFO:

用vivodo示例一下,16的位宽,实际可以做可变位宽

module async_fifo #(
    parameter PTR = 4,
              DATA_WIDTH = 16,
              DATA_DEPTH = 16
) (
    input                       wr_clk,
    input   [DATA_WIDTH-1:0]    wr_data,
    input                       wr_en,
    input                       wr_rst_n,
    output     reg              full,

    input                       rd_clk,
    output   [DATA_WIDTH-1:0]   rd_data,
    input                       rd_en,
    input                       rd_rst_n,
    output       reg            empty
    
);
//*******************generate ptr
    localparam PTR_MAX = (DATA_DEPTH<<1)-1;
    reg  [PTR:0] wr_ptr,wr_ptr_nxt;
    reg  [PTR:0] rd_ptr,rd_ptr_nxt;

    always@(*)begin
        wr_ptr_nxt = wr_ptr ;
        if(wr_en)begin
            if(wr_ptr_nxt==PTR_MAX)
                wr_ptr_nxt = 'd0;
            else
                wr_ptr_nxt = wr_ptr_nxt + 'd1;
        end
    end

always@(posedge wr_clk or negedge wr_rst_n)
    if (wr_rst_n)
        wr_ptr <= 'd0;
    else 
        wr_ptr <= wr_ptr_nxt;

    always@(*)begin
        rd_ptr_nxt = rd_ptr ;
        if(rd_en)begin
            if(rd_ptr_nxt==PTR_MAX)
                rd_ptr_nxt = 'd0;
            else
                rd_ptr_nxt = rd_ptr_nxt + 'd1;
        end
    end

always@(posedge rd_clk or negedge rd_rst_n)
    if (rd_rst_n)
        rd_ptr <= 'd0;
    else 
        rd_ptr <= rd_ptr_nxt;

//**********************b2g
    reg  [PTR:0]  wr_ptr_b2g;
    reg  [PTR:0]  rd_ptr_b2g;    
    wire [PTR:0]  wr_ptr_b2g_nxt;
    wire [PTR:0]  rd_ptr_b2g_nxt;
    binary2gray_wireout #(
    .PTR(PTR+1))
    b2g_wr
 (
    .binary_in(wr_ptr),
    .gray_out(wr_ptr_b2g_nxt)
);

    binary2gray_wireout #(
    .PTR(PTR+1))
    b2g_rd
 (
    .binary_in(rd_ptr),
    .gray_out(rd_ptr_b2g_nxt)
);

always@(posedge wr_clk or negedge wr_rst_n)
    if (wr_rst_n)
        wr_ptr_b2g <= 'd0;
    else 
        wr_ptr_b2g <= wr_ptr_b2g_nxt;

always@(posedge rd_clk or negedge rd_rst_n)
    if (rd_rst_n)
        rd_ptr_b2g <= 'd0;
    else 
        rd_ptr_b2g <= rd_ptr_b2g_nxt;
//********************************sync
reg  [PTR:0]wr_ptr_sync2rd_1,wr_ptr_sync2rd_2;
reg  [PTR:0]rd_ptr_sync2wr_1,rd_ptr_sync2wr_2;


always@(posedge rd_clk or negedge rd_rst_n)
    if (rd_rst_n)begin
        wr_ptr_sync2rd_1 <= 'd0;
        wr_ptr_sync2rd_2 <= 'd0;
    end
    else begin
        wr_ptr_sync2rd_1 <= wr_ptr_b2g;
        wr_ptr_sync2rd_2 <= wr_ptr_sync2rd_1;
    end

always@(posedge wr_clk or negedge wr_rst_n)
    if (wr_rst_n)begin
        rd_ptr_sync2wr_1 <= 'd0;
        rd_ptr_sync2wr_2 <= 'd0;
    end
    else begin
        rd_ptr_sync2wr_1 <= rd_ptr_b2g;
        rd_ptr_sync2wr_2 <= rd_ptr_sync2wr_1;
    end

//*******************************g2b
reg   [PTR:0]rd_ptr_sync2wr_2_g2b;
reg   [PTR:0]wr_ptr_sync2rd_2_r2b;
wire  [PTR:0]rd_ptr_sync2wr_2_g2b_nxt;
wire  [PTR:0]wr_ptr_sync2rd_2_r2b_nxt;
gray2binary_wireout #(
    PTR+1
)rd2wr_g2b 
(
    .gray_in(rd_ptr_sync2wr_2),
    .binary_out(rd_ptr_sync2wr_2_g2b_nxt)
);

gray2binary_wireout #(
    PTR+1
)wr2rd_g2b 
(
    .gray_in(wr_ptr_sync2rd_2),
    .binary_out(wr_ptr_sync2rd_2_r2b_nxt)
);

always@(posedge wr_clk or negedge wr_rst_n)
    if (wr_rst_n)
        rd_ptr_sync2wr_2_g2b <= 'd0;
    else 
        rd_ptr_sync2wr_2_g2b <= rd_ptr_sync2wr_2_g2b_nxt;

always@(posedge rd_clk or negedge rd_rst_n)
    if (rd_rst_n)
        wr_ptr_sync2rd_2_r2b <= 'd0;
    else 
        wr_ptr_sync2rd_2_r2b <= wr_ptr_sync2rd_2_r2b_nxt;
//*******************************full,empty

wire full_nxt,empty_nxt;

assign full_nxt = (rd_ptr_sync2wr_2_g2b[PTR]!=wr_ptr[PTR])&&(rd_ptr_sync2wr_2_g2b[PTR-1:0]==wr_ptr[PTR-1:0]);
assign empty_nxt = (wr_ptr_sync2rd_2_r2b==rd_ptr);

always@(posedge wr_clk or negedge wr_rst_n)
    if (wr_rst_n)
        full <= 'd0;
    else 
        full <= full_nxt;

always@(posedge rd_clk or negedge rd_rst_n)
    if (rd_rst_n)
        empty <= 'd0;
    else 
        empty <= empty_nxt;

//**********************************RAM
Dual_port_RAM Dual_port_RAM_U (
  .clka(wr_clk),    // input wire clka
  .wea(wr_en),      // input wire ena
  .addra(wr_ptr[PTR-1:0]),  // input wire [3 : 0] addra
  .dina(wr_data),  // input wire [15 : 0] douta
  .clkb(rd_clk),    // input wire clkb
  .enb(rd_en),      // input wire enb
  .addrb(rd_ptr[PTR-1:0]),  // input wire [3 : 0] addrb
  .doutb(rd_data)  // output wire [15 : 0] doutb
);

endmodule

ptr指针信号做了一位的拓宽,用于表示套圈,最高位相等而低位相同,视为套一整圈,即写满。实际满、空信号因为异步同步的时延,都是未满报满,未空报空。

格雷码解码到空满信号打了一拍,优化了延迟,(格雷到二进制逻辑延迟比较大,和行波进位加法类似,每一位计算需要等高一位的输出),不过vivado也会自动优化:

参考:Verilog高级数字系统设计技术与示例分析,Kishore Mishra,电子工业出版社。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值