← Back to list

一生科科準備資工在職專班讀書筆記 — 計算機組織 CH3 PC Arithmetic

介紹電腦邏輯元件, 運算元件,以及如何構成 ALU, 乘法邏輯, 除法邏輯, 浮點數邏輯

TH K · 2025-06-20 05:28 · 0 claps · 24.2 min read
#computer-organization #logic #computer-architecture #alu #cpu-design
Open on Medium ↗
Wiki topics: 🏛️ · Architecture

一生科科準備資工在職專班讀書筆記 — 計算機組織 CH3 PC Arithmetic

計算機組織進入第三章了,樂觀一點說是書的一半內容,但我感覺越看越慢,而且覺得有點無聊 ( 可能是因為看不太懂 ),這次會介紹電腦運算,以及一點邏輯閘,了解ALU怎麼算數的。

一個很重要的警告: 這篇有一些邏輯電路的東西,雖然我多是根據原文書還有問AI來寫,但是我完全沒有實做過,所以我總覺得一定會有一些地方說的不完全正確,只是因為吻合我的思路跟邏輯,所以我覺得應該是正確的。另外如果讀者希望透過這篇文章的知識點去跟專業者討論,必須抱持這篇可能有錯誤的心態,而不是認為內容不可能錯誤。我當然期許自己不是在寫垃圾文章餵給讀者,如果讀者有疑問或是發現錯誤歡迎提出討論。

ALU(Arithmetic Logic Unit)是執行算術運算(如加法、減法)和邏輯運算(如AND、OR)的核心單元,這些運算都依賴邏輯閘的組合。因此我們需要先跳到 Appendix B 了解基礎邏輯設計。從硬體到軟體之間其實經過了很多層的抽象包裝,所以在看第三章介紹運算、加速運算的時候,我只要想不通實際運作就看不懂,所以不可避免的要理解 Appendix B,會用到離散數學(聽到數學不要嚇跑其實就是邏輯而已),了解這些對我來說的幫助是說服自己這不是不可能的技術,再看技術怎麼被應用就覺得合理多了。

邏輯與邏輯電路

大家應該很熟悉且聽爛了,電腦系統是由 0 跟 1 組成的,大概是高中的時候聽電腦老師說的,當時對我來說實在太抽象了,我當時想說聽你在唬爛,請換一個說詞吸引人好嗎 ? 不過假設你有看前面的文章,那應該很熟悉用0跟1的組合來做訊息交換 (instruction, address …),只能是 0 跟 1 是因為我們是利用實體電路來記錄 0 跟 1 的,實體電路怎麼知道 0 還是 1 ? 具體來說,0 和1 是由電路的電壓高低來區分的,例如高電壓代表 1 (相當於有電),低電壓代表 0 (相當於沒電)。我們常用的 and, or, not, xor 都可以由邏輯電路來實現,這些邏輯電路也能夠互相組合稱之為logical blocks。

and, or, not, xor 真值表及邏輯電路

and, or, not, xor 真值表及邏輯電路

AND 操作類似乘法,用 · 表示,會稱之為 product。

OR 操作類似加法,用 + 表示,會稱之為 sum。

NOT 可以在變數前用 ¬ 表示。

這些邏輯會遵守以下規則:

  • Identity law: A + 0 = A ; A · 1 = A
  • Zero and One laws: A + 1 = 1 ; A · 0 = 0
  • Inverse laws: A + ¬A = 1; A · ¬A = 0
  • Commutative laws: A + B = B + A ; A · B = B · A
  • Associative laws: A + (B + C) = (A + B) + C ; A · (B · C) = (A · B) · C
  • Distributive laws: A · (B + C) = (A · B) + (A · C) ; A + (B · C) = (A + B) · (A + C)
  • DeMorgan’s laws: A · B = ¬ (A + B); A + B = ¬ (A · B)

logical blocks 可以分成兩種

  1. 電路可以儲存狀態並用於運算邏輯稱之為 sequential logic, 如 flip-flop。
  2. 電路無狀態單純依賴輸入來運算邏輯稱之為 combinational logic ,如AND、OR、XOR 等邏輯閘的組合就是 combinational logic,因為輸出僅取決於當前輸入,沒有記憶功能

電腦中常用的 logical blocks

Decoder 解碼器功能是將一個 n-bit 的二進制輸入轉換成 2ⁿ 個獨立的輸出線。例如 instruction 中的 opcode,假設 00 代表加法, 01 代表輸出, 10 代表儲存, 11代表跳址,這些屬於兩個 bit 的輸入,輸出則是 0001, 0010, 0100, 1000。 這樣的設計目的是可以快速的對應到明確的輸出,如右邊第一個位置是 1 的輸出就只會是 0001,所以像 opcode 這種固定且常用的東西硬體設計就會傾向用這種方式來存取跟使用,另一個例子是記憶體位址,不過我們現在的記憶體位址是以 32 或 64 bit 表示的這代表輸出線會需要 2³² 或 2⁶⁴ 以找到對應位址, 這當然是錯的!!如果要表示這麼多個位元數代表實體電路要非常大,decoder 可以分層解碼,先找出是實體位置的上中下層,再繼續用 decoder 往下找。目前解析記憶體位址的時間複雜度通常是 O(log n) [這裡的n是指記憶體大小],因為分層解碼需要逐層查找;存取單個記憶單元的理想時間複雜度是 O(1),但實際存取時間可能受其他因素影響。

Decoder的輸出通常是「one-hot」格式,即只有一個輸出線為1,其餘為0(例如0001, 0010等)

Decoder的輸出通常是「one-hot」格式,即只有一個輸出線為1,其餘為0(例如0001, 0010等)

Multiplexor 多工器功能是從 2ⁿ 個輸入中選擇一個輸出。名字很花俏其實就是 selector,根據選擇線的值,從多個輸入中選擇一個傳送到單一輸出。

2 to 1 multiplexor 真值表及邏輯

2 to 1 multiplexor 真值表及邏輯

可以看到邏輯圖 NOT gate 在畫的時候會省略三角形只留下空心圓,假設有兩個輸入來源 A, B 使用一個選擇線輸入得到 0 或 1 可以篩選輸出訊號是根據 A 的輸入還是 B 的輸入,假設有四個輸入,就會使用兩條選擇線輸入 00 , 01, 10,11 來篩選輸出,使用到 Multiplexor 的例子是當使用 add 或 addi 指令時需要用 ALU 做加法時,根據指令 opcode值傳到 Multiplexor 的選擇線,以此篩選運算的數字是來自 register 還是 instruction。

複習指令

複習指令

Two-Level Logic and PLAs

根據布林運算其實任何的邏輯都可以用 AND, OR, NOT 來實現,如 XOR 可以用 Sum of Product 形式表示為 (A · ¬B) + (¬A · B),也可以用 Product of Sum形式表示為 ¬((A + B) · (¬A + ¬B)))。Sum of Product 是先用 AND 計算每一項,再用 OR 合併;Product of Sum 則是先用 OR 計算每一項,再用 AND 合併。

Sum of Product & Product of Sum of A XOR B

Sum of Product & Product of Sum of A XOR B

只要都寫成 Sum of Product 就可以格式化邏輯閘(如下圖),可以運算多個輸入, 多個輸出,還有透過控制輸入是否要用 NOT gate 來控制輸入,稱為programmable logic array (PLA),PLA 包含一個 AND 閘陣列(生成產品項)和一個 OR 閘陣列(生成最終輸出),通過程式設計可以靈活設定哪些產品項參與運算。好處除了格式化也能夠簡單的利用真值表去做出邏輯閘。multiplexor 是一個很好的例子(有興趣者可以練習畫看看 4 to1 Multiplexor 邏輯圖)。

Read-Only Memory 唯讀記憶體(ROM) 是一種非揮發性記憶體,即使在電源關閉後,儲存的資料也不會消失。ROM 通常透過快閃記憶體(Flash Memory)或在製造過程中就將資料寫入的遮罩ROM(Mask ROM)來實現。由於其內容難以更改,因此非常適合用來儲存電腦最底層、最核心的啟動程式碼,也就是所謂的韌體(Firmware),例如 BIOS 或 UEFI。

更具體地說:

  • CPU 上電後的程式計數器(PC)會指向一個預設地址(如 0xFFFF0)。
  • 這個地址會送到 ROM 的 address 線。
  • ROM 裡這個地址對應的內容就是一條 機器指令(如 JMP 到 BIOS 主程式)。
  • CPU 讀出這條指令 → 執行 → 再讀下一條指令(下一個地址)… 重複下去。

其他數位邏輯設計概念

  1. Don’t care: 以 ABC 三個輸入舉例,

result = (¬A · B · C) + (A · ¬B · C) + (A · B · ¬C) + (A · B · C)

當 AB 皆為 1 無論 C 是 0 或 1 都可以得到結果是 1, 當 BC 皆為 1 無論 A 是 0 或 1 都可以得到結果是 1, 當 AC 皆為 1 無論 B 是 0 或 1 都可以得到結果是 1。因此我們得到 result = (A · B ) + (B · C) + (A · C)

ABC 真值表

ABC 真值表

這個概念可以利用 Karnaugh Maps 可以簡單地找到上述的簡化邏輯。下圖根據 ABC 真值表來演示怎麼用 Karnaugh Maps。

如何利用 Karnaugh Maps

如何利用 Karnaugh Maps

  1. Bus 匯流排: 利用平行的導線或線路。每一條導線傳遞一個位元的資訊。前面提到 Multiplexor可以用於選擇輸入端,像 register 內應該裝有 32bit 資料,如果是每個bit依序通過一個 Multiplexor一定就要32次通過 Multiplexor的時間,我也可以利用 bus 一次將 32bit 同時傳到 32 個 Multiplexor,這樣就省下大量的時間。

主機板上 ssd 插槽是一種 bus

主機板上 ssd 插槽是一種 bus

  1. Verilog and VHDL: 是硬體語言,我覺得這已經跟理解電腦架構設計跟運作原理相去甚遠,就不多作介紹,有興趣者可以閱讀原文書B20-B25。

建構一個 ALU

目前基本的邏輯概念都有了,可以來看看如何建構一個 1 bit ALU,還記得我們的運算指令可以做加, 減, 乘, 除, AND, OR ,所以一個單位的 ALU 有兩個輸入,邏輯則有兩層,第一層邏輯是 AND, OR 跟一個 adder ,第二層邏輯是一個 Multiplexor,ALU 的 Multiplexor 根據 opcode 選擇AND, OR 或 adder 的輸出。

1 bit ALU

1 bit ALU

AND, OR 操作很直觀,adder 則相對複雜,因為還需要考慮進位的問題,所以對 adder 來說應該需要 3 個輸入,除了兩個數 (a, b) 還需要考慮前一位的運算有沒有進位稱為 carryin (c),輸出則需要 sum 跟 carryout,我們來看sum 跟 carryout 的邏輯應該怎麼建構。

sum 輸出 1 的情況就是奇數個 1 。

sum = (a · ¬b · ¬c) + (¬a · b · ¬c) + (¬a · ¬b · c) + (a · b · c)

可以簡化成 sum = a ⊕ b ⊕ c (⊕, XOR) [文末補充如何簡化]

carryout 輸出 1 的情況是擁有 2 個 1 或是 3 個 1。

carryout = (¬a · b · c) + (a · ¬b · c) + (a · b · ¬c) + (a · b · c)

用 Karnaugh maps 可以簡化成 carryout = (a · b) + (b · c) + (a · c)

carryout 邏輯會如下圖,但是這並沒有滿足 sum 的計算

carryout = (a · b) + (b · c) + (a · c),圖示僅實現 carryout 而忽略 sum,則全加器不完整

carryout = (a · b) + (b · c) + (a · c),圖示僅實現 carryout 而忽略 sum,則全加器不完整

carryout = (¬a · b · c) + (a · ¬b · c) + (a · b · ¬c) + (a · b · c)

carryout 也可以簡化成 carryout = ((a ⊕ b) · c) + (a · b)

加上 sum = a ⊕ b ⊕ c (⊕, XOR)

最後 adder 邏輯會如下圖

全加器

全加器

要完成一個完整的 ALU 需要串聯 32 個的 1bit ALU 還要加入減法 (加負數) 功能, 實現 slt 指令,overflow detect…等,這些也是蠻有趣的,但我大約就是用文字說明概念如果有興趣可以去看原文書 B31-B35。

  1. 串聯32個很簡單,就是把 carryout 接到下一個單元的 carryin。

  2. 實現減法功能,複習一下 MIPS 中將一個數字從正轉負或是負轉正都是透過 two’s complement (所有bit invert之後再對該數字加1)。只需要再輸入端a, b分出一條執行not邏輯,然後使用 Multiplexor去選擇要正數還是負數,第一個單元 ALU 的 carryin 用於對數字加 1。當 opcode 指示減法時,Multiplexor 選擇b的反相(¬b),並將最低位的 carryin 設為1,以實現two’s complement 加法。

  3. slt 指令複習: slt $s1,$s2,$s3 → if ($s2 < $s3) $s1 = 1; else $s1 = 0; 利用 $s2 < $s3 → $s2 — $s3 < 0 ,用 adder 對兩數做減法然後數字的最高位的0跟1 本來就代表了數字是 >= 0還是 <0 ,但如果發生溢位時,結果的符號位可能不正確,因此需要額外的邏輯檢查溢位並修正 slt 結果。

  4. overflow detection 溢位檢測通常檢查兩個輸入的符號位與結果的符號位是否一致。例如,兩個正數相加若得到負數,或兩個負數相加得到正數,則表示溢位。

  5. zero detection 零檢測是將所有位元進行NOR運算,如果輸出為1,則表示結果為0。

Faster Addition: Carry Lookahead 預測 carryin 優化加法速度

根據前面的介紹可以看出 a, b 兩個數字可以被平行輸入 ALU 問題在於 carryin 會依賴前一位的運算,這樣必定需要,因此有了 Fast Carry,再次觀察 Karnaugh maps 簡化的 carryout

每一個位子的 carryin, carryout 也可以追溯到c0 而推算出來,這個邏輯叫 carry-lookahead adder

每一個位子的 carryin, carryout 也可以追溯到c0 而推算出來,這個邏輯叫 carry-lookahead adder

目前用 (a(i) · b(i)) , (a(i) + b(i)) 看式子會很眼花撩亂,

使用 g = a(i) · b(i) 代表 generate, p = a(i) + b(i) 代表propagate

由此可知越高位的 bit 要預算 carryin 需要越多的 AND gate, OR gate, 這代表需要更大的電路,電路越大使電子路徑越長反而可能造成運算效率降低,權衡成本跟效率可以改成每通過每 4 位一組計算進位,減少了高位進位計算的 AND 和 OR 閘數量,從而降低電路複雜度和延遲。

改成每通過每 4 位一組計算進位也就是只有 c4, c8, c12, c16, c20, c24, c28, c32 用到 carry-lookahead adder 別忘了這些 carryin 要並行運算才能達到加速, p(i) 跟 g(i) 都只依賴a(i), b(i)就可以算出來,所以第一階段是並行算出p(i)跟 g(i) 然後才是並行算 c(i) ,不會有計算 c8 依賴 c4 的情況。

Appendix B 先介紹到這個段落,已經足夠應付 CH3 的內容,我覺得我腦子要炸了,我的腦子屬於 CPU 還算可以但 memory 嚴重不足,這種迭代概念的東西,我看的頭好痛,看了後面忘記前面,一直重看。

MIPS 指令架構中的溢位(Overflow)

在介紹 MIPS 指令架構時,算術運算包含 無符號運算(Unsigned)有符號運算(Signed) 兩種模式。電腦的位元(bit)記憶與運算依賴實體電路進行儲存與邏輯運算,位元數受限於硬體規格,常見的有 32 位元或 64 位元,這也決定了運算的範圍,進而涉及 溢位(overflow) 的問題。例如,在一個 3 位元系統中,運算 100 (-4)+ 111 (-1) = 1011(-5),但是被截斷為 011 (3),這便是發生溢位。

MIPS 架構中,無符號運算主要用於計算記憶體位址,因為位址永遠為正整數。當無符號運算發生溢位時,硬體設計會讓結果自動循環,即按 mod 規則截斷,不會觸發錯誤提示。相反,有符號運算若發生溢位,硬體會發送錯誤訊號,提醒溢位狀況。

許多 C 語言編譯器傾向使用 unsigned 運算以避免觸發硬體溢位錯誤。然而,若溢位導致記憶體位址錯誤,程式可能因此崩潰。好在這類崩潰僅影響軟體層面,不會導致硬體系統卡死。

如何檢查溢位

電腦運算主要基於加法。減法可轉換為正數加負數,乘法是多次加法,除法是多次正數加負數。因此,以下以加法邏輯為基礎,搭配 3 位元運算範例說明溢位檢查。

無符號運算檢查溢位

以 101 + 100 為例,檢查溢位的方法是:

  1. 計算第一個數字(101)的補數(~101 = 010)。
  2. 檢查第二個數字(100)是否小於等於補數(011)。若否,則表示溢位。
# MIPS 程式碼如下:
addu $t0, $t1, $t2
nor $t3, $t1, $zero # $t3 = $t1的補數
sltu $t3, $t3, $t2 # 若 $t2 > $t3(補數),$t3 = 1(溢位),否則 $t3 = 0
bne $t3, $zero, Overflow

有符號運算檢查溢位

有符號運算僅在正數加正數或負數加負數時可能發生溢位。因此,檢查步驟如下:

  1. 檢查兩個輸入數字的符號是否相同(用 XOR 判斷)。
  2. 若符號相同,檢查結果與任一輸入數字的符號是否相反。
# MIPS 程式碼如下:
addu $t0, $t1, $t2 # 注意這邊使用無符號運算和
xor $t3, $t1, $t2 # 如果 $t1, $t2符號不同, $t3 一定是1xx…
slt $t3, $t3, $zero # 如果 $t3 < 0 (1xx… 以有符號標準來看一定是負數),$t3 = 1,否則 $t3 = 0 (可能發生溢位)
bne $t3, $zero, No_overflow # $t3 = 1代表 $t1, $t2是正數+負數必不會發生溢位
# 相同的邏輯看數字和 $t0,因為正數 + 正數 = 正數, 負數 + 負數 = 負數
# $t0 跟 $t1如果符號不同就是發生溢位
xor $t3, $t0, $t1
slt $t3, $t3, $zero
bne $t3, $zero, Overflow

硬體如何處理溢位

MIPS 硬體使用輔助暫存器 $k0 和 $k1 來處理溢位:

  • $k0 儲存溢位處理程式碼的位址(mfc0)。
  • $k1 儲存當前指令的位址(current address)。
  • 當溢位發生時,硬體跳轉至 mfc0 指定的程式碼處理錯誤,處理完成後返回 $k1 的位址。

乘法

由圖可知乘法邏輯就是多個加法

由圖可知乘法邏輯就是多個加法

在 32 位元系統中,乘法初始化 product 為 0,檢查 multiplier 的最右位(第0 位)是 0 還是 1。若為 1,則將 product 與 multiplicand 相加;接著,左移multiplicand,右移 multiplier,如此重複檢查和加法操作,共進行 32 次。為避免溢位,product 和 multiplicand 需擴展至 64 位元。

初版乘法器

初版乘法器

優化乘法

每輪計算和時,需對 multiplicand 和 multiplier 執行 shift 操作。為適應shift,multiplicand 和 product 需擴展至64位元。然而,可優化為將 32 位元product 與 32 位元 multiplier 合併,組成 64 位元 product’(product 在高 32位,multiplier 在低 32 位)。每次 shift 移除 multiplier 的最右位,multiplicand(32位元)始終與 product’ 的高 32 位對齊進行加法,最終結果為 product’ 的低 32 位元。

使用 4 bit 舉例優化乘法器

使用 4 bit 舉例優化乘法器

加速乘法

傳統乘法依賴單一 ALU 逐位計算,若使用多個 ALU 平行處理每位加法,可大幅加速。例如,1000 * 1111可分解為 10001000 + 10000100 + 10000010 + 10000001。進一步優化時,這些部分積可兩兩相加,需 log₂n 層加法即可得結果(如 4 個部分積,單次相加需 4 步,兩兩相加僅需 2 層)。

加速乘法

加速乘法

除法

除法滿足 Dividend = Quotient * Divisor + Remainder,通過移位和減法確定Quotient 與 Remainder。初始將 Dividend 視為 Remainder,Divisor 為 64 位元。考慮除以 1 的情況,需將 Divisor(例如 1)左移至第 32 位與Remainder 相減,得出 Quotient 最高位。Remainder 擴展至 64 位元以匹配Divisor,初始 Dividend 放置於低 32 位元。每次計算 Remainder - Divisor = Result,若Result >= 0,更新 Remainder 為 Result 並將 Quotient 填 1;若Result < 0,Remainder 不變,Quotient 填 0。完成一位後,左移 Divisor 和Quotient,進入下一輪檢查。

初版除法器

初版除法器

優化除法

優化除法邏輯與乘法類似,差異在於 ALU 執行加法還是減法。關鍵點是計算Remainder - Divisor = Result,當 Result < 0時,除將 Quotient 填 0 外,可選擇:加回 Divisor 至 Remainder、保持 Remainder不更新,或使用 Result作為新Remainder。但在下一輪執行 Remainder - Divisor前,若發現Remainder 為負數,需加回 Divisor以確保正確性。

使用 4 bit 舉例優化除法器

使用 4 bit 舉例優化除法器

加速除法

除法需檢查餘數是否足以扣除 Divisor,無法像乘法透過分配實現平行計算。可採用 SRT division 加速,我完全沒有想知道著個除法要怎麼做,還有硬體如何實現,有興趣這自行查找。

浮點數

之前專注於整數運算,現在進入小數點領域。使用位元表示如 0.1 = 十進制的 1 2⁻¹(也就是 0.5 ),0.01 = 十進制的 1 2⁻²(也就是 0.25),依此類推。 由於位元僅記 0 和 1,某些小數(如1/3)無法精確表示,這是新手常見的話題。電腦不直接記小數點,需統一格式。若簡單將第一位設為正負符號,剩餘 31 位分為整數和小數部分,數字範圍和精度將極其有限。例如,15 表示整數部分,16 位表示小數部分,那麼數字範圍約是 ± 2¹⁵,精度最小到 2⁻¹⁶。採用科學記號(1.xxxx 2ʸ)可解決此問題:y 為exponent(2 的次方),x 為 fraction(標準化為 1.xxxx,可省略 1的表示 ),那麼數字範圍約是 ± 2 10³⁸,最小精度約 2 * 10⁻³⁸。

二進位數字 = -1ˢ * 1.fraction*2ᵉˣᵖᵒⁿᵉⁿᵗ

二進位數字 = -1ˢ 1.fraction2ᵉˣᵖᵒⁿᵉⁿᵗ

fraction 的部分因為都會標準化表示成 1.xxxx 所以在格式上我們可以省略掉 1的表示,

exponent 用正負整數來表示 2 的次方,值得注意的是 exponent 整數表示法並不採用 two’s complement(如 Appendix B 所述,two’s complement 利於加減法,但浮點運算需對齊 exponent)。取而代之,使用 bias 表示法。IEEE 754 32位浮點數中,exponent 範圍為 -126 至 +127(偏置127),overflow 發生於 exponent > 127,underflow 發生於 exponent < -126。

數字表示法

數字表示法

練習

練習

32bit浮點數特殊值說明配置:0(exponent = 0,fraction = 0)、±∞(exponent = 127 (exponent 每一位都是1),fraction = 0)、NaN(exponent = 127 (exponent 每一位都是1),fraction ≠ 0)。

浮點數加法

浮點數運算類似科學記號,需先將 exponent 調整一致,再用 fraction 相加減。由於 fraction 標準化為 1.xxxx,exponent 通常對齊較大值,fraction 右移。例如,8 位浮點數計算 0.5 – 0.25:0.25 = 0 001 0000(1.0000 2⁻²),0.5 = 0 010 0000(1.0000 2⁻¹),調整後 (1.0000–0.1000) * 2⁻¹ = 0.25。但 fraction右移會丟失最右位,導致精度損失

浮點數加法器

浮點數加法器

浮點數乘法

浮點數的表示形式為 -1ˢ 1.fraction2ᵉˣᵖᵒⁿᵉⁿᵗ,其中 s 表示正負號,fraction 是尾數,exponent 是指數。進行浮點數乘法時,運算步驟如下:

  1. 正負號處理:根據兩數的正負號(s)是否相同,決定結果的正負號(相同為正,相異為負)。
  2. 指數相加:將兩數的指數相加。
  3. 尾數相乘:將 1.fraction 部分相乘。
  4. 標準化:將結果調整為標準浮點數格式(即 1.fraction * 2ᵉˣᵖᵒⁿᵉⁿᵗ)。
  5. 溢位檢查:檢查結果是否超出浮點數的表示範圍。

MIPS 提供專用的浮點數暫存器和指令,支援加法(add.s)、減法(sub.s)、乘法(mul.s)、除法(div.s)以及比較等運算。這些指令的邏輯與整數指令相似,但針對浮點數格式進行優化。MIPS 支援單精度(float)和雙精度(double)浮點數,雙精度使用兩個暫存器來儲存。

以下是一個將華氏溫度轉攝氏溫度的 C 函數及其對應的 MIPS 組譯程式碼:

float f2c(float fahr) {
    return (5.0 / 9.0) * (fahr - 32.0);
}

對應的 MIPS 組譯程式碼:

f2c:
    lwc1 $f16, const5($gp)   # 載入 5.0 到 $f16
    lwc1 $f18, const9($gp)   # 載入 9.0 到 $f18
    div.s $f16, $f16, $f18   # $f16 = 5.0 / 9.0
    lwc1 $f18, const32($gp)  # 載入 32.0 到 $f18
    sub.s $f18, $f12, $f18   # $f18 = fahr - 32.0
    mul.s $f0, $f16, $f18    # $f0 = (5.0 / 9.0) * (fahr - 32.0)
    jr $ra                   # 返回

Guard 和 Round

由於浮點數的小數部分以 2ⁿ(n<0) 表示,許多數字無法精確表示,因此需要使用 guard bitround bit 來提高運算精度:

  • Guard bit:保留運算結果右邊的額外位元,避免因截斷而丟失資訊。
  • Round bit:根據 guard bit 和 sticky bit(記錄 round bit 右邊是否有非零位元)決定是否進位。
  • Sticky bit:若 round bit 右邊的位元非零,則設為 1,強制進位。

範例:2.5610⁰+2.3410²

  1. 對齊指數:將 2.56×10⁰ 改為0.0256 *10²。
  2. 保留 guard bit:將 0.0256 10² + 2.340010²相加,得 2.3656*10²。
  3. 捨入處理:檢查 0.0056,因為 56 > 50,進位後得 2.37*10²。
  4. 若不使用 guard 和 round:直接截斷為 0.0210²+2.3410²=2.36*10²,結果較不精確。

子字並行(Subword Parallelism)

子字並行是一種利用處理器寬字(wide word)進行並行運算的技術,常用於圖形和音頻處理。它屬於 資料層並行(Data-Level Parallelism),也稱為 SIMD(Single Instruction, Multiple Data) 或向量運算。

例如,在圖形處理中,像素的紅(R)、綠(G)、藍(B)三色值(各 0–255)可儲存在單一暫存器中:

  • 0–7 位表示紅色。
  • 8–15 位表示藍色。
  • 16–31 位表示綠色。

透過 SIMD 指令,可同時處理多個像素的顏色值,無需逐一處理,提升效率。

SIMD 與浮點數:雖然 SIMD 可加速多資料處理,但浮點數的精確運算通常不將多個值打包至同一暫存器,而是逐一計算以確保精度。

SIMD 與浮點數:雖然 SIMD 可加速多資料處理,但浮點數的精確運算通常不將多個值打包至同一暫存器,而是逐一計算以確保精度。

常見謬誤與陷阱

謬誤:整數右移等於除以 2

  • 在有符號整數中,最高位表示正負號,右移並不總等於除以 2(例如,負數右移會保留符號位)。

謬誤:浮點數加法滿足結合律

  • 由於精度損失,浮點數加法的結果依賴運算順序,不滿足結合律。

謬誤:整數並行運算邏輯適用於浮點數

  • 浮點數的非結合律特性使其並行運算邏輯與整數不同,需特別處理精度問題。

這章我看得很痛苦,整理得也很痛苦,很多核心技術在現在的科技已經層層包裝進化了,所以整個知識內容廣到不行,而且有很多細節,少了那些細節你也做不出整個邏輯電路,如果又往細節探討又要再用大篇幅說明另一層原理。我覺得浮點數的部分我寫的有點倉促跟敷衍,但我覺得理解核心的數字標準化然後可以將十進位的小數轉換成浮點數表示法就夠了,提供邏輯只是想複習一下前面讓人頭很痛的邏輯電路。

邏輯推導範例

(¬a · ¬b)+ (a · b) = ¬(a ⊕ b) 是很難直接看出來的

(¬a · ¬b)+ (a · b) = ¬(a ⊕ b) 是很難直接看出來的

Reference

Computer Organization and Design: The Hardware/Software Interface,fifth edition,David A. Patterson and John L. Hennessy。

https://www.ariat-tech.tw/blog/mastering-digital-logic-functions-the-core-of-modern-electronics.html


메타데이터
post_id
1a86ad0c698c
slug
一生科科準備資工在職專班讀書筆記-計算機組織-ch3-pc-arithmetic-1a86ad0c698c
url
https://medium.com/@thk1106/%E4%B8%80%E7%94%9F%E7%A7%91%E7%A7%91%E6%BA%96%E5%82%99%E8%B3%87%E5%B7%A5%E5%9C%A8%E8%81%B7%E5%B0%88%E7%8F%AD%E8%AE%80%E6%9B%B8%E7%AD%86%E8%A8%98-%E8%A8%88%E7%AE%97%E6%A9%9F%E7%B5%84%E7%B9%94-ch3-pc-arithmetic-1a86ad0c698c
canonical_url
https://medium.com/@thk1106/%E4%B8%80%E7%94%9F%E7%A7%91%E7%A7%91%E6%BA%96%E5%82%99%E8%B3%87%E5%B7%A5%E5%9C%A8%E8%81%B7%E5%B0%88%E7%8F%AD%E8%AE%80%E6%9B%B8%E7%AD%86%E8%A8%98-%E8%A8%88%E7%AE%97%E6%A9%9F%E7%B5%84%E7%B9%94-ch3-pc-arithmetic-1a86ad0c698c
author_url
https://medium.com/@thk1106
status
ok
fetched_at
2026-06-24 04:09:36