verilog:一种资源节约型的BCD码转二进制码模块

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 };
两种写法的作用。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值