集成电路技术分享

 找回密码
 我要注册

QQ登录

只需一步,快速开始

搜索
查看: 9843|回复: 26

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

[复制链接]
lcytms 发表于 2016-11-15 21:53:38 | 显示全部楼层 |阅读模式
FPGA初级课程
第十三讲 BCD转二进制

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| 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》的文件,我们来讲解一下。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| 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。
架构图如下所示。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-15 22:06:42 | 显示全部楼层
在前级加上b2bcd模块,用于检验数据能否复原为正确的二进制数,整体架构图如下。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-15 22:15:41 | 显示全部楼层
建模主体框架

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

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-15 22:20:05 | 显示全部楼层
添加上一讲中编写的b2bcd模块,包括3个文件,b2bcd.v、shift.v、pre_shift.v。后两个为前者的子模块。
b2bcd.v代码如下。
module b2bcd (din, dout);

        input [19:0] din;
       
        output [23:0] dout;
       
        wire [43:0] data [20:0];
       
//        assign data[0] = {24'b0, din};
        assign data[3] = {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[i+1]));                //第二步:移位阶段。依次进行17个(20-3)小步操作。具体动作在shift子模块中描述。
                end
        endgenerate

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

endmodule

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-15 22:26:54 | 显示全部楼层
shift移位子模块shift.v代码如下:
module shift (datain, dataout);

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

endmodule

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
您需要登录后才可以回帖 登录 | 我要注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|小黑屋|手机版|Archiver|集成电路技术分享 ( 京ICP备20003123号-1 )

GMT+8, 2024-5-3 19:30 , Processed in 0.085384 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表