歡迎來到機器的心臟!
你好!今天我們將深入探討電腦的內部世界。你有沒有想過,電腦究竟是如何理解像 x = 5 + 2 這樣的程式碼呢?電腦並不使用 Python 或 Java;它們使用的是電訊號的語言——二進位(Binary)(即 0 和 1)。
在本章中,我們將學習組合語言(Assembly Language)。你可以把它想像成人類世界與電腦底層電訊號之間的「橋樑」。它強大且快速,讓你能夠完全掌控處理器(Processor)。如果剛開始覺得它看起來有點「機器化」也不用擔心——一旦你掌握了其中的規律,這就像是在解一個有趣的邏輯謎題!
1. 機器碼與組合語言
在編寫任何程式之前,我們需要先了解「低階(Low-level)」語言的兩個層級:
機器碼(Machine Code):這是處理器唯一能直接理解的東西,完全由二進位(例如 01101010)組成。對人類來說,要在不犯錯的情況下閱讀或編寫機器碼幾乎是不可能的。
組合語言(Assembly Language):為了讓事情變得簡單,我們使用助憶碼(Mnemonics)。助憶碼是一種簡短、易於記憶的縮寫,代表了特定的機器碼指令。例如,與其輸入一長串二進位代碼來相加兩個數字,我們只需寫下 ADD。
重點複習:
• 機器碼 = 1 和 0 的組合(給電腦看)。
• 組合語言 = 像 ADD 或 LDR 這樣的助憶碼(給人類看)。
• 組譯器(Assembler) = 將組合語言轉換為機器碼的軟體。
你知道嗎?每一種不同類型的處理器(例如你手機裡的處理器與筆電裡的處理器)都有其專屬的指令集(Instruction Set)。這意味著為某種處理器編寫的組合語言程式,可能無法在另一種處理器上執行!
2. 指令格式
每一條組合語言指令通常分為兩個主要部分。你可以把它想像成一個簡單的句子:包含一個動詞和一個名詞。
操作碼(Opcode,即動詞)
操作碼(Operation Code 的縮寫)告訴處理器要做什麼。常見的例子包括 ADD(相加)、SUB(相減)或 MOV(移動)。
運算元(Operand,即名詞)
運算元告訴處理器對什麼進行操作。它可以是一個固定的數字、一個記憶體位址,或是一個暫存器(Register,即 CPU 內超高速的小型儲存空間)。
比喻:如果你正在按照食譜做菜,指令是「切洋蔥」,那麼操作碼就是「切」,而運算元就是「洋蔥」。
關鍵總結: 指令 = 操作碼(動作)+ 運算元(資料或位置)。
3. 定址模式:尋找資料
「定址模式(Addressing Modes)」告訴 CPU 如何解讀運算元。Oxford AQA 要求你掌握三種特定的類型。不用擔心,我們用一個比喻來說明!
1. 立即定址(Immediate Addressing):
運算元本身就是你要使用的實際數值。
例子: ADD #5(直接將數字 5 相加)。
比喻: 有人直接遞給你 \( \$5 \) 現金。你手裡立刻就有了這些錢!
2. 直接定址(Direct Addressing):
運算元是一個記憶體位址。CPU 必須前往該位址才能找到數值。
例子: LDR R1, 101(前往記憶體位置 101,將其中的內容載入到暫存器 R1)。
比喻: 有人給你一個置物櫃號碼。你必須親自去那個置物櫃才能拿到錢。
3. 間接定址(Indirect Addressing):
運算元是一個暫存器,該暫存器中存放的是資料的記憶體位址。
例子: 如果暫存器 R2 裡存著數字「200」,而你使用間接定址,CPU 會先前往位置 200,才能找到真正的資料。
比喻: 你拿到一張紙條,上面寫著:「置物櫃的鑰匙在藍色盒子裡。」你得先去藍色盒子找到鑰匙,才能前往相應的位置拿到錢。
常見錯誤: 學生常混淆「直接定址」與「立即定址」。記住:立即定址直接使用該數字(通常標有 # 號),而直接定址則將數字視為一個「門牌號碼」,用來尋找另一個數值。
4. OxfordAQA 組合語言指令集
在考試中,你將會使用基於 ARM 處理器的特定指令集。以下是你必須掌握的最重要指令:
資料傳輸
• LDR (Load): 從記憶體中複製一個值到暫存器。
• STR (Store): 將一個值從暫存器複製到記憶體中。
• MOV (Move): 將一個值從一個地方複製到另一個地方(例如在兩個暫存器之間)。
算術與邏輯
• ADD: 將兩個值相加。
• SUB: 將兩個值相減。
• AND, OR, NOT, XOR: 執行位元運算。
• LSL (Logical Shift Left): 將位元向左移(乘以 2)。
• LSR (Logical Shift Right): 將位元向右移(除以 2)。
程式流程(分支)
通常,CPU 會按順序一條接一條地執行指令。分支(Branching)允許程式「跳轉」到程式碼的其他部分。
• CMP (Compare): 比較兩個值(通常在跳轉指令前使用)。
• B (Branch): 無條件跳轉到特定標籤。
• BEQ / BNE: 條件跳轉(若相等則跳轉 / 若不相等則跳轉)。
• HALT: 停止程式執行。
5. 追蹤與編寫程式
當題目要求你「追蹤(trace)」一個程式時,你的角色就像是一台電腦。你需要一步步執行指令,並記錄暫存器與記憶體中的變化。
執行流程範例:
1. MOV R1, #10 (暫存器 R1 現在存有 10)。
2. MOV R2, #5 (暫存器 R2 現在存有 5)。
3. ADD R1, R1, R2 (將 R1 和 R2 相加,結果存回 R1。R1 現在是 15)。
4. STR R1, 100 (將數值 15 儲存到記憶體位置 100)。
記憶小撇步: 大多數指令都遵循此格式:目的位置(Destination), 來源 1(Source 1), 來源 2(Source 2)。排在第一個的暫存器幾乎總是存放「答案」的地方!
最終總結:重點複習
1. 組合語言是人類可讀的: 我們使用助憶碼(簡短詞彙)而不是二進位。
2. 指令結構: 每一條指令都有操作碼(指令內容)和運算元(資料或位置)。
3. 定址方式至關重要: 區分立即定址(直接用數字)、直接定址(用位址)和間接定址(用存放位址的暫存器)。
4. 暫存器速度極快: 組合語言的核心在於資料在暫存器與主記憶體(RAM)之間的移動。
5. 程式流程: 使用 CMP 和 Branch 指令在組合語言中實現「if 判斷」和「迴圈」。
如果剛開始覺得很難也不用擔心!組合語言是一種邏輯性極強的語言。一旦你習慣了手動將資料移入移出小盒子(暫存器)的概念,一切就會變得豁然開朗。繼續練習簡單的 ADD 和 MOV 指令吧!