2-10 進制碼,也稱為 BCD 碼,它的編碼方式則是通過一個 4 位二進制來表示一個 10 進制數,部分十進制對應的 BCD 碼如下
十進制數 | BCD 碼
13 --> 0001_0011
14 --> 0001_0100
19 --> 0001_1001
20 --> 0010_0000
99 --> 1001_1001
對於任意的三位十進制整數存在以下公式:
(ABC) 10 = A*102 + B*101 + C*100
顯然,對於任意一個三位數分離它的百位、十位和個位可以通過整除來實現,verilog 語法同時也支持相乘(*)、相除(/)和取模(%)的運算符,Quartus 綜合器發現這些運算符時會通過調用 FPGA 內部的嵌入式乘法器來實現這些運算。由於在數字電路中乘除法和浮點數的實現較為復雜,所以其他的綜合器或許並不直接提供支持或者會出現仿真與實際不一致的結果,在 verilog 代碼中使用乘除法或者取模會使得代碼失去可移植性,這里並不建議使用。
這里介紹一種通用的算法用於分離十進數的各個數位,這種稱為 移位加 3 算法 的算法 只使用加減和移位運算,它可以滿足代碼移植性的要求,移位加三算法的流程如下(這里假設要分離的只有 3 個數位):
-
將二進制數左移一位(未滿 4 位在前面填 0)
-
如果移動了 8 位,那么二進制數就在 百位、十位和個位列,計算結束
-
在任何一個 BCD 列中,如果任何一個二進制數 大於或者等於 5,就把這個數 加上 3
-
回到步驟 1
下圖展示了十六進制數 0x3F 其轉化 BCD 碼的流程:
根據上圖,可以很容易的編寫對應的 verilog 代碼:
module bin2bcd8 ( input wire [7:0] binary, output wire [3:0] b, output wire [3:0] c, output wire [3:0] d ); //***********************// /* * z 作為存儲 BCD 碼和 二進制碼的寄存器 * 如果輸入為 8 位,那么 z 需要的長度為 * 0xFF = 255 ---> 10-0101-0101 +++ ????-???? * 總共 18 位 */ reg [17:0] z; //***********************// always @ (*) begin z = 18'b0; //置 0 z[7:0] = binary; //讀入低 8 位 repeat (8) //重復 8 次 begin if(z[11:8 ]>4) //大於 4 就加 3 z[11:8 ] = z[11:8 ] + 2'b11; if(z[15:12]>4) z[15:12] = z[15:12] + 2'b11; z[17:1] = z[16:0]; //左移一位 end end
assign b = z[17:16]; //輸出 BCD 碼
assign c = z[15:12]; assign d = z[11:8] ; endmodule
部分仿真結果如下圖:
同理,16 位二進制數的轉化流程如下,和上圖不同的是移動次數增加了,這次共需要移動 16 次,各位可以試着寫出對應的 verilog 代碼。