目录
前言
二进制码转换为格雷码的方法
格雷码转换为二进制码的过程
更多一点讨论之generate for
更多一点讨论之for
最后对格雷码的介绍
以前的博客也有写这方面的内容,只是没有显式的命名,导致查找复习的时候并不能立即找到,这里单独成立一篇,记录与此,方便你我他。
这篇博客来自于FPGA之道,其中提到了格雷码;
和格雷码相关的其他问题也贴出来吧:关于格雷码和独热码消耗资源情况;
从自然二进制码到格雷码
该过程也称为格雷码的编码,方法是从二进制码的最右边一位(最低位)起,依次将每一位与左边一位进行异或运算,作为对应格雷码该位的值,而最左边一位(最高位)不变。 对应公式如下:
g[n] = b[n],
g[i] = b[i] xor b[i+1] (i∈N,n-1≥i≥0);
其中g、b分别对应n位的格雷码和二进制码。
例如,将自然二进制码“10110”转换为格雷码,可以形象的用下图表示其转换过程:
简单说来,就是对二进制码右移移位,与其本身相异或即可。
根据以上说法,用Verilog描述为:
assign gray_value = binary_value ^ (binary_value>>1);
该过程也称为格雷码的解码,方法是从格雷码左边第二位(次高位)起,将每一位与其左边一位解码后的值异或,作为该位解码后的值,而最左边一位(最高位)的解码结果就是它本身。对应公式如下:
b[n] = g[n],
b[i] = g[i] xor b[i+1] (i∈N, n-1≥i≥0)。
其中g、b分别对应n位的格雷码和二进制码。
例如,将格雷码“11101”转换为自然二进制码,可以形象的用下图表示其转换过程:
我的理解是先根据格雷码的最高位,得到二进制的最高位,然后,用二进制码的最高位与格雷码的次高位相异或,得到二进制的次高位,依次类推。
根据理解写出对应的Verilog设计:
module gray2bin #(
parameter N = 4
)(
input [N-1:0] gray,
output [N-1:0] bin
);
assign bin[N-1] = gray[N-1];
genvar i;
generate
for(i = N-2; i >= 0; i = i - 1) begin: gray_2_bin
assign bin[i] = bin[i + 1] ^ gray[i];
end
endgenerate
endmodule
这是其对应的RTL原理图:
上图中粗的绿线代表总线,画的比较清晰了,但是呢?
如果我们自己手工画,应该是?
上图不考虑任何延迟。
上述代码用到了generate for,在其内部是将assign语句展开,这里验证下:
换一种写法,就是for中的i不从N-2开始,从0开始到N-2,如果二者的RTL电路一致,则可代表generate for是将内部循环语句,展开来实现:
module gray2bin #(
parameter N = 4
)(
input [N-1:0] gray,
output [N-1:0] bin
);
assign bin[N-1] = gray[N-1];
genvar i;
generate
/* for(i = N-2; i >= 0; i = i - 1) begin: gray_2_bin
assign bin[i] = bin[i + 1] ^ gray[i];
end */
for(i = 0; i <= N-2; i = i + 1) begin: be
assign bin[i] = bin[i + 1] ^ gray[i];
end
endgenerate
endmodule
可见,RTL原理图一致;
那用for语句实现上述电路会是怎么样呢?
module gray_to_binary #(parameter N = 4)(
input [N-1:0] gray_value,
output [N-1:0] binary_value
);
reg [N-1:0] binary_value;
integer i;
always@(*)begin
binary_value[N-1] = gray_value[N-1];
for(i=0; i<=N-2; i=i+1)begin:U1
binary_value[i] = binary_value[i+1]^gray_value[i];
end
end
endmodule
RTL原理图:
可见,同样可以实现同样的功能。
简单的电路,我就不进行行为仿真了。
在FPGA之道这本书上,对格雷码的一点描述作为结尾:
格雷码,英文全称:Gray code。由于自然二进制码在相邻数据之间可能存在多个bit的变化,例如自然数7和8对应的4bits自然二进制码分别“0111”、“1000”,因此当寄存器的输出从7变到8时,寄存器的每一位都会发生变化,从而造成不稳定态,并且会使得数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点,因为格雷码是一种数字排序系统,其中的所有相邻整数在它们的二进制表示中仅有一位不同。例如下表给出了4bits自然二进制码、格雷码与十进制整数的对照表:
十进制数 |
自然二进制编码 |
格雷码 |
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 |
从上表我们看出,格雷码在任意两个相邻的数之间转换时,只有1个bit发生了变化,所以它有效的避免了寄存器由一个数值到下一个数值时的不稳定态。并且由于格雷码中最大数与最小数之间也仅1个bit不同,因此通常又被称作循环二进制码或者反射二进制码。
不过格雷码也有一个缺点,那就是相比于自然二进制码来说,它是一种无权码(而自然二进制码实际上是“8421”码,因此很难直接进行比较和数学运算,所以一般都需要将采集到的以格雷码为表示形式的数据先转换成自然二进制码,然后再参与运算。
而二者之间的转换,上面也说了。
参考书籍:FPGA之道