CSAPP(深入理解計算機系統)
前言
自己這段時間上了微機原理,想起來這本書也看完了,就一同綜合做個筆記。因而有部分是隻屬於MIPS的,我會標註出來,如果不需要應付考試的話我是不推薦讀裡面相關段落的一個字的,而為應付考試的話標註屬於MIPS的應為重點,利用crtl +F 搜尋MIPS即可
第二章:資訊的表示與處理
總綱
主要是二進位制的位元串的存放規則與譯碼規則的不同
2.1資訊儲存
2.1.1 位元組
儲存的基本單元:
- 大多數計算機利用8位的塊(位元組byte)來作為最小的可定址的儲存器單位
即如地址0x00000001
中儲存了0xcc
這樣的資料
2.1.2 字
字:
- 每臺計算機擁有字長(word size)指明整數與指標資料的表稱大小,也就是CPU一次能處理的位數
- 同時也是虛擬地址的定址空間
2.1.4 定址與位元組順序
定址:
- 多位元組物件被儲存為連續的位元組序列,物件的地址為所使用的位元組中最小的地址
如int x地址為0x100
; 即&x = 0x100
,x的四個位元組儲存在0x100 0x101 0x102 0x103
處
- 位元組順序(大端機與小端機):
大端機:最高有效位元組在最前面
小端機:最高有效位元組在最後面
如 0x01234567 高位是0x01 低位是0x67
地址 | 0x100 |
0x101 |
0x102 |
0x013 |
---|---|---|---|---|
大端機 | 0x01 |
0x23 |
0x45 |
0x67 |
小端機 | 0x67 |
0x45 |
0x23 |
0x01 |
- show_bytes程式
//可用於按位模式顯示資料
#include<stdio.h>
typedef unsigned char *byte_pointer;
template <typename T>
void show_bytes(T x)
{
byte_pointer start = (byte_pointer)&x;
for (int i =0;i<sizeof(T);++i)
{
printf("%.2x", start[i]);
}
printf ("\n");
}
2.1.10位移運算
- 左移k位:丟棄最高的k位,右端補零
右移k位:邏輯右移:左端補0
算術右移:左端補1 (有符號數幾乎都是用算術右移)
Attention: 加減優先順序比位移高
2.2 整數表示
注意,以下僅討論整數,那麼提升,擷取等都只對整數而言.
2.2.2 無符號數編碼
2.2.3 補碼編碼
B2T_w(Binary to Two’s-complement)
反碼與原碼
反碼(Ones’ Complement): 為 補碼 的最高有效位的權 小一
B2Ow(x⃗ )=.−xw−1(2w−1−1)+∑i=0w−2xi2i 原碼(Sign-Magnitude):最高有效位是符號位,用於確定剩下的位應該取正還是負
原碼,反碼,補碼關係
- 正數: 三者相同
- 負數:
- 反碼: 原碼符號位以外的各位求反
- 補碼: 原碼除符號位外取反(反碼)後在末尾加1
2.2.4 有符號數與無符號數之間的轉換
強制型別轉換: 結果保持位值不變,只是改變了解釋這些位的方式
Attention: 隱式/顯示 型別轉換 見Cpp_Prime 4.11 Type Conversions 筆記
2.2.6 擴充套件一個數字的位表示
- 零擴充套件(zero extension):將無符號數變大,在開頭添0
- 符號擴充套件(sign extension):補碼數字變大,新增 最高有效位值 的副本
2.2.7 截斷數字
簡單的丟棄掉前面多的位數.
2.3 整數運算
- 就是進行位級別的運算,只是注意溢位,這裡給出一個例子
#include <iostream>
using namespace std;
float sum_elements(float a[], unsigned length)
{
float sum = 0;
for (int i=0;i<= length-1;++i)//由於length 為unsigned,當length=0時,length-1會下溢
{
sum += a[i];
}
return sum;
}
int main()
{
float x[4] = { 1.0,2.0,3.0,4.0 };
cout << sum_elements(x, 0) << endl;
}
- 關於乘以常數,可以利用位運算加速,如
x∗14=x∗(24−21)=(x<<4)−(x<<1)
2.4 浮點數
2.4.2 IEEE浮點數表示
這裡先給出數學表示式,再講述其中符號的意思,再說明如何自己譯碼並進行計算.
- 數學表達
符號解釋
符號(sign) s
尾數(significand) M
階碼(exponent) E
將浮點數的位表示劃分為三個欄位,分別為這些值進行譯碼
- 一個單獨的符號位s直接編碼符號s
- k位的階碼欄位,
exp=ek−1...e1e0 編碼階碼E - n位小數字段
frac=fn−1...f1f0 編碼尾數M,但其也依賴於階碼欄位的值
單精度float 32位 各個欄位
31 | 30 23 | 22 0 |
---|---|---|
s | exp | frac |
雙精度double 64位 各個欄位
63 | 62 52 | 51 0 |
---|---|---|
s | exp | frac |
3. 譯碼
以float說明如何解釋各個欄位並讀出十進位制值這裡記住偏置
- 格式化的值(即階碼為不為全0 或者全1)那麼階碼為將階碼段值以無符號解釋出來(設為e)後減去偏置 即
E=e−Bias 小數字段frac為描述小數值f=0.fn−1...f1f0 此時的尾數M=1+f 即自帶了一個整數1 - 非格式化的值(階碼為全0) 此時
E=1−Bias 而M=f , 注意此時不包含隱含的1 - 無窮大(階碼全為1 並且 小數段全為0)
- NaN(階碼全為1 但是 小數字段不為全0) 不是數
2.4.5 浮點運算(與補充)
由於以下運算步驟,因而1+1e120-1e120 = 0,而1e120-1e120+1 = 1
加減計算方式
大體分為六步
- 0運算元檢查
- 比較階碼,並完成對階碼
- 尾數求和運算
- 結果規格化
- 舍入處理
- 溢位處理
這裡用一個例子綜合地回顧浮點數的表示與運算(also MIPS)
1.3+3.7
1.3(float表示):易知s = 0
1.3二進位制數為
1.3_d = 1.0 1001 1001 1001 10011001 1001..._b
那麼為規範數.其階碼為0,加上偏置(bias = 127) 得到階碼位為
127_d = 0111 1111_b
然後其小數位就需要去除整數部分的1,然後進行舍入到23位,為
0 1001 1001 1001 1001 1001 10
最後其二進位制表示就是
0(符號位)0111 1111(階碼位)0 1001 1001 1001 1001 1001 10
整理為16進位制就是
0x3fa66666
在小端機上就會顯示為0x66 66 a6 3f
3.7(float表示):易知 s= 0
3.7二進位制數為
3.7_d = 11.1 0110 0110 0110 0110 0110 0110 0110..._b
那麼為規範數小數點需左移一位,那麼階碼為1,加上偏置得到階碼位
128_d = 1000 0000_b
左移後數為
1.11 0110 0110 0110 0110 0110 0110 0110..._b
然後進行小數位舍入得到
11 0110 0110 0110 0110 0110 1
注意左後的1是舍入得到的最後其二進位制表示就是
0(符號位)1000 0000(階碼位)11 0110 0110 0110 0110 0110 1
整理為16進位制就是
0x406ccccd
在小端機上就會顯示為0xcd cc 6c 40
1.3 + 3.7 相加
均不為0
1.3階碼小,進行對階,將小數部左移1位,相當於
21∗0.101001100110011001100110... 此時再將位數相加,這裡要注意3.7尾數前有隱含的1,而1.3對階後沒有了隱含的1,那麼相當於
1.1101 1001 1001 1001 1001 101 +
0.1010 0110 0110 0110 0110 011
的到
10.1000 0000 0000 0000 0000 000
規範化,由上一步算出來的式子還需要左移一位得到規範的尾數,那麼階碼+1 得到為2 加上偏置為129.
階碼
129_d =1000 0001
尾數變為010 0000 0000 0000 0000 0000
得到結果為
0 1000 0001 010 0000 0000 0000 0000 0000
16進製為0x40 a0 00 00
第三章:程式的機器級表示
總綱
當做一門新的語言來,但是是一門貼近硬體的底層語言,在應用過程中加深對底層架構的理解。像硬體應用開發一樣,直接操作暫存器,記憶體。
MIPS的彙編
3.0.1 彙編基本概念
- 彙編: 把組合語言翻譯為機器語言的過程
- 彙編程式:實現彙編過程的軟體程式
- 指令: 計算機能執行的程式碼的最小單位
- 程式: 指令的有序組合
- 指令集: 計算機能執行的所有的指令的集合
3.0.2 常用指令集和(複習用)
3.0.3 資料儲存方式
- 資料存放採取位元組對齊: 半字型別資料從偶地址開始存放,字型別從4的整數倍地址開始存放
- 由於為精簡指令集,指令長度都為32位即佔