前言
在用FPGA实现数码管显示数据时,要用到二进制转BCD码,显示数据
一、为什么要这样做?
如果对于一个十进制的数字123,要想将其每一位分别提取出来,那么我们通常用这个算法
百位 = 123 / 100;
十位 = 123%100/10;
个位 = 123%10。
但是在FPGA里面这样时浪费资源的(虽然我没试过)。
二、常见的实现方式
1.小梅哥
module bcd_single_modify(bcd_in, bcd_out);
input [3:0] bcd_in;
output [3:0] bcd_out;
reg [3:0] bcd_out;
always @ (bcd_in)
begin
if (bcd_in > 4)
bcd_out = bcd_in + 2'd3;
else
bcd_out = bcd_in;
end
endmodule
module bcd_modify(data_in, data_out);
input [59:0] data_in;
output [59:0] data_out;
bcd_single_modify bcd9(.bcd_in(data_in[59:56]), .bcd_out(data_out[59:56]));
bcd_single_modify bcd8(.bcd_in(data_in[55:52]), .bcd_out(data_out[55:52]));
bcd_single_modify bcd7(.bcd_in(data_in[51:48]), .bcd_out(data_out[51:48]));
bcd_single_modify bcd6(.bcd_in(data_in[47:44]), .bcd_out(data_out[47:44]));
bcd_single_modify bcd5(.bcd_in(data_in[43:40]), .bcd_out(data_out[43:40]));
bcd_single_modify bcd4(.bcd_in(data_in[39:36]), .bcd_out(data_out[39:36]));
bcd_single_modify bcd3(.bcd_in(data_in[35:32]), .bcd_out(data_out[35:32]));
bcd_single_modify bcd2(.bcd_in(data_in[31:28]), .bcd_out(data_out[31:28]));
assign data_out[27:0] = data_in[27:0];
endmodule
module bin_to_BCD(bin, bcd);
input [27:0] bin;
output [31:0] bcd;
wire [59:0] shift_reg [28:0];
assign shift_reg[28] = {32'b0, bin};
bcd_modify b27(.data_in(shift_reg[28]<<1), .data_out(shift_reg[27]));
bcd_modify b26(.data_in(shift_reg[27]<<1), .data_out(shift_reg[26]));
bcd_modify b25(.data_in(shift_reg[26]<<1), .data_out(shift_reg[25]));
bcd_modify b24(.data_in(shift_reg[25]<<1), .data_out(shift_reg[24]));
bcd_modify b23(.data_in(shift_reg[24]<<1), .data_out(shift_reg[23]));
bcd_modify b22(.data_in(shift_reg[23]<<1), .data_out(shift_reg[22]));
bcd_modify b21(.data_in(shift_reg[22]<<1), .data_out(shift_reg[21]));
bcd_modify b20(.data_in(shift_reg[21]<<1), .data_out(shift_reg[20]));
bcd_modify b19(.data_in(shift_reg[20]<<1), .data_out(shift_reg[19]));
bcd_modify b18(.data_in(shift_reg[19]<<1), .data_out(shift_reg[18]));
bcd_modify b17(.data_in(shift_reg[18]<<1), .data_out(shift_reg[17]));
bcd_modify b16(.data_in(shift_reg[17]<<1), .data_out(shift_reg[16]));
bcd_modify b15(.data_in(shift_reg[16]<<1), .data_out(shift_reg[15]));
bcd_modify b14(.data_in(shift_reg[15]<<1), .data_out(shift_reg[14]));
bcd_modify b13(.data_in(shift_reg[14]<<1), .data_out(shift_reg[13]));
bcd_modify b12(.data_in(shift_reg[13]<<1), .data_out(shift_reg[12]));
bcd_modify b11(.data_in(shift_reg[12]<<1), .data_out(shift_reg[11]));
bcd_modify b10(.data_in(shift_reg[11]<<1), .data_out(shift_reg[10]));
bcd_modify b9(.data_in(shift_reg[10]<<1), .data_out(shift_reg[9]));
bcd_modify b8(.data_in(shift_reg[9]<<1), .data_out(shift_reg[8]));
bcd_modify b7(.data_in(shift_reg[8]<<1), .data_out(shift_reg[7]));
bcd_modify b6(.data_in(shift_reg[7]<<1), .data_out(shift_reg[6]));
bcd_modify b5(.data_in(shift_reg[6]<<1), .data_out(shift_reg[5]));
bcd_modify b4(.data_in(shift_reg[5]<<1), .data_out(shift_reg[4]));
bcd_modify b3(.data_in(shift_reg[4]<<1), .data_out(shift_reg[3]));
bcd_modify b2(.data_in(shift_reg[3]<<1), .data_out(shift_reg[2]));
bcd_modify b1(.data_in(shift_reg[2]<<1), .data_out(shift_reg[1]));
assign shift_reg[0] = shift_reg[1]<<1;
assign bcd = shift_reg[0][59:28];
endmodule
这是在小梅哥的频率计里面写的,实现的电路
总览
局部
2.利用循环写的( 来自维基百科的实现???)
可以看出,二进制位宽为W,则BCD位宽只需要(W + (W - 4) / 3+1)位。如W=8,只需要10位,范围0-255,百位只需要两位就可以表示。
为了和小梅哥的类比,使用28位bin
`timescale 1ns / 1ps
module binTobcd #(
parameter W = 28
) // 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
实现的电路
相当的炸裂!!!
局部
3.使用状态机
实现 输入位宽 和 输出位宽 可变
module Binary_to_BCD(
//Inputs
i_Clock,
i_Rst_n,
i_Binary,
i_Start,
//Outputs
o_BCD,
o_DV
);
parameter INPUT_WIDTH = 28;
parameter DECIMAL_DIGITS = 32;
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
实现的电路
总结
实现功能进行了