方案一,使用求余法
思路一 使用assign
module bcd_8421_999999(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [19:0] data , //十进制
output wire [3:0] ones_place , //个位//对应的bcd_8421码
output wire [3:0] tens_place , //十位
output wire [3:0] huns_place , //百位
output wire [3:0] thos_place , //千位
output wire [3:0] ten_thos_place , //万位
output wire [3:0] hun_thos_place //十万位
);
//方案一
assign ones_place = data % 10;
assign tens_place = (data /10 ) %10;
assign huns_place = (data /100 ) %10;
assign thos_place = (data /1000 ) %10;
assign ten_thos_place = (data /10000 ) %10;
assign hun_thos_place = data / 100_000;
endmodule
tb代码
`timescale 1ns/1ns
module tb_bcd_8421_999999();
reg sys_clk ;
reg sys_rst_n ;
reg [19:0] data ;
wire [3:0] ones_place ;
wire [3:0] tens_place ;
wire [3:0] huns_place ;
wire [3:0] thos_place ;
wire [3:0] ten_thos_place ;
wire [3:0] hun_thos_place ;
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
data <= 20'd987_654;
#20
sys_rst_n <= 1'b1;
#200
data <= 20'd123_496;
#200
data <= 20'd008_013;
#500 $stop;
end
always #10 sys_clk = ~sys_clk;
bcd_8421_999999 u_bcd_8421_999999(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.data (data ),
.ones_place (ones_place ),
.tens_place (tens_place ),
.huns_place (huns_place ),
.thos_place (thos_place ),
.ten_thos_place (ten_thos_place ),
.hun_thos_place (hun_thos_place )
);
endmodule
仿真
资源使用量
思路二:将8个时钟为一组,第0个时钟进行初始化等操作,第1-6个时钟进行运算操作,第7个时钟进行输出。将输入传入到该模块,最大需要16个时钟周期才能传出结果
RTL代码如下
/*
将十进制最大为 19'd999_999 的data 转为由6个8421的bcd码进行输出
*/
module bcd_8421_999999(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [19:0] data , //十进制
output reg [3:0] ones_place , //个位//对应的bcd_8421码
output reg [3:0] tens_place , //十位
output reg [3:0] huns_place , //百位
output reg [3:0] thos_place , //千位
output reg [3:0] ten_thos_place , //万位
output reg [3:0] hun_thos_place //十万位
);
//方案一--取模运算-----不建议-耗费资源比较多
//六个时钟周期后输出
reg [2:0] cnt ;
parameter CNT_MAX = 3'd7;//0阶段为初始化阶段,1-6为运算阶段,7为输出阶段
reg flag_cnt;
reg [19:0] data_temp;
reg [3:0] temp_ones_place ;
reg [3:0] temp_tens_place ;
reg [3:0] temp_huns_place ;
reg [3:0] temp_thos_place ;
reg [3:0] temp_ten_thos_place ;
reg [3:0] temp_hun_thos_place ;
//计数
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 3'd0;
else if(cnt == CNT_MAX)
cnt <= 3'd0;
else
cnt <= cnt + 1'b1;
end
//计数_flag
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)//复位时
flag_cnt <= 1'b0;
else if(cnt == (CNT_MAX -1))
flag_cnt <= 1'b1;
else
flag_cnt <= 1'b0;
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
ones_place <= 4'b0000;
tens_place <= 4'b0000;
huns_place <= 4'b0000;
thos_place <= 4'b0000;
ten_thos_place <= 4'b0000;
hun_thos_place <= 4'b0000;
temp_ones_place <= 4'b0000;
temp_tens_place <= 4'b0000;
temp_huns_place <= 4'b0000;
temp_thos_place <= 4'b0000;
temp_ten_thos_place <= 4'b0000;
temp_hun_thos_place <= 4'b0000;
data_temp <= data;
end
else if(flag_cnt == 1'b0)begin
case(cnt)
4'd0 : begin
temp_ones_place <= 4'b0000;
temp_tens_place <= 4'b0000;
temp_huns_place <= 4'b0000;
temp_thos_place <= 4'b0000;
temp_ten_thos_place <= 4'b0000;
temp_hun_thos_place <= 4'b0000;
data_temp <= data;
end
4'd1 : begin
temp_ones_place <= data_temp % 10;
data_temp <= data_temp / 10;
end
4'd2 : begin
temp_tens_place <= data_temp % 10;
data_temp <= data_temp / 10;
end
4'd3 : begin
temp_huns_place <= data_temp % 10;
data_temp <= data_temp / 10;
end
4'd4 : begin
temp_thos_place <= data_temp % 10;
data_temp <= data_temp / 10;
end
4'd5 : begin
temp_ten_thos_place <= data_temp % 10;
data_temp <= data_temp / 10;
end
4'd6 : begin
temp_hun_thos_place <= data_temp % 10;
data_temp <= data_temp / 10;
end
//取不到4'd7 : cnt== 4'd7 flag_cnt == 1'b1;
default : ;
endcase
end
else begin
ones_place <= temp_ones_place ;
tens_place <= temp_tens_place ;
huns_place <= temp_huns_place ;
thos_place <= temp_thos_place ;
ten_thos_place <= temp_ten_thos_place;
hun_thos_place <= temp_hun_thos_place;
end
end
endmodule
下面是仿真结果
所使用资源
方案二 使用<<法,推荐
思路:创建一个二分频的时钟周期,为移位判断信号,低电平时(一个时钟周期)进行判断,高电平时(一个时钟周期)进行移位
十进制最大为999_999的data,位宽为20,需要移动20次 ,根据上面创建的二分频时钟进行计数,最大为21。 0为初始化,1-20为判断和位移阶段,21为输出阶段
将输入传入到该模块,最大需要44个时钟周期才能传出结果
参考十进制转8421_BCD码_8421bcd码-CSDN博客
这是我写的RTL代码
module bcd_8421_999999(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [19:0] data , //十进制
output reg [3:0] ones_place , //个位//对应的bcd_8421码
output reg [3:0] tens_place , //十位
output reg [3:0] huns_place , //百位
output reg [3:0] thos_place , //千位
output reg [3:0] ten_thos_place , //万位
output reg [3:0] hun_thos_place //十万位
);
//方案二 使用<<法,推荐
reg flag_shift ;//移位判断信号,低电平判断,高电平移位,共计两个周期,第一个周期为底电平,第二个周期为高电平
reg [4:0] cnt ;//data 数据位宽20位,需要移动20次
parameter CNT_MAX = 5'd21 ;//0阶段为初始化阶段,1-20为运算阶段,21为输出阶段
reg [43:0] data_shift ;//六个BCD吗加上data,共计24+20=44位宽
//移位判断信号,低电平判断,高电平移位,共计两个周期,第一个周期为底电平,第二个周期为高电平
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
flag_shift <= 1'b0;
else
flag_shift <= ~flag_shift;
end
//计数
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 5'd0;
else if((cnt == CNT_MAX) && (flag_shift == 1'b1))
cnt <= 5'd0;
else if(flag_shift == 1'b1)
cnt <= cnt + 1'b1;
else
cnt <= cnt;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
data_shift <= 44'd0;
else if(cnt == 5'd0)
data_shift <= {24'b0,data};//计数器为0时,初始化阶段
else if((cnt <= 5'd20) && flag_shift == 1'b0)begin
data_shift[23:20] <= (data_shift[23:20]) > 4 ?(data_shift[23:20] + 2'd3):(data_shift[23:20]);
data_shift[27:24] <= (data_shift[27:24]) > 4 ?(data_shift[27:24] + 2'd3):(data_shift[27:24]);
data_shift[31:28] <= (data_shift[31:28]) > 4 ?(data_shift[31:28] + 2'd3):(data_shift[31:28]);
data_shift[35:32] <= (data_shift[35:32]) > 4 ?(data_shift[35:32] + 2'd3):(data_shift[35:32]);
data_shift[39:36] <= (data_shift[39:36]) > 4 ?(data_shift[39:36] + 2'd3):(data_shift[39:36]);
data_shift[43:40] <= (data_shift[43:40]) > 4 ?(data_shift[43:40] + 2'd3):(data_shift[43:40]);
end
else if((cnt <= 5'd20) && flag_shift == 1'b1)
data_shift <= data_shift << 1'b1;
else
data_shift <= data_shift;//cnt == 21 最后一个阶段 保持,输出
end
//输出
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
ones_place <= 4'b0000;
tens_place <= 4'b0000;
huns_place <= 4'b0000;
thos_place <= 4'b0000;
ten_thos_place <= 4'b0000;
hun_thos_place <= 4'b0000;
end
else if(cnt == 5'd21)begin
ones_place <= data_shift[23:20] ;
tens_place <= data_shift[27:24] ;
huns_place <= data_shift[31:28] ;
thos_place <= data_shift[35:32] ;
ten_thos_place <= data_shift[39:36] ;
hun_thos_place <= data_shift[43:40] ;
end
else begin
ones_place <= ones_place ;
tens_place <= tens_place ;
huns_place <= huns_place ;
thos_place <= thos_place ;
ten_thos_place <= ten_thos_place;
hun_thos_place <= hun_thos_place;
end
end
endmodule
仿真结果
所用资源
方案三,使用组合逻辑一个时钟周期完成转换,推荐
上图可知,需要两个操作,一个时移位,一个是判断加3
框图如下
模块一,输入四位编码,判断是否大于4,大于,加三在输出,否则直接输出
模块二 进行一次移位和判断
顶层模块
bcd_8421_adjust 代码
module bcd_8421_adjust (
input wire [3:0] bcd_in,
output wire [3:0] bcd_out
);
//判断
assign bcd_out = (bcd_in > 4) ? bcd_in + 3 : bcd_in;
endmodule
bcd_8421_move 代码
module bcd_8421_move(
input [19:0] move_in ,
output [19:0] move_out
);
//三个十进制bcd 码
wire [3:0] bcd_reg_1;
wire [3:0] bcd_reg_2;
wire [3:0] bcd_reg_3;
wire [19:0] d_reg;
//十进制百位
bcd_8421_adjust bcd_8421_adjust_inst1(
.bcd_in (move_in[19:16]),
.bcd_out (bcd_reg_1)
);
//十进制十位
bcd_8421_adjust bcd_8421_adjust_inst2(
.bcd_in (move_in[15:12]),
.bcd_out (bcd_reg_2)
);
//十进制个位
bcd_8421_adjust bcd_8421_adjust_inst3(
.bcd_in (move_in[11:8]),
.bcd_out (bcd_reg_3)
);
assign d_reg = {bcd_reg_1, bcd_reg_2, bcd_reg_3, move_in[7:0]};
assign move_out = d_reg << 1;
endmodule
bcd_8421 代码
module bcd_8421(
input wire [7:0] in_binary , //最大值为十进制8'b1111_1111 = 8'd255
output wire [11:0] out_bcd //三位十进制需要三个4位的bcd 吗,共计12位
);
/*
可以定义为数组模式
wire [19:0] data_reg [8:0];
则 data_reg_0 = data_reg[0];,以此类推......
*/
wire [19:0] data_reg_0 ;
wire [19:0] data_reg_1 ;
wire [19:0] data_reg_2 ;
wire [19:0] data_reg_3 ;
wire [19:0] data_reg_4 ;
wire [19:0] data_reg_5 ;
wire [19:0] data_reg_6 ;
wire [19:0] data_reg_7 ;
wire [19:0] data_reg_8 ;
assign data_reg_0 = {12'b0000_0000_0000,in_binary};//初始化
//第一次移动和判断
bcd_8421_move move1(
.move_in (data_reg_0),
.move_out (data_reg_1)
);
//第2次移动和判断
bcd_8421_move move2(
.move_in (data_reg_1),
.move_out (data_reg_2)
);
//第3次移动和判断
bcd_8421_move move3(
.move_in (data_reg_2),
.move_out (data_reg_3)
);
//第4次移动和判断
bcd_8421_move move4(
.move_in (data_reg_3),
.move_out (data_reg_4)
);
//第5次移动和判断
bcd_8421_move move5(
.move_in (data_reg_4),
.move_out (data_reg_5)
);
//第6次移动和判断
bcd_8421_move move6(
.move_in (data_reg_5),
.move_out (data_reg_6)
);
//第7次移动和判断
bcd_8421_move move7(
.move_in (data_reg_6),
.move_out (data_reg_7)
);
//第8次移动和判断
bcd_8421_move move8(
.move_in (data_reg_7),
.move_out (data_reg_8)
);
//最后将结果输出
assign out_bcd = data_reg_8[19:8];
endmodule
tb代码
`timescale 1ns/1ns
module tb_bcd_8421();
reg [7:0] in_binary ;
wire [11:0] out_bcd ;
initial begin
in_binary = 8'd123;
#20
in_binary = 8'd234;
#100
in_binary = 8'd12;
#100;
end
bcd_8421 bcd_8421_inst(
.in_binary (in_binary ),
.out_bcd (out_bcd )
);
endmodule
仿真截图
资源使用量
简单做个记录