一、BCD码概念
BCD码(Binary-Coded Decimal),利用四个2进制位储存一个10进制的数,如下表所示。本文所讨论的问题均以8421BCD码为例,十进制的0~9分别用0000~1001来表示。
十进制数23,可表示为0010_0011,十进制数129,可表示为0001_0010_1001。
即分别对个位、十位、百位求对应的BCD码。
二、二进制数到BCD码的转换
先根据输入不同位数的二进制数,求对应的BCD码
假设输入1位二进制数1,则对应的BCD码为0001,对应十进制1;
若输入2位二进制数11,则BCD码为0011,对应十进制3;
若输入3位二进制数111,则BCD码为0111,对应十进制7;
若输入4位二进制数1110,那么问题来了,BCD码范围在0000~1001之间, 是满10进位的, 它只能表示十进制数0~9,而1110对应的十进制数为14!理应转换为0001_0100才对!
那怎么才能转换成0001_0100呢?
需要对进位的时机做一些处理,
先看看以下的分析:
1110(十进制14,BCD码需要表示十位和个位)是111(十进制7)左移一位的结果,其大小等于二倍的111,同理:
1100(十进制12,BCD码需要表示十位和个位)是110(十进制6)左移一位的结果,其大小等于二倍的110,
1010(十进制10,BCD码需要表示十位和个位)是101(十进制5)左移一位的结果,其大小等于二倍的101,
1000(十进制8,BCD码只需要表示个位)是100(十进制4)左移一位的结果,其大小等于二倍的100,
左移相当于乘2, 那么当二进制数 ≥ 0101b, 即≥5(或> 0100b, 即 >4)的时候,左移以后就 ≥ 1010b , 即 ≥ 10,对应的BCD码就需要表示个位和十位了,那么对于一个 4 位的二进制数,先输入的高3位在 ≥5 (或 > 4 )的时候,要对它们处理一下,使得最低位输入进来后,表示十位的BCD码为0001。
这个处理过程, 称为:
加3移位法
举例说明一下, 先设输入一个4位二进制数, 记作abcd,输出为其对应的8421BCD码.
在最低位输入前,如果高3位的 abc ≥ 0101(或 abc > 0100)时, 对其加上3(即0011), 最低位d输入, 使得加过3的高3位整体左移一位.
这相当于(abc + 0011)*2+d,即abc*2 + 6 + d,红字的部分就直接 ≥ 16 了,超过了4位2进制数表示的范围, 向更高位进一位!那么此时表示十位的BCD码为0001。
举两个实例, 更容易理解:
例1:
还是以输入为4位二进制数1110(十进制14)为例:
送入最高位得到0001;
送入第二位得到0011;
送入第三位得到0111 > 0100,在0111基础上进行修正,即0111 + 0011 = 1010;
在修正的结果上送入第四位得到1_0100,即0001_0100即为1110的BCD码(十进制14)。
例2:
再以输入为8位二进制数10100101(十进制165)为例,8位二进制数表示范围为0~255,BCD码需要表示百位、十位、个位, 将10100101b从高位到低位依次送入:
送入最高位1, 得到0001;
送入第二位0, 得到0010;
送入第三位1, 得到0101 ,因为0101 > 0100,修正:0101 + 0011 = 1000;
送入第四位0, 得到0001_0000;
送入第五位0, 得到0010_0000;
送入第六位1, 得到0100_0001;
送入第七位0, 得到1000_0010,1000 > 0100,修正:1000 + 0011 = 1011;
送入第八位1, 得到0001_0110_0101,得到输出结果为0001_0110_0101(十进制165)。
归纳为: 每次当新的一位输入前, 都需要对表示 百位/十位/个位 的连续4bit数据判断大小. 大于4, 则进行加3移位处理.
下面为二进制转BCD码的verilog实现过程:
三、verilog实现
设计一个8位无符号二进制数(取值范围0 ~ 255)到10位BCD码的转换组合逻辑电路。其中10位BCD码定义如下:
数据位 | 描述 |
9:8 | 百位BCD码,取值0 ~ 2 |
7:4 | 十位BCD码,取值0 ~ 9 |
3:0 | 个位BCD码,取值0 ~ 9 |
例如:
输入8'b10100101(十进制165),输出10'b01_0110_0101;
输入8'b11110000(十进制240),输出10'b10_0100_0000.
模块输入输出功能定义:
名称 | 方向 | 位宽 | 描述 |
bin_in | I | 8 | 输入二进制数 |
bcd_out | O | 10 | 输出BCD编码 |
要求:
Verilog实现代码可综合,逻辑延迟越小越好,给出仿真结果。
设计代码:
注:此处通过阻塞赋值实现移位寄存器的功能,用阻塞赋值描述移位寄存器是可行的(但这种风格并不好),通过阻塞赋值,只要赋值的顺序正确,就可以通过组合逻辑描述移位寄存器。相较于时序逻辑,可以有更小的逻辑延迟和资源消耗。
参考:夏宇闻《verilog数字系统设计教程》-- 14.5.寄存器模型 -- 例14.6
module binary_bcd(
input [7:0] bin_in,
output [9:0] bcd_out
);
reg [3:0] ones;
reg [3:0] tens;
reg [1:0] hundreds;
integer i;
always @(*) begin
ones = 4'd0;
tens = 4'd0;
hundreds = 2'd0;
for(i = 7; i >= 0; i = i - 1) begin
if (ones >= 4'd5) ones = ones + 4'd3;
if (tens >= 4'd5) tens = tens + 4'd3;
if (hundreds >= 4'd5) hundreds = hundreds + 4'd3;
hundreds = {hundreds[0],tens[3]};
tens = {tens[2:0],ones[3]};
ones = {ones[2:0],bin_in[i]};
end
end
assign bcd_out = {hundreds, tens, ones};
endmodule
testbench:
`timescale 1ns / 1ps
module tb_binary_bcd();
reg [7:0] bin_in;
wire [9:0] bcd_out;
initial begin
bin_in = 8'b1010_0101; //十进制165
#100
bin_in = 8'b1111_0000; //十进制240
#100
bin_in = 8'b1111_1111; //十进制255
end
binary_bcd u_binary_bcd(
.bin_in (bin_in),
.bcd_out(bcd_out)
);
endmodule
仿真结果:
综合结果: