K7DJ

深入浅出:格雷码在异步FIFO中的应用及Verilog实现

12 0 0 0

1. 什么是异步FIFO?

2. 跨时钟域数据传输的挑战:亚稳态

2.1 什么是亚稳态?

2.2 亚稳态的危害

3. 二进制码的困境:多比特跳变

3.1 什么是多比特跳变?

3.2 多比特跳变的危害

4. 格雷码的救赎:单比特跳变

4.1 格雷码的特性

4.2 格雷码的优势

5. Verilog实现:二进制码与格雷码的转换

5.1 二进制码转格雷码

5.2 格雷码转二进制码

6. 异步FIFO设计中的格雷码应用

7. 总结

你好,我是“FPGA老司机”。今天咱们来聊聊格雷码(Gray Code)在异步FIFO设计中的核心作用。相信你作为一名FPGA工程师,一定对异步FIFO不陌生,也或多或少听说过格雷码。但你真的完全理解为什么在异步FIFO中要用格雷码,而不用二进制码吗?格雷码又是如何保证跨时钟域数据传输的可靠性的呢?别着急,这篇文章将带你深入剖析其中的奥秘,并提供Verilog代码示例,让你彻底掌握格雷码的应用。

1. 什么是异步FIFO?

在深入格雷码之前,我们先简单回顾一下异步FIFO。FIFO,即First-In, First-Out(先进先出)的缩写,是一种数据缓冲器,常用于不同模块之间的数据传输。而异步FIFO,顾名思义,就是指写入数据和读出数据的时钟信号是不同的,也就是跨时钟域的数据传输。

异步FIFO的主要应用场景:

  • 速率匹配: 当写入数据和读出数据的速率不一致时,异步FIFO可以起到缓冲的作用,防止数据丢失或溢出。
  • 数据接口: 连接不同时钟域的模块,例如CPU和外设之间的数据传输。
  • 数据缓冲: 在数据处理过程中,临时存储数据,平滑数据流。

2. 跨时钟域数据传输的挑战:亚稳态

在异步FIFO设计中,最大的挑战就是跨时钟域数据传输的可靠性问题。由于写入时钟和读出时钟是异步的,它们之间可能存在相位差,甚至频率也可能不同。这就导致了一个严重的问题——亚稳态(Metastability)。

2.1 什么是亚稳态?

亚稳态是指触发器在时钟边沿采样数据时,数据输入信号恰好在建立时间(Setup Time)和保持时间(Hold Time)的窗口内变化,导致触发器的输出无法稳定在0或1,而是在一个中间状态振荡,并且需要一段不确定的时间才能稳定下来。这段时间被称为决断时间(Resolution Time)。

2.2 亚稳态的危害

如果触发器的输出在决断时间内无法稳定下来,就可能导致后续电路的逻辑错误,甚至系统崩溃。在异步FIFO中,如果读写指针的比较出现错误,就可能导致数据读取错误或FIFO溢出/下溢。

3. 二进制码的困境:多比特跳变

在异步FIFO中,我们需要用读写指针来指示FIFO的空满状态。通常,我们会用计数器来生成读写指针。如果直接使用二进制计数器,就会遇到一个严重的问题:多比特跳变。

3.1 什么是多比特跳变?

二进制计数器在递增或递减时,可能会出现多个比特位同时变化的情况。例如,从0111(7)到1000(8),有4个比特位同时发生了变化。

3.2 多比特跳变的危害

在跨时钟域的情况下,如果读写指针的多个比特位同时变化,由于亚稳态的存在,这些比特位到达目标时钟域的时间可能会不一致。这就可能导致目标时钟域采样到的指针值是错误的,进而导致FIFO空满状态判断错误。

例如,写指针从0111跳变到1000,如果由于亚稳态,读时钟域采样到的值可能是0000、0100、1100等等,这些错误的值会导致FIFO的空满状态判断错误。

4. 格雷码的救赎:单比特跳变

为了解决二进制码多比特跳变的问题,格雷码应运而生。格雷码是一种特殊的二进制编码,它的特点是相邻的两个码字之间只有一位不同。

4.1 格雷码的特性

格雷码的定义:任意两个相邻的码字之间只有一位不同。

例如,4位格雷码的编码如下:

十进制 二进制 格雷码
0 0000 0000
1 0001 0001
2 0010 0011
3 0011 0010
4 0100 0110
5 0101 0111
6 0110 0101
7 0111 0100
8 1000 1100
9 1001 1101
10 1010 1111
11 1011 1110
12 1100 1010
13 1101 1011
14 1110 1001
15 1111 1000

4.2 格雷码的优势

由于格雷码相邻码字之间只有一位不同,因此在跨时钟域传输时,即使发生亚稳态,最多也只会有一个比特位出错。这样,即使读写指针的值不正确,也不会导致FIFO空满状态的误判。

例如,写指针从0100(格雷码,对应十进制7)跳变到1100(格雷码,对应十进制8),即使由于亚稳态,读时钟域采样到的值可能是0100或1100,但这两种情况都不会导致FIFO空满状态的误判。

5. Verilog实现:二进制码与格雷码的转换

在异步FIFO设计中,我们需要将二进制计数器生成的读写指针转换为格雷码,然后在目标时钟域再将格雷码转换回二进制码进行比较。

5.1 二进制码转格雷码

二进制码转格雷码的Verilog代码如下:

// Binary to Gray Code Conversion
function [WIDTH-1:0] bin2gray;
  input [WIDTH-1:0] bin;
  begin
    bin2gray = (bin>>1) ^ bin;
  end
endfunction

转换的原理很简单:将二进制码右移一位,然后与原二进制码进行异或操作。

5.2 格雷码转二进制码

格雷码转二进制码的Verilog代码如下:

// Gray Code to Binary Conversion
function [WIDTH-1:0] gray2bin;
  input [WIDTH-1:0] gray;
  integer i;
  begin
    gray2bin[WIDTH-1] = gray[WIDTH-1];
    for (i = WIDTH-2; i >= 0; i = i - 1) begin
      gray2bin[i] = gray2bin[i+1] ^ gray[i];
    end
  end
endfunction

转换的原理:从高位到低位,每一位的值等于当前格雷码位与前一位二进制码位的异或值。

6. 异步FIFO设计中的格雷码应用

在异步FIFO设计中,格雷码的应用主要体现在读写指针的跨时钟域同步上。具体步骤如下:

  1. 写时钟域:
    • 使用二进制计数器生成写指针(wptr_bin)。
    • 将wptr_bin转换为格雷码(wptr_gray)。
    • 使用两级触发器同步wptr_gray到读时钟域(wptr_gray_sync)。
  2. 读时钟域:
    • 使用二进制计数器生成读指针(rptr_bin)。
    • 将rptr_bin转换为格雷码(rptr_gray)。
    • 使用两级触发器同步rptr_gray到写时钟域(rptr_gray_sync)。
    • 将同步过来的写指针格雷码 wptr_gray_sync 转换为二进制(wptr_bin_sync)。
    • 将wptr_bin_sync 与 本时钟域的读指针 rptr_bin 比较以产生 empty 信号。
  3. 写时钟域:
    • 将同步过来的读指针格雷码 rptr_gray_sync 转换为二进制(rptr_bin_sync)。
    • 将rptr_bin_sync 与 本时钟域的写指针 wptr_bin 比较以产生 full 信号。

通过以上步骤,我们可以确保读写指针的跨时钟域同步是可靠的,避免了亚稳态导致的FIFO空满状态误判。

7. 总结

格雷码在异步FIFO设计中扮演着至关重要的角色。它通过单比特跳变的特性,有效避免了二进制码在跨时钟域传输时可能出现的多比特跳变问题,从而提高了异步FIFO的可靠性。希望通过这篇文章,你已经对格雷码在异步FIFO中的应用有了更深入的理解。记住,在进行异步FIFO设计时,一定要使用格雷码来同步读写指针,这是保证设计正确性的关键。

如果你还有其他关于FPGA设计的问题,欢迎随时提问,我会尽力为你解答。

Apple

Comment

打赏赞助
sponsor

感谢您的支持让我们更好的前行