Conversion principle
Binary to BCD code can use the Double_dabble algorithm, wikipedia has a detailed description, can be simply called “shift plus 3” algorithm.
8-bit binary number 243, shift plus 316-bit binary 65244, shift plus 3
Verilog implementation
Method 1: Pure combinatorial logic implementation
Implementation from Wikipedia. It can be seen that the binary bit width is W, so the BCD bit width only needs (W + (W – 4) / 3+1) bits. For example, if W=8, only 10 bits are needed, ranging from 0 to 255, and only two bits are needed for hundreds. BinTobcd. V file:
`timescale 1ns / 1ps
module binTobcd #(
parameter W = 18
) // input width
(
//Inputs
input [W - 1 : 0] bin , // binary
//Outputs
output reg [W + (W - 4) / 3: 0] bcd
); // bcd {... ,thousands,hundreds,tens,ones}
integer i, j;
always @(bin) begin
for (i = 0; i <= W + (W - 4) / 3; i = i + 1)
bcd[i] = 0; // initialize with zeros
bcd[W - 1: 0] = bin; // initialize with input vector
for (i = 0; i <= W - 4; i = i + 1) // iterate on structure depth
for (j = 0; j <= i / 3; j = j + 1) // iterate on structure width
if (bcd[W - i + 4 * j - : 4] > 4) // if > 4
bcd[W - i + 4 * j - : 4] = bcd[W - i + 4 * j - : 4] + 4 'd3; // add 3
end
endmodule
Copy the code
Method 2: Using the state machine to achieve variable bit width
From nandland. Binary_to_bcd.v, the actual measurement will consume more clock cycles.
/* INPUT_WIDTH = 8; DECIMAL_DIGITS = 3; It consumes 60 CLK */
module Binary_to_BCD #(
parameter INPUT_WIDTH,
parameter DECIMAL_DIGITS
)(
//Inputs
input i_Clock,
input i_Rst_n,
input [INPUT_WIDTH - 1 : 0] i_Binary,
input i_Start,
//Outputs
output [DECIMAL_DIGITS * 4 - 1 : 0] o_BCD,
output o_DV
);
localparam s_IDLE = 3'b000;
localparam s_SHIFT = 3'b001;
localparam s_CHECK_SHIFT_INDEX = 3'b010;
localparam s_ADD = 3'b011;
localparam s_CHECK_DIGIT_INDEX = 3'b100;
localparam s_BCD_DONE = 3'b101;
reg [2 : 0] r_SM_Main = s_IDLE;
reg [DECIMAL_DIGITS * 4 - 1 : 0] r_BCD = 0;
reg [INPUT_WIDTH - 1 : 0] r_Binary = 0;
reg [DECIMAL_DIGITS - 1 : 0] r_Digit_Index = 0;
reg [7 : 0] r_Loop_Count = 0;
reg r_DV = 1'b0;
wire [3 : 0] w_BCD_Digit = r_BCD[r_Digit_Index * 4 + : 4];
assign o_BCD = r_BCD;
assign o_DV = r_DV;
always @(posedge i_Clock) begin
if(! i_Rst_n) begin
r_BCD <= 'h0; r_Binary <= 'h0;
r_DV <= 'h0; r_SM_Main <= 'h0;
r_Loop_Count <= 'h0; r_Digit_Index <= 'h0;
end
else begin
case (r_SM_Main)
// Stay in this state until i_Start comes along
s_IDLE : begin
r_DV <= 1'b0;
if (i_Start == 1'b1) begin
r_Binary <= i_Binary;
r_SM_Main <= s_SHIFT;
r_BCD <= 0;
end
else
r_SM_Main <= s_IDLE;
end
// Always shift the BCD Vector until we have shifted all bits through
// Shift the most significant bit of r_Binary into r_BCD lowest bit.
s_SHIFT : begin
r_BCD <= r_BCD << 1;
r_BCD[0] <= r_Binary[INPUT_WIDTH - 1];
r_Binary <= r_Binary << 1;
r_SM_Main <= s_CHECK_SHIFT_INDEX;
end
// Check if we are done with shifting in r_Binary vector
s_CHECK_SHIFT_INDEX : begin
if (r_Loop_Count == INPUT_WIDTH - 1) begin
r_Loop_Count <= 0;
r_SM_Main <= s_BCD_DONE;
end
else begin
r_Loop_Count <= r_Loop_Count + 1;
r_SM_Main <= s_ADD;
end
end
// Break down each BCD Digit individually.? Check them one-by-one to
// see if they are greater than 4.? If they are, increment by 3.
// Put the result back into r_BCD Vector.?
s_ADD : begin
if (w_BCD_Digit > 4) begin
r_BCD[(r_Digit_Index * 4) + : 4] <= w_BCD_Digit + 3;
end
r_SM_Main <= s_CHECK_DIGIT_INDEX;
end
// Check if we are done incrementing all of the BCD Digits
s_CHECK_DIGIT_INDEX : begin
if (r_Digit_Index == DECIMAL_DIGITS - 1) begin
r_Digit_Index <= 0;
r_SM_Main <= s_SHIFT;
end
else begin
r_Digit_Index <= r_Digit_Index + 1;
r_SM_Main <= s_ADD;
end
end
s_BCD_DONE : begin
r_DV <= 1'b1;
r_SM_Main <= s_IDLE;
end
default :
r_SM_Main <= s_IDLE;
endcase
end
end // always @ (posedge i_Clock)?
endmodule // Binary_to_BCD
Copy the code
Simulation file, binary_to_bcd_tb.v:
`timescale 1ns/1ps
module Binary_to_BCD_tb;
reg clk;
reg rst_n;
reg start;
reg [7:0] bin;
wire [11:0] dec;
wire done;
wire [3:0] dec_b = dec[11:8];
wire [3:0] dec_s = dec[7:4];
wire [3:0] dec_g = dec[3:0];
wire [7:0] dec_real = dec_b * 100 + dec_s * 10 + dec_g;
reg [7:0] idx;
always # (10/2) clk <= ! clk; initial begin clk =0;
rst_n = 0;
start = 0;
bin = 0;
idx = 0;
#50
@(posedge clk);
rst_n = 1;
#50
@(posedge clk);
for(idx = 0; idx < 254; idx = idx + 1)
trig_bcd_covert(idx);
#2000;
$stop();
$display("stop");
end
task trig_bcd_covert(
input [7:0] i_bin
);
begin
#80
@(posedge clk);
bin = i_bin;
start = 1;
@(posedge clk);
start = 0;
@(posedge done);
if(dec_real == i_bin)
$display("ok:%3d -> %1x%1x%1x", bin, dec_b, dec_s, dec_g);
else
$display("err:%3d -> %1x%1x%1x", bin, dec_b, dec_s, dec_g);
end
endtask
Binary_to_BCD #(
.INPUT_WIDTH(8),
.DECIMAL_DIGITS(3)
)Binary_to_BCD_ut0(
//Inputs
.i_Clock(clk),
.i_Rst_n(rst_n),
.i_Binary(bin[7:0]),
.i_Start(start),
//Outputs
.o_BCD(dec[11:0]),
.o_DV(done)
);
endmodule
Copy the code
Method 3: Personal write state machine-based BCD code conversion
Only 8 binary to BCD is supported. The same operation is performed for other bit widths, bin_to_bCd.v
/* Binary to BCD code 243(11110011) = 0010 0100 0011 = 2/4/3 CLK = 9+8 */
module bin_to_bcd(
input clk,
input rst_n,
input start, //1 clk high pulse
input [7:0] bin,
output reg [11:0] bcd, //[W + (W - 4) / 3: 0], w=8 -> 8+1=9:0=10
output done //need 17 clk time
);
localparam S0_IDLE = 0;
localparam S1_SHIFT = 1;
localparam S2_ADD = 2;
localparam S3_FINISH = 4;
reg [3:0] fsm;
reg [3:0] cnt_shift; //max=8
reg [7:0] bin_buf;
reg [11:0] bcd_buf;
assign done = (fsm == S3_FINISH);
always @ (posedge clk) begin
if(! rst_n) begin
fsm <= S0_IDLE;
cnt_shift <= 'h0; bcd_buf <= 'h0;
bin_buf <= 'h0; bcd <= 'h0;
end
else begin
case(fsm)
S0_IDLE: begin
if(start) begin
fsm <= S1_SHIFT;
bin_buf <= bin;
cnt_shift <= 'h0; bcd_buf <= 'h0;
end
end
// Shift operation
S1_SHIFT: begin
if(cnt_shift ! =8) begin
cnt_shift <= cnt_shift + 1;
{bcd_buf, bin_buf} <= {bcd_buf, bin_buf} << 1;
fsm <= S2_ADD;
end
else
fsm <= S3_FINISH;
end
// Add 3
S2_ADD: begin
if(cnt_shift ! =8) begin
fsm <= S1_SHIFT;
if(bcd_buf[11:8] > 4)
bcd_buf[11:8] <= bcd_buf[11:8] + 'd3; if(bcd_buf[7:4] > 4) bcd_buf[7:4] <= bcd_buf[7:4] + 'd3;
if(bcd_buf[3:0] > 4)
bcd_buf[3:0] <= bcd_buf[3:0] + 'd3; end else begin fsm <= S3_FINISH; bcd <= bcd_buf; End end // Finish S3_FINISH: begin FSM <= S0_IDLE; bin_buf <= 'h0;
cnt_shift <= 'h0; bcd_buf <= 'h0;
end
endcase
end
end
endmodule
Copy the code
Simulation file, bin_to_bcd_tb.v:
`timescale 1ns/1ps
module bin_to_bcd_tb;
reg clk;
reg rst_n;
reg start;
reg [7:0] bin;
wire [11:0] bcd;
wire done;
wire [3:0] bcd_b = bcd[11:8];
wire [3:0] bcd_s = bcd[7:4];
wire [3:0] bcd_g = bcd[3:0];
wire [7:0] bcd_real = bcd_b * 100 + bcd_s * 10 + bcd_g;
reg [7:0] idx;
always # (10/2) clk <= ! clk; initial begin clk =0;
rst_n = 0;
start = 0;
bin = 0;
idx = 0;
#50
@(posedge clk);
rst_n = 1;
#50
@(posedge clk);
for(idx = 0; idx < 254; idx = idx + 1)
trig_bcd_covert(idx);
#2000;
$stop();
$display("stop");
end
task trig_bcd_covert(
input [7:0] i_bin
);
begin
#80
@(posedge clk);
bin = i_bin;
start = 1;
@(posedge clk);
start = 0;
@(posedge done);
if(bcd_real == i_bin)
$display("ok:%3d -> %1x%1x%1x", bin, bcd_b, bcd_s, bcd_g);
else
$display("err:%3d -> %1x%1x%1x", bin, bcd_b, bcd_s, bcd_g);
end
endtask
bin_to_bcd bin_to_bcd_ut0(
.clk(clk),
.rst_n(rst_n),
.start(start),
.bin(bin[7:0]),
.bcd(bcd[11:0]),
.done(done)
);
endmodule
Copy the code