verilog實現格雷碼和二進位制碼的相互轉換

糊涂二蛋發表於2024-06-20

目錄
  • 格雷碼的介紹
  • 二進位制碼轉化為格雷碼
  • 格雷碼轉化為二進位制碼
  • 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

image

可以看到二進位制碼先轉化為格雷碼,再轉回二進位制碼,得到期望的值。而且相鄰數的格雷碼確實是只差1位數。

相關文章