计算机组成原理复习(2)
考研复习第 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位(带符号)遵循这么个步骤:
- 取符号,结果的符号为俩符号的异或。
- z 取 |y| 为当前结果,扩展 n+1 位。
- 每次取得 z 的最低位的值,如果为 1,那么高 n 位整体加上 |x|,否则加上0,加完之后,逻辑右移一位。
- 重复(步骤3) n次。
举个例子,拿两个八位有符号整数的原码。
x=0.10010101
y=0.11010110
首先符号都是正的没问题,然后设定一个 z,值跟|y|一样,然后扩展 8+1 位,这里我扩展到了点之前,这个点不是小数点。
- z=00.0000000011010110|
- 取出z的最低位 为 0,给z的高八位加上0,然后逻辑右移,z=00.0000000001101011|0
- 取出z的最低位 为 1,给z的高八位加上|x|,然后逻辑右移,z=00.0100101010110101|10
- 取出z的最低位 为 1,给z的高八位加上|x|,然后逻辑右移,z=00.0110111111011010|110
- 取出z的最低位 为 0,给z的高八位加上0,然后逻辑右移,z=00.0011011111101101|0110
- 取出z的最低位 为 1,给z的高八位加上|x|,然后逻辑右移,z=00.0110011001110110|10110
- 取出z的最低位 为 0,给z的高八位加上0,然后逻辑右移,z=00.0011001100111011|010110
- 取出z的最低位 为 1,给z的高八位加上|x|,然后逻辑右移,z=00.0110010000011101|1010110
- 取出z的最低位 为 1,给z的高八位加上|x|,然后逻辑右移,z=00.01111100100011100|11010110
- 结束,z 最后就是最后的结果,再加上符号即可。
这里需要注意,为什么需要扩展 N+1 位,因为临时乘,然后加,最高位可能产生进位,如果不保留那么移位之后,高位必为0,显然是不合理的。
最后算结果的时候,因为还要加符号,所以直到最后出结果也是需要 2N+1位的。
补码一位乘法(BOOTH算法)
总结来说就是:所有位均参与运算
假设x,y的位数为n+1(有符号)位。
- 取z为y的值,末位加一个辅助位。
- 取最低位+辅助位的组合,若组合为00或11,则直接右移一位,若组合为01,则加x的补码,10则加-x的补码,也就是
~x+1
加完之后都要算数右移一位。 - 重复(步骤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。
不过这里不能和之前一样了,跟之前的有点出入,但是按照上面那个思路是能得到正确结果的,只是不连通,介绍一个连通的思路:
- 取z=0,y补码末尾添0。
- 从低位开始,扫补码的低两位,每次左移一位。
- 若组合为00或11,则直接右移一位,若组合为01,则加x的补码,10则加-x的补码,也就是
~x+1
加完之后都要算数右移一位。 - 重复(步骤2)n+1 次。
模拟一遍:
- z=00.0000,[x]补=[y]补=11.1111,[-x]补=00.0001,然后把 y 变成这种形式:1.111[10]。
- 取得10,加上[-x]补,再算数右移一位,得到00.00001,同时y也移动:1.11[11]0。
- 取得11,加0,算数右移一位,得到00.000001,同时y也移动:1.1[11]10。
- 取得11,加0,算数右移一位,得到00.0000001,同时y也移动:1.[11]110。
- 取得11,加0,算数右移一位,得到00.00000001,同时y也移动:[1.1]1110。
- 取得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。