Verilog实现的格雷码与⼆进制码的互相转换
1、什么是格雷码
格雷码是⼀种循环⼆进制码或者叫作反射⼆进制码。格雷码的特点是从⼀个数变为相邻的⼀个数时,只有⼀个数据位发⽣跳变,由于这种特点,就可以避免⼆进制编码计数组合电路中出现的亚稳态。格雷码常⽤于通信,FIFO 或者 RAM 地址寻址计数器中。
下表给出了4bit⾃然⼆进制码、4bit典型格雷码(⽆特殊说明,典型格雷码即格雷码)与4bit⼗进制整数的对照:
可以看到,上表中格雷码的每次变化位数只有⼀位,这就有效的避免了在CDC情况(跨时钟域情况)下亚稳态问题发⽣的概率。⽐如当数字从 7 变为 8 时,4 位⼆进制数都发⽣跳变,如果直接使⽤异步时钟采样这些数字信号,这就很可能会发⽣亚稳态或者数据采样错误。⽽采⽤格雷码,就可以避免 4 位⼆进 制数都同时发⽣跳变,导致出现的亚稳态,就算出现亚稳态,最多也就⼀位出现错误。
但是由于格雷码是⼀种变权码,每⼀位码没有固定的⼤⼩,所以很难直接进⾏⽐较⼤⼩和算术运算。
2、⼆进制转格雷码
⼆进制码转化为格雷码原理如下:
⼆进制的最⾼位作为格雷码的最⾼位,次⾼位的格雷码为⼆进制的⾼位和次⾼位相异或得到,其他位与次⾼位类似。转化过程如下图:
假如是4bit的⼆进制数据转成格雷码则是:
gray[3] = 0        ^ bin[3];----gray[3] = bin[3] 异或0等于⾃⾝
gray[2] = bin[3]  ^ bin[2];
gray[1] = bin[2]  ^ bin[1];
gray[0] = bin[1]  ^ bin[0];
根据上⾯的式⼦不难推到出⼀般公式:gray = (bin >> 1) ^ bin。根据公式很容易写出⼆进制码转换为格雷码的Verilog代码:
//⼆进制转格雷码
module bin2gray
#(
parameter data_width  = 'd4  //数据位宽
)
(
input [data_width - 1 : 0] bin ,  //⼆进制
output [data_width - 1 : 0] gray //格雷码
);
assign gray = (bin >> 1) ^ bin;
endmodule
3、格雷码转⼆进制
格雷码转化为⼆进制码原理如下:
使⽤格雷码的最⾼位作为⼆进制的最⾼位,⼆进制次⾼位产⽣过程是使⽤⼆进制的⾼位和次⾼位格雷码相异或得到,其他位的值与次⾼位产⽣过程类似。转化过程如下图:
假如是4bit的格雷码转成⼆进制则是:
bin[3] = gray[3] ;
bin[2] = gray[2] ^ bin[3];
bin[1] = gray[1] ^ bin[2];
bin[0] = gray[0] ^ bin[1];
可以看到,最⾼位不需要转换,从次⾼位开始使⽤⼆进制的⾼位和次⾼位格雷码相异或,那么可以使⽤generate--for来构建重复赋值语,具体代码如下:
//格雷码转⼆进制
module gray2bin
二进制编码转换
#(
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];  //最⾼位直接相等
//从次⾼位到0,⼆进制的⾼位和次⾼位格雷码相异或
genvar i;
generate
for(i = 0; i <= N-2; i = i + 1)
begin: gray          //需要有名字
assign bin[i] = bin[i + 1] ^ gray[i];
end
endgenerate
endmodule
4、测试
构建⼀个测试脚本对两个模块进⾏测试:⽣成0-15的4bit⼆进制数据,通过bin2gray转换成格雷码,观察格雷码输出;将转换后的格雷码输出通过gray2bin再转换成2进制码,然后对⽐三组数据是否符合转换规则。
`timescale 1ns/1ns //时间单位/精度
//------------<;模块及端⼝声明>----------------------------------------
module  gray_code();
parameter data_width  = 'd4;    //数据位宽
reg  [data_width - 1 : 0] bin_in;  //⽣成的⼆进制码
wire [data_width - 1 : 0] gray;  //转换后的格雷码
wire  [data_width - 1 : 0] bin_out;  //转换后的⼆进制码
//------------<;例化被测试模块>----------------------------------------
bin2gray
#(
.data_width (data_width)
)
bin2gray_inst(
.bin  (bin_in  ),
.gray  (gray  )
);
gray2bin
#(
.data_width (data_width)
)
gray2bin_inst(
.bin  (bin_out ),
.gray  (gray  )
);
//------------<;设置初始测试条件>----------------------------------------
initial begin
bin_in = 4'd0;
forever #20 bin_in = bin_in + 1; //每隔20ns累加1
end
//打印输出
initial $monitor("bin_in:%b, gray:%b, bin_out:%b",bin_in,gray,bin_out);
endmodule
仿真结果如下:
可以看到两次转换的结果都是正确的,接下来看⼀下命令窗⼝打印的输出:
可以看到这个转换结果与第⼀章的对照表是⼀致的。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。