二进制转换成BCD的原理与verilog实现 --加3左移
FPGA中的lcd显示、串口收发等应用会涉及到二进制和BCD码之间的转换,常见的有3种方法:除法取模运算、查找表、加3左移。 大位宽下,取模除法运算耗费大量lut资源,查找表也不方便,常用一种加3左移的方法。
加3左移相当于左移后再加6,基本过程有很多人描述过了,可以参考下面的博客,其过程介绍得很清楚。
https://www.cnblogs.com/SummerSunnyDay/p/5013835.html
我这里着重补充一下为什么通过这种有条件的移位就能转换,其实可以追溯到10进制转换成二进制的原理----除二取余法,二进制转换成BCD可以认为是类似于除二取余的逆运算,即从下往上进行,但要加上BCD中的逢10进6问题,这里需要好好体会一下。
逆向运算,按照这种乘2加余,一定可以把一个二进制恢复成10进制数,问题的关键是存放个、十、百位的位置受BCD码规则需要进行变动。
verilog例程:32bit bin – 40bit bcd
//可综合转换代码
module BCD(
input clk,
input rstn,
input [31:0] data_bin,
output reg [39:0] data_bcd,
output reg valid
);
reg[71:0] data_shift;
reg[7:0] cnt;
always @(posedge clk ) begin
if (!rstn) begin
cnt <= 0;
end
else begin
if(cnt >= 65)
cnt <= 0;
else
cnt <= cnt +1;
end
end
always @(posedge clk) begin
if (!rstn) begin
valid <= 0;
data_bcd <= 0;
data_shift <= 0;
end
else begin
if(cnt==0) begin
valid <= 0;
data_shift <= data_bin; //0 缓存数值
end
else if(cnt <= 64) begin //1-64 移位转换
if (cnt[0]) begin //1 3 5 7 63
data_shift[71:32] = MoreFourAddThree(data_shift[71:32]);
end
else begin
data_shift = data_shift << 1;
end
end
else if(cnt == 65) begin //转换结束,输出
valid <= 1'b1;
data_bcd <= data_shift[71:32];
end
end
end
function [39:0] MoreFourAddThree (input [39:0] a);
begin
MoreFourAddThree[ 3: 0] = a[ 3: 0]> 4'd4 ? a[ 3: 0]+ 4'd3 : a[ 3: 0];
MoreFourAddThree[ 7: 4] = a[ 7: 4]> 4'd4 ? a[ 7: 4]+ 4'd3 : a[ 7: 4];
MoreFourAddThree[11: 8] = a[11: 8]> 4'd4 ? a[11: 8]+ 4'd3 : a[11: 8];
MoreFourAddThree[15:12] = a[15:12]> 4'd4 ? a[15:12]+ 4'd3 : a[15:12];
MoreFourAddThree[19:16] = a[19:16]> 4'd4 ? a[19:16]+ 4'd3 : a[19:16];
MoreFourAddThree[23:20] = a[23:20]> 4'd4 ? a[23:20]+ 4'd3 : a[23:20];
MoreFourAddThree[27:24] = a[27:24]> 4'd4 ? a[27:24]+ 4'd3 : a[27:24];
MoreFourAddThree[31:28] = a[31:28]> 4'd4 ? a[31:28]+ 4'd3 : a[31:28];
MoreFourAddThree[35:32] = a[35:32]> 4'd4 ? a[35:32]+ 4'd3 : a[35:32];
MoreFourAddThree[39:36] = a[39:36]> 4'd4 ? a[39:36]+ 4'd3 : a[39:36];
end
endfunction
endmodule
测试testbench:
`timescale 1ns/1ns
module tb_BCD (
);
reg clk,rstn;
wire valid;
reg[31:0] data_bin;
wire[39:0] data_bcd;
BCD u_BCD(
.clk (clk ),
.rstn (rstn ),
.data_bin (data_bin ),
.data_bcd (data_bcd ),
.valid (valid )
);
initial begin
rstn = 0;
#10
rstn = 1;
end
initial begin
clk = 0;
forever begin
#1 clk = !clk;
end
end
initial begin
data_bin = 0;
#200
data_bin = 32'd1234567890;
#200
data_bin = 32'd1111111111;
#200
data_bin = 32'd1999999999;
end
endmodule
以及modelsim do脚本:
quit -sim
vlib work
vmap work work
vlog -work work tb_BCD.v
vsim -voptargs=+acc work.tb_BCD
#-decimal
#-hex
add wave -color Green -height 20 /tb_BCD/clk
add wave -color Green -height 20 /tb_BCD/rstn
add wave -color Green -height 20 -Radix decimal /tb_BCD/u_BCD/cnt
add wave -color Green -height 20 /tb_BCD/valid
add wave -color Green -height 20 -Radix decimal /tb_BCD/data_bin
add wave -color Green -height 20 -Radix hex /tb_BCD/data_bcd
add wave -color Green -height 20 -Radix hex /tb_BCD/u_BCD/data_shift
run 1000ns
仿真测试结果:
可以看到:32bit的二进制数(10进制显示),分散到了40bit的hex中,延时65个时钟周期