相关文章
目录
1.格雷码编码/解码
格雷编码在弗兰克·格雷在1953年公布的专利中出现,主要特点是相邻编码值只有一位比特发生改变,下表中给出了三比特和四比特二进制码和对应的格雷码,从图中可以清晰地看到这一特点,而这一特点也使格雷码有十分广泛的应用。
三比特格雷码
十进制编码 | 二进制编码 | 格雷编码 |
0 | 000 | 000 |
1 | 001 | 001 |
2 | 010 | 011 |
3 | 011 | 010 |
4 | 100 | 110 |
5 | 101 | 111 |
6 | 110 | 101 |
7 | 111 | 100 |
四比特格雷码
十进制编码 | 二进制编码 | 格雷编码 | 十进制编码 | 二进制编码 | 格雷编码 |
0 | 0000 | 0000 | 8 | 1000 | 1100 |
1 | 0001 | 0001 | 9 | 1001 | 1101 |
2 | 0010 | 0011 | 10 | 1010 | 1111 |
3 | 0011 | 0010 | 11 | 1011 | 1110 |
4 | 0100 | 0110 | 12 | 1100 | 1010 |
5 | 0101 | 0111 | 13 | 1101 | 1011 |
6 | 0110 | 0101 | 14 | 1110 | 1001 |
7 | 0111 | 0100 | 15 | 1111 | 1000 |
格雷编码被广泛应用于使用两个不同时钟的异步FIFO(First In First Out,先入先出存储器)中。一般来说,当多位数据穿越时钟域边界时,不能直接使用传统的同步器分别同步各位数据,因为无法保证这些数据会被同时同步,可能会出现较高的错误率。但如果多位数据是使用格雷编码,每次只可能有一比特数据改变,则可以直接同步。
在异步FIFO中,写地址和读地址指针分别保存在不同的时钟域中,而为了表示FIFO状态,我们需要分别在写时钟域中产生FIFO_full信号,在读时钟域中产生FIFO_rmpty信号,而判断FIFO状态时,需要对比读写指针的值,两个不同时钟域中的值不能直接比较。所以,我们需要先把二进制编码的指针先转换成格雷码,并使格雷编码从一个时钟域穿越到另一个时钟域,然后使用转换公式再把格雷编码转换回二进制码,并与目标时钟域的指针比较。整个同步的过程如下图所示。
我们通过一些真实的案例来深入分析这一过程,然后再看不使用这一转换方法时存在的问题。下面的例子中CLKA时钟域内,一个值从十进制值5变为6,我们来分析一下多位数据的传递过程。
十进制数值 | 二进制数值 | 格雷码值 | 同步后的二进制值 | 同步后的十进制值 |
5 | 101 | 111 | 111 | 5 |
6 | 110 | 101 | 111或101 | 5或6 |
在CLKA中,当十进制数从5变成6时,经过同步器后,在目标时钟域变为101或暂时为原来的111(一至两个时钟周期后,依旧会变为101)。可以看出,无论是101还是111,最终的结果都是按先后顺序出现的合法值。
如果不使用上面的二进制-格雷码相互转换的电路,直接在CLKB时钟域使用同步器,会发生什么呢?下表给出了可能的结果。
十进制数值 | 二进制数值 | 同步后的二进制值 | 同步后的十进制值 |
5 | 101 | 101 | 5 |
6 | 110 | 101或110或100或111 | 5或6或4或7 |
可以看出,同步后的值可能是旧值101、新值,但也可能变为100或111。因为多位数据是分别进行同步的,无法保证多位信号在同一个时钟沿被采样到,这些独立同步的信号有效值可能出现在不同的时钟沿。
虽然最终能得到正确值,即最终输出变为。但是在此期间可能会出现违反规则的值。在该例中,出现了两种非法值,如果同时有更多位数据跳变,则可能会产生大量不合法的值,输出端会保留这些值一至两个周期。
对于FIFO来说,空\满信号是根据指针对比得到的,当出现这些非法值时,FIFO可能会出现错误的空\满信号,导致系统工作错误甚至崩溃。
2.二进制码转格雷码Verilog实现
module binary_to_gray #(parameter PTR = 8)
(input [PTR:0]binary_value,
output [PTR:0]gray_value);
genvar i;
generate
for(i = 0;i < PTR;i = i+1) begin
assign gray_value[i] = binary_value[i] ^ binary_value[i+1];
end
endgenerate
assign gray_value[PTR] = binary_value[PTR];
endmodule
3.格雷码转二进制码Verilog实现
module gray_to_binary #(parameter PTR = 8)
(output [PTR:0]binary_value,
input [PTR:0]gray_value);
genvar i;
generate
for(i = 0;i < PTR;i = i+1) begin
assign binary_value[i] = binary_value[i+1] ^ gray_value[i];
end
endgenerate
assign binary_value[PTR] = gray_value[PTR];
endmodule
以上内容来源于《Verilog高级数字系统设计技术和实例分析》