上节课我们学习了如何用二进制表示和存储数字,但是真正的目标是计算与有意义地处理数字。计算机的算术逻辑单元(ALU)用于实现计算机的算术操作,ALU被称作计算机的数学大脑。ALU是计算机里负责运算的组件,基本上其他所有部件都用到了他。Intel 74181是第一个封装到芯片中的ALU。本节课将尝试制造一个简单的ALU电路,实现和74181一样的功能。然后我们在余下的几集中将使用它制造出一台计算机。
ALU有着2个单元:1个算术单元和1个逻辑单元。ALU负责计算机的所有运算,包括加减乘除以及自增等等。我们尝试使用逻辑门(与或非门、异或门)电路建立ALU。
最简单的加法电路,将两个bit相加得到1个bit的结果。输入和输出的对应关系恰好是一个异或门。因为1+1=10,所以我们还需要1个位作为进位的标识,这个进位值我们可以用一个与门实现,如下所示。这样的逻辑电路就是一个半加器,然后我们还可以将半加器继续抽象化。
如果我们需要进行超过1+1的、超过两个bit之间运算,我们就需要“全加器”。因为超过两个bit的数之间的运算必然会产生进位,因此全加器的逻辑表一定是3个输入和两个输出的(进位与总和)。全加器可以使用两个半加器组成,根据逻辑表设计的逻辑电路如下所示。然后我们在将全加器的电路抽象化。
我们可以使用全加器的新组件来尝试将两个长度为8位(1个字节)的数字相加。每一位的对应位与上一个对应位产生的进位相加,产生总和作为总和数字的对应位;然后产生进位交给下一个对应位的全加器:
以上完成两个大小为1个字节长度的数字相加的逻辑电路称为8位行波进位加法器。如果最下面的全加器产生了进位,说明能够表示的数字已经超过了一个字节的限制,这个现象就叫做“溢出”——当两个数相加的结果过于大,以至于你无法使用超过8位的数字进行表示。为了避免溢出,我们可以使用更多全加器来操作2个(16bits)或者4个(32bits)字节长度的数字。这样会带来以下缺点:(1)我们*使用更多的逻辑门。(2)由于每次进位都需要一点时间,就会造成产生计算结果的延迟。在几十亿次运算的量级下这个延迟造成的影响是显著的。因此现代计算机主要使用“超前进位加法器”,它的速度更快,实现的功能相同。ALU还可以实现加法、进位加法、减法、借位减法、增量、减量、数字无改变通过等操作。ALU并没有专门的电路实现乘除法,只是将乘法用多次加法来实现、除法用多次减法来实现。一些比较低端的电子设备(遥控器、微波炉等等)可以使用这种方法,而计算机一般会用专门的乘法电路解决问题。
之前讲完了算术操作单元,现在我们开始讲逻辑操作单元。除了基本的与或非之外,它还可以做一些数值测试,比如检查输出是否为0的电路:
74181接受4位输入。只能执行加减操作,不能执行乘除法。使用了70个逻辑门,是ALU小型化的重要标志。8位ALU甚至要使用上百个逻辑门,我们还可以进一步抽象化8位ALU。
如下图所示。8位ALU接受两个8位的数据,operation code接受4位的编码来指示要对这两个数执行什么样的操作。输出的数位8位,除此之外还会有一系列标志(flag)输出,overflow表示是否溢出、或者说计算结果是否超过8位;zero表示计算结果是否为0;negative表示运算结果是否为负数(这三个标志是ALU最普遍见到的flag)。