【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)

配套教材:
Computer Organization and Design: The Hardware / Software Interface (5th Edition)
这是专业必修课《计算机组成原理》的复习指引。建议将本复习指导与博客中的《简明操作系统原理》配合复习。
在本文的最后附有复习指导的高清截图。需要掌握的概念在文档截图中以蓝色标识,并用可读性更好的字体显示 Linux 命令和代码。代码部分语法高亮。
计算机组成原理不是语言课,本复习指导对用到的编程语言的语法的讲解也不会很细致。如果不知道代码中的一些关键字、指令或函数的具体用法,你应该自行查找相关资料。


第三章 算术

第一节 整数的四则运算

1、CPU核心中的算术逻辑单元(Arithmetic logic unit,ALU)用于进行算术和逻辑运算。计算机用二补数表示法表示数。无论参与加减运算的两个数的正负性如何、是否有符号,都可以统一进行运算。两个有符号数运算时,如结果为负,最高位(符号位)会自动变成1。
为了实现更快的加法,超前进位(carry lookahead)成为了应用最广泛的方案。其时间复杂度与操作数的二进制位数的对数成正比。
关于加法器的实现,请参考数字逻辑电路的相关资料,也可以参考我发布的《数字设计基础与应用》知识梳理(2.2 常用的MSI组合逻辑模块)。

2、当负数与非负数相加时,不会溢出。理由很简单:一个负数与一个非负数的和一定不大于这个非负数。当两个符号相同的数相减时,不会溢出。理由相同。也可以把两个同号的数相减看成一个非负数加一个负数,就可以套用符号相反的数相加不会溢出的理由来直接证明了。两个同号数相加,或者用正数减负数、负数减正数,都有可能溢出。当发生溢出时,溢出部分会直接丢失。
下标是两个有符号数相加减的可能发生溢出情况。

如果是两个地址做运算,溢出常被忽略(注意:地址是无符号的。)MIPS中,只有在有符号数参与的运算溢出时,才会抛出异常。不过,MIPS对立即数进行的是符号扩展,即使运算是无符号的。
C语言和Java在计算结果溢出时不产生异常,Fortran、Ada则会产生异常。

3、异常(exception)在很多计算机上是中断的一种。关于中断请参考复习指导《简明操作系统原理》。
MIPS有专门的寄存器EPC(Exception program counter)来存储导致异常的指令。发生异常后,使用专门的指令mfc0可以将EPC的值复制到一个寄存器中,方便运行在MIPS处理器上的软件来获得产生异常的位置。
MIPS保留了两个寄存器k0k0、k1,它们可以被操作系统使用。类似地,MIPS中的atOS使at寄存器是留给汇编器的。保留的寄存器中的内容在上下文切换时不会被保存。OS可以使用k0和$k1来保存返回地址,以便在异常处理程序执行完毕后顺利跳回产生异常的位置。

4、有的处理器处理溢出的办法是将结果设置为这个数据类型能够表示的最大正数或负数。这在多媒体方面很有用,例如如果试图将音量设置得超过最大值,就会自动纠正为最大值。多媒体相关的指令集,如MMX,通常提供了这种处理方式。

5、最早的硬件乘法器是这样的:

这种乘法器模拟的是笔算乘法的步骤。对两个32-bit的无符号数进行乘法时,被乘数(multiplicand)要放在一个64-bit的寄存器里,乘数(multiplier)则放在32-bit的寄存器里。当乘数的最低位为1时,将此时的被乘数加入累加结果。以后每次加法将被乘数左移一位,乘数右移一位。于是加法要进行32次。总的来说,如果每一步需要1个周期,那么完成一次两个32-bit的数据参与的乘法,需要大约100个周期。
很容易想到这种方法的改进策略:将被乘数的左移和乘数的右移以及累加合并到一个周期内。此外,被乘数所在的寄存器只需要32位,乘数与结果共用一个寄存器。其电路大致如下:

6、现在,几乎所有的编译器都会尽可能将乘法用位移代替(主要是一个因数为2的幂次时)。因此,编程的时候无需将乘法写成位移,编译器会帮我们做这些优化工作。

7、对于有符号计算,一个办法是:先把两数的正负记录下来,然后把有符号数转换成无符号数并计算,再根据被乘数和乘数的正负确定符号。

8、一种改进的乘法器的实现如下图。
它的原理仍然与第5点所说的最原始的乘法器一致,需要将32个左移位数各不相同的数加起来。于是我们用16个加法器,每个加2个数。再用8个加法器,每个加两个。以此类推。最后一个加法器运算后的结果就是64-bit的。可见,加法器一共有5层,时间复杂度降低到了对数级别。配合保留进位(carry-save)加法器,乘法器可以更快。出于篇幅的考虑,我会单独归纳更快的加法器和乘法器的实现,在本复习指导中就不专门给出了。

9、最初的除法器和运算过程如下。

32位除数(divisor)、余数(remainder)都保存在64位的寄存器里,其中除数保存在左半部分;商(quotient)的寄存器则是32位的。ALU也是64位。这个除法器模拟的是手算除法的过程,余数的初始值是被除数(dividend),商的初值是0。
与人类不同,计算机在计算除法时并不知道除数什么时候小于被除数,所以要将余数先减去除数(相减的结果直接存在余数寄存器中)。当结果为非负时,代表除数不大于被除数,就把商先左移一位,然后把空出来的最低位写1。如果结果为负,那么将减掉的除数加回去,商左移一位(新的最低位为0)。然后把除数右移一位,继续计算。当计算完毕后,商和余数的寄存器中就保存了最终结果。除数为32位,这个计算过程最多要重复33次(第一次计算时不移位,之后的移位最多共计32次)。
这个算法和硬件当然也是可以改进的。余数减除数、商的左移和除数的右移这三个过程可以同时进行。改进的除法器中,ALU、除数和商的寄存器都是32位的,余数寄存器依然是64位。余数寄存器的右半部分存放的是商。

10、与乘法一样,如需计算有符号数的除法,一个办法是:先把两数的正负记录下来。当被除数和除数的符号不匹配时,把商变为相反数。

11、我们在前面用大量的加法器来同时将乘法器中的一些过程并行化,但是这个套路不能套用在除法器上,因为决定下一步的行为的是本次计算中的余数是否为负;而乘法器中被并行的部分的中间结果是没有任何依赖关系的。所以我们要换用别的方法。
SRT算法通过预测来加快除法的计算速率。这个算法用6个bit的余数和4个bit的除数来尝试猜测商的接下来几位,并且在预测错误时也有相应的步骤进行纠正。
【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)

【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)【梳理】计算机组成与设计 第3章 算术 第1节 整数的四则运算(内附文档高清截图)