考研复习第 3,4 天

计算机组成原理相关内容的复习

  • 原码,补码,反码,移码
  • 移位,加减法,乘法运算

数据编码

原码,补码,反码,移码

原码

字面意思,有符号时,最高位表示负号

补码

最高位权值为负,其它与原码一致。

反码

在原码的基础上,若最高位为1,则对原码除符号位所有位取反

移码

看成无符号然后-一个偏置值即可。

单符号与双符号

单符号一般写的时候用小数点隔开,但是不表示小数点的含义,比如 0.0001 如果是原码表示正数的1,1.0001 如果是原码表示负数的1。在此基础上,还可以再做一个符号的扩展,用于判断溢出。若出现 01,则表示正溢,若出现 10,则表示负溢。

比如 00.1111 如果表示原码就是正数的15,11.1111 如果表示原码就是负数的15,而 10.0001 不能表示一个正确的数,因为它溢出了,同样 01.0001 也不行。但是在下面的乘法算法的时候,允许临时溢出。

移位运算

主要是循环移位有一个带进位和不带进位的区别。带进位就是说,在挪出去的过程中要算上 CF 一起,如果不带进位,那么原本被丢弃的位进入 CF 和最高位或者最低位。

乘法和除法

有这么几种算法,学一下吧~

原码一位乘法

总结来说就是:被乘数和乘数均取绝对值参加运算,符号位不参与运算单独考虑~

然后自己也豁然开朗了,假设两数为n+1位(带符号)遵循这么个步骤:

  1. 取符号,结果的符号为俩符号的异或。
  2. z 取 |y| 为当前结果,扩展 n+1 位。
  3. 每次取得 z 的最低位的值,如果为 1,那么高 n 位整体加上 |x|,否则加上0,加完之后,逻辑右移一位。
  4. 重复(步骤3) n次。

举个例子,拿两个八位有符号整数的原码。

x=0.10010101

y=0.11010110

首先符号都是正的没问题,然后设定一个 z,值跟|y|一样,然后扩展 8+1 位,这里我扩展到了点之前,这个点不是小数点。

  1. z=00.0000000011010110|
  2. 取出z的最低位 为 0,给z的高八位加上0,然后逻辑右移,z=00.0000000001101011|0
  3. 取出z的最低位 为 1,给z的高八位加上|x|,然后逻辑右移,z=00.0100101010110101|10
  4. 取出z的最低位 为 1,给z的高八位加上|x|,然后逻辑右移,z=00.0110111111011010|110
  5. 取出z的最低位 为 0,给z的高八位加上0,然后逻辑右移,z=00.0011011111101101|0110
  6. 取出z的最低位 为 1,给z的高八位加上|x|,然后逻辑右移,z=00.0110011001110110|10110
  7. 取出z的最低位 为 0,给z的高八位加上0,然后逻辑右移,z=00.0011001100111011|010110
  8. 取出z的最低位 为 1,给z的高八位加上|x|,然后逻辑右移,z=00.0110010000011101|1010110
  9. 取出z的最低位 为 1,给z的高八位加上|x|,然后逻辑右移,z=00.01111100100011100|11010110
  10. 结束,z 最后就是最后的结果,再加上符号即可。

这里需要注意,为什么需要扩展 N+1 位,因为临时乘,然后加,最高位可能产生进位,如果不保留那么移位之后,高位必为0,显然是不合理的。

最后算结果的时候,因为还要加符号,所以直到最后出结果也是需要 2N+1位的。

补码一位乘法(BOOTH算法)

总结来说就是:所有位均参与运算

假设x,y的位数为n+1(有符号)位。

  1. 取z为y的值,末位加一个辅助位。
  2. 取最低位+辅助位的组合,若组合为00或11,则直接右移一位,若组合为01,则加x的补码,10则加-x的补码,也就是~x+1 加完之后都要算数右移一位。
  3. 重复(步骤2) n+1次。

比如x = -0.1101,y=0.1011

分别写出它们的补码:[x]补=11.0011,[y]补=00.1011,[-x]补=00.1101。

先取 y 的值作为 z 的值,并进行扩展(这里可能是符号扩展)z=00.00001011|0(辅助位)|

取出最低位和辅助位的组合,结果为 10,那么加上 -x 的补码,再右移一位,z=00.01101101|1|0

取出最低位和辅助位的组合,结果为 11,那么加上 0,再右移一位,z=00.00110110|1|10

取出最低位和辅助位的组合,结果为 01,那么加上 x 的补码,再右移一位,z=11.10110011|0|110

取出最低位和辅助位的组合,结果为 10,那么加上 -x 的补码,再右移一位,z=00.01000001|1|0110

最后一个步骤比较特殊,它要看当前 y 补码的符号位和辅助位的组合:那么得到了 01,就是加上 x 的补码并且不会右移了,最后得到 z=11.01110001。

再比如,最简单的x=-0.0001 y=-0.0001

不过这里不能和之前一样了,跟之前的有点出入,但是按照上面那个思路是能得到正确结果的,只是不连通,介绍一个连通的思路:

  1. 取z=0,y补码末尾添0。
  2. 从低位开始,扫补码的低两位,每次左移一位。
  3. 若组合为00或11,则直接右移一位,若组合为01,则加x的补码,10则加-x的补码,也就是~x+1 加完之后都要算数右移一位。
  4. 重复(步骤2)n+1 次。

模拟一遍:

  1. z=00.0000,[x]补=[y]补=11.1111,[-x]补=00.0001,然后把 y 变成这种形式:1.111[10]。
  2. 取得10,加上[-x]补,再算数右移一位,得到00.00001,同时y也移动:1.11[11]0。
  3. 取得11,加0,算数右移一位,得到00.000001,同时y也移动:1.1[11]10。
  4. 取得11,加0,算数右移一位,得到00.0000001,同时y也移动:1.[11]110。
  5. 取得11,加0,算数右移一位,得到00.00000001,同时y也移动:[1.1]1110。
  6. 取得11,加0,结束。最后得到00.00000001,显然就是1的补码。

其实也能理解加小数点的原因,因为它要移位什么的就很麻烦,就像前面说的,我要说成这种形式:与这个数的高8位相加。而且如果长度不一样我还要改高几位,不如我用个小数点,把它定在那边,我默认就是对小数点靠近左边的那几个数相加,往右移走的数我完全不用管,大概就是这样的做法了。

标志寄存器

这里有两个标志寄存器需要注意一下:CF,OF分别表示 carry flag和 overflow flag,无符号溢出标志和有符号溢出标志。

这里稍微注意一下三个概念:

  • 最高位进位:指的是,数的最高位是否进位。
  • 符号位进位:指的是,次高位是否进位(进位即改变符号)。
  • 最低位进位:因为减法是取补,而对于电路来说,取反是很容易实现的,但是取反+1相当于再做了一次运算,于是取补就变成了取反再给最低位的进位设置成1。这样就相当于 + 1了,所以最低进位的值等同于是否进行减法运算,减法运算则最低仅为为1,否则为0。

进位标志与溢出标志

  • CF:加法减法好像是有区别的,如果是减法指令,那么仅仅观察目的操作数是否大于源操作数(无符号大于),是就为 1。如果是加法指令,只需要关心它的最高位进位是否为 1。总结来说——减法标记(sub指令时=1)异或 最高位进位标记 就是 CF 的值
  • OF:同时要判断两个值,一个是最高位进位,一个是符号位进位,若不相等则 OF=1。