下边这些数字电路模块是构成CPU的根本,在理解CPU实行指令过程之前,须要把这些模块的事理都搞清楚。
加法器
前边说过处理单个二进制位相加的加法器:

但是我们利用的加法是好多位的,这也好说,把多个全加器串联起来就好了:
从右到左看这个电路图,这是一个32位二进制加法的电路图。初始的时候进位为0,然后每一位相加的进位输出当作高一位相加的进位输入,这样就跟接力棒一样,以此经由各个全加器之后,末了 C31S31S30S29S28…S2S1S0 便是末了的加法结果。我们把这个电路画个大略的示意图:
这种加法器由于须要先利用低位的加法器,把进位输出当作高一位的进位输入类似接力棒的办法通报进位,以是效率有点慢。后来人们又发明了些别的加法器电路,以求更快的实现二进制加法运算,比如先行进位加法器、行波进位加法器啥的,由于韶光有限,我就不想看了,等往后韶光充裕了再研究。
对付减法来说,某种程度上可以把它转换成一种加法。比方说我们现在处理10以内的减法,比方说下边这个式子:
5 - 2 = 3
实在这个减法可以转换成这样的写法:
5 + (10 - 2) - 10 = 5 + 8 - 10
个中,2和8是相对付10的补数,a-b相称于a和b补数的和再减去进位。对付二进制减法,我们也可以用这个办法。比方说我们做4位二进制内的减法,比方说这样
1001 - 0010 = 1001 + (10000 - 0010) - 10000
怎么求一个给定位数的二进制数的补数呢?这个超级大略:
先把一个二进制数的每一位都取反,比方说这样0010的每一位都取反便是1101,这样0010 + 1101 = 1111,但是两个互为补数的和是10000,以是让取反后的结果再加1就好了,也便是0010的4位二进制补数便是1101 + 1 = 1110。以是:
1001 - 0010 = 1001 + 1110 - 10000
用普通一点的措辞描述一下,比方说求A-B的结果,我们把B取反后的结果记为B,然后B的4为二进制数的补数便是B + 1。以是:
A - B = A + B + 1 - 10000
对付4位二进制数的加法,我们只有4个全加器,末了的进位会被放到C3中,我们只须要忽略这个最高位的进位,就相称于减去了10000。
以是我们可以这样修正一下上边的加法器来让它可以做减法:
与上边的加法器电路比较,改了两个地方:
初始的进位输入从0改为了1。减数B会被取反。那怎么表示负数呢?-5不便是相称于0 - 5么,也便是说负数相称于0和这个数对应的绝对值的减法,二进制的负数也是这个意思。0减去一个数相称于和这个数的补数相加后减去进位,0作为加数没有什么意义,也便是说负数相称于它的绝对值的补数减去进位。由于进位没啥意义,我们不关心,以是一个负数就相称于它绝对值的补数。我们以4位二进制数为例,看看怎么表示十进制数-5:
首先十进制数5用4位二进制数表示出来便是0101。求0101的补数。先取反得1010,再加1,得1011。也便是说这个十进制数-5用4位二进制数表示得结果便是1011。可是我们怎么差异1011表示得是-5还是11呢?规定:首位为1的便是负数,首位为0得便是正数,这样就成功的把负数表示出来了。
但是利用首位来区分正负数的话,4位二进制数就不能表示0 ~ 15这16个非负数了,表示范围变成了-8~7。8位、16位、32位、64位的数值表示和减法运算都可以参照4位二进制数来打算。
比较器
对付两个给定的输入,我们怎么知道这两个给定的输入是否完备相同呢?先把问题简化一下,怎么判断两个二进制位是否相同?我们可以规定:如果输出为1则相同,为0则不相同。很随意马虎想到这个异或门的定义:输入相同得0,输入不同得1:,以是我们利用异或非门(NXOR)就可以达到我们得目的:
如果须要比较得两个输入等分别有n位,那意味着只要n位中有一位比较输出为0,那么全体比较输出便是0,很随意马虎想到用与门来完成这个汇聚各个位比较结果的任务(以4位比较器为例):
算术逻辑单元
不知道你有没有以为我们不知不觉学了好多电路模块,现在我们提到加法器,只须要知道把输入和输出接上去,然后这个电路自动就帮我们把结果输出来了,对付一个须要利用加法器得小朋友来说,他就不须要理解这个加法器内部到底是怎么布局出来的,利用了哪些逻辑门,我们再一次强调抽象的好处:你不须要理解过多的实现细节,照着解释书(供应的接口)利用就行了。这个抽象的过程我们有时候也称为封装,用户不关心某个模块的内部实现,只须要调用这个模块供应的接口就好。对付我们前边说的一些电路模块,我们想把它们再次进行一次抽象,以供应更大略的利用接口,这便是我们所说的ALU(算术逻辑单元),直接看下边这个ALU的一个实现电路图:
这个电路共有5个输入,可以被分为两种类型
数据输入,包括:输入A和输入B掌握输入,包括:输入F0、F1和F2,图中F0和F1写在了一起,以这种符号表示:F1:0。这个所谓的ALU便是把各种运算模块集中到了一起,用户可以通过修正掌握旗子暗记F0、F1和F2的输入来掌握对数据输入A和B进行何种运算,各个掌握旗子暗记对应的运算类型如下:
掌握旗子暗记F2:0的值运算类型000A AND B001A OR B010A + B001未利用100A AND B101A AND B110A - B111判断A<B是否成立
我们以减法运算为例看一下上边的ALU是怎么事情的。从表格中可以看到,处理减法运算的掌握旗子暗记为:F2=1,F1=1,F0=0。
当F2=1时,最上边的2-1选择器会输出将旗子暗记B取反后的结果,并且加法器的进位输入的值也为1。以是该加法器实际实行的是A - B的操作。当F1=1,F0=0时,最下边的4-1选择器会选择输出加法器的运算输出,也便是输出Y=A - B。其他类型的运算的道理是一样的,就不一一推导了。末了再说一下,掌握旗子暗记F2=1,F1=1,F0=1的情形表示判断A<B是否成立,如果A<B成立,则Y=1,否则Y=0。这是怎么做到的呢?还是利用了加法器做了A - B的操作,如果结果为负,意味着加法器的输出的符号为为1,那图中的0扩展的电路黑盒便是把符号位作为Y的末了一位,其他位补0的浸染,以是当Y=1时意味着A<B。反之当Y=0时,A<B不成立。
以是之后我们再用到这个ALU时,就不用再考虑它里边繁芜的电路是怎么画的了,只须要用下边大略的示意图代替就好:
如此简洁。。。抽象的强大浸染,往后我们想做点大略的运算时就可以直接把这个ALU给拿出来,输入对应的数据和掌握性好就可以得到我们的结果,而不用关心它里边用了啥神器的魔术,666666666。更繁芜的ALU中须要的电路更多,掌握旗子暗记也会更多,我们这个只是做个演示,让大家知道事理的一个大略单纯版ALU。
移位器
我们编程序的时候会常常利用到下边几种移位操作:
左移:将所有二进制位向左移动多少位,在低位补0。逻辑右移:将所有二进制位向右移动多少位,在高位补0。算术右移:将所有二进制位向右移动多少位,在高位补与符号为相同的值,也便是正数的算数右移高位补0,负数的算数右移高位补1。下边以4位二进制数的左移为例来看一下电路图:
A3A2A1A0是我们指定的4位二进制数,shamt1:0是我们须要左移的位数,它连接着下边的4个4-1选择器。大家可以自己剖析一下当移动位数从0~3的这几种情形分别会发生什么。
乘法器
二进制乘法比十进制乘法更加大略,由于我们都不用再背九九乘法表,它的单个位相乘的运算规则超级大略:
×01000101
这样的规律和与门的运算是一样一样的,以是我们可以很轻易的利用与门去完成单个位的乘法运算。对付多个位相乘的运算只不过是在重复但个位的运算规律而已,如下:
0100和0101分别代表十进制的4和5,末了的结果1010代表十进制的20。4位二进制相乘的通用示意图可以这样表示:
结果便是P7P6P5P4P3P2P1P0。下边是一个电路实现:
是的,很繁芜,当位数多一点的话更繁芜,以是打算乘法的时候还是比较耗时的。
除法器
除法器更麻烦,就不说了。反正终极还是可以通过电路实现的,我们调用接口就好了(抽象的好处~)。
计数器
有时候我们须要计数,也便是数数,0,1,2,3,4,5,6…可以利用下边这个电路:
个中复位旗子暗记是让寄存器R1的输出Q为0,然后每当时钟上升沿到来时,加法器的输出值都加1。也便是说这个电路可以对时钟周期进行计数。这个很有用。