verilog:一种资源节约型的BCD码转二进制码模块
上一篇文章分享了一种资源节约型(时间换资源)的二进制转BCD码的verilog代码写法(加3左移),本篇则介绍一种BCD码转换成2进制码的可综合verilog。
任务描述
首先,假设有一个40bit的BCD码data_bcd[39:0] ,并任意设data_bcd = 40’h1234567980 ,现在要把它转换成32bit的二进制数data_bin[31:0],有data_bin = 32’d1234567890。
原理方法
首先最容易想到的:
(*use_dsp = "no"*)module temp_bcd2bin(
input [39:0] data_bcd,
output [31:0] data_bin
);
assign data_bin = data_bcd[39:36]*1000_000_000 + data_bcd[35:32]*1000_000_00
+ data_bcd[31:28]*1000_000_0 + data_bcd[27:24]*1000_000
+ data_bcd[23:20]*1000_00 + data_bcd[19:16]*1000_0
+ data_bcd[15:12]*1000 + data_bcd[11: 8]*100
+ data_bcd[ 7: 4]*10 + data_bcd[ 3: 0] ;
endmodule
RTL:
综合后资源:
消耗了214个lut ,
资源消耗其实也还好,从RTL看出,编译器已经进行了优化,即每4bit一组进行运算。
但是,就资源来说还可以进一步优化,而且上述写法,加法链很长,不利于跑高速。
实现
和2进制转BCD类似,我们可以使用一种串行方式进行。
即对data_bcd = 40’h123456790 :
i=1, data_bin = 1;
i=2, data_bin = data_bin *10 +2;
i=3, data_bin = data_bin *10 +3;
i=4, data_bin = data_bin *10 +4;
i=5, data_bin = data_bin *10 +5;
i=6, data_bin = data_bin *10 +6;
i=7, data_bin = data_bin *10 +7;
i=8, data_bin = data_bin *10 +8;
i=9, data_bin = data_bin *10 +9;
i=10, data_bin = data_bin *10 +0;
由于i是计数器,经过10次计数,
这样,实际生成的只有一个乘法和加法器,而且*10还可以改写成加法移位形式,从而达到节约lut资源目的。
最终可综合的verilog代码:
//40bit的bcd码转32bit的2进制
//
module BCD2BIN(
input clk,
input rstn,
input [39:0] data_bcd,
output reg [31:0] data_bin,
output reg valid
);
reg [ 7:0] cnt;
reg [39:0] data_bcd_temp;
reg [31:0] data_bin_temp;
always @(posedge clk ) begin
if (!rstn) begin
cnt <= 0;
end
else begin
if(cnt >= 11)
cnt <= 0;
else
cnt <= cnt +1;
end
end
always @(posedge clk ) begin
if(!rstn ) begin
valid <= 1'd0;
data_bcd_temp <= 40'd0;
data_bin_temp <= 32'd0;
end
else begin
if ( cnt == 8'd0 ) begin
valid <= 1'd0;
data_bcd_temp <= data_bcd;
data_bin_temp <= 32'd0;
end
else if( cnt <= 8'd10 ) begin
data_bin_temp <= MULTI10(data_bin_temp) + data_bcd_temp[(8'd43-cnt*4)-:4]; //注意位索引写法,表示8'd43-cnt*4开始低4位
end
else if ( cnt == 8'd11) begin
data_bin <= data_bin_temp;
valid <= 1'd1;
end
end
end
//加法和位拼接:乘10运算--*8+*2
//注意:输出数据为32bit,即要求最终计算结果不能超过2^32-1
function [31:0] MULTI10 (input [31:0] a);
begin
MULTI10[ 31:0] = { a[28:0],3'b000 } + { a[30:0],1'b0 };
end
endfunction
endmodule
以及modelsim测试代码:
`timescale 1ns/1ns
module tb_BCD2BIN (
);
reg clk,rstn;
wire valid;
wire[31:0] data_bin;
reg [39:0] data_bcd;
BCD2BIN u_BCD2BIN(
.clk (clk ),
.rstn (rstn ),
.data_bin (data_bin ),
.data_bcd (data_bcd ),
.valid (valid )
);
initial begin
rstn = 0;
#10
rstn = 1;
end
initial begin
clk = 0;
forever begin
#1 clk = !clk;
end
end
initial begin
data_bcd = 0;
#100
data_bcd = 40'h1234567890;
#100
data_bcd = 40'h1111111111;
#100
data_bcd = 40'h1999999999;
end
endmodule
结果
modelsim功能测试正常:
vivado综合情况(zynq-7020):
消耗LUTs从开始的217降到64 ,总的slice从67降到39,但是多消耗了113个寄存器
总结
1.消耗lut减少了
2.增加了reg的消耗
3.数据延迟了11拍
4.逻辑层数变少,容易进行高速时钟下的时序约束。
另外注意:
data_bin_temp <= MULTI10(data_bin_temp) + data_bcd_temp[(8’d43-cnt*4)-:4];
MULTI10[ 31:0] = { a[28:0],3’b000 } + { a[30:0],1’b0 };
两种写法的作用。