ICS5 PA
PA1-1 24.5.30
又开始了ICS之旅,这次又给自己下了一个难度,找到了汪亮老师讲解的ICS 5!
target
第一课的目标是修正一个register错误声明
insteresting
- 中途网易源Bad Gateway 502了,更换清华源,学会了
:%s/163/tuna/g
非常爽! - 又学了几个终端快捷键
- 想到了用
ccache
加速我的PA
problems
union
和struct
的区别?
unioin
在同一个内存空间中存储不同的数据类型。
struct
则是同时存储不同的数据类型。- 为什么要用
union
?阅读i386手册
2.3.1 General Registers
As Figure 2-5 shows, the low-order word of each of these eight registers has a separate name and can be treated as a unit. This feature is useful for handling 16-bit data items and for compatibility with the 8086 and 80286 processors. The word registers are named AX, BX, CX, DX, BP, SP, SI, and DI.
对于CPU来说,可以把AH AX AL看成单独的单元,拆分成小块。所以它们是共用关系。
PA1-2 ALU 24.6.5
target
实现ALU中的各类运算,包括设置标志位
knowledge
Appendix C
Name | Function |
---|---|
CF | Carry Flag ── Set on high-order bit carry or borrow; cleared otherwise. |
PF | Parity Flag ── Set if low-order eight bits of result contain an even number of 1 bits; cleared otherwise. |
ZF | Zero Flag ── Set if result is zero; cleared otherwise. |
SF | Sign Flag ── Set equal to high-order bit of result (0 is positive, 1 if negative). |
OF |
Overflow Flag ── Set if result is too large a positive number or too small a negative number (excluding sign-bit) to fit in destination operand; cleared otherwise. |
ADD
Operation
DEST ← DEST + SRC;
Flags Affected
OF, SF, ZF, AF, CF, and PF as described in Appendix C
ADC
ADD with Carry:“带进位的加法”操作,需要看操作数是否已经进位
Operation
DEST ← DEST + SRC + CF;
Flags Affected
OF, SF, ZF, AF, CF, and PF as described in Appendix C
注意CF标志位需要特殊设置,考虑之前的进位状态
SUB
借位:A - B,当A小于B时,结果为一个负数,产生了借位。
根据这个规则完成set_CF_sub()
在做减法时,
如果用一个正数减去一个负数得到一个负的结果,
或者用一个负数减去一个正数然后得到一个正的结果,
则发生了溢出 。
根据上面的规则比较符号,即可完成set_OF_sub()
SBB
Sub with Borrow
什么时候产生借位?
1. 和普通减法一样10-1, 0<1,产生借位
2. 已经借位的时候,130-31,3 不小于 3,但是3已经产生借位,所以(3-1借位)<3的时候,产生借位
根据上面规则,即可完成set_CF_sbb()
SHL
Shift Left
左移操作,CF位是最高位;只移1位时才需要设置OF(CF和操作数不相同时)
注意:符号位不等于最高位!
DIV
实现除法需要完成MOD
注意,dest是被除数,src是除数
PA1-3 FPU 24.7.30
按照手册和伪代码实现FPU的规格化操作,以及加法和乘法。注意NEMU的实现中,fraction包含Guard、Round、Sticky位,共23+3=26位。
加法
小阶向大阶对齐,shift right,exp–
根据guide处理各种情况即可
inline uint32_t internal_normalize(uint32_t sign, int32_t exp, uint64_t sig_grs) { |
乘法
非常简单,浮点相乘就是尾数相乘,阶码相加
加入GRS bits后,等同于约定中间结果的小数部分为26位。
对于除法而言,将被除数左移shift位后除以除数得到的小数部分为shift位,为了保证中间结果的小数部分为26位且真值不变,将多余的shift – 26位从阶码中减去,最后的阶码等于fa.exponent - fb.exponent + 127 – (shift – 26)
。
对于乘法而言,用两个小数点后为23位的尾数相乘得到的乘积尾数小数点后为46位,为了保证中间结果的小数点后依然是26位,我们将多出来的46 – 26 = 20位归于阶码,因此阶码就是fa.exponent + fb.exponent - 127 - 20
。
规格化
如果sig_grs >> (23 + 3) > 1,则需要右规直至sig_grs >> (23 + 3) == 1;
反之如果sig_grs >> (23 + 3) == 0且不是非规格化浮点数(exp > 0),则需要左规直至sig_grs >> (23 + 3) == 1。
注意这里的23 + 3的取值是因为我们在临时尾数的最低三位保留了GRS bits的缘故,也就是上文所述的等同于中间结果尾数sig_grs的小数部分约定为26位。
在规格化过程中,根据规格化的方向确定尾数右移还是左移,并对阶码进行增减操作。右规过程中需要保留粘位。
同时在每次右移前都要检查阶码上溢(exp >= 0xff)的情形。
在左规过程中,则有可能发生结果出现非规格化浮点数的情况(阶码变为exp == 0),此时需要将尾数额外右移1位以对应非规格化浮点数阶码是2 ^-126的约定(否则单纯从数值上看阶码全0对应2 ^ -127)。
整数部分不是1,(sig_grs >> 26) > 1,,需要进行右移;整数部分 < 1(也就是等于0)则需要进行左移
舍入
就近舍入偶数的规则可以参考视频和袁春风老师的书。
- Guard位为0,Round、Sticky不为0,舍去
- Guard位为1,Round、Sticky为0,确保尾数是偶数
- Guard位为1,Round、Sticky不为0,进位
注意最后要处理掉GRS位
PA2-1
示例修改文件
objdump -d ./testcase/bin/mov | less |