异步 FIFO 设计

作者:Linest-5,文章来源:CSDN博客

写在前面

FIFO 通常用于将数据从一个时钟域安全地传递到另一个异步时钟域。使用 FIFO 将数据从一个时钟域传递到另一个时钟域需要多异步时钟设计技术。有许多方法可以正确设计 FIFO,但仍然难以正确综合和分析设计。

简介

异步 FIFO 指一种 FIFO 设计,其中数据值从一个时钟域写入 FIFO 缓冲区,而数据值从另一个时钟域的同一 FIFO 缓冲区读取,其中两个时钟域彼此异步。异步 FIFO 用于将数据从一个时钟域安全地传递到另一个时钟域。本文讨论了一种 FIFO 设计风格以及在进行异步 FIFO 设计时必须考虑的重要细节。

传递多个异步信号

试图将来自一个时钟域的多个变化信号同步到一个新时钟域并确保所有变化信号同步到新时钟域中的同一时钟周期已被证明是有问题的。 FIFO 在设计中用于安全地将多位数据字从一个时钟域传递到另一个时钟域。

通过一个时钟域中的控制信号将数据字放入 FIFO 缓冲存储器阵列中,并且通过来自第二时钟域的控制信号从同一 FIFO 缓冲存储器阵列的另一个端口移除数据字。从概念上讲,使用这些假设设计 FIFO 的任务似乎很容易。

与进行 FIFO 设计相关的困难与生成 FIFO 指针和找到可靠的方法来确定 FIFO 上的满和空状态有关。

同步 FIFO 指针

对于同步 FIFO 设计(写入和读取 FIFO 缓冲区在同一时钟域中进行的 FIFO),一种实现计算写入和读取 FIFO 缓冲区的次数以递增(在 FIFO 写入时,但没有读取)、递减(在 FIFO 读取但不写入)或保持(不写入和读取,或同时写入和读取操作)FIFO 缓冲区的当前填充值。当 FIFO 计数器达到预定的满值时,FIFO 是满的,而当 FIFO 计数器为零时,FIFO 是空的。

但是对于异步 FIFO 设计,不能使用递增递减 FIFO 填充计数器,因为需要两个不同的异步时钟来控制计数器。要确定异步 FIFO设计的满和空状态,必须比较写和读指针。

异步FIFO指针

为了理解 FIFO 设计,需要了解 FIFO 指针是如何工作的。写指针总是指向下一个要写的字;因此,在复位时,两个指针都设置为零,这也恰好是要写入的下一个 FIFO 字位置。在 FIFO 写入操作中,写入指针指向的内存位置被写入,然后写入指针递增以指向下一个要写入的位置。

类似地,读指针始终指向要读取的当前 FIFO 字。再次复位时,两个指针都复位为零,FIFO 为空且读取指针指向无效数据(因为 FIFO 为空且空标志置位)。第一个数据字写入 FIFO 后,写指针递增,清空标志,仍在寻址第一个 FIFO 存储器字内容的读指针立即将第一个有效字驱动到 FIFO数据输出端口,由接收逻辑读取。读取指针始终指向下一个要读取的 FIFO 字这一事实意味着接收器逻辑不必使用两个时钟周期来读取数据字。如果接收器在读取 FIFO 数据之前首先必须增加读取指针字,接收器将计时一次以从 FIFO 输出数据字,然后再计时一次以将数据字捕获到接收器中。那将是不必要的低效。

当读写指针相等时,FIFO 为空。这种情况发生在复位操作期间两个指针都复位为零时,或者当读指针赶上写指针时,已经从 FIFO 中读取了最后一个字。

当指针再次相等时,即当写指针回绕并赶上读指针时,FIFO 已满。这是个问题。当指针相等时,FIFO 要么是空的,要么是满的,但是哪个?

用于区分满和空的一种设计技术是向每个指针添加一个额外的位。当写指针递增超过最终 FIFO 地址时,写指针将递增未使用的 MSB,同时将其余位设置回零,如图所示(FIFO 已包装并切换指针 MSB)。读取指针也是如此。如果两个指针的 MSB 不同,则表示写指针比读指针多绕了一圈。如果两个指针的 MSB 相同,则表示两个指针的回绕次数相同。

1.png

使用 n 位指针,其中 (n‑1) 是访问整个 FIFO 内存缓冲区所需的地址位数,当两个指针(包括 MSB)相等时,FIFO 为空。当两个指针(除了 MSB 相等)时,FIFO 已满。

二进制 FIFO 指针注意事项

尝试将二进制计数值从一个时钟域同步到另一个是有问题的,因为 n 位计数器的每个位都可以同时更改(例如 7‑>8 二进制数是 0111‑>1000,所有位都已更改)。解决该问题的一种方法是在保持寄存器中采样和保持周期性二进制计数值,并将同步就绪信号传递到新时钟域。当就绪信号被识别时,接收时钟域向发送时钟域发送回一个同步的确认信号。在接收到来自接收时钟域的确认信号之前,采样指针不得改变。使用这种技术可以将具有多个变化位的计数值安全地传输到新的时钟域。接收到确认信号后,发送时钟域有权清除就绪信号并重新采样二进制计数值。

相当于是握手机制,接收方接收完成后发给发送方以ready信号,表示数据正确接收到了,可以再发送下一次的数据。

使用这种技术,二进制计数器值被定期采样,并不是所有的二进制计数器值都可以传递到新的时钟域。问题是我们是否需要关注二进制计数器可能继续递增和溢出的情况或采样计数器值之间的FIFO下溢?答案是否定的。

  • 当写指针赶上同步和采样的读指针时,FIFO 已满。同步和采样的读指针可能不会反映实际读指针的当前值,但写指针不会尝试超出同步读指针值的计数。不会发生溢出。

  • 当读指针赶上同步和采样的写指针时,FIFO 为空。同步和采样的写指针可能不会反映实际写指针的当前值,但读指针不会尝试计数超过同步的写指针值。不会发生下溢。

FIFO 计数器指针的一种常见方法是使用格雷码计数器。格雷码只允许每次时钟转换改变一位,从而消除了与尝试在同一时钟边沿同步多个变化信号相关的问题。

FIFO测试问题

测试 FIFO 设计的细微设计问题几乎是不可能的。问题的根源在于 RTL 模拟中的 FIFO 指针表现理想,即使如果实施不正确,如果在实际设计中使用它们可能会导致灾难性故障。

在 RTL 仿真中,如果设计中包含二进制计数 FIFO 指针,则所有 FIFO 指针位将同时改变;没有机会观察同步和比较问题。在没有反向注释延迟的门级仿真中,如果上升沿和下降沿信号的门转换不同,则只有很小的机会观察到问题,即使那样,也必须幸运并具有正确的序列位在时钟上升沿之前和之后发生变化。对于更高速度的设计,上升沿和下降沿信号之间的延迟差异会减小,并且检测到问题的可能性也会减小。对于具有反向注释延迟的门级设计来说,发现实际的 FIFO 设计问题是最大的,但即使进行这种类型的仿真,也很难找到问题,并且随着信号传播延迟的减少,再次观察到设计问题的几率也会降低。

以下模块准确地确定何时应设置 FIFO 满和空状态位,并可用于确定应存储到工作 FIFO 中的数据值。但不适用于综合!

module beh_fifo (rdata, wfull, rempty,
       wdata, winc, wclk, wrst_n,
       rinc, rclk, rrst_n);
 
parameter   DSIZE     =  8;
parameter   ASIZE     =  4;
parameter   MEMDEPTH  =  1<<ASIZE;
 
output [DSIZE-1:0]      rdata;
output                  wfull;
output                  rempty;
input  [DSIZE-1:0]      wdata;
input                   winc, wclk, wrst_n;
input                   rinc, rclk, rrst_n;
 
reg    [ASIZE:0]        wptr;  
reg    [ASIZE:0]        rptr;  
reg    [ASIZE:0]        wrptr1;
reg    [ASIZE:0]        rwptr1;
reg    [ASIZE:0]        wrptr2;
reg    [ASIZE:0]        rwptr2;
reg    [ASIZE:0]        wrptr3;  
reg    [ASIZE:0]        rwptr3;  
 
reg    [DSIZE-1:0]      ex_mem  [0:MEMDEPTH-1];
 
always @(posedge wclk or negedge wrst_n) begin
	if (!wrst_n) 
		wptr <= 0;
	else if (winc && !wfull) begin
		ex_mem[wptr[ASIZE-1:0]] <= wdata;
		wptr <= wptr+1;
	end	
end
 
always @(posedge wclk or negedge wrst_n) begin
	if (!wrst_n) begin
		{wrptr3,wrptr2,wrptr1} <= 0;		
	end
	else begin
		{wrptr3,wrptr2,wrptr1} <= {wrptr2,wrptr1,rptr};	
	end
end
 
always @(posedge rclk or negedge rrst_n) begin
	if (!rrst_n) begin
		rptr <= 0;
	end	
	else if (rinc && !rempty) begin
		rptr <= rptr+1;
	end 
end
 
always @(posedge rclk or negedge rrst_n) begin
	if (!rrst_n) begin
		{rwptr3,rwptr2,rwptr1} <= 0;
	end	
	else begin
		{rwptr3,rwptr2,rwptr1} <= {rwptr2,rwptr1,wptr};	
	end 	
end
 
assign rdata   =  ex_mem[rptr[ASIZE-1:0]];
assign rempty  =  (rptr == rwptr3);
assign wfull   =  ((wptr[ASIZE-1:0]==wrptr3[ASIZE-1:0])&&(wptr[ASIZE]!=wrptr3[ASIZE]));
 
endmodule

格雷码计数器 ‑ 样式 #1

格雷码是以 1953 年最初获得该代码专利的人 Frank Gray 的名字命名的。有多种方法可以设计格雷码计数器。本节详细介绍了一种简单直接的设计方法。本文中描述的技术仅使用一组触发器作为格雷码计数器。使用两组触发器来实现更高速度的第二种方法在后面中详细介绍。

格雷码模式

由于稍后将描述的原因,希望同时创建一个n位格雷码计数器和一个(n‑1)位格雷码计数器。单独创建两个计数器当然很容易,但是创建一个通用的 n 位格雷码计数器然后修改第2 个MSB 以形成一个共享的 (n‑1) 位格雷码计数器也很容易和高效LSB。在本文中,这将被称为“双 n 位格雷码计数器”。

2.png

为了更好地理解将 n 位格雷码转换为 (n‑1) 位格雷码的问题,请考虑创建双 4 位和 3 位格雷码计数器的示例,如上图所示。

如图所示,最常见的格雷码是一种反射码,其中除 MSB 之外的任何列中的位都关于序列中点对称。这意味着 4 位格雷码的后半部分是前半部分的镜像,其中 MSB 反转。

要将 4 位转换为 3 位格雷码,我们不希望 4 位序列后半部分的 LSB 是前半部分 LSB 的镜像,而是希望后半部分的 LSB后半部分重复前半部分的 4 位 LSB 序列。

经过仔细检查,很明显,将 4 位格雷码的后半部分的第二个 MSB 反转将在 4 位序列的三个 LSB 中产生所需的 3 位格雷码序列。唯一的另一个问题是具有额外 MSB 的 3 位格雷码不再是真正的格雷码,因为当序列从 7 (Gray 0100) 变为 8 (~Gray 1000) 并再次从 15 (~Gray 1100) 变为0(灰色 0000),两位正在改变,而不仅仅是一位。真正的格雷码在计数之间只改变一位。

格雷码计数器基础

关于格雷码,要记住的第一个事实是任何两个相邻数之间的编码距离仅为 1(只有一位可以从一个格雷计数更改为下一位)。关于格雷码计数器要记住的第二个事实是,最有用的格雷码计数器在序列中必须有 2 次幂计数。可以制作一个格雷码计数器来计算偶数个序列,但是与这些序列的转换通常不像标准格雷码那样简单。另请注意,没有奇数长度的格雷码序列,因此无法制作 23 深度的格雷码。这意味着本文中描述的技术用于制作深度为2^n的 FIFO。

下图是双 n 位格雷码计数器的框图。格雷码计数器假定寄存器位的输出是格雷码值本身(ptr,wptr或rptr )。格雷码输出然后被传递给一个格雷到二进制转换器(bin),它被传递给一个条件二进制值增量器以生成下一个二进制计数值(bnext),它被传递给一个二进制到格雷码转换器,生成下一个格雷码数值(gnext),该值被传递到寄存器输入。框图的上半部分显示了所描述的逻辑流程,而下半部分显示了与第二个格雷码计数器相关的逻辑。

3.png

额外的格雷码计数器注意事项

如上图所示,二进制值递增器以“if not full”或“if not empty”测试为条件,以确保适当的 FIFO 指针不会在 FIFO 满或 FIFO 空情况下递增FIFO缓冲区的上溢或下溢。

如果在断言 FIFO 满状态时,向 FIFO 发送数据的逻辑块可靠地停止发送数据,则可以通过从 FIFO 写指针中删除满测试逻辑来简化 FIFO设计。

FIFO 指针本身并不能保护 FIFO 缓冲区不被覆盖,但可以向 FIFO 内存缓冲区添加额外的调节逻辑,以确保在 FIFO 满状态期间不会激活 write_enable 信号。

额外的“粘滞”状态位,ovf(上溢)或 unf(下溢),可以添加到指针设计中,以指示在满时发生了额外的 FIFO 写操作,或者在空时发生了额外的 FIFO 读操作,以指示错误情况只能在复位期间清除。

总结:应该设置满状态、空状态响应来激活write_enable 信号和read_enable 信号,以及上溢出和下溢出的指示信号,避免过写和过读。

格雷码计数器 ‑ 样式 #2

FIFO 实现使用格雷码计数器样式#2,它实际上使用了两组寄存器来消除将格雷指针值转换为二进制值的需要。第二组寄存器(二进制寄存器)也可用于直接寻址 FIFO 存储器,无需将存储器地址转换为格雷码。仍需要 n 位格雷码指针将指针同步到相反的时钟域,但 n-1 位二进制指针可用于直接寻址存储器。如果需要,二进制指针还可以更轻松地运行计算以生成“几乎满”和“几乎空”位.

4.png

FIFO 模块划分图

5.png

为了便于对 FIFO 设计进行静态时序分析,将设计分为以下六个

具有以下功能和时钟域的 Verilog 模块:

fifo1.v --这是包含所有时钟的顶层模块。顶层模块仅用作包装器,用于例化设计中使用的所有其他 FIFO 模块。如果将此 FIFO 用作更大 ASIC 或 FPGA 设计的一部分,则可能会去掉这个顶层模块,以允许将其他 FIFO 模块分组到它们各自的时钟域中,以改进综合和静态时序分析。

fifomem.v --这是写入和读取时钟域都可以访问的 FIFO 内存缓冲区。这个缓冲区很可能是一个实例化的同步双端口 RAM。其他存储器样式可以调整为 FIFO 缓冲器。

sync_r2w.v --这是一个同步器模块,用于将读指针同步到写时钟域。 wptr_full模块将使用同步读取指针来生成 FIFO 满状态。该模块仅包含与写时钟同步的触发器。此模块中不包含其他逻辑。

sync_w2r.v --这是一个同步器模块,用于将写指针同步到读时钟域。 rptr_empty模块将使用同步的写指针来生成 FIFO 空条件。该模块仅包含与读取时钟同步的触发器。此模块中不包含其他逻辑。

rptr_empty.v--该模块与读时钟完全同步域并包含 FIFO 读指针和空标志逻辑。

wptr_full.v --该模块与写时钟完全同步域并包含 FIFO 写指针和满标志逻辑。

为了使用这种 FIFO 样式执行 FIFO 满和 FIFO 空测试,必须将读取和写入指针传递到相反的时钟域以进行指针比较。

与其他 FIFO 设计一样,由于两个指针是从两个不同的时钟域生成的,因此需要将指针“安全地”传递到相反的时钟域。本文展示的技术是同步格雷码指针,以确保一次只能更改一个指针位。

处理满空情况

FIFO full 和 FIFO empty 的具体实现方式取决于设计。

本文中的 FIFO 设计假设空标志将在读时钟域产生,以确保当 FIFO 缓冲区为空时,即读指针赶上写时立即检测到空标志指针(包括指针 MSB)。

本文中的 FIFO 设计假设在写时钟域中会产生满标志,以确保在 FIFO 缓冲区满时立即检测到满标志,即写指针赶上读的那一刻指针(不同的指针 MSB 除外)。

产生空标志

当读指针和同步写指针相等时,FIFO 为空。空比较很容易做到。使用比寻址 FIFO 内存缓冲区所需的指针大一位的指针。如果两个指针的额外位(指针的 MSB)相等,则指针的回绕次数相同,如果读指针的其余部分等于同步的写指针,则 FIFO 为空。

格雷码写指针必须通过 sync_w2r 模块中的一对同步器寄存器同步到读时钟域。由于使用格雷码指针一次只更改一位,因此在时钟域之间同步多位转换没有问题。

为了有效地寄存 rempty 输出(会延时一个时钟周期),同步的写指针实际上与 rgraynext (将寄存到 rptr 中的下一个格雷码)进行比较(这样就可以在同一个时刻里比较读、写指针值)。

产生满标志

由于在写时钟域中通过运行写指针和读指针之间的比较来生成满标志,因此进行 FIFO 设计的一种安全技术要求在进行指针比较之前将读指针同步到写时钟域。

完全比较不像空比较那么简单。比寻址 FIFO 内存缓冲区所需的指针大一位的指针仍用于比较,但简单地使用带有额外位的格雷码计数器进行比较对于确定满状态是无效的。问题是格雷码是对称码,除了MSB。

6.png

考虑上图中所示的 8 深度 FIFO 示例。在此示例中,使用 3 位格雷码指针来寻址存储器,并添加一个额外位(4 位格雷码的 MSB)来测试满和空情况。如果允许 FIFO 填充前七个位置(字 0‑6),然后如果通过读回相同的七个字来清空 FIFO,则两个指针将相等并指向地址 Gray‑7(FIFO 为空)。在下一次写操作时,写指针将递增 4 位格雷码指针(请记住,只有 3 个 LSB 用于寻址存储器),使 4 位指针的 MSB 不同,但写指针的其余部分位将与读取指针位匹配,因此 FIFO 已满标志将被置位。这是错误的!不仅 FIFO未满,而且 3 个 LSB 也没有改变,这意味着寻址的内存位置将覆盖最后写入的 FIFO 内存位置。这也是错误的!

这是使用双 n 位格雷码计数器的原因之一。

执行完整比较的正确方法是通过将 rptr 同步到 wclk 域中来完成,三个条件都是 FIFO 已满所必需的:

(1) wptr 和同步的 rptr MSB 不相等(因为 wptr 必须比 rptr 多回绕一次)。

(2) wptr 的最高位MSB 和同步的 rptr 次高位 MSB 不相等(因为一个指针的倒置的次高位 MSB 必须针对来自另一个指针的未倒置的次高位 MSB 进行测试,如果 MSB 也是彼此的倒置,这是必需的)。

(3) 所有其他 wptr 和同步 rptr 位必须相等。

为了有效寄存 wfull 输出(延时一个时钟周期输出),同步读取指针实际上与 wgnext (将在wptr 中寄存的下一个格雷码)进行比较(这样就可以在同一个时刻里比较读、写指针值)。

不同的时钟速度

由于异步 FIFO 的时钟来自两个不同的时钟域,显然这些时钟以不同的速度运行。当将较快的时钟同步到较慢的时钟域时,由于较快的时钟将在较慢的时钟边沿之间半周期性地递增两次,因此会跳过一些计数值。这引发了对以下两个问题的讨论:

第一个问题。请注意,递增两次但仅采样一次的同步格雷码将显示同步值的多位变化,这会导致多位同步问题吗?

答案是不会。仅当多个位在同步时钟的上升沿附近发生变化时,同步多位变化才是一个问题。格雷码计数器可以在较慢的同步时钟边沿之间增加两次(或更多)的事实意味着第一次格雷码变化将在较慢时钟的上升沿之前发生,并且只有第二次格雷码转换可能会在上升时钟附近发生变化边缘。格雷码计数器不存在多位同步问题。

第二个问题。再次注意到较快的格雷码计数器可能在较慢时钟信号的上升沿之间增加不止一次,来自较快时钟域的格雷码计数器是否有可能增加到满状态更多的值,导致 FIFO 溢出而不识别 FIFO 曾经满?(这个问题同样适用于 FIFO empty)。

同样,答案是否定的,使用本文中描述的实现。首先考虑 FIFO full 的生成。当写指针赶上同步读指针并且在写时钟域中检测到 FIFO 满状态时,FIFO 变满。如果wclk‑domain 比rclk‑domain 快,写指针最终会赶上同步读指针,FIFO 将满, wfull位将被设置,FIFO 将退出写操作,直到同步读指针前进再次。写指针不能超过wclk 域中的同步读指针。

对空标志的类似检查表明,当读指针赶上同步写指针并且在读时钟域中检测到 FIFO 空状态时,FIFO 变为空。如果 rclk‑domain 比 wclk‑domain 快,读指针最终会赶上同步写指针,FIFO 将为空, rempty位将被设置,FIFO 将退出读操作,直到同步写指针前进再次。读指针不能超过 rclk 域中的同步写指针。

悲观的满空

本文描述的 FIFO 使用“悲观”方法实现了全删除和空删除。也就是说,“full”和“empty”都准确地按时断言,但删除较晚。

由于写时钟用于生成 FIFO‑full 状态,并且当写指针赶上同步读指针时发生 FIFO‑full,因此完全检测是“准确的”和即时的。移除“完整”状态是悲观的,因为“完整”比较是通过同步读指针完成的。当读指针增加时,FIFO 不再满,但在两个 wclk 上升沿将更新的 rptr 同步到wclk域之前,全生成逻辑不会检测到变化。这通常不是问题,因为这意味着数据发送硬件正在“延迟”或通知 FIFO 仍然满了几个额外的 wclk 边沿。

重要的细节是确保 FIFO 不会溢出。发信号通知数据发送方不要在几个额外的wclk边沿发送更多数据,这只会给 FIFO 时间腾出空间来接收更多数据。

类似地,由于读取时钟用于生成 FIFO‑empty 状态,并且当读取指针赶上同步写入指针时发生 FIFO‑empty,因此空检测是“准确的”和即时的。删除“空”状态是悲观的,因为“空”比较是使用同步的写指针完成的。当写指针确实增加时,FIFO 不再为空,但空生成逻辑将不会检测到更改,直到两个rclk上升沿将更新的wptr同步到rclk域。这通常不是问题,因为这意味着数据接收逻辑被“推迟”或通知 FIFO 对于几个额外的rclk边沿仍然是空的。重要的细节是确保 FIFO 不会下溢。向数据接收器发出信号以停止从 FIFO 中删除数据以获得几个额外的rclk边沿,这只是为 FIFO 提供了时间来填充更多数据。

满空“准确”设置

请注意,如果两个指针同时递增,则设置完整标志或空标志可能不太准确。例如,如果写指针赶上同步读指针,将设置满标志,但如果读指针与写指针同时递增,则满标志将提前设置,因为 FIFO 是由于读操作与“写满”操作同时发生,因此读操作并未真正满,但读指针尚未同步到写时钟域。全旗的设置有点太早了,有点悲观。这不是设计问题。

多位异步复位

已经非常注意确保 FIFO 指针一次只改变一位。问题是,是否会出现与异步复位相关的问题,这通常会导致多个指针位同时更改?

答案是不会。复位表示 FIFO 也已复位,并且 FIFO 中没有有效数据。在复位断言时,所有同步寄存器、 wclk 域逻辑(包括已寄存的完整标志)和rclk 域逻辑同时异步复位。注册的空标志也同时设置。更重要的问题涉及到复位信号的有序移除。

将满将空信号

许多设计需要通过生成“几乎满”和“几乎空”状态位来通知待处理的满或空状态。有很多方法可以实现这两个状态位,每种实现都取决于指定的设计要求。

一些 FIFO 设计需要可编程的 FIFO‑full 和 FIFO‑empty 差值,这样当两个指针之间的差值小于编程差值时,相应的几乎满或几乎空位被断言。其他 FIFO 可以以固定差异实现,以生成几乎满或空。当 FIFO 指针的 MSB 接近时,其他 FIFO 可能会满足于松散地生成几乎满和空。而其他设计可能只需要知道 FIFO 何时多于或少于半满。

记住当 wptr 赶上同步的rptr 时 FIFO 已满,几乎满的情况可以描述为(wptr+4)赶上同步的rptr 时的情况。 ( wptr+4) 值可以在格雷码指针逻辑中生成。

7.png

上图通过在 Gray‑to‑binary 组合逻辑之后放置第二个加法器来将四加到二进制值并记录结果。这个寄存的值在被转换为 wclk 域中的二进制值后,将用于对同步的 rptr 进行减法运算,如果差值小于 4,则可以设置一个 almost_full 位。当wptr在追赶同步 rptr 的 0‑4 个计数范围内时,小于操作可确保将 almost_full 位设置为全范围。可以在rclk 域中使用类似的逻辑来生成 almost_empty 标志。

最新文章

最新文章