首页 > 其他分享 >异步FIFO设计

异步FIFO设计

时间:2024-08-09 21:50:01浏览次数:7  
标签:异步 raddr waddr rptr FIFO wptr 设计 ADDRSIZE 时钟

Asynchronous FIFO Design

总结来自Clifford E. Cummings论文 《Simulation and Synthesis Techniques for Asynchronous FIFO Design》

一、设计难点

  • 使用格雷码计数时空和满的判断。
  • 同步FIFO读写时钟相同,而异步FIFO读写来自不同两个读写时钟,需要考虑跨时钟域设计。

二、设计思路

把多bit信号跨时钟域是有问题的。设计一般通过FIFO对多bit信号进行安全的跨时钟域传递。

2.1 空满判断

1、二进制空满判断

如图1,在二进制计数nbit地址时,判断full和empty的条件都是waddr==raddr,为了区分,增加1bit,这样地址位宽范围变为[n:0]。此时,当 waddr[n:0]==raddr[n:0] 时,为empty。而full时,waddr会绕raddr一圈,因此判定为

{~waddr[n],waddr[n-1:0]}==raddr[n:0]

image-20240802163021289

2、格雷码空满判断

但采用格雷码计数时,虽然MSB依然是前半部分是0,后半部分是1,但[n-1:0]却不是循环,而是对称,如下图所示。

image-20240805093747915 image-20240805093559025

但是也能看出来,当最高位变成1后,除了最高的前两位,其余位是符合最高位是0时候的顺序规律。因此可通过

{~waddr[n],~waddr[n-1:0],waddr[n-2:0]}==raddr[n:0]判断full。当 waddr[n:0]==raddr[n:0] 时,为empty。

3、保守空满

思考一下,当判断空或满的时候,总有一个指针是通过两级触发器同步过来的,也就意味着有延迟,那这样的判断真的准确吗?下面分别从空和满的角度去分析:

  1. 假空

判断空的时候,需要用读指针和经过读时钟同步过来的写指针来比较。如果在同步写指针时,继续写操作,同步过来的仍然是之前落后的写指针,此时即使读指针和经过读时钟同步过来的写指针满足空的条件,FIFO仍有新写入的数据,即假空。

  1. 假满

判断满的时候,需要写指针和经过写时钟同步过来的读指针进行比较。如果在同步读指针时,继续读操作,同步过来的仍然是之前落后的读指针,此时即使写指针和经过写时钟同步过来的读指针满足满的条件,FIFO仍然有数据已经被读出,即假满。

综上所述,假满和假空虽然存在,但最多会降低运行吞吐率,性能降低,功能仍正确,而不会出现上溢出和下溢出。

但是想一想为什么要在写侧判断满,而在读测判断空?在读测判断满行不行?

答案是不可以。如果在读侧判断满,当读指针和读时钟同步过来的写指针满足满的条件式,已经有了延迟,如果写操作仍在进行,就会覆盖数据,造成功能不正确

2.2 Multi-bit 跨时钟域同步

1、快时钟频率是慢时钟的两倍甚至更快,那么快域地址变化两次,慢时钟域采样一次,前后采样值变化了两次,会产生多位同步的问题吗?

不会,只有多个位同时变化时才会有问题。因为在慢时钟域下只能看到最近的一次跳变,格雷码相邻跳变只有一位不同。

2、Multi-bit 异步复位

异步复位通常会导致指针位多bit产生变化,这会有问题吗?

因为复位后fifo里的数据已经无效,因此不会有问题,另外,虽然读写各有单独的复位信号,但单侧复位时必须通知另一侧,否则会出错。

2.3 格雷码计数器设计

文章给出两种结构,下面依次介绍

1、 第一种

第一种寄存器存储的均是格雷码。

image-20240805173534195

2、第二种

第二种计数器存储的是二进制,直接用二进制对存储器寻址。二进制到格雷码转换的逻辑转移到下面的寄存器。即格雷码只用于跨时钟域的同步。这样做减少延迟,提高频率。

image-20240805173649528

三、RTL结构与设计

1、FIFO结构

结构如下。

image-20240805180008595

根据不同的功能和时钟域,分为以下六个模块:

名字 功能 时钟域
fifo1.v 顶层 所有
fifomem.v 存储,一般用伪双端口ram 所有
sync_r2w.v 写时钟同步读指针
sync_w2r.v 读时钟同步写指针
rptr_empty.v 空判断
wptr_full.v 满判断

2、Verilog代码

  1. fifo.v
module fifo1 #( parameter DSIZE = 8,
                parameter ASIZE = 4)(
    output [DSIZE-1:0] rdata,
    output wfull,
    output rempty,
    input [DSIZE-1:0] wdata,
    input winc, wclk, wrst_n,
    input rinc, rclk, rrst_n
);

    wire [ASIZE-1:0] waddr, raddr;
    wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr;

    sync_r2w sync_r2w (.wq2_rptr(wq2_rptr), .rptr(rptr),
    .wclk(wclk), .wrst_n(wrst_n));

    sync_w2r sync_w2r (.rq2_wptr(rq2_wptr), .wptr(wptr),
    .rclk(rclk), .rrst_n(rrst_n));

    fifomem #(DSIZE, ASIZE) fifomem
    (.rdata(rdata), .wdata(wdata),
    .waddr(waddr), .raddr(raddr),
    .wclken(winc), .wfull(wfull),
    .wclk(wclk));

    rptr_empty #(ASIZE) rptr_empty
    (.rempty(rempty),
    .raddr(raddr),
    .rptr(rptr), .rq2_wptr(rq2_wptr),
    .rinc(rinc), .rclk(rclk),
    .rrst_n(rrst_n));
    
    wptr_full #(ASIZE) wptr_full
    (.wfull(wfull), .waddr(waddr),
    .wptr(wptr), .wq2_rptr(wq2_rptr),
    .winc(winc), .wclk(wclk),
    .wrst_n(wrst_n));
endmodule
  1. fifomem.v
module fifomem #(   parameter DATASIZE = 8, // Memory data word width
                    parameter ADDRSIZE = 4)( // Number of mem address bits
    output  [DATASIZE-1:0]  rdata,
    input   [DATASIZE-1:0]  wdata,
    input   [ADDRSIZE-1:0]  waddr, raddr,
    input                   wclken, wfull, wclk);
`ifdef VENDORRAM
    // instantiation of a vendor's dual-port RAM
    vendor_ram mem (.dout(rdata), .din(wdata),
    .waddr(waddr), .raddr(raddr),
    .wclken(wclken),
    .wclken_n(wfull), .clk(wclk));
`else
    // RTL Verilog memory model
    localparam DEPTH = 1<<ADDRSIZE;
    reg [DATASIZE-1:0] mem [0:DEPTH-1];
    assign rdata = mem[raddr];
    always @(posedge wclk)
        if (wclken && !wfull) mem[waddr] <= wdata;
`endif
endmodule
  1. sync_r2w.v
module sync_r2w #(parameter ADDRSIZE = 4)(
    output reg  [ADDRSIZE:0] wq2_rptr,
    input       [ADDRSIZE:0] rptr,
    input                    wclk, wrst_n
);
reg  [ADDRSIZE:0] wq1_rptr;
always @(posedge wclk, negedge wrst_n) begin
    if(!wrst_n)
        {wq2_rptr,wq1_rptr} <=  'b0;
    else 
        {wq2_rptr,wq1_rptr} <=  {wq1_rptr,rptr};       
end
endmodule
  1. sync_w2r.v
module sync_w2r #(parameter ADDRSIZE = 4)(
    output reg  [ADDRSIZE:0] rq2_wptr,
    input       [ADDRSIZE:0] wptr,
    input                    rclk, rrst_n
);
reg  [ADDRSIZE:0] rq1_wptr;
always @(posedge rclk, negedge rrst_n) begin
    if(!rrst_n)
        {rq2_wptr,rq1_wptr} <=  'b0;
    else 
        {rq2_wptr,rq1_wptr} <=  {rq1_wptr,wptr};       
end
endmodule
  1. rptr_empty.v
module rptr_empty #(parameter ADDRSIZE = 4) (
    output  reg                 rempty, 
    output      [ADDRSIZE-1:0]  raddr, 
    output  reg [ADDRSIZE :0]   rptr, 
    input       [ADDRSIZE :0]   rq2_wptr, 
    input                       rinc, rclk, rrst_n
);
reg  [ADDRSIZE:0]   rbin;
wire [ADDRSIZE:0] bnext,gnext;
assign raddr = rbin[ADDRSIZE-1:0];
// bin counter
assign bnext = rbin + (rinc & ~rempty);
always @(posedge rclk or negedge rrst_n) begin
    if(!rrst_n)
        rbin    <=  {(ADDRSIZE+1){1'b0}};
    else
        rbin    <=  bnext;
end
// gray counter
assign gnext = (bnext>>1) ^ bnext;
always @(posedge rclk or negedge rrst_n) begin
    if(!rrst_n)
        rptr    <=  {(ADDRSIZE+1){1'b0}};
    else
        rptr    <=  gnext;
end
// empty flag
always @(posedge rclk or negedge rrst_n) begin
    if(!rrst_n)
        rempty    <=  1'b1;
    else
        rempty    <=  rq2_wptr == gnext;
end
endmodule
  1. wptr_full.v
module wptr_full #(parameter ADDRSIZE = 4)(
    output reg                  wfull,
    output      [ADDRSIZE-1:0]  waddr,
    output reg  [ADDRSIZE :0]   wptr,
    input       [ADDRSIZE :0]   wq2_rptr,
    input                       winc, wclk, wrst_n
);
reg  [ADDRSIZE:0]   wbin;
wire [ADDRSIZE:0] bnext,gnext;

assign waddr = wbin[ADDRSIZE-1:0];
// bin counter
assign bnext = wbin + (winc & ~wfull);
always @(posedge wclk or negedge wrst_n) begin
    if(!wrst_n)
        wbin    <=  {(ADDRSIZE+1){1'b0}};
    else
        wbin    <=  bnext;
end
// gray counter
assign gnext = (bnext>>1) ^ bnext;
always @(posedge wclk or negedge wrst_n) begin
    if(!wrst_n)
        wptr    <=  {(ADDRSIZE+1){1'b0}};
    else
        wptr    <=  gnext;
end
// full flag
always @(posedge wclk or negedge wrst_n) begin
    if(!wrst_n)
        wfull   <=  1'b0;
    else
        wfull   <=  gnext == {~wq2_rptr[ADDRSIZE:ADDRSIZE-1],wq2_rptr[ADDRSIZE-2:0]};
end
endmodule

标签:异步,raddr,waddr,rptr,FIFO,wptr,设计,ADDRSIZE,时钟
From: https://www.cnblogs.com/HiDark/p/18351563

相关文章

  • Java 基于微信小程序的学校心理咨询聊天室系统 uniapp毕业设计
    文末获取资源,收藏关注不迷路文章目录项目介绍功能需求技术介绍项目界面关键代码目录项目介绍该课题旨在创建一个专门针对大学生心理健康的知识科普平台,其受众包含大学生与其父母,包含知识科普,自我筛查,在线咨询,与匿名倾诉(包含父母与大学生)四个大点。全方位的对大学生......
  • Java基于微信小程序的琴房管理系统 uniapp 毕业设计
    文末获取资源,收藏关注不迷路文章目录项目介绍用户需求分析学生用户管理员用户技术介绍项目界面关键代码目录项目介绍随着互联网技术的发发展,计算机技术广泛应用在人们的生活中,逐渐成为日常工作、生活不可或缺的工具,钢琴培训企业各种管理系统层出不穷,为钢琴培训企......
  • [设计模式]工厂模式
    简单工厂//计算类的基类@Setter@GetterpublicabstractclassOperation{privatedoublevalue1=0;privatedoublevalue2=0;protectedabstractdoublegetResule();}//加法publicclassOperationAddextendsOperation{@Overrideprote......
  • Java毕业设计-基于ssm框架开发的车辆管理系统-毕业论文(附毕设源代码)
    文章目录前言一、毕设成果演示(源代码在文末)二、毕设摘要展示1、开发说明2、需求/流程分析3、系统功能结构三、系统实现展示1、个人中心2、员工管理3、用户管理4、基础数据管理5、车辆管理6、保养登记管理7、事故登记管理8、维修登记管理9、违章登记管理四、毕设内容和......
  • [米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-09 ICMP层程序设计
    软件版本:Anlogic-TD5.9.1-DR1_ES1.1操作系统:WIN1064bit硬件平台:适用安路(Anlogic)FPGA实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板板卡获取平台:https://milianke.tmall.com/登录"米联客"FPGA社区http://www.uisrc.com视频课程、答疑解惑! 5上板调试5.1硬件连接本次......
  • [米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-04 IP层程序设计
    软件版本:Anlogic-TD5.9.1-DR1_ES1.1操作系统:WIN1064bit硬件平台:适用安路(Anlogic)FPGA实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板板卡获取平台:https://milianke.tmall.com/登录"米联客"FPGA社区http://www.uisrc.com视频课程、答疑解惑! 3.3IP层ICMP层数据和UDP层数......
  • [米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-05 ARP层程序设计
    软件版本:Anlogic-TD5.9.1-DR1_ES1.1操作系统:WIN1064bit硬件平台:适用安路(Anlogic)FPGA实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板板卡获取平台:https://milianke.tmall.com/登录"米联客"FPGA社区http://www.uisrc.com视频课程、答疑解惑 3.4ARP层该层具有接收ARP请求......
  • [米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-06 UDP层程序设计
    软件版本:Anlogic-TD5.9.1-DR1_ES1.1操作系统:WIN1064bit硬件平台:适用安路(Anlogic)FPGA实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板板卡获取平台:https://milianke.tmall.com/登录"米联客"FPGA社区http://www.uisrc.com视频课程、答疑解惑! 3.5UDP层该层实现用户数据和U......
  • 消灭星星游戏程序设计【连载十】——小星星的残影轨迹
    消灭星星游戏程序设计【连载十】——小星星的残影轨迹大家每次都可以在页面中下载本节内容的实现代码,一步一步从简单开始,逐步完成游戏的各种功能,如果大家有任何问题也欢迎留言交流。游戏整体效果展示:1、本节要达到的效果这一节课,我们需要添加小星星的残影轨迹效果,也......
  • [米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-07 ICMP层程序设计
    软件版本:Anlogic-TD5.9.1-DR1_ES1.1操作系统:WIN1064bit硬件平台:适用安路(Anlogic)FPGA实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板板卡获取平台:https://milianke.tmall.com/登录"米联客"FPGA社区http://www.uisrc.com视频课程、答疑解惑! 3.6ICMP层该层在程序中为IP层......