文章目录
一、格雷码简介
格雷码是一种循环二进制码或者叫作反射二进制码。跨时钟域会产生亚稳态问题(CDC问题):从时钟域A过来的信号难以满足时钟域B中触发器的建立时间和保持时间,输入与clk的变化不同步而导致了亚稳态。此时触发器输出端Q在有效时钟沿之后比较长的一段时间处于不确定的状态,在这段时间里Q端在0和1之间处于振荡状态,而不是等于数据输入端D的值。而格雷码的每次变化位数只有一位,因此使用格雷码可以有效避免这种情况。所以格雷码常用于通信,FIFO 或者 RAM 地址寻址计数器中。
下面是典型的格雷码与二进制的转换:
二、二进制转格雷码
二进制转格雷码的原理:
二进制的最高位作为格雷码的最高位,次高位的格雷码为二进制的高位和次高位相异或得到,其他位与次高位类似。
代码实现:
c
module bin_gray #(parameter data_width = 'd4)(
input [data_width-1:0] bin,
output [data_width-1:0] gray
);
assign gray = (bin >> 1) ^ bin;//二进制转格雷码:二进制右移一位与二进制相异或
endmodule
三、格雷码转二进制
格雷码转二进制的原理:
使用格雷码的最高位作为二进制的最高位,二进制次高位产生过程是使用二进制的高位和次高位格雷码相异或得到,其他位的值与次高位产生过程类似。
代码实现:
c
module gray_bin #(parameter data_width = 'd4)(
input [data_width-1:0] gray,
output [data_width-1:0] bin
);
assign bin[data_width-1] = gray[data_width-1];//格雷码转二进制:最高位直接相等
genvar i;
generate
for(i=0;i<=data_width-2;i=i+1)begin:BLOCK1
assign bin[i] = bin[i+1] ^ gray[i]; //次高位等于高位与格雷码次高位相异或
end
endgenerate
endmodule
四、仿真
仿真代码:
c
`timescale 1ns/1ns
module gray_code_tb ();
parameter data_width = 'd4 ;
reg [data_width-1:0] bin_in ;
wire [data_width-1:0] gray ;
wire [data_width-1:0] bin_out ;
initial begin
bin_in = 4'd0;
repeat(20)begin
#20 bin_in = bin_in + 1'd1;
end
$stop;
end
bin_gray #(.data_width (data_width)) u_bin_gray(
.bin (bin_in),
.gray (gray)
);
gray_bin #(.data_width (data_width)) u_gray_bin(
.gray (gray),
.bin (bin_out)
);
endmodule
仿真波形:
通过波形可以看到二进制转格雷码再转二进制结果无误。