【Verilog 常见设计】(0)二进制码和格雷码互转 Verilog 实现
目錄
格雷碼介紹
轉化原理
Verilog 實現
testbench 測試代碼
仿真波形
格雷碼介紹
在一組數的編碼中,若任意兩個相鄰的代碼只有一位二進制數不同,則稱這種編碼為格雷碼(Gray Code),另外由于最大數與最小數之間也僅一位數不同,即“首尾相連”,因此又稱循環碼或反射碼。在數字系統中,常要求代碼按一定順序變化。例如,按自然數遞增計數,若采用8421碼,則數0111變到1000時四位均要變化,而在實際電路中,4位的變化不可能絕對同時發生,則計數中可能出現短暫的其它代碼(1100、1111等)。在特定情況下可能導致電路狀態錯誤或輸入錯誤。使用格雷碼可以避免這種錯誤。
在常見的 IP 設計中就會用到格雷碼,比如異步 FIFO 的實現,在讀時鐘域同步到寫時鐘域或寫時鐘域同步到讀時鐘域時,就需要將數據由二進制碼轉化為格雷碼,轉化后的數據響相鄰數據之間只有一位不同,這樣就大大降低了數據同步時出錯的概率。
以下為四位二進制碼和格雷碼之間的對應關系:
| Decimal | Binary | Gray Code |
| 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位和第0位的異或結果。
格雷碼轉二進制碼
如下圖所示,格雷碼轉二進制碼,二進制碼的最高位和格雷碼的最高位一致,次高位為格雷碼的最高位和二進制碼的次高位的異或結果,同理可得格雷碼最低位為格雷碼的第1位和二進制碼的第0位的異或結果。
Verilog 實現
二進制碼轉格雷碼
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /* Engineer : Linest-5 /* File : bin2gray.v /* Create : 2022-08-30 15:35:07 /* Revise : 2022-08-30 15:35:07 /* Module Name : bin2gray /* Description : 二進制碼轉格雷碼 /* Editor : sublime text3, tab size (4) /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/module bin2gray#( parameter DATA_WIDTH = 'd8)(input [DATA_WIDTH-1:0] bin_code,output [DATA_WIDTH-1:0] gray_code );generategenvar i;for (i=0;i<DATA_WIDTH-1;i=i+1) beginassign gray_code[i] = bin_code[i+1] ^ bin_code[i];end endgenerateassign gray_code[DATA_WIDTH-1] = bin_code[DATA_WIDTH-1];endmodule格雷碼轉二進制碼
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /* Engineer : Lqc /* File : gray2bin.v /* Create : 2022-08-30 15:09:27 /* Revise : 2022-08-30 15:09:27 /* Module Name : gray2bin /* Description : 格雷碼轉二進制碼 /* Editor : sublime text3, tab size (4) /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/module gray2bin#(parameter DATA_WIDTH = 'd8)(input [DATA_WIDTH-1:0] gray_code,output [DATA_WIDTH-1:0] bin_code );generategenvar i;for (i=0;i<DATA_WIDTH-1;i=i+1) beginassign bin_code[i] = bin_code[i+1] ^ gray_code[i];end endgenerateassign bin_code[DATA_WIDTH-1] = gray_code[DATA_WIDTH-1];endmoduletestbench 測試代碼
將兩個模塊都例化到測試模塊中,輸入二進制碼轉化成格雷碼,然后再轉化回二進制碼,以此來驗證兩個模塊的設計正確性。
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /* Engineer : Lqc /* File : tb_bin_gray.v /* Create : 2022-08-30 15:40:10 /* Revise : 2022-08-30 15:40:10 /* Module Name : tb_bin_gray /* Description : 二進制碼和格雷碼互轉仿真模塊 /* Editor : sublime text3, tab size (4) /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ `timescale 1ns/1ps module tb_bin_gray();reg [7:0] bin_code_in; wire [7:0] gray_code_out; wire [7:0] bin_code_out;//每10個單位時間輸入的數據加1 integer i; initial beginfor (i=0;i<256;i=i+1) beginbin_code_in = #20 i;end end //例化二進制碼轉格雷碼模塊 bin2gray #(.DATA_WIDTH(8) ) inst_bin2gray (.bin_code(bin_code_in), .gray_code(gray_code_out) );//例化格雷碼轉二進制碼模塊 gray2bin #(.DATA_WIDTH(8) ) inst_gray2bin (.gray_code(gray_code_out), .bin_code(bin_code_out) );endmodule仿真波形
依次輸入8位二進制數據 0-255,可以看到格雷碼相鄰的數據都只變化一位,并且重新轉化為二進制碼的數據也和輸入的數據一致,設計正確!
總結
以上是生活随笔為你收集整理的【Verilog 常见设计】(0)二进制码和格雷码互转 Verilog 实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tomcat内存溢出,性能优化配置讲解
- 下一篇: mysql返回yyyy mm dd_怎么