verilog实现格雷码和二进制码的相互转换

格雷码的介绍

在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。
在数字系统中,常要求代码按一定顺序变化。例如,按自然数递增计数,若采用8421码,则数0111变到1000时四位均要变化,而在实际电路中,4位的变化不可能绝对同时发生,则计数中可能出现短暂的其它代码(1100、1111等)。在特定情况下可能导致电路状态错误或输入错误。使用格雷码可以避免这种错误。

二进制码转化为格雷码

二进制码转换成二进制格雷码,其法则是保留二进制码的最高位作为格雷码的最高位,而次高位格雷码为二进制码的高位与次高位相异或,而格雷码其余各位与次高位的求法相类似。
假设有n位二进制数:

n位二进制数 Bn-1 Bn-2 Bn-3 ... B1 B0

其转化位相应n位格雷码的转化法则为:

n位格雷码 Gn-1 Gn-2 Gn-3 ... G1 G0
转化规则 Bn-1 Bn-1^Bn-2 Bn-2^Bn-3 ... B2^B1 B1^B0

verilog中,假设有 logic [n-1:0] bin; logic [n-1:0] grey;

则有:

bin Bn-1 Bn-2 Bn-3 ... B1 B0
bin>>1 0 Bn-1 Bn-2 Bn-3 ... B1
grey Bn-1^0 Bn-1^Bn-2 Bn-2^Bn-3 ... B2^B1 B1^B0
grey Bn-1 Bn-1^Bn-2 Bn-2^Bn-3 ... B2^B1 B1^B0

因为Bn-1^0=Bn-1,所以在verilog中,我们可以用下面的几行代码,得到二进制编码到格雷码的转化:

logic [n-1:0] bin; 
logic [n-1:0] grey
assign grey = bin ^ (bin>>1);

格雷码转化为二进制码

从前面二进制码转化为格雷码法则,我们知道
Gn-i=Bn-i+1^Bn-i
则有
Bn-i+1^Gn-i = Bn-i+1 ^ Bn-i+1 ^ Bn-i
Bn-i+1 ^ Gn-i = 0 ^ Bn-i-1= Bn-i

所以格雷码转化为二进制码的规则为:

n位二进制 Bn-1 Bn-2 Bn-3 ... B1 B0
转化规则 Gn-1 Gn-2^Bn-1 Gn-3^Bn-2 ... G1^B2 B0^B1

在verilog中我们可以用一个generate块内循环实现转换

//从次高位到0,二进制的高位和次高位格雷码相异或
genvar i;
generate
	for(i = 0; i <= DATA_WIDTH-2; i = i + 1) 
		begin:
			assign bin[i] = bin[i + 1] ^ grey[i];
		end
endgenerate

verilog实现代码

文件名称:code4_41.v

`timescale 1ns/1ps	

module grey_tb;
 
	logic clk=0;

	always #5 clk = ~clk;

	initial begin

    	$display("start a clock pulse");
    	$dumpfile("grey.vcd"); 
    	$dumpvars(0, grey_tb); 
   		#300 $finish;
	end

	logic [7:0] bin;
	logic [7:0] grey;
	logic [7:0] bin2;

	logic [7:0] bin_1=0;
	logic [7:0] grey_1;
	logic [7:0] bin2_1;

	initial begin

// 重复执行10次随机数生成过程
		repeat(10) begin 
			@(posedge clk) begin

			bin <= $random();

			end
		end
// 重复执行32次的循环,用于对bin_1进行自增操作
		repeat(32) begin 
			@(posedge clk) begin

			bin_1 <= bin_1+1;

			end
		end

	end

	bin2grey #(.DATA_WIDTH(8)) bin2grey_inst(.bin(bin),.grey(grey));
	grey2bin #(.DATA_WIDTH(8)) grey2bin_inst(.grey(grey),.bin(bin2));

	bin2grey #(.DATA_WIDTH(8)) bin2grey_inst1(.bin(bin_1),.grey(grey_1));
	grey2bin #(.DATA_WIDTH(8)) grey2bin_inst1(.grey(grey_1),.bin(bin2_1));

endmodule


//二进制转格雷码
module	bin2grey
#(
	parameter DATA_WIDTH=8
)
(
	input wire [DATA_WIDTH-1:0] bin,

	output logic [DATA_WIDTH-1:0] grey

);                                                              
 
	assign grey = bin ^(bin>>1);
 
endmodule

//格雷码转二进制码
module grey2bin
#(
	parameter DATA_WIDTH=8
)
(
	input wire [DATA_WIDTH-1:0] grey,

	output logic [DATA_WIDTH-1:0] bin

);                                                              
 
	assign bin[DATA_WIDTH-1] = grey[DATA_WIDTH-1];

genvar i;
generate
	for(i=DATA_WIDTH-2;i>=0;i=i-1) begin
		assign bin[i] = bin[i+1] ^ grey[i];
	end
endgenerate

 
endmodule

在vscode中执行以下命令,编译code,打开波形文件:

iverilog -o myrun -g 2012  code4_42.v
vvp myrun
gtkwave grey.vcd

可以看到二进制码先转化为格雷码,再转回二进制码,得到期望的值。而且相邻数的格雷码确实是只差1位数。

热门相关:兵王传说   我能改变东西颜色   萌妻鲜嫩:神秘老公晚上见   大数据修仙   退婚后我嫁给了前任他叔