bcd码:以4bit二进制码表示一个十进制码
例如,432(d) = 0100-0011-0010(bcd)
这里具体的判断方法为:(满5)加3法
二进制位宽为W,则BCD位宽只需要(W + (W - 4) / 3+1)位
FPGA Verilog实现二进制转BCD码
二进制数转换成BCD码的Verilog实现
/*方法1:来自维基百科,可以看出,二进制位宽为W,则BCD位宽只需要(W + (W - 4) / 3+1)位。
如W=8,只需要10位,范围0-255,百位只需要两位就可以表示。
*/
module binary2bcd#(parameter WIDTH = 20)(
input [WIDTH-1:00] bin_data, //
output reg [WIDTH+(WIDTH-4)/3:00] bcd_data
);
//Parameter Declarations
integer i,j;
always @(bin_data)begin
for(i = 0;i <= WIDTH+(WIDTH-4)/3; i = i + 1)
bcd_data[i] = 0;
bcd_data[WIDTH-1:0] = bin_data;
for(i = 0;i <= WIDTH-4; i = i + 1)
for(j = 0;j <= i / 3; j = j + 1)
if(bcd_data[WIDTH-i+4*j-:4] > 4)begin
bcd_data[WIDTH-i+4*j-:4] <= bcd_data[WIDTH-i+4*j-:4] + 4'd3;
end
end //always end
endmodule
方法2:状态机实现,延迟时间为 (输入数据位宽+2) * Tclk
/* ================================================ *\
Filename ﹕ binary2bcd.v
Author ﹕ Adolph
Description ﹕ 实现32bit以内的二进制数据转换为BCD
Called by ﹕
Revision History ﹕ 2023-07-07 11:50:10
Revision 1.0
Email﹕ [email protected]
Company﹕ AWCloud...Std
\* ================================================ */
module binary2bcd #(parameter BIN_W = 32, BCD_W = 40)(
input Clk , //system clock 50MHz
input Rst_n , //reset, low valid
input Start , //
input [BIN_W-1:00] Bin_data, //
output reg bcd_vld , //
output reg [BCD_W-1:00] Bcd_data //
);
//Parameter Declarations
//状态机参数定义
parameter
IDLE = 4'b0001,
READY = 4'b0010,
SHIFT = 4'b0100,
DONE = 4'b1000;
//Internal wire/reg declarations
reg [BIN_W-1:00] din_r; //
reg [05:00] cnt ; //Counter 移位计数器
wire add_cnt ; //Counter Enable
wire end_cnt ; //Counter Reset
reg [03:00] state_c, state_n; //
reg [03:00] mem_r [09:00] ; //
wire [03:00] mem_w [09:00] ; //
wire [39:00] bcd_res ; //
wire idle2ready ; //
wire shift2done ; //
// reg bcd_vld ; //
//Logic Description
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
cnt <= 'd0;
end
else if(add_cnt)begin
if(end_cnt)begin
cnt <= 'd0;
end
else begin
cnt <= cnt + 1'b1;
end
end
else begin
cnt <= cnt;
end
end
assign add_cnt = state_c == SHIFT;
assign end_cnt = add_cnt && cnt >= BIN_W - 1;
//第一段设置状态转移空间
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end //always end
//第二段、组合逻辑定义状态转移
always@(*)begin
case(state_c)
IDLE:begin
if(idle2ready)begin
state_n = READY;
end
else begin
state_n = state_c;
end
end
READY:begin
state_n = SHIFT;
end
SHIFT:begin
if(shift2done)begin
state_n = DONE;
end
else begin
state_n = state_c;
end
end
DONE:begin
state_n = IDLE;
end
default: begin
state_n = IDLE;
end
endcase
end //always end
assign idle2ready = state_c == IDLE && Start;
assign shift2done = state_c == SHIFT && end_cnt;
//第三段,定义状态机输出情况,可以时序逻辑,也可以组合逻辑
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
din_r <= 'd0;
end
else if(Start)begin
din_r <= Bin_data;
end
else if(state_c == SHIFT)begin //移位状态下,每个时钟周期向左移1位
din_r <= din_r << 1;
end
else begin
din_r <= din_r;
end
end //always end
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
mem_r[0] <= 4'd0;
mem_r[1] <= 4'd0;
mem_r[2] <= 4'd0;
mem_r[3] <= 4'd0;
mem_r[4] <= 4'd0;
mem_r[5] <= 4'd0;
mem_r[6] <= 4'd0;
mem_r[7] <= 4'd0;
mem_r[8] <= 4'd0;
mem_r[9] <= 4'd0;
end
else if(idle2ready)begin
mem_r[0] <= 4'd0;
mem_r[1] <= 4'd0;
mem_r[2] <= 4'd0;
mem_r[3] <= 4'd0;
mem_r[4] <= 4'd0;
mem_r[5] <= 4'd0;
mem_r[6] <= 4'd0;
mem_r[7] <= 4'd0;
mem_r[8] <= 4'd0;
mem_r[9] <= 4'd0;
end
else if(state_c == SHIFT)begin
mem_r[0] <= {mem_w[0][2:0],din_r[BIN_W-1]};
mem_r[1] <= {mem_w[1][2:0],mem_w[0][3] };
mem_r[2] <= {mem_w[2][2:0],mem_w[1][3] };
mem_r[3] <= {mem_w[3][2:0],mem_w[2][3] };
mem_r[4] <= {mem_w[4][2:0],mem_w[3][3] };
mem_r[5] <= {mem_w[5][2:0],mem_w[4][3] };
mem_r[6] <= {mem_w[6][2:0],mem_w[5][3] };
mem_r[7] <= {mem_w[7][2:0],mem_w[6][3] };
mem_r[8] <= {mem_w[8][2:0],mem_w[7][3] };
mem_r[9] <= {mem_w[9][2:0],mem_w[8][3] };
end
else ;
end //always end
//组合逻辑近乎没有时延
assign mem_w[0] = (mem_r[0] > 4'd4) ? (mem_r[0] + 4'd3) : mem_r[0];
assign mem_w[1] = (mem_r[1] > 4'd4) ? (mem_r[1] + 4'd3) : mem_r[1];
assign mem_w[2] = (mem_r[2] > 4'd4) ? (mem_r[2] + 4'd3) : mem_r[2];
assign mem_w[3] = (mem_r[3] > 4'd4) ? (mem_r[3] + 4'd3) : mem_r[3];
assign mem_w[4] = (mem_r[4] > 4'd4) ? (mem_r[4] + 4'd3) : mem_r[4];
assign mem_w[5] = (mem_r[5] > 4'd4) ? (mem_r[5] + 4'd3) : mem_r[5];
assign mem_w[6] = (mem_r[6] > 4'd4) ? (mem_r[6] + 4'd3) : mem_r[6];
assign mem_w[7] = (mem_r[7] > 4'd4) ? (mem_r[7] + 4'd3) : mem_r[7];
assign mem_w[8] = (mem_r[8] > 4'd4) ? (mem_r[8] + 4'd3) : mem_r[8];
assign mem_w[9] = (mem_r[9] > 4'd4) ? (mem_r[9] + 4'd3) : mem_r[9];
assign bcd_res = {mem_r[9],mem_r[8],mem_r[7],mem_r[6],mem_r[5],mem_r[4],mem_r[3],mem_r[2],mem_r[1],mem_r[0]};
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
bcd_vld <= 1'b0;
end
else begin
bcd_vld <= (state_c == DONE);
end
end //always end
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
Bcd_data <= 'd0;
end
else if(state_c == DONE)begin
Bcd_data <= bcd_res[BCD_W-1:0];
end
else begin
Bcd_data <= Bcd_data;
end
end //always end
endmodule
//仿真测试文件
/* ================================================ *\
Filename ﹕ tb_binary2bcd.v
Author ﹕ Adolph
Description ﹕
Called by ﹕
Revision History ﹕ 2023-07-07 11:50:10
Revision 1.0
Email﹕ [email protected]
Company﹕ AWCloud...Std
\* ================================================ */
`timescale 1ns/1ns //仿真系统时间尺度定义
`define clk_period 20 //时钟周期宏定义
module tb_binary2bcd;
//激励信号定义
reg Clk ;
reg Rst_n ;
reg [31:00] bin_data; //
reg Start ; //
//响应信号定义
// wire [24:00] bcd_data;
//实例化
binary2bcd #(.BIN_W (32), .BCD_W(40)) BIN2BCD(
/*input */.Clk (Clk ), //system clock 50MHz
/*input */.Rst_n (Rst_n ), //reset, low valid
/*input */.Start (Start ), //
/*input [BIN_W-1:00] */.Bin_data (bin_data), //
/*output reg */.bcd_vld (), //
/*output reg [BCD_W-1:00] */.Bcd_data () //
);
//产生时钟
initial Clk = 1'b0;
always #(`clk_period / 2) Clk = ~Clk;
//产生激励
initial begin
Rst_n = 1'b0;
bin_data = 0;
Start = 1'b0;
#(`clk_period * 1 + 3);
Rst_n = 1'b1;
repeat(30)begin
bin_data = {$random} % 99999;
Start = 1'b1;
#`clk_period Start = 1'b0;
@(negedge BIN2BCD.bcd_vld);
#`clk_period;
end
#(`clk_period * 20);
$stop(2);
end
endmodule