lcytms 发表于 2016-11-15 21:53:38

FPGA初级课程第十三讲 BCD转二进制

FPGA初级课程
第十三讲 BCD转二进制

Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:BCD转二进制。
本节课我先简要地介绍一下BCD转二进制的基本原理,然后实际演示一下BCD转二进制逻辑电路的建模与仿真,并通过仿真查看效果。

lcytms 发表于 2016-11-15 21:54:47

上一讲我们讲了二进制转BCD的实现方法。
同时也简要介绍了BCD转二进制的原理,今天就来实现它的转换逻辑。

举个例子吧,比如说BCD码255,要转换成二进制。
计算机里面存的BCD码是12'h255(对应二进制为12'b0010_0101_0101),肯定不能直接进行运算,必须要转换成机器识别的二进制数值12'h0FF(对应二进制为12'b0000_1111_1111)。

当然你可以用查表法,比如说256以内的数值,直接用查表的方式,一一对应,就像我们FPGA采用LUT表实现真值表那样,或者说用ROM表来根据不同输入得到不同输出。
这样当然也是可以的,不过,它的范围往往比较有限,不适于数量比较大的情况。

当然简单粗暴的方法就是,百位乘以100,十位乘以10,个位不变,然后求和即可。在使用移位和加法来代替乘法执行可以节约乘法器资源,简单点的有10=8+2,100=64+32+4,更多位数的有,1000 = 1024-16-8,10000 = 8192+2048-256+16,100000 = 65536+32768+1024+512+128+32,这些拆解都要提前做好,位数更大的时候通用性不够。

lcytms 发表于 2016-11-15 21:57:46

我们这里讨论第三种方法,通用性更好。

先算前两位,直接2*10+5,得到结果25,然后再将结果*10+下一位,即25*10+5,最终结果为255,完了。
就这么简单。当然这里255只有三位BCD位,如果更多的话,以此类推。
将前一步结果*10+下一位,得到当前结果。
当然实现起来还有一些小的技巧,x*10要占用乘法器资源,如果乘法器资源足够那无所谓,但在资源有限的情况下通常用(x<<3)+(x<<1)(对应x*8+x*2)来实现。
即用移位和加法来代替乘法操作。
当然也可以把BCD数字的每一位直接变成各种左移数值的组合,比如x*100 = x*64 + x*32 * x*4 = (x<<6) + (x<<5) +( x<<2)。
上面就是BCD码转成二进制的实现原理。

结合我们的《把BCD(12’h255)转换为二进制(8’hFF)步骤列表(一张表说透彻).pdf》的文件,我们来讲解一下。

lcytms 发表于 2016-11-15 22:02:24

第一步:准备阶段。
我们将输入BCD数在高位补齐全0的二进制位,生成二进制全序列的初始状态,
二进制部分位数要求,最大数值上限不得小于输入值对应上限。

第二步:十进位阶段。
第二步相对比较复杂。
这一步分为多个小步,每小步将二进制全序列进行两个操作。
包括一次二进制部分*10 + BCD高位的操作和BCD部分循环左移一位操作。
一旦原理明白了,我们编写Verilog代码想必也就水到渠成了。后面就是Verilog语言练习和具体实现的事了。

第三步:输出阶段。
这一步,最简单,实际上第二步的最后环节已经得出结果了,只不过它包含在全序列里面,我们只要取出需要的二进制部分,输出即可。

lcytms 发表于 2016-11-15 22:03:16

本堂课要解决的课题

原理讲过之后,我们要做一个更多位数的例子。
我们将ZX_1开发板中需要用到的BCD数000000~999999转换成二进制数20'h00000~20'hF423F(对应20'd0~20'd99999)。

显然这里的24位输入20位输出,比表格中的12位输入8位输出要多了很多,当然我们不是手工推导,而是要用FPGA来做,用Verilog代码来建模。

lcytms 发表于 2016-11-15 22:05:08

BCD转二进制的原理既然已经清楚,我们下面来进行系统设计。
命名逻辑为bcd2b。
架构图如下所示。

lcytms 发表于 2016-11-15 22:06:42

在前级加上b2bcd模块,用于检验数据能否复原为正确的二进制数,整体架构图如下。

lcytms 发表于 2016-11-15 22:15:41

建模主体框架

首先建立工程文件夹bcd2b。
新建模块bcd2b.v文件。
先来一个简单粗暴的实现方式,直接百位乘以100,十位乘以10等等,也就是第二种方法。
module bcd2b (din, dout);

        input din;
       
        output dout;
       
        assign dout =        din +                                                                                                                                // BCD0
                                                + (din<<3) + (din<<1)                                                                        // BCD1, 10=8+2
                                                + (din<<6) + (din<<5) + (din<<2)                        // BCD2, 100=64+32+4
                                                + (din<<10) - (din<<4) - (din<<3)        // BCD3, 1000=1024-16-8
                                                                                                                                                        // BCD4, 10000 = 16*625 = 8192+2048-256+16
                                                + (din<<13) + (din<<11) - (din<<8) + (din<<4)
                                                        // BCD5, 100000 = 32*3125 = 32*(2048+1024+32+16+4+1) = 65536+32768+1024+512+128+32
                                                + (din<<16) + (din<<15) + (din<<10)
                                                + (din<<9) + (din<<7) + (din<<5);
                                               
endmodule

lcytms 发表于 2016-11-15 22:20:05

添加上一讲中编写的b2bcd模块,包括3个文件,b2bcd.v、shift.v、pre_shift.v。后两个为前者的子模块。
b2bcd.v代码如下。
module b2bcd (din, dout);

        input din;
       
        output dout;
       
        wire data ;
       
//        assign data = {24'b0, din};
        assign data = {21'b0, din, 3'b0};               //第一步:准备阶段。将输入二进制数在高位补齐全0的BCD位,直接左移三位,生成二进制全序列的初始状态。
       
        genvar i;
       
//        generate for (i=0; i<20; i=i+1)
        generate for (i=3; i<20; i=i+1)
                begin        :        g4i
                        shift s (.datain(data), .dataout(data));                //第二步:移位阶段。依次进行17个(20-3)小步操作。具体动作在shift子模块中描述。
                end
        endgenerate

        assign dout = data;                //第三步:输出阶段。取出BCD部分,作为输出。

endmodule

lcytms 发表于 2016-11-15 22:26:54

shift移位子模块shift.v代码如下:
module shift (datain, dataout);

        input datain;
       
        output dataout;
       
        wire data;
       
        assign data = datain;
       
//        pre_shift p0 (.d4in(datain), .d4out(data));
//        pre_shift p1 (.d4in(datain), .d4out(data));
//        pre_shift p2 (.d4in(datain), .d4out(data));
//        pre_shift p3 (.d4in(datain), .d4out(data));
//        pre_shift p4 (.d4in(datain), .d4out(data));
//        pre_shift p5 (.d4in(datain), .d4out(data));
       
        genvar i;
       
        generate for (i=0; i<24; i=i+4)
                begin        :        g4i
                        pre_shift p (.d4in(datain), .d4out(data));        //对应第二步各小步下的a操作,此处为6个BCD位的大四加三操作。具体动作见preshift移位预操作子模块。
                end
        endgenerate
       
        assign dataout = {data, 1'b0};                //对应第二步各小步下的b操作,此处为全序列的左移移位操作。

endmodule
页: [1] 2 3
查看完整版本: FPGA初级课程第十三讲 BCD转二进制