Asynchronous FIFO and synchronous FIFO-翻译自外网

Synchronous FIFO

先进先出 (FIFO) 是一种非常流行且有用的设计块,用于模块之间的同步和握手机制。

FIFO 的深度: FIFO 中的槽数或行数称为 FIFO 的深度。

FIFO 的宽度:每个槽或行中可以存储的位数称为 FIFO 的宽度。

在同步 FIFO 中,数据读取和写入操作使用相同的时钟频率。通常,它们与高时钟频率一起使用以支持高速系统。

synchronous fifo

Signals:

wr_en: 写使能

wr_data: 写数据write data

full: FIFO is full 满

empty: FIFO is empty 空

rd_en: 读使能 read enable

rd_data: 读数据read data

w_ptr: 写指针write pointer

r_ptr: 读指针 read pointer

FIFO 可以根据 wr_en 信号在时钟的每个 posege 存储/写入 wr_data,直到满为止。每次将数据写入 FIFO 存储器时,写入指针都会递增。

根据rd_en信号,可以在时钟的每个周期从FIFO中取出或读取数据,直到为空为止。每次从 FIFO 存储器读取数据时,读指针都会递增。

method
empty condition

w_ptr == r_ptr 即写指针和读指针具有相同的值。

full condition

满的情况意味着 FIFO 中的每个槽都被占用,但是 w_ptr 和 r_ptr 将再次具有相同的值。因此,无法确定是满状态还是空状态。因此,故意将 FIFO 的最后一个槽保持为空,满条件可以写为 (w_ptr+1’b1) == r_ptr)

code
module synchronous_fifo #(parameter DEPTH=8, DATA_WIDTH=8) (input clk, rst_n,input w_en, r_en,input [DATA_WIDTH-1:0] data_in,output reg [DATA_WIDTH-1:0] data_out,output full, empty
);reg [$clog2(DEPTH)-1:0] w_ptr, r_ptr;reg [DATA_WIDTH-1:0] fifo[DEPTH];// Set Default values on reset.always@(posedge clk) beginif(!rst_n) beginw_ptr <= 0; r_ptr <= 0;data_out <= 0;endend// To write data to FIFOalways@(posedge clk) beginif(w_en & !full)beginfifo[w_ptr] <= data_in;w_ptr <= w_ptr + 1;endend// To read data from FIFOalways@(posedge clk) beginif(r_en & !empty) begindata_out <= fifo[r_ptr];r_ptr <= r_ptr + 1;endendassign full = ((w_ptr+1'b1) == r_ptr);assign empty = (w_ptr == r_ptr);
endmodule
testbench
module sync_fifo_TB;parameter DATA_WIDTH = 8;reg clk, rst_n;reg w_en, r_en;reg [DATA_WIDTH-1:0] data_in;wire [DATA_WIDTH-1:0] data_out;wire full, empty;// Queue to push data_inreg [DATA_WIDTH-1:0] wdata_q[$], wdata;synchronous_fifo s_fifo(clk, rst_n, w_en, r_en, data_in, data_out, full, empty);always #5ns clk = ~clk;initial beginclk = 1'b0; rst_n = 1'b0;w_en = 1'b0;data_in = 0;repeat(10) @(posedge clk);rst_n = 1'b1;repeat(2) beginfor (int i=0; i<30; i++) begin@(posedge clk);w_en = (i%2 == 0)? 1'b1 : 1'b0;if (w_en & !full) begindata_in = $urandom;wdata_q.push_back(data_in);endend#50;endendinitial beginclk = 1'b0; rst_n = 1'b0;r_en = 1'b0;repeat(20) @(posedge clk);rst_n = 1'b1;repeat(2) beginfor (int i=0; i<30; i++) begin@(posedge clk);r_en = (i%2 == 0)? 1'b1 : 1'b0;if (r_en & !empty) begin#1;wdata = wdata_q.pop_front();if(data_out !== wdata) $error("Time = %0t: Comparison Failed: expected wr_data = %h, rd_data = %h", $time, wdata, data_out);else $display("Time = %0t: Comparison Passed: wr_data = %h and rd_data = %h",$time, wdata, data_out);endend#50;end$finish;endinitial begin $dumpfile("dump.vcd"); $dumpvars;end
endmodule
method2
Empty condition

count == 0 i.e. FIFO contains nothing.

Full condition

count == FIFO_DEPTH i.e. counter value has reached till the depth of FIFO

method3
Empty condition

w_ptr == r_ptr i.e. write and read pointers has the same value. MSB of w_ptr and r_ptr also has the same value.

Full condition

w_ptr == r_ptr i.e. write and read pointers has the same value, but the MSB of w_ptr and r_ptr differs.

Asynchronous FIFO

在异步 FIFO 中,数据读取和写入操作使用不同的时钟频率。由于写入和读取时钟不同步,因此称为异步 FIFO。通常,这些用于数据需要从一个时钟域传递到另一个时钟域的系统,这通常被称为“时钟域交叉”。因此,异步 FIFO 有助于同步工作在不同时钟上的两个系统之间的数据流。

asynchronous fifo usage

Gray code

在这里插入图片描述

Asynchronous FIFO Block Diagram

asynchronous fifo

Signals:

wr_en: 写使能write enable

wr_data: 写数据write data

full: FIFO is full满

empty: FIFO is empty 空

rd_en: read enable 读使能

rd_data: read data 读数据

b_wptr: binary write pointer 二进制写指针

g_wptr: gray write pointer 格雷码写指针

b_wptr_next: binary write pointer next 指示用于二进制写入新数据的下一个可用地址。

g_wptr_next: gray write pointer next 指示用于格雷码写入新数据的下一个可用地址。

b_rptr: binary read pointer 二进制读指针

g_rptr: gray read pointer 格雷码读指针

b_rptr_next: binary read pointer next 指示用于二进制读新数据的下一个可用地址。

g_rptr_next: gray read pointer next 指示用于格雷码读入新数据的下一个可用地址。

b_rptr_sync: binary read pointer synchronized

b_wptr_sync: binary write pointer synchronized

同步必要性:

  • 异步 FIFO:它们具有独立的读写时钟,通常以不同的频率运行。
  • 时钟域交叉 (CDC):这些域之间的数据传输带来了同步挑战。
  • 亚稳态:跨时钟域的信号可能进入亚稳态(不确定值),可能导致数据损坏。
Asynchronous FIFO Operation

在同步 FIFO 的情况下,写入和读取指针在同一时钟上生成。然而,在异步 FIFO 的情况下,写指针与写时钟域对齐,而读指针与读时钟域对齐。因此,需要跨域来计算 FIFO 满和空的情况。这会导致实际设计中的亚稳态。为了解决这种亚稳态问题,可以使用2个触发器或3个触发器同步器来传递写入和读取指针。为了便于解释,我们将使用 2 个触发器同步器。请注意,单个“2 FF 同步器”只能解决一位的亚稳态问题。因此,根据写入和读取指针,需要多个 2FF 同步器。

img

module synchronizer #(parameter WIDTH=3) (input clk, rst_n, [WIDTH:0] d_in, output reg [WIDTH:0] d_out);reg [WIDTH:0] q1;always@(posedge clk) beginif(!rst_n) beginq1 <= 0;d_out <= 0;endelse beginq1 <= d_in;d_out <= q1;endend
endmodule
Usage of Binary to Gray code converter and vice-versa in Asynchronous FIFO

到目前为止,我们讨论了如何在各个时钟域中获取异步写入和读取指针。但是,我们不应该传递二进制格式的写入和读取指针值。由于亚稳态,整体写入或读取指针值可能不同。

示例:当写时钟域的二进制值 wr_ptr = 4’b1101 通过 2FF 同步器传输时,读时钟域的 wr_ptr 值可能会接收为 4’b1111 或任何其他不可接受的值。而格雷码则保证与之前的值相比只有一位变化。因此,写指针和读指针都需要首先转换为其相应域中的等效格雷码,然后将它们传递到相反的域。要检查另一个域中 FIFO 满和空的情况,我们有两种方法。

Way 1

将接收到的格雷码格式的指针转换为二进制格式,然后检查满和空的情况。

FIFO full condition
g2b_converter g2b_wr(g_rptr_sync, b_rptr_sync);
wrap_around = b_rptr_sync[PTR_WIDTH] ^ b_wptr[PTR_WIDTH];
wfull = wrap_around & (b_wptr[PTR_WIDTH-1:0] == b_rptr_sync[PTR_WIDTH-1:0]);
FIFO empty condition
g2b_converter g2b_rd(g_wptr_sync, b_wptr_sync);
rempty = (b_wptr_sync == b_rptr_next);
Way 2

借助接收到的格雷码写入和读取指针直接检查满和空状况。这是高效的,因为它不需要额外的硬件来将格雷码写入和读取指针转换为等效的二进制形式。

FIFO full condition
wfull = (g_wptr_next == {~g_rptr_sync[PTR_WIDTH:PTR_WIDTH-1], g_rptr_sync[PTR_WIDTH-2:0]});
FIFO empty condition
rempty = (g_wptr_sync == g_rptr_next);
Asynchronous FIFO Verilog Code

同步器 g_rptr_sync 的输出作为“写指针处理程序”模块的输入,用于生成 FIFO 满状态。如果二进制写指针 (b_wptr) 满足 (w_en & !full) 条件,则它会递增。该 b_wptr 值被馈送到 fifo_mem 模块以将数据写入 FIFO。

Write Pointer Handler
module wptr_handler #(parameter PTR_WIDTH=3) (input wclk, wrst_n, w_en,input [PTR_WIDTH:0] g_rptr_sync,output reg [PTR_WIDTH:0] b_wptr, g_wptr,output reg full
);reg [PTR_WIDTH:0] b_wptr_next;reg [PTR_WIDTH:0] g_wptr_next;reg wrap_around;wire wfull;assign b_wptr_next = b_wptr+(w_en & !full);assign g_wptr_next = (b_wptr_next >>1)^b_wptr_next;always@(posedge wclk or negedge wrst_n) beginif(!wrst_n) beginb_wptr <= 0; // set default valueg_wptr <= 0;endelse beginb_wptr <= b_wptr_next; // incr binary write pointerg_wptr <= g_wptr_next; // incr gray write pointerendendalways@(posedge wclk or negedge wrst_n) beginif(!wrst_n) full <= 0;else        full <= wfull;endassign wfull = (g_wptr_next == {~g_rptr_sync[PTR_WIDTH:PTR_WIDTH-1], g_rptr_sync[PTR_WIDTH-2:0]});endmodule
Read Pointer Handler

同步器 g_wptr_sync 的输出作为“读指针处理程序”模块的输入,以生成 FIFO 空条件。如果二进制读指针 (b_rptr) 满足 (r_en & !empty) 条件,则它会递增。该 b_rptr 值被馈送到 fifo_mem 模块以从 FIFO 读取数据。

module rptr_handler #(parameter PTR_WIDTH=3) (input rclk, rrst_n, r_en,input [PTR_WIDTH:0] g_wptr_sync,output reg [PTR_WIDTH:0] b_rptr, g_rptr,output reg empty
);reg [PTR_WIDTH:0] b_rptr_next;reg [PTR_WIDTH:0] g_rptr_next;assign b_rptr_next = b_rptr+(r_en & !empty);assign g_rptr_next = (b_rptr_next >>1)^b_rptr_next;assign rempty = (g_wptr_sync == g_rptr_next);always@(posedge rclk or negedge rrst_n) beginif(!rrst_n) beginb_rptr <= 0;g_rptr <= 0;endelse beginb_rptr <= b_rptr_next;g_rptr <= g_rptr_next;endendalways@(posedge rclk or negedge rrst_n) beginif(!rrst_n) empty <= 1;else        empty <= rempty;end
endmodule
FIFO Memory

基于二进制编码的写和读指针,数据分别写入 FIFO 或从 FIFO 读取。

module fifo_mem #(parameter DEPTH=8, DATA_WIDTH=8, PTR_WIDTH=3) (input wclk, w_en, rclk, r_en,input [PTR_WIDTH:0] b_wptr, b_rptr,input [DATA_WIDTH-1:0] data_in,input full, empty,output reg [DATA_WIDTH-1:0] data_out
);reg [DATA_WIDTH-1:0] fifo[0:DEPTH-1];always@(posedge wclk) beginif(w_en & !full) beginfifo[b_wptr[PTR_WIDTH-1:0]] <= data_in;endend/*always@(posedge rclk) beginif(r_en & !empty) begindata_out <= fifo[b_rptr[PTR_WIDTH-1:0]];endend*/assign data_out = fifo[b_rptr[PTR_WIDTH-1:0]];
endmodule
Top Module
`include "synchronizer.v"
`include "wptr_handler.v"
`include "rptr_handler.v"
`include "fifo_mem.v"module asynchronous_fifo #(parameter DEPTH=8, DATA_WIDTH=8) (input wclk, wrst_n,input rclk, rrst_n,input w_en, r_en,input [DATA_WIDTH-1:0] data_in,output reg [DATA_WIDTH-1:0] data_out,output reg full, empty
);parameter PTR_WIDTH = $clog2(DEPTH);reg [PTR_WIDTH:0] g_wptr_sync, g_rptr_sync;reg [PTR_WIDTH:0] b_wptr, b_rptr;reg [PTR_WIDTH:0] g_wptr, g_rptr;wire [PTR_WIDTH-1:0] waddr, raddr;synchronizer #(PTR_WIDTH) sync_wptr (rclk, rrst_n, g_wptr, g_wptr_sync); //write pointer to read clock domainsynchronizer #(PTR_WIDTH) sync_rptr (wclk, wrst_n, g_rptr, g_rptr_sync); //read pointer to write clock domain wptr_handler #(PTR_WIDTH) wptr_h(wclk, wrst_n, w_en,g_rptr_sync,b_wptr,g_wptr,full);rptr_handler #(PTR_WIDTH) rptr_h(rclk, rrst_n, r_en,g_wptr_sync,b_rptr,g_rptr,empty);fifo_mem fifom(wclk, w_en, rclk, r_en,b_wptr, b_rptr, data_in,full,empty, data_out);endmodule
Testbench Code
module async_fifo_TB;parameter DATA_WIDTH = 8;wire [DATA_WIDTH-1:0] data_out;wire full;wire empty;reg [DATA_WIDTH-1:0] data_in;reg w_en, wclk, wrst_n;reg r_en, rclk, rrst_n;// Queue to push data_inreg [DATA_WIDTH-1:0] wdata_q[$], wdata;asynchronous_fifo as_fifo (wclk, wrst_n,rclk, rrst_n,w_en,r_en,data_in,data_out,full,empty);always #10ns wclk = ~wclk;always #35ns rclk = ~rclk;initial beginwclk = 1'b0; wrst_n = 1'b0;w_en = 1'b0;data_in = 0;repeat(10) @(posedge wclk);wrst_n = 1'b1;repeat(2) beginfor (int i=0; i<30; i++) begin@(posedge wclk iff !full);w_en = (i%2 == 0)? 1'b1 : 1'b0;if (w_en) begindata_in = $urandom;wdata_q.push_back(data_in);endend#50;endendinitial beginrclk = 1'b0; rrst_n = 1'b0;r_en = 1'b0;repeat(20) @(posedge rclk);rrst_n = 1'b1;repeat(2) beginfor (int i=0; i<30; i++) begin@(posedge rclk iff !empty);r_en = (i%2 == 0)? 1'b1 : 1'b0;if (r_en) beginwdata = wdata_q.pop_front();if(data_out !== wdata) $error("Time = %0t: Comparison Failed: expected wr_data = %h, rd_data = %h", $time, wdata, data_out);else $display("Time = %0t: Comparison Passed: wr_data = %h and rd_data = %h",$time, wdata, data_out);endend#50;end$finish;endinitial begin $dumpfile("dump.vcd"); $dumpvars;end
endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/613633.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

6.2 声音编辑工具GoldWave5简介(1)

不管你的MP3歌曲的简单剪接或者音频格式的转换,还是更加高级的后期加工 GoldWave5都可以令你轻松胜,甚至你自己录一首卡拉OK,也可以经过GoldWave5的修饰成为像歌星一样水晶般的动人声音!除了附有许多的效果处理功能外&#xff0c;它还能将编辑好的文件存成WAV、AU、SND、RAW、A…

vue 公众号开发,调用jssdk封装

vue 公众号开发&#xff0c;经常会使用到 转发朋友&#xff0c;朋友圈&#xff0c;调用扫一扫等功能&#xff0c;这时就要使用微信的 jssdk 微信jssdk传送门 1. 安装jssdk 插件 (jweixin-module) npm install jweixin-module --save 2. 封装方法 utils/jwx.js let jweixin…

sqlilabs第四十九五十关

Less-49(GET - Error based - String Bind - ORDER BY CLAUSE) 手工注入 无回显(还是单引号闭合)&#xff0c;只能使用延时注入 自动脚本 和上一关一样 Less-50(GET - Error based - ORDER BY CLAUSE -numeric- Stacked injection) 手工注入 这里需要使用堆叠注入的思路 自…

Qt优秀开源项目之二十:RedPanda-CPP(小熊猫C++)

小熊猫C是跨平台、轻量易用的开源C/C集成开发环境。 官网&#xff1a;http://royqh.net/redpandacpp github&#xff1a;https://github.com/royqh1979/RedPanda-CPP 小熊猫C&#xff08;原名小熊猫Dev-C 7)是基于Qt开发的Dev-C替代版本。和经典的Dev-C 5.11、新的Embarcadero …

TDengine 签约积成电子

随着电力系统的复杂性和数据量不断增加&#xff0c;电力负荷、电压、频率等庞大的时序数据需要更高效的存储和处理能力&#xff0c;才能确保数据的可靠性和实时性。此外&#xff0c;电力系统还需要对实时数据进行快速分析和决策&#xff0c;以确保电网的稳定运行。然而&#xf…

openssl3.2 - 官方dmeo学习 - sconnect.c

文章目录 openssl3.2 - 官方dmeo学习 - sconnect.c概述笔记END openssl3.2 - 官方dmeo学习 - sconnect.c 概述 TLS客户端 - 使用根证书, 非阻塞, 向服务器要东西. 笔记 开始一个新demo学习时, 要从头配置包含路径, 麻烦. 直接拷贝上一个实现工程, 换掉实现.c方便一些. 换的…

(超详细)4-YOLOV5改进-添加ShuffleAttention注意力机制

1、在yolov5/models下面新建一个SE.py文件&#xff0c;在里面放入下面的代码 代码如下&#xff1a; import numpy as np import torch from torch import nn from torch.nn import init from torch.nn.parameter import Parameterclass ShuffleAttention(nn.Module):def __…

C //练习 4-12 运用printd函数的设计思想编写一个递归版本的itoa函数,即通过递归调用把整数转换为字符串。

C程序设计语言 &#xff08;第二版&#xff09; 练习 4-12 练习 4-12 运用printd函数的设计思想编写一个递归版本的itoa函数&#xff0c;即通过递归调用把整数转换为字符串。 注意&#xff1a;代码在win32控制台运行&#xff0c;在不同的IDE环境下&#xff0c;有部分可能需要…

【IOS】惯性导航详解(包含角度、加速度、修正方式的api分析)

参考文献 iPhone的惯性导航&#xff0c;基于步态。https://www.docin.com/p-811792664.html Inertial Odometry on Handheld Smartphones: https://arxiv.org/pdf/1703.00154.pdf 惯性导航项目相关代码&#xff1a;https://github.com/topics/inertial-navigation-systems use…

openssl3.2 - 官方dmeo学习 - 索引贴

文章目录 openssl3.2 - 官方dmeo学习 - 索引贴概述笔记工程的搭建和调试环境BIOBIO - client-arg.cBIO - client-conf.cBIO - saccept.cBIO - sconnect.cBIO - server-arg.cBIO - server-cmod.cBIO - server-conf.cBIO - 总结certsEND openssl3.2 - 官方dmeo学习 - 索引贴 概述…

长尾分布定义,举个物种长尾分布和词频长尾分布的例子。

问题描述&#xff1a;长尾分布定义&#xff0c;举个物种长尾分布和词频长尾分布的例子。 问题解答&#xff1a; 长尾分布是一种概率分布的类型&#xff0c;它描述的是一种极端事件或者稀有事件的发生概率。具体来说&#xff0c;长尾分布描述的是少量的类别占据了大部分的样本…

SpringIOC之support模块GenericXmlApplicationContext

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

STM32(HAL库) CubeMX+Keil5 建立工程

STM32&#xff08;HAL库&#xff09; CubeMXKeil5 建立工程 目标选择 菜单栏 File 新建工程打开工程退出软件 Window 输出窗口的开启软件字体设置 Help 软件帮助文档检查软件更新管理MCU 已存在工程&#xff08;Existing Projects&#xff09; 最近打开过的工程(Recent Open…

2024年值得关注的10种自动化测试趋势

超级自动化测试这是利用人工智能&#xff08;AI&#xff09;和机器学习&#xff08;ML&#xff09;来自动化测试任务。超级自动化测试可以帮助减少手动测试的需求&#xff0c;提高测试的效率&#xff0c;并在开发生命周期的早期发现缺陷。 TestOps集成TestOps是将DevOps实践扩…

PyPDF2 3.0.0更新,一些函数被弃用,需要重新写

1.PdfFileWriter is deprecated and was removed in PyPDF2 3.0.0. Use PdfWriter instead. 这错误表明你正在使用的 PyPDF2 版本中已经移除了 PdfFileWriter&#xff0c;并在版本 3.0.0 中被替代为 PdfWriter。这是因为在 PyPDF2 的更新中&#xff0c;一些 API 被重新组织和更…

中霖教育:专业不对口,能考会计师吗?

学的不是会计专业&#xff0c;专业不对口&#xff0c;能不能考会计师? 从学历要求来看&#xff0c;考会计师并无硬性规定必须具备哪个专业的学历。所以只要符合报考条件&#xff0c;非会计专业的人也可以报考会计师。 除了基本条件外&#xff0c;报名参加中级会计考试的人员…

html学习之路:简述html文档头部 <meta> 的 http-equiv 属性

&#x1f9cb;当输入网址打开网页时&#xff0c;设置html头部meta的http-equiv属性&#xff0c;可以帮助浏览器更加精确和正常却的显示网页内容&#xff0c;比如设置网页多久自动刷新&#xff0c;设置网页在浏览器缓存中的时限&#xff0c;设置多少事件跳转到指定的网页地址&am…

leetcode-合并两个有序数组

88. 合并两个有序数组 题解&#xff1a; 这是一个经典的双指针问题&#xff0c;我们可以使用两个指针分别指向nums1和nums2的最后一个元素&#xff0c;然后比较两个指针所指向的元素大小&#xff0c;将较大的元素放入nums1的末尾&#xff0c;并将对应的指针向前移动一位。重复…

Redis系列-15.Redis的IO多路复用原理解析

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术&#x1f525;如果感觉博主的文章还不错的…

[DM8] 达梦8配置兼容Oracle

查看版本信息 select *&#xff0c;id_code from v$version; 查询解释&#xff1a; DM Database Server 64 V8 1-1-190-21.03.12-136419-ENT 64 版本位数标识&#xff0c;64表示为64位版本&#xff0c;无64则表示为32位版本 V8 大版本号&#xff0c;目前主要是V7、V8 1-1-190…