我们每个人从小最先学的数学就是1+1=2,然后就是小九九,因为这是我们长大以后混世界的最基本的能力,加、减、乘、除是人脑“数字逻辑”的基础。作为替代人脑进行运算的数字计算机,无论是控制器还是处理器,无论是简单的单片机还是大型的服务器,以加、减法为基础的算术单元自然是最重要的核心部件。
虽然我们对十进制的加减乘除都已经熟悉到了本能的地步,如何让晶体管构建的、以二进制为基础的数字电路来实现我们人类需要的加、减、乘、除?
著名科普专家“冬瓜哥”在其定价为600元的巨著《大话计算机》开篇就对这个问题进行了阐述:
十余年的困惑,自然是上升到了常人不可达的层面才想明白的一些道理,有兴趣的同学可以跟着他的思路绕一绕,苏老师读了半个小时就已经感觉到脑细胞严重疲劳。
他切入计算机的入口就是加法器,准确地讲就是在我们的数字电路中一带而过的Adder - 半加器、全加器以及超前进位加法器(很多教程仅给出了半页的篇幅)。冬瓜哥得出的结论是“CPU内部就是个加法器”。可见它的重要性,也可见我们对它真的是严重忽略了,就像1+1=2一样,它重要得实在太平凡了。
但,它确实是我们数字计算的基础,理解了它才能够理解整个的数字逻辑世界。
我们先通过硬禾学堂制作的一个7分钟的视频教程来看一下加法器最基本的两个示例:
第一个案例 - 1位半加器
根据我们人类在十进制领域定义的加法规则,来操作2个1位的数据相加,从最基本的门的功能以及加法的规则需求,我们得到来实现它的电路 - 通过一个“异或门”得到加法以后的1位的结果,以及通过一个“与门”得到一个“进位”位的值,就像我们十进制的加法,如果两个数字相加超过了一个“位”(十进制的位)能够表达的范围,就要生成一个进位信号。通过真值表能够比较直观地看出反映2个输入位同经过加法操作以后得到的输出位的关系。
使用Verilog代码的1位半加器:
module halfadder
(
input a, //第一个加数a
input b, //第二个加数b
output sum, //显示和的led
output cout //显示进位的led
);
assign sum=a ^ b; //sum=a⊕b
assign cout=a & b; //cout=ab
endmodule
第二个案例 - 1位全加器
毕竟2个1位的数相加只是基础,太局限,我们扩展一下,如果需要有超过1位的数字相加,该如何操作?那就需要将“进位”的值考虑进来,作为一个输入,有了进位输入、进位输出的加法器被称之为“全加器”,全了,谁都不缺了。
使用Verilog代码的1位全加器的Verilog代码:
module adder1
(
input wire a, //输入的低位进位及两个加数cin、a、b
input wire b,
input wire cin,
output wire sum, //输出的和与进位
output wire cout
);
wire s1,s2,s3; //定义中间变量
xor (s1,a,b); //调用基本异或门
xor (sum,s1,cin);
nand (s2,a,b); //调用基本与非门
nand (s3,s1,cin);
nand (cout,s2,s3);
endmodule
通过上面的两段Verilog代码,可以看出用Verilog这种硬件描述语言的一些特点,这个在后面的文章中会专门介绍。
多数的“数字电路”教程关于加法器也基本上点到此为止了。
但上述的基本单元能用来做啥的?如果不做扩展,同学们很难有进一步的理解,因此我建议大家可以自行做一些扩展:
支持多位二进制数相加的并行二进制加法器
比如2个4位二进制的加法器,它可以由3个全加器和1个半加器构成,低位的加法进位可以作为相邻高位加法的一个输入端,最低位仅用一个半加器,最高位生成的进位信号作为后续电路的输入。
是不是像极了我们的十进制加法?原理是一样的,只是采用的进制不同,而二进制可以通过数字电路的0、1比较容易地实现。
了解了加法器,减法器也就不难理解,就像我们十进制中的加和减的关系一样。它的基本规则:
0 - 0 = 0
0 - 1 = (借)1 1
1 - 0 = 1
1 - 1 = 0
对应的也有:
1位半减器
一位半减器的符号、电路构成以及真值表
1位全减器
用半减器构成的全减器
并行二进制减法
用三个全减器和一个半减器构成的4位并行减法器
用4个全加器也可以构成一个4位并行减法器
既然多位的全减器也可以用全加器来实现,是不是可以有一种统一的结构能够实现加、减的功能?毕竟减和加是对偶的,减法也可以看作是+(-)的操作。
统一结构的并行加、减法
从前面的加减法构成可以看出,加法器和减法器都可以用共同的加法器来实现,如果我们添加一个控制信号M,最低位也使用一个全加器,将这个M值连接到该全加器的进位输入端,就可以通过这个M是0或1来决定此电路时加法电路还是减法电路:
M=1的时候为减法器
M=0的时候行使加法器的功能。
如果你需要将更多的位数的二进制数字相加或相减,你可以使用更多个加法器级联即可得到。细心和动脑的同学会发现,如果任何操作需要哪怕一丁点的时间(有了时间的概念也就意味着 - 因果之间有了先后,有了“时延”,我们生存的世界时间是一个客观存在的维度),那么图中的操作在每个位上的输出就会产生时间上的差异,最高位的值和进位依赖于低位的值和每一位加法操作的时间(也就是构成加法器的门的响应时间)。就像绿灯亮起,并不是所有等待的车同时启动前行,而是从第一辆车逐级传递过来的一样。
用上述方法构建的加法器、减法器,位数越多,由于电路门时延带来的计算结果会越慢出现,聪明的前辈大神们竟然通过一系列的逻辑运算发明了“超前进位加法器”的结构,即便实际的电路上每个操作都有先后带来的时延,我们也可以不需要考虑每个进位的逐级传递,而是一次性地根据各个输入端的位上的值直接得出运算以后的结果。
是不是很不可思议?
为啥需要逐级传递的信息可以提前预知?为什么在布尔表达式中的一些变量经过逻辑化简以后发现它们只是打酱油的可有可无?
我们的生活中是否也是如此?每当绿灯亮起的时候所有的车是否也能同步启动前行?
这些问题留给大家思考。
有了加法器、减法器,也就很容易构建乘法器 - 重复多次的加,和除法器 - 重复多次的减。
因此加法器是构成整个数字计算的基础,是最重要的一个部件,它的设计好坏直接影响了处理器/控制器的性能、性价比等。
比如在电子森林“电路仿真”中的Brent-Kung树形加法器就是一种最小化芯片面积和成本的结构。有兴趣的同学可以点击https://www.eetree.cn/war/circuitjs.html?lang=zh 来体验一下。
正如前面文章所述,在FPGA没有大面积普及应用的年代,曾经有一系列的中等规模的集成电路模块推出,最著名的就是74系列的器件,其中74HC283就是一种4位超前进位的全加器器件。很多高校可能还在拿它做数电的实验,
外形长这样
内部功能这样
最后,给大家介绍一款国外公司制作的4位加法器的训练套件
我们平时在面包板上做是这样的
这个公司画成了电路板,就卖55美元了 - 想不想学习一下自己设计PCB?也是很重要的一个技能。
功能框图
为了方便大家实验,这个产品中包含了如下的一些器件:
1个多路选择器(CD74HC157E)
2个寄存器 /4个D触发器 (CD74HC173E)
1个4位全加器 (CD74HC283E)
1个6通道具有施密特触发器输入的反相器 (CD74HC14E)
1个4位幅度比较器 (CD74HC85E)
1个双4输入异或门 (CD74HC4002E)
1个4组 2输入异或门 (CD74HC86E)
得说,这个套件的文档写得特别的棒,有兴趣的老师和同学可以自己搜一下。
这个套件用了8颗中等规模的集成电路,加上很多连线连线。其实呢,用小脚丫FPGA内部的不到1%的资源就能实现,而且只需要写很短的几行Verilog代码。
要不您试一下?
前期与数电相关的文章:
浅谈“数字电路”的学习(1)- 我们身处的“数字逻辑”世界
浅谈“数字电路”的学习(2)- 在兴趣和体验中高效学习
浅谈“数字电路”的学习(3)- 不需要安装软件、人人一学就会的FPGA学习板
浅谈"数字电路"的学习 (4) - 学用FPGA从点灯开始
浅谈“数字电路”的学习(5) - “组合逻辑”的学习逻辑。
浅谈“数字电路”的学习(6) - 看视频了解什么是FPGA?