基于FPGA器件实现异步FIFO读写系统的设计

时间:2025-06-16  作者:Diven  阅读:0

FIFO 简介

基于FPGA器件实现异步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. 读写指针的工作原理

读指针:总是指向下一个将要被写入的单元,复位时,指向第 1 个单元(编号为 0)。

写指针:总是指向当前要被读出的数据,复位时,指向第 1 个单元(编号为 0)

2.FIFO 的“空”/“满”检测

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

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

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

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

方法 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 码同步到另一个时钟域进行对比,作为空满状态的检测。

4. 使用 gray 码进行对比,如何判断“空”与“满”

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

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

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

wptr 和同步过来的 rptr 的 MSB 不相等,因为 wptr 必须比 rptr 多折回一次。

wptr 与 rptr 的次高位不相等,如上图位置 7 和位置 15,转化为二进制对应的是 0111 和 1111,MSB 不同说明多折回一次,111 相同代表同一位置。

剩下的其余位完全相等。

5. 总体实现

系统的总体框图如下:

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; 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 #(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;endassign 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//---------------------------------------------------------------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 pointeralways @(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

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

猜您喜欢

数字晶体管是关键的电子元件,应用于多个领域。在计算机和手机等消费电子产品中,数字晶体管是构建处理器和存储器的基础,推动了信息技术的飞速发展。在通信领域,数字晶体...
2020-01-03 00:00:00


速度传感器主要是一种广泛应用于工业控制、汽车、航空航天等领域的关键设备,它通过感知物体的运动状态,将运动速度转化为电信号输出。本文将深入探讨速度传感器的结构组成...
2023-11-21 18:10:00

梅花盘头机螺钉是常见的紧固件,应用于机械、电子等领域。根据不同的用途和特性,梅花盘头机螺钉可以分为以下几类。根据材质的不同,梅花盘头机螺钉可分为碳钢、不锈钢和合...
2011-03-23 00:00:00

二极管是重要的半导体器件,应用于电子电路中。主要功能是单向导电,即允许电流在一个方向上流动,而在另一个方向上阻止电流的流动。二极管的型号种类繁多,针对不同的应用...
2025-04-06 20:00:03

现代电子设备中,连接器的选择非常重要。TERMINAL_40.87X11.1MM作为一种新型连接器,以其独特的设计和优越的性能受到广泛关注。本文将深入探讨TER...
2025-03-07 19:15:23

扩音器是应用于各个领域的重要设备,主要用于增强声音传播,确保信息的清晰传达。在教育领域,扩音器帮助教师在大型教室或户外活动中清晰地传达知识,提升了教学效果。在商...
2009-10-14 00:00:00

现代市场中,配件的选择对产品的整体性能和用户体验非常重要。其中,"Accessories_17.5X11.3MM_TM"作为一款特定尺寸的配...
2025-03-05 17:58:37

电子电路中,二极管是重要的元件,其中开关二极管和稳压二极管是应用最的两种类型。虽然都属于二极管的范畴,但在功能和应用上存在显著的差异。本文将详细介绍这两种二极管...
2025-04-01 09:01:08