我是靠谱客的博主 烂漫冬瓜,最近开发中收集的这篇文章主要介绍Verilog实现异步FIFO&异步FIFO常见问题集锦1.FIFO顶层框图2.设点要点3.设计代码4.FIFO相关问题,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 1.FIFO顶层框图
  • 2.设点要点
    • (1)“写满”与“读空”
    • (2)二进制转格雷码
  • 3.设计代码
  • 4.FIFO相关问题
    • (1) FIFO中,为什么多比特格雷码编码能够用两级触发器同步
    • (2) FIFO中,读空/写满信号会有设计错误吗
    • (3)FIFO中,使用格雷码后产生亚稳态之后有什么影响
    • (4)大多数情形下,异步FIFO两端的时钟不是同频的,或者读快写慢,或者读慢写快,这时候进行地址同步的时候,可能会有地址遗漏,这会对空满信号判断产生影响吗
    • (5) FIFO在跨时钟域时是怎么处理的
    • (6) FIFO中使用格雷码传输的特点

1.FIFO顶层框图

在这里插入图片描述

2.设点要点

(1)“写满”与“读空”

写满:下一轮写追上读
读空:同一轮读追上写

写满信号(wfull)在写钟域产生
读空信号(rempty)在读钟域产生

以格雷码为例
在这里插入图片描述

(2)二进制转格雷码

在这里插入图片描述
电路中实现为:

gaddr=addr ^ (addr>>1)

3.设计代码

`timescale  1ns/1ns
module  fifo #(
parameter   MEM_WIDTH=8,
parameter   MEM_HEIGHT=16,
parameter   ADDR_SIZE=4,
parameter   CNT_MAX=15
)(
    input       wire                        wclk,//慢时钟域
    input       wire                        rclk,//快时钟域
    input       wire                        rst_n,
    input       wire                        win,
    input       wire                        rin,
    input       wire [MEM_WIDTH-1:0]        wdata,
    output      reg  [MEM_WIDTH-1:0]        rdata,
    output      wire                        wfull,
    output      wire                        rempty
);

reg [MEM_WIDTH-1:0]     mem[MEM_HEIGHT-1:0];//8*16存储单元
wire [ADDR_SIZE-1:0]    waddr,raddr;
reg [ADDR_SIZE:0]       waddr_r,raddr_r;
reg [ADDR_SIZE:0]       wgaddr,rgaddr;
wire [ADDR_SIZE:0]      wgaddr_w,rgaddr_w;

wire [ADDR_SIZE:0]      wgaddr_syn,rgaddr_syn;

reg [ADDR_SIZE:0]       wgaddr_syn_reg1,wgaddr_syn_reg2;
reg [ADDR_SIZE:0]       rgaddr_syn_reg1,rgaddr_syn_reg2;

wire    wen,ren;

assign  wen=win&(~wfull);
assign  ren=rin&(~rempty);

assign  wfull=({~wgaddr_w[ADDR_SIZE:ADDR_SIZE-1],wgaddr_w[ADDR_SIZE-2:0]}==rgaddr_syn);//写满:下一轮写指针追上读指针
assign  rempty=(rgaddr_w==wgaddr_syn);//读空:同一轮读指针追上写指针

always  @(posedge   wclk or negedge rst_n)begin
    if(rst_n==1'b0) waddr_r<=0;
    else    if(wen==1'b1)
        waddr_r<=waddr_r+1'b1;
end
assign  waddr=waddr_r[ADDR_SIZE-1:0];

assign  wgaddr_w=waddr_r^(waddr_r>>1);
always  @(posedge   wclk or negedge rst_n)begin
    if(rst_n==1'b0) wgaddr<=0;
    else    wgaddr<=wgaddr_w;
end


always  @(posedge   rclk or negedge rst_n)begin
    if(rst_n==1'b0) raddr_r<=0;
    else    if(ren==1'b1)
        raddr_r<=raddr_r+1'b1;
end
assign  raddr=raddr_r[ADDR_SIZE-1:0];

assign  rgaddr_w=raddr_r^(raddr_r>>1);
always  @(posedge   rclk or negedge rst_n)begin
    if(rst_n==1'b0) rgaddr<=0;
    else    rgaddr<=rgaddr_w;
end

//同步单元
always  @(posedge   rclk or negedge rst_n)begin
    if(rst_n==1'b0) begin
        wgaddr_syn_reg1<=0;
        wgaddr_syn_reg2<=0;
    end
    else    begin
        wgaddr_syn_reg1<=wgaddr;
        wgaddr_syn_reg2<=wgaddr_syn_reg1;
    end
end
assign  wgaddr_syn=wgaddr_syn_reg2;

always  @(posedge   wclk or negedge rst_n)begin
    if(rst_n==1'b0) begin
        rgaddr_syn_reg1<=0;
        rgaddr_syn_reg2<=0;
    end
    else    begin
        rgaddr_syn_reg1<=rgaddr;
        rgaddr_syn_reg2<=rgaddr_syn_reg1;
    end
end
assign  rgaddr_syn=rgaddr_syn_reg2;

always  @(posedge   wclk )begin
    if(wen==1'b1)   mem[waddr]<=wdata;
end  

always  @(posedge   rclk )begin
    if(ren==1'b1)   rdata<=mem[raddr];
end  

endmodule

仿真图
在这里插入图片描述
在这里插入图片描述

4.FIFO相关问题

(1) FIFO中,为什么多比特格雷码编码能够用两级触发器同步

FIFO中,相邻格雷码只有一位数据发生变化,使用多组两级触发器同步时,只有一组触发器的采样信号发生变化,其他组的信号保持不变能够被正确采样,因此相当于只有1bit变化数据,因而可以使用两级触发器同步

关联问题:
为什么多比特数据不能用两级触发器同步

如果使用两级触发器对多比特数据进行同步,那么就需要多组两级触发器链,每组触发器链的第一级触发器都有可能产生亚稳态,稳定到错误电平。那么多组触发器就有可能发送多组电平出错,导致数据传输出错概率增大

(2) FIFO中,读空/写满信号会有设计错误吗

读空信号:写地址同步到读时钟域中,与读地址进行对比后(读地址=写地址)产生,采用的同步器一般是2级触发器链(2个周期的延迟),也就是说写地址A同步到读时钟域时,写时钟域的写地址已经变为A+2。如果A和读地址B相等,产生读空信号,但实际上此时FIFO中还有两个数据,并没有真正空,由于我们产生读空信号,是为了防止真正读空时,读出重复错误的数据,因此提前把读空信号拉高,是我们可以接受的,不算是设计错误。
写满信号同理

(3)FIFO中,使用格雷码后产生亚稳态之后有什么影响

没有影响。
假设二进制1000,转为格雷码传输给读时钟域,没有产生亚稳态时,应该传输为1100,如果在传输过程中产生亚稳态,稳定到错误电平,传输给读时钟域的信号为0100(二进制0111对应的格雷码为0100,所以在上次传输(传输0111)和本次传输(1000)过程中,后三位不变,不会发生亚稳态),和正确的地址相差为1,相当于提前一个周期拉高读空信号,因此不会造成影响。(写格雷码是“延时”过来的,因此不会造成影响)

此时,写时钟域操作的地址为0x8;
传递到读时钟域的地址为0x7;
因此,即使误产生了读空信号,此时FIFO中仍然有数据,不存在FIFO中无数据而读空信号未产生的错误

(4)大多数情形下,异步FIFO两端的时钟不是同频的,或者读快写慢,或者读慢写快,这时候进行地址同步的时候,可能会有地址遗漏,这会对空满信号判断产生影响吗

假设写慢读快

读空信号:写地址同步到读时钟域为慢到快,写地址能够被正确采样,同步后的写地址滞后与当前写地址(一般为二级同步器),“读空”信号被提前拉高。
写满信号:读地址同步到写时钟域为快到慢,读地址存在漏传现象。假设读地址从0-7,在数据同步过程中只传递了地址1,3,5,当同步地址为5时,实时读地址可能为7,相当于“在写时钟域还没反应过来的情况下,读时钟域又偷偷地读了几个数据”,这样读地址与写地址比较时,就不存在“写满”继续写操作,因此漏掉的地址没有对FIFO的逻辑操作产生影响。

(5) FIFO在跨时钟域时是怎么处理的

使用分离的读写模块,将时钟域分割开来,通过读空/写满信号进行指示,完成相应的读写操作。FIFO内部使用格雷码进行跨时钟域处理,因为FIFO的读写地址均为自增1,所以相邻格雷码之间只有1bit数据发生变化,可以使用两级同步器进行跨时钟域处理。

(6) FIFO中使用格雷码传输的特点

优点:1.相邻位只有一位数据发生变化,能够降低亚稳态发生概率;
2.并且即使发生亚稳态(逻辑误判),也能够保证FIFO正常工作
缺点:需要增加相应的组合逻辑

最后

以上就是烂漫冬瓜为你收集整理的Verilog实现异步FIFO&异步FIFO常见问题集锦1.FIFO顶层框图2.设点要点3.设计代码4.FIFO相关问题的全部内容,希望文章能够帮你解决Verilog实现异步FIFO&异步FIFO常见问题集锦1.FIFO顶层框图2.设点要点3.设计代码4.FIFO相关问题所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部