数字IC前端学习笔记:格雷编码及其Verilog实现

张开发
2026/5/21 15:57:15 15 分钟阅读
数字IC前端学习笔记:格雷编码及其Verilog实现
相关文章数字IC前端专栏https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482一、格雷码编码格雷编码在弗兰克·格雷在1953年公布的专利中出现主要特点是相邻/中心对称的编码值只有一位比特发生改变如表1和表2所示。表1 三比特格雷编码十进制编码二进制编码格雷编码00000001001001201001130110104100110510111161101017111100表2 四比特格雷编码十进制编码二进制编码格雷编码十进制编码二进制编码格雷编码000000000810001100100010001910011101200100011101010111130011001011101111104010001101211001010501010111131101101160110010114111010017011101001511111000格雷编码被广泛应用于使用两个不同时钟的异步FIFOFirst In First Out先入先出存储器中。当穿越时钟域边界时如果多位数据使用二进制编码每次变化可能有多比特数据改变传统的两级同步器分别同步各比特后无法保证比特间同步会出现较高的错误率如果多位数据使用格雷编码每次变化只可能有一比特数据改变可以直接同步。在异步FIFO中写地址和读地址指针分别保存在不同的时钟域中而为了表示FIFO状态需要分别在写时钟域中产生Full信号在读时钟域中产生Empty信号而产生这两个信号时需要对比读写指针但两个不同时钟域中的值不能直接比较。所以需要先把二进制编码的指针先转换成格雷编码然后将格雷编码从一个时钟域传递到另一个时钟域最后再把格雷编码转换回二进制编码并与目标时钟域的指针比较整个同步的过程如图1所示。图1 指针同步下面通过一个真实的案例来分析这一过程。十进制数值二进制数值格雷码数值同步后的格雷码数值51011111116110101111或101在CLKA时钟域中当十进制数从5变成6时经过同步器后在目标时钟域变为101或暂时为原来的111一至两个周期后依旧会变为101。可以看出无论是101还是111最终的结果都是按先后顺序出现的合法值。如果不使用上面的二进制-格雷码相互转换的电路直接在CLKB时钟域使用两级同步器会发生什么呢下面给出了可能的结果。十进制数值二进制数值同步后的二进制数值51011016110101或110或100或111可以看出同步后的值可能是旧值101、新值110但也可能变为100或111。因为多位数据是分别进行同步的无法保证多位信号在同一个时钟沿被采样到这些独立同步的信号有效值可能出现在不同的时钟沿。虽然最终能得到正确值即最终输出变为110但是在此期间可能会出现违反规则的值。在该例中出现了两种非法值如果同时有更多位数据跳变则可能会产生大量不合法的值输出端会保留这些值一至两个周期。对于FIFO来说Full/Empty信号是根据指针对比得到的当出现这些非法值时FIFO可能会出现错误的Full/Empty信号导致系统工作错误甚至崩溃。二、二进制编码转格雷编码二进制编码转格雷编码的公式和Verilog实现如下所示。最高位其他位Verilog实现module binary_to_gray #(parameter N 8) (input [N-1:0]binary_value, output [N-1:0]gray_value); genvar i; generate for(i 0; i N - 1; i i 1) begin assign gray_value[i] binary_value[i] ^ binary_value[i1]; end endgenerate assign gray_value[N-1] binary_value[N-1]; endmodule三、格雷编码转二进制编码格雷编码转二进制编码的公式和Verilog实现如下所示。最高位其他位递归定义Verilog实现module gray_to_binary #(parameter N 8) (output [N-1:0]binary_value, input [N-1:0]gray_value); genvar i; generate for(i 0; i N - 1; i i 1) begin assign binary_value[i] gray_value[i] ^ binary_value[i1]; end endgenerate assign binary_value[N-1] gray_value[N-1]; endmodule非递归定义Verilog实现module gray_to_binary #(parameter N 8) (output [N-1:0]binary_value, input [N-1:0]gray_value); integer i; always(*) begin for (i 0; i N; i i 1) begin binary_value[i] ^(gray_value i); end end endmodule

更多文章