課程:Introduction to Computer Organization (CCIT4026) 主題:多周期處理器的架構、執行流程與 FSM 控制單元設計
目錄
- 學習目標
- 單周期處理器的回顧與限制
- Single-Cycle vs Multi-Cycle 比較
- 效能比較範例
- 多周期處理器的設計理念
- 多周期處理器的硬體架構
- 新增的暫存器:IR、MDR、A、B、ALUOut
- 多周期執行的五個步驟
- 各類指令的微操作(Actions for Instructions)
- 完整執行範例
- 多周期處理器的控制單元(FSM)
- 重點整理與小結
學習目標
完成本章後,你應該能夠:
- 說明單周期處理器的效能限制以及為何需要多周期設計。
- 比較單周期與多周期處理器在時脈周期、CPI、執行時間上的差異。
- 識別多周期處理器中需要新增的內部暫存器(IR、MDR、A、B、ALUOut)的用途。
- 描述多周期處理器執行一條指令的五個步驟及每步驟的微操作。
- 為 R-type、lw、sw、beq、j 指令列出完整的多周期執行序列。
- 理解有限狀態機(FSM) 如何用於產生多周期處理器的控制訊號。
單周期處理器的回顧與限制
單周期處理器的特性
在單周期處理器中: - 每條指令在一個時脈周期內完成,因此 CPI(每指令周期數)= 1。 - 時脈周期長度由最慢指令所需的時間決定(即 lw)。
為何單周期效能差?
公式:
CPU 時間 = 指令數 × CPI × 時脈周期
= N × 1 × T_longest
雖然 CPI = 1 看似理想,但 T_longest 太長 → 整體執行時間偏長。
各指令的功能單元使用情況
| 指令類別 | 使用的功能單元(依序) |
|---|---|
| R-format | Instruction fetch → Register access → ALU → Register access |
| Load word | Instruction fetch → Register access → ALU → Memory access → Register access |
| Store word | Instruction fetch → Register access → ALU → Memory access |
| Branch | Instruction fetch → Register access → ALU |
| Jump | Instruction fetch |
觀察: -
lw用了 5 個功能單元(最長路徑)。 -Jump只用 1 個功能單元,但仍需等整整一個時脈周期 → 嚴重浪費!
主要問題
- 時脈周期受最慢指令限制 — 即使簡單指令也要等。
- 資源浪費 — 必須複製 ALU、Adder 等多份硬體(一個算 PC+4、一個算 Branch、一個算 ALU 運算)。
Single-Cycle vs Multi-Cycle 比較
時脈周期示意圖
單周期實作
CLK ──┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐
└────┘ └────┘ └────┘ └────┘ └────┘ (週期長度由 lw 決定)
lw ► |Inst Fetch|Reg Access| ALU |DM Access|Reg Access| ◄ 一個 CLK 內全部完成
j ► |Inst Fetch| | ◄ 浪費的時間
多周期實作
CLK ─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ (週期較短)
└──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘
lw ► |Inst Fetch|Reg Access| ALU | DM Access | Reg Access| ◄ 5 個 CLK
j ► |Inst Fetch| ◄ 1 個 CLK
多周期的三大優勢
- 更快的時脈速率(Faster Clock) - 時脈周期長度由最慢的單一功能單元決定,而非整個指令路徑。
- 每條指令的時脈周期數可以不同 - Jump 只需 1~3 個 CLK;lw 需要 5 個 CLK。
- 減少實體資源(Reduce physical resources) - ALU、Memory 等可在不同周期被重複使用,不需要複製多份。
設計哲學:「犧牲 CPI(變大),換取更短的時脈周期,總時間反而可能縮短」。
效能比較範例
題目設定
假設一個程式中各種指令所佔比例如下:
| 指令類別 | 比例 |
|---|---|
| R-Type | 20% |
| LW | 10% |
| SW | 20% |
| Branch | 25% |
| Jump | 25% |
各功能單元的延遲時間(單位:ns):
| 指令類別 | Instruction Memory | Register Read | ALU operation | Data Memory | Register Write | Total |
|---|---|---|---|---|---|---|
| R-format | 2 | 1 | 2 | 0 | 1 | 6 ns |
| Load word | 2 | 1 | 2 | 2 | 1 | 8 ns |
| Store word | 2 | 1 | 2 | 2 | 0 | 7 ns |
| Branch | 2 | 1 | 2 | 0 | 0 | 5 ns |
| Jump | 2 | 0 | 0 | 0 | 0 | 2 ns |
單周期分析
時脈周期 T = max(6, 8, 7, 5, 2) = 8 ns(受 lw 限制)。
平均執行時間 (Single-cycle)
= 1 條指令 × 8 ns
= 8 ns / instruction
時脈頻率 = 1 / 8 ns = 125 MHz
多周期分析
時脈周期 T = 2 ns(最慢的單一功能單元,即 Instruction Memory)。
各指令所需時脈周期數:
| 指令類別 | CPI |
|---|---|
| R-format | 4 (IM → RR → ALU → RW) |
| Load word | 5 (IM → RR → ALU → DM → RW) |
| Store word | 4 (IM → RR → ALU → DM) |
| Branch | 3 (IM → RR → ALU) |
| Jump | 1 (IM) |
平均 CPI:
Avg CPI = 0.20 × 4 + 0.10 × 5 + 0.20 × 4 + 0.25 × 3 + 0.25 × 1
= 0.80 + 0.50 + 0.80 + 0.75 + 0.25
= 3.10
平均執行時間:
Avg time per instr = CPI × T = 3.10 × 2 ns = 6.2 ns / instruction
時脈頻率 = 1 / 2 ns = 500 MHz
結論
| 項目 | Single-Cycle | Multi-Cycle |
|---|---|---|
| 時脈周期 | 8 ns | 2 ns |
| CPI | 1 | 3.10 |
| 平均每條指令時間 | 8 ns | 6.2 ns |
| 時脈頻率 | 125 MHz | 500 MHz |
多周期實作約快 1.29 倍!
多周期處理器的設計理念
核心思想
將一條指令的執行拆分為一系列步驟,每個步驟對應一個功能單元的操作,每個步驟佔用一個時脈周期。
設計原則
- 重用功能單元:同一個功能單元(如 ALU)在不同周期可被同一條指令多次使用,但同一周期內不能被同一條指令重複使用。
- 資源共享:例如 ALU 既可用於計算 PC + 4,又可用於 R-type 的運算,又可用於 lw/sw 的位址計算 → 減少所需 ALU 數量。
- 記憶體合併:原本單周期有獨立的 Instruction Memory 與 Data Memory,現在可以共享一個 Memory 單元(不同周期取指或存取資料)。
- 新增暫存器:在每個重要功能單元的輸出端新增暫存器,保留中間結果到下一個時脈周期使用。
主要硬體簡化
| 元件 | 單周期 | 多周期 |
|---|---|---|
| Memory | 兩個(Instr + Data) | 一個(共用) |
| ALU | 一個 ALU + 兩個 Adder | 一個 ALU(兼任 Adder) |
多周期處理器的硬體架構
高階方塊圖
┌──────────────────────┐
│ Control Unit (FSM) │
└──┬───────────────────┘
│ 控制訊號
│ (PCWrite, PCWriteCond, IorD,
│ MemRead, MemWrite, IRWrite,
│ MemtoReg, RegDst, RegWrite,
│ ALUSrcA, ALUSrcB, ALUOp, PCSource)
▼
┌───┐ ┌──────────────┐
│PC ├──┐ ┌──MUX(IorD)────►│ │
└───┘ │ │ │ │── MemData
▲ │ │ │ Memory │
│ └────┴──Address────────│ (合併 IM & │
│ │ DM) │
│ │ │── Write data ◄── B
│ └──────┬───────┘
│ │
│ ┌───────┴─────────┐
│ │ │
│ ▼ ▼
│ ┌──────────────┐ ┌──────────────┐
│ │ IR │ │ MDR │
│ │ (Instr Reg) │ │ (Mem Data │
│ └──────┬───────┘ │ Reg) │
│ │ └──────┬───────┘
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ Register File │ │
│ │ │ │
│ │ Read data 1 ─► A ─┐ │ │
│ │ Read data 2 ─► B ─┼─┼─┐ │
│ └────────▲────────────│ │ │
│ │ │ │ │
│ Write Data ◄──── MUX(MemtoReg)◄┘
│ │ │
│ ▼ ▼
│ ┌─────────────┐
│ │ │
│ ALUSrcA┼►MUX A │
│ │ │
│ │ ALU │── ALUOut(register)
│ ALUSrcB┼►MUX B │ │
│ │ │ │
│ └─────────────┘ │
│ │
│ ┌────PCSource MUX─┐
│ │ │
└──────────────────────────────────────────────┘ ▼
新 PC(PC + 4 / Branch / Jump)
關鍵特徵: - PC 之後的 MUX (IorD) 決定 Memory 是讀指令(IorD=0,用 PC)還是讀資料(IorD=1,用 ALUOut)。 - ALU 前的兩個 MUX(ALUSrcA、ALUSrcB)讓 ALU 在不同周期能執行不同運算。 - PCSource MUX 決定下一個 PC 從何而來。 - 所有黃色(高亮)的暫存器(IR、MDR、A、B、ALUOut)在每個時脈邊緣自動寫入,不需要顯式控制(除了 IR)。
新增的暫存器:IR、MDR、A、B、ALUOut
由於功能單元的共享,必須在每個重要單元的輸出端加上暫存器,將其輸出保留到下一周期使用。
5 個新增暫存器
| 暫存器 | 全名 | 用途 |
|---|---|---|
| IR | Instruction Register | 保留從 Memory 讀出的指令(在後續周期中各個 field 仍可使用) |
| MDR | Memory Data Register | 保留從 Memory 讀出的資料(lw 用) |
| A | — | 保留 Register File 的 Read data 1(即 rs 暫存器的值) |
| B | — | 保留 Register File 的 Read data 2(即 rt 暫存器的值) |
| ALUOut | — | 保留 ALU 的輸出結果 |
為何需要這些暫存器?
原因:在多周期處理器中,功能單元在每個時脈周期之後可能要做不同的事。如果不把它的輸出存起來,下一個周期它就會被覆蓋。
範例:lw 的執行
Cycle 1: Memory ── 讀指令 ──► IR
Cycle 2: Register File ── 讀 rs ──► A
── 讀 rt ──► B
Cycle 3: ALU ── A + sign_ext(immediate) ──► ALUOut
Cycle 4: Memory ── 用 ALUOut 當位址,讀資料 ──► MDR
Cycle 5: Register File ── 將 MDR 寫回 rt
如果沒有 ALUOut,第 3 周期 ALU 的結果就無法在第 4 周期使用!
多周期執行的五個步驟
不論哪種指令,前兩步驟總是相同的(Instruction Fetch、Decode/Register Read)。從第 3 步開始,依指令類型分歧。
Step 1:Instruction Fetch(取指)
IR = Memory[PC] ← 從記憶體讀指令,存入 IR
PC = PC + 4 ← PC 增加 4(為下一條指令準備)
此階段: -
IorD = 0(記憶體輸入位址用 PC) -MemRead = 1、IRWrite = 1-ALUSrcA = 0(ALU 第一輸入用 PC) -ALUSrcB = 01(ALU 第二輸入用常數 4) -ALUOp = 00(ALU 做加法) -PCWrite = 1、PCSource = 00(PC ← ALU 結果)
Step 2:Instruction Decode / Register Fetch
A = Reg[IR[25-21]] ← 讀 rs 暫存器
B = Reg[IR[20-16]] ← 讀 rt 暫存器
ALUOut = PC + (sign-extend(IR[15-0]) << 2) ← 預先計算 Branch Target
巧妙之處:因為此時還不知道指令是甚麼類型(解碼還沒完成),但 Register File 是非同步讀取(不需要控制訊號),所以可以「順便」把 rs、rt 的值讀進 A、B。同時 ALU 也閒置,順便預計算分支目標。如果結果用不到,沒關係(沒有副作用)。
Step 3:Execution / Address Computation / Branch Completion
依指令類型分歧:
| 指令 | Step 3 動作 |
|---|---|
| R-type | ALUOut = A op B |
| lw / sw | ALUOut = A + sign-extend(IR[15-0])(位址計算) |
| beq | if (A == B) PC = ALUOut(用 Step 2 預先算的 Branch Target) |
| j | PC = PC[31-28] \|\| (IR[25-0] << 2) |
Step 4:Memory Access / R-type Completion
依指令類型分歧:
| 指令 | Step 4 動作 |
|---|---|
| R-type | Reg[IR[15-11]] = ALUOut(寫回 rd) |
| lw | MDR = Memory[ALUOut](讀記憶體到 MDR) |
| sw | Memory[ALUOut] = B(將 B 的值寫入記憶體) |
| beq, j | (已完成,無動作) |
Step 5:Memory Read Completion
只有 lw 有此步驟:
Reg[IR[20-16]] = MDR ← 將 MDR 寫回 rt
各指令所需的步驟數總覽
| 指令類別 | 所需步驟 | CPI |
|---|---|---|
| R-type | 1, 2, 3, 4 | 4 |
| lw | 1, 2, 3, 4, 5 | 5 |
| sw | 1, 2, 3, 4 | 4 |
| beq | 1, 2, 3 | 3 |
| j | 1, 2, 3 | 3 |
各類指令的微操作(Actions for Instructions)
多周期處理器執行表(重要!)
| Step name | R-type | Memory references (lw/sw) | Branches (beq) | Jumps (j) |
|---|---|---|---|---|
| 1. Instruction fetch | IR = Memory[PC]; PC = PC + 4 |
(相同) | (相同) | (相同) |
| 2. Instruction decode / register fetch | A = Reg[IR[25-21]]B = Reg[IR[20-16]]ALUOut = PC + (sign-extend(IR[15-0]) << 2) |
(相同) | (相同) | (相同) |
| 3. Execution / addr comp. / branch / jump completion | ALUOut = A op B |
ALUOut = A + sign-extend(IR[15-0]) |
if (A == B) PC = ALUOut |
PC = PC[31-28] \|\| (IR[25-0] << 2) |
| 4. Memory access / R-type completion | Reg[IR[15-11]] = ALUOut |
Load: MDR = Memory[ALUOut]Store: Memory[ALUOut] = B |
— | — |
| 5. Memory read completion | — | Load: Reg[IR[20-16]] = MDR |
— | — |
| Total steps | 4 | load: 5 / store: 4 | 3 | 3 |
這張表幾乎是考試必出!必須背熟每一步驟在做甚麼。
完整執行範例
題目
下列指令序列在多周期處理器上執行,請追蹤接下來 11 個時脈周期內每條匯流排上的資料:
L1: sw $t1, 5($s0)
sub $t0, $s1, $s2
beq $t0, $t1, L1
機器碼
| 指令 | opcode | rs | rt | rd | shamt | funct | 或 immediate |
|---|---|---|---|---|---|---|---|
| sw | 101011 | 10000 ($s0) | 01001 ($t1) | — | — | — | 0000 0000 0000 0101 |
| sub | 000000 | 10001 ($s1) | 10010 ($s2) | 01000 ($t0) | 00000 | 100010 | — |
| beq | 000100 | 01000 ($t0) | 01001 ($t1) | — | — | — | 1111 1111 1111 1101 (-3) |
初始狀態
| 暫存器/記憶體 | 值 |
|---|---|
$s0 |
100 |
$s1 |
5 |
$s2 |
3 |
$t1 |
2 |
L1 |
400 |
mem[105] |
6 |
註:題目假設
L1位於位址 400,因此第一條 sw 指令的 PC = 400。
周期追蹤表(11 cycles)
| Clock | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 指令 | sw | sw | sw | sw | sub | sub | sub | sub | beq | beq | beq |
| Step (cycle / inst) | 1 | 2 | 3 | 4 | 1 | 2 | 3 | 4 | 1 | 2 | 3 |
詳細追蹤
| Component | Cycle 1 (sw, S1) | Cycle 2 (sw, S2) | Cycle 3 (sw, S3) | Cycle 4 (sw, S4) |
|---|---|---|---|---|
| PC | 400 | PC = PC+4 = 404 | 404 | 404 |
| Memory | Memory[PC](讀指令) |
— | — | B → Memory[ALUout](寫資料) |
| IR | IR = Memory[PC](Instruction Fetch) |
— | — | — |
| Register File (A,B) | — | A = $s0 = 100B = $t1 = 2 |
— | — |
| ALU output (ALUOut) | Calculate PC + 4= 404 |
Branch addr pre-calculate | ALUOut = A + 5= 100 + 5 = 105 |
— |
| Memory[105] | — | — | — | = 2 (sw 完成) |
| Component | Cycle 5 (sub, S1) | Cycle 6 (sub, S2) | Cycle 7 (sub, S3) | Cycle 8 (sub, S4) |
|---|---|---|---|---|
| PC | 404 | PC+4 = 408 | 408 | 408 |
| Memory | Memory[PC] |
— | — | — |
| IR | IR = Memory[PC] |
— | — | — |
| Register File (A,B) | — | A = $s1 = 5B = $s2 = 3 |
— | $t0 = ALUOut = 2 |
| ALU output | Calculate PC + 4= 408 |
Branch addr pre-calculate | ALUOut = A - B= 5 - 3 = 2 |
— |
| Component | Cycle 9 (beq, S1) | Cycle 10 (beq, S2) | Cycle 11 (beq, S3) |
|---|---|---|---|
| PC | 408 | PC+4 = 412 | PC = ALUOut(if A == B) |
| Memory | Memory[PC] |
— | — |
| IR | IR = Memory[PC] |
— | — |
| Register File (A,B) | — | A = $t0 = 2B = $t1 = 2 |
— |
| ALU output | Calculate PC + 4= 412 |
Branch address pre-calculate = 412 + (-3 × 4) = 400 |
(A == B?) → Yes,PC = 400 |
觀察與結論
- sw 用 4 個 cycle(無 Step 5)。
- sub 用 4 個 cycle(R-type,Step 4 寫回暫存器)。
- beq 用 3 個 cycle(在 Cycle 11 判斷後,PC 跳回 400)。
- 三條指令共用 4 + 4 + 3 = 11 cycles。
- Branch target 預計算:在 Cycle 10 計算分支目標 = 412 + (sign-extend(-3) << 2) = 412 - 12 = 400。
- 由於
$t0 == $t1(都是 2),條件成立,PC 跳回 L1,迴圈再次開始。
多周期處理器的控制單元(FSM)
為何控制單元變得複雜?
單周期的控制單元只是一組真值表(純組合邏輯)— 輸入是 opcode,輸出立即是控制訊號。
多周期的控制單元必須記住「目前在哪一步驟」,因為相同的指令在不同周期需要不同的控制訊號。例如,lw 在 Step 1 與 Step 4 都用 Memory,但分別對應指令位址與資料位址 → IorD 訊號不同。
解決方案:有限狀態機(FSM)
控制單元用 FSM(Finite State Machine) 實作: - 每個狀態對應某條指令在某個步驟時的控制訊號集合。 - 根據目前狀態與目前指令的 opcode,FSM 決定下一個狀態。
多周期處理器的 FSM(總共 10 個狀態)
┌────────┐
start │ S0 │ Instruction Fetch
│ │ (公共起點)
└───┬────┘
│
▼
┌────────┐
│ S1 │ Instruction Decode / Register Fetch
└───┬────┘
│
┌─────────┼──────────┬───────────┬─────────┐
│ │ │ │ │
│ (Op= │ (Op= │ (Op=R- │ (Op= │
│ LW or │ BEQ) │ type) │ J) │
│ SW) │ │ │ │
▼ ▼ ▼ ▼ │
┌──────┐ ┌──────┐ ┌─────────┐ ┌────────┐ │
│ S2 │ │ S8 │ │ S6 │ │ S9 │ │
│ Mem │ │Branch│ │Execution│ │Jump │ │
│ Addr │ │ 完 │ │ │ │完成 │ │
│ comp │ │ 成 │ │ │ │ │ │
└──┬───┘ └──┬───┘ └────┬────┘ └────┬───┘ │
│ │ │ │ │
┌─┴────┐ └─────► S0 ▼ └──► S0 │
│ │ ┌──────┐ │
▼ ▼ │ S7 │ │
┌───────┐┌──────┐ │R-type│ │
│ S3 ││ S5 │ │完成 │ │
│ Mem ││ Mem │ └──┬───┘ │
│ Read ││ Write│ │ │
│ (load)││(store│ └─► S0 │
└──┬────┘└──┬───┘ │
│ │ │
▼ └────────────► S0 │
┌────────┐ │
│ S4 │ │
│Write │ │
│back │ │
└──┬─────┘ │
│ │
└─────► S0 │
各狀態對應的控制訊號
| 狀態 | 步驟 | 主要控制訊號 |
|---|---|---|
| S0 | Step 1 (Instr Fetch) | MemRead=1, IorD=0, IRWrite=1, ALUSrcA=0, ALUSrcB=01, ALUOp=00, PCWrite=1, PCSource=00 |
| S1 | Step 2 (Decode/Reg Fetch) | ALUSrcA=0, ALUSrcB=11, ALUOp=00(預計算 Branch target) |
| S2 | Step 3 (Mem Addr Comp, lw/sw) | ALUSrcA=1, ALUSrcB=10, ALUOp=00(A + sign_ext(imm)) |
| S3 | Step 4 (Memory Read, lw) | MemRead=1, IorD=1 |
| S4 | Step 5 (Write-back, lw) | RegDst=0, RegWrite=1, MemtoReg=1 |
| S5 | Step 4 (Memory Write, sw) | MemWrite=1, IorD=1 |
| S6 | Step 3 (Execution, R-type) | ALUSrcA=1, ALUSrcB=00, ALUOp=10 |
| S7 | Step 4 (R-type completion) | RegDst=1, RegWrite=1, MemtoReg=0 |
| S8 | Step 3 (Branch completion) | ALUSrcA=1, ALUSrcB=00, ALUOp=01, PCWriteCond=1, PCSource=01 |
| S9 | Step 3 (Jump completion) | PCWrite=1, PCSource=10 |
新增的控制訊號
相較單周期,多周期需要更多控制訊號:
| 訊號 | 用途 |
|---|---|
IorD |
Memory 位址來源(0 = PC,取指;1 = ALUOut,取資料) |
IRWrite |
是否將 Memory 輸出寫入 IR |
PCWrite |
是否更新 PC(無條件) |
PCWriteCond |
是否更新 PC(條件式 — 配合 Zero 訊號用於 beq) |
PCSource |
下一個 PC 的來源(00 = ALU 結果,01 = ALUOut,10 = Jump address) |
ALUSrcA |
ALU 第一輸入(0 = PC,1 = A) |
ALUSrcB |
ALU 第二輸入(00 = B,01 = 4,10 = sign_ext(imm),11 = sign_ext(imm) << 2) |
PCWrite 的真實邏輯
PCEnable = PCWrite OR (PCWriteCond AND Zero)
- 對於取指階段(S0):
PCWrite = 1→ 直接更新 PC = PC + 4。 - 對於 beq(S8):
PCWriteCond = 1,必須加上 ALU 的 Zero 訊號才會真正更新 PC。 - 對於 j(S9):
PCWrite = 1、PCSource = 10,直接跳。
重點整理與小結
核心觀念
-
多周期 vs 單周期: - 將指令拆成多個小步驟,每步驟一個 cycle。 - 時脈周期變短(由最慢的單一功能單元決定,而非整條指令的延遲)。 - 不同指令所需 cycle 數不同(CPI 不再是 1)。
-
共享資源、新增暫存器: - 一個 ALU 取代 ALU + 兩個 Adder。 - 一個 Memory 取代 Instr Mem + Data Mem。 - 新增 IR、MDR、A、B、ALUOut 暫存器以保留中間結果。
-
五個執行步驟:
- Instruction Fetch
- Instruction Decode / Register Fetch(順便預計算 Branch target)
- Execution / Address Computation / Branch / Jump Completion
- Memory Access / R-type Completion
-
Memory Read Completion(僅 lw)
-
控制單元升級為 FSM: - 共 10 個狀態(S0~S9)。 - 不僅取決於 opcode,也取決於目前的步驟。
必背的微操作表
Step 1: IR = Memory[PC]; PC = PC + 4
Step 2: A = Reg[IR[25-21]]
B = Reg[IR[20-16]]
ALUOut = PC + (sign-extend(IR[15-0]) << 2)
Step 3:
R-type: ALUOut = A op B
lw / sw: ALUOut = A + sign-extend(IR[15-0])
beq: if (A == B) PC = ALUOut
j: PC = PC[31-28] || (IR[25-0] << 2)
Step 4:
R-type: Reg[IR[15-11]] = ALUOut
lw: MDR = Memory[ALUOut]
sw: Memory[ALUOut] = B
Step 5:
lw: Reg[IR[20-16]] = MDR
性能分析公式
Single-Cycle:
T_cycle = max(指令延遲)
CPU 時間 = N × 1 × T_cycle
Multi-Cycle:
T_cycle = max(單一功能單元延遲)
平均 CPI = Σ (各指令比例 × 各指令所需 cycles)
CPU 時間 = N × 平均 CPI × T_cycle
比較表
| 項目 | 單周期 | 多周期 |
|---|---|---|
| CPI | 1 | 3~5(依指令) |
| 時脈周期 | 長(由最慢指令決定) | 短(由最慢單一單元決定) |
| 功能單元 | 多份(ALU, Adders, IM, DM 分開) | 共享(一個 ALU、一個 Memory) |
| 控制單元 | 純組合邏輯(真值表) | 有狀態(FSM) |
| 設計複雜度 | 簡單 | 較複雜 |
| 整體效能 | 受最慢指令拖累 | 較佳 |
| 典型延遲樂觀估計 | 8 ns / instr | 6.2 ns / instr(範例中快約 1.29 倍) |
常見題型
- 效能比較題:給定指令分布與各功能單元延遲,計算單周期/多周期的平均執行時間。
- 微操作追蹤題:給定一段 MIPS 程式,列出每個 cycle 各 register、bus、memory 的值(如本章範例)。
- 控制訊號題:給定指令與步驟,列出所需的控制訊號(FSM 狀態)。
- 真值表題:列出某個控制訊號(如 PCWrite、IorD)在何時為 1。
與後續課程的銜接
多周期處理器仍有缺點:當一條指令在執行時,其他指令必須等待。這引出Pipeline(管線) 的概念:讓多條指令同時在不同階段執行,理想 CPI 趨近 1,且時脈周期維持短。Pipeline 才是現代處理器的主流設計。