0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于FPGA的异步FIFO的实现

FPGA学习交流 来源:互联网 作者:佚名 2018-06-21 11:15 6605次阅读

大家好,又到了每日学习的时间了,今天我们来聊一聊基于FPGA的异步FIFO的实现。

一、FIFO简介

FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,它与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

用途1:
异步FIFO读写分别采用相互异步的不同时钟。在现代集成电路芯片中,随着设计规模的不断扩大,一个系统中往往含有数个时钟,多时钟域带来的一个问题就是,如何设计异步时钟之间的接口电路。异步FIFO是这个问题的一种简便、快捷的解决方案,使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据。

用途2:
对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

二、分类
同步FIFO是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作;
异步FIFO是指读写时钟不一致,读写时钟是互相独立的。

三、FIFO的常见参数
FIFO的宽度:即FIFO一次读写操作的数据位;
FIFO的深度:指的是FIFO可以存储多少个N位的数据(如果宽度为N)。
满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。
空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。
读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。

读写指针的工作原理
写指针:总是指向下一个将要被写入的单元,复位时,指向第1个单元(编号为0)。
读指针:总是指向当前要被读出的数据,复位时,指向第1个单元(编号为0)

FIFO的“空”/“满”检测
FIFO设计的关键:产生可靠的FIFO读写指针和生成FIFO“空”/“满”状态标志。

当读写指针相等时,表明FIFO为空,这种情况发生在复位操作时,或者当读指针读出FIFO中最后一个字后,追赶上了写指针时,如下图所示:
123118sawxcouuaacy3ck4.png


当读写指针再次相等时,表明FIFO为满,这种情况发生在,当写指针转了一圈,折回来(wrapped around)又追上了读指针,如下图:
122509xslrjygkggjyghr5.png


为了区分到底是满状态还是空状态,可以采用以下方法:

方法1:在指针中添加一个额外的位(extra bit),当写指针增加并越过最后一个FIFO地址时,就将写指针这个未用的MSB加1,其它位回零。对读指针也进行同样的操作。此时,对于深度为2n的FIFO,需要的读/写指针位宽为(n+1)位,如对于深度为8的FIFO,需要采用4bit的计数器,0000~1000、1001~1111,MSB作为折回标志位,而低3位作为地址指针。

* 如果两个指针的MSB不同,说明写指针比读指针多折回了一次;如r_addr=0000,而w_addr = 1000,为满。
* 如果两个指针的MSB相同,则说明两个指针折回的次数相等。其余位相等,说明FIFO为空;

3.二进制FIFO指针的考虑
将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题,因为采用二进制计数器时所有位都可能同时变化,在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路,将地址值转换为相应的gray码,然后将该gray码同步到另一个时钟域进行对比,作为空满状态的检测。
122509e29dmvv62g2bg4os.png


4.
使用gray码进行对比,如何判断“空”与“满”
使用gray码解决了一个问题,但同时也带来另一个问题,即在格雷码域如何判断空与满。

对于“空”的判断依然依据二者完全相等(包括MSB);

而对于“满”的判断,如下图,由于gray码除了MSB外,具有镜像对称的特点,当读指针指向7,写指针指向8时,除了MSB,其余位皆相同,不能说它为满。因此不能单纯的只检测最高位了,在gray码上判断为满必须同时满足以下3条:

* wptr和同步过来的rptr的MSB不相等,因为wptr必须比rptr多折回一次。
* wptr与rptr的次高位不相等,如上图位置7和位置15,转化为二进制对应的是0111和1111,MSB不同说明多折回一次,111相同代表同一位置。
* 剩下的其余位完全相等。
122510vqu8elbujwakye4n.png

5.总体实现
系统的总体框图如下:
122510pdyt99tfhddmob5t.png


1)顶层模块
module AsyncFIFO
#(parameter ASIZE = 4, //地址位宽
parameter DSIZE = 8) //数据位宽
(
input [DSIZE-1:0] wdata,
input winc, wclk, wrst_n, //写请求信号,写时钟,写复位
input rinc, rclk, rrst_n, //读请求信号,读时钟,读复位
output [DSIZE-1:0] rdata,
output wfull,
output rempty
);
wire [ASIZE-1:0] waddr, raddr;
wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr; /************************************************************
* In order to perform FIFO full and FIFO empty tests using
* this FIFO style, the read and write pointers must be
* passed to the opposite clock domain for pointer comparison
*************************************************************/
/*在检测“满”或“空”状态之前,需要将指针同步到其它时钟域时,使用格雷码,可以降低同步过程中亚稳态出现的概率*/
sync_r2w I1_sync_r2w(
.wq2_rptr(wq2_rptr),
.rptr(rptr),
.wclk(wclk),
.wrst_n(wrst_n));
sync_w2r I2_sync_w2r (
.rq2_wptr(rq2_wptr),
.wptr(wptr),
.rclk(rclk),
.rrst_n(rrst_n));
/*
* DualRAM
*/
DualRAM #(DSIZE, ASIZE) I3_DualRAM(
.rdata(rdata),
.wdata(wdata),
.waddr(waddr),
.raddr(raddr),
.wclken(winc),
.wclk(wclk));

/*
* 空、满比较逻辑
*/
rptr_empty #(ASIZE) I4_rptr_empty(
.rempty(rempty),
.raddr(raddr),
.rptr(rptr),
.rq2_wptr(rq2_wptr),
.rinc(rinc),
.rclk(rclk),
.rrst_n(rrst_n));
wptr_full #(ASIZE) I5_wptr_full(
.wfull(wfull),
.waddr(waddr),
.wptr(wptr),
.wq2_rptr(wq2_rptr),
.winc(winc),
.wclk(wclk),
.wrst_n(wrst_n));
endmodule

2)DualRAM模块
module DualRAM
#(
parameter DATA_SIZE = 8, // 数据位宽
parameter ADDR_SIZE = 4 // 地址位宽
)
(
input wclken,wclk,
input [ADDR_SIZE-1:0] raddr, //RAM read address
input [ADDR_SIZE-1:0] waddr, //RAM write address
input [DATA_SIZE-1:0] wdata, //data input
output [DATA_SIZE-1:0] rdata //data output
);
localparam RAM_DEPTH = 1 << ADDR_SIZE;   //RAM深度 = 2^ADDR_WIDTH
reg [DATA_SIZE-1:0] Mem[RAM_DEPTH-1:0];
always@(posedge wclk)
begin
if(wclken)
Mem[waddr] <= wdata;
end
assign rdata = Mem[raddr];
endmodule

3)同步模块
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 or negedge wrst_n)
if (!wrst_n)
{wq2_rptr,wq1_rptr} <= 0;
else
{wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr};
endmodule

4)同步模块2
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 or negedge rrst_n)
if (!rrst_n)
{rq2_wptr,rq1_wptr} <= 0;
else
{rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr};
endmodule

5)空判断逻辑
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] rgraynext, rbinnext;
wire rempty_val;
//-------------------
// GRAYSTYLE2 pointer: gray码读地址指针
//-------------------
always @(posedge rclk or negedge rrst_n)
if (!rrst_n)
begin
rbin <= 0;
rptr <= 0;
end
else
begin
rbin <= rbinnext ;
rptr <= rgraynext;
end
// gray码计数逻辑
assign rbinnext = !rempty ? (rbin + rinc) : rbin;
assign rgraynext = (rbinnext>>1) ^ rbinnext; //二进制到gray码的转换
assign raddr = rbin[ADDRSIZE-1:0];
//---------------------------------------------------------------
// FIFO empty when the next rptr == synchronized wptr or on reset
//---------------------------------------------------------------
/*
* 读指针是一个n位的gray码计数器,比FIFO寻址所需的位宽大一位
* 当读指针和同步过来的写指针完全相等时(包括MSB),说明二者折回次数一致,FIFO为空
*
*/
assign rempty_val = (rgraynext == rq2_wptr);
always @(posedge rclk or negedge rrst_n)
if (!rrst_n)
rempty <= 1'b1;
else
rempty <= rempty_val;
endmodule

6)满判断逻辑
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] wgraynext, wbinnext;
wire wfull_val;
// GRAYSTYLE2 pointer
always @(posedge wclk or negedge wrst_n)
if (!wrst_n)
begin
wbin <= 0;
wptr <= 0;
end
else
begin
wbin <= wbinnext;
wptr <= wgraynext;
end
//gray 码计数逻辑
assign wbinnext = !wfull ? wbin + winc : wbin;
assign wgraynext = (wbinnext>>1) ^ wbinnext;
assign waddr = wbin[ADDRSIZE-1:0];
/*由于满标志在写时钟域产生,因此比较安全的做法是将读指针同步到写时钟域*/
/**/
//------------------------------------------------------------------
// Simplified version of the three necessary full-tests:
// assign wfull_val=((wgnext[ADDRSIZE] !=wq2_rptr[ADDRSIZE] ) &&
// (wgnext[ADDRSIZE-1] !=wq2_rptr[ADDRSIZE-1]) &&
// (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0]));
//------------------------------------------------------------------
assign wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1],
wq2_rptr[ADDRSIZE-2:0]});
always @(posedge wclk or negedge wrst_n)
if (!wrst_n)
wfull <= 1'b0;
else
wfull <= wfull_val;
endmodule

quartus中有异步FIFO IP核,为安全起见推荐使用IP核定制FIFO,本文的目的只是作为思路参考。

今天就聊到这里,各位,加油。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1632

    文章

    21814

    浏览量

    606978
收藏 人收藏

    相关推荐

    FIFO IP核的使用教程

    在数字设计中,利用FIFO进行数据处理是非常普遍的应用,例如,实现时钟域交叉、低延时存储器缓存、总线位宽调整等。下图给出了FIFO生成器支持的一种可能配置。
    的头像 发表于 01-03 09:36 1867次阅读
    <b class='flag-5'>FIFO</b> IP核的使用教程

    FPGA复位的8种技巧

    FPGA 设计中,复位起到的是同步信号的作用,能够将所有的存储元件设置成已知状态。在数字电路设计中,设计人员一般把全局复位作为一个外部引脚来实现,在加电的时候初始化设计。全局复位引脚与任何
    的头像 发表于 11-16 10:18 480次阅读
    <b class='flag-5'>FPGA</b>复位的8种技巧

    FIFO Generator的Xilinx官方手册

    FIFO作为FPGA岗位求职过程中最常被问到的基础知识点,也是项目中最常被使用到的IP,其意义是非常重要的。本文基于对FIFO Generator的Xilinx官方手册的阅读与总结,汇总主要知识点
    的头像 发表于 11-12 10:46 801次阅读
    <b class='flag-5'>FIFO</b> Generator的Xilinx官方手册

    FIFO的深度应该怎么计算

    FIFOFPGA/IC设计中经常使用到的模块,它经常被用在两个模块之间进行数据的缓存,以避免数据在传输过程中丢失。同时FIFO也经常被用在跨时钟域处理中。
    的头像 发表于 10-25 15:20 498次阅读
    <b class='flag-5'>FIFO</b>的深度应该怎么计算

    分享一个嵌入式通用FIFO环形缓冲区实现

    开源项目ringbuff ,是一款通用FIFO环形缓冲区实现的开源库,作者MaJerle,遵循 MIT 开源许可协议。
    的头像 发表于 10-23 16:20 587次阅读
    分享一个嵌入式通用<b class='flag-5'>FIFO</b>环形缓冲区<b class='flag-5'>实现</b>库

    Efinity FIFO IP仿真问题 -v1

    Efinity目前不支持联合仿真,只能通过调用源文件仿真。 我们生成一个fifo IP命名为fifo_sim 在Deliverables中保留Testbench的选项。 在IP的生成目录下会有以下
    的头像 发表于 10-21 11:41 1175次阅读
    Efinity <b class='flag-5'>FIFO</b> IP仿真问题 -v1

    Java CompletableFuture 异步超时实现探索

    简介 JDK 8 中 CompletableFuture 没有超时中断任务的能力。现有做法强依赖任务自身的超时实现。本文提出一种异步超时实现方案,解决上述问题。 前言 JDK 8 是一次重大的版本
    的头像 发表于 07-25 14:06 451次阅读

    FPGA同步复位和异步复位

    FPGA(Field-Programmable Gate Array,现场可编程门阵列)中的复位操作是设计过程中不可或缺的一环,它负责将电路恢复到初始状态,以确保系统的正确启动和稳定运行。在FPGA设计中,复位方式主要分为同步复位和异步
    的头像 发表于 07-17 11:12 1840次阅读

    FPGA异步信号处理方法

    FPGA(现场可编程门阵列)在处理异步信号时,需要特别关注信号的同步化、稳定性以及潜在的亚稳态问题。由于异步信号可能来自不同的时钟域或外部设备,其到达时间和频率可能不受FPGA内部时钟
    的头像 发表于 07-17 11:10 1352次阅读

    如何使用FX3同步从属fifo模式通过FPGA传输传感器数据?

    我们正试图使用 FX3 同步从属 fifo 模式通过 FPGA 传输传感器数据。 USB type-C 接口需要选择一个多路复用器来决定使用哪一边的 USB。 因此,我们考虑使用 FX3 GPIO
    发表于 07-17 08:04

    具有FIFO的双异步通信元件TL16C552A数据表

    电子发烧友网站提供《具有FIFO的双异步通信元件TL16C552A数据表.pdf》资料免费下载
    发表于 06-26 11:28 0次下载
    具有<b class='flag-5'>FIFO</b>的双<b class='flag-5'>异步</b>通信元件TL16C552A数据表

    同步FIFO异步FIFO区别介绍

    ,并且间隔时间长,也就是突发写入。那么通过设置一定深度的FIFO,可以起到数据暂存的功能,且使得后续处理流程平滑。 时钟域的隔离:主要用异步FIFO。对于不同时钟域的数据传输,可以通过FIFO
    的头像 发表于 06-04 14:27 1917次阅读
    同步<b class='flag-5'>FIFO</b>和<b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>区别介绍

    FPGA能否正确接收来自FX3同步从站FIFO的数据?

    低电平,则不对数据总线进行采样。 6. t6 时,FPGA 用新地址更新地址总线,依此类推; 在此过程之后,FPGA 能否正确接收来自 FX3 同步从站 FIFO 的数据? 非常感谢!
    发表于 05-31 08:09

    关于同步FIFO异步FIFO的基础知识总结

    FIFO是一种先进先出数据缓存器,它与普通存储器的区别是没有外部读写地址线,使用起来非常简单,缺点是只能顺序读写,而不能随机读写。
    的头像 发表于 04-09 14:23 3485次阅读
    关于同步<b class='flag-5'>FIFO</b>和<b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>的基础知识总结

    如何将USB-UART bridge固件复合进来,实现synchronous slave FIFO和USB-UART bridge同时工作?

    ,USB-UART bridge ,可实现虚拟COM端口 请问如何将USB-UART bridge 固件复合进来,实现synchronous slave FIFO和USB-UART bridge 同时工作
    发表于 02-29 07:09