National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 72 24°C PM2.5 13
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 10

馮紐曼架構與電腦的工作原理

程式和資料都存在記憶體裡:擷取、解碼、執行
Interaction 25 minute(s)

Learning Objectives

  • 說出馮紐曼架構的組成:運算、控制、記憶體、輸入、輸出,以及連接它們的匯流排
  • 解釋「儲存程式」的概念:程式和資料都以位元存在同一個記憶體裡
  • 描述指令週期的擷取、解碼、執行三個階段,以及 PC、IR、MAR、MDR、ACC 各自的角色
  • 比較馮紐曼架構與哈佛架構,說明「馮紐曼瓶頸」指的是什麼

同一台手機,為什麼能跑各種 App

你的手機今天裝了一個新遊戲,明天裝了記帳 App,硬體一顆螺絲都沒動,卻能做完全不同的事。 洗衣機、微波爐就不行:它們的功能在出廠時就固定了。

差別在於:手機(以及所有通用電腦)把程式當成資料存在記憶體裡。換一個程式,只是把記憶體裡的位元換掉。 這個想法叫做儲存程式(stored program),是今天幾乎所有電腦的共同設計,通常稱為馮紐曼架構(von Neumann architecture)。

這一課要回答三個問題:

  1. 一台電腦由哪幾個部分組成?它們之間怎麼傳遞資料?
  2. 程式和資料存在哪裡?CPU 怎麼分辨哪一格是指令、哪一格是資料?
  3. CPU 一條一條執行指令時,裡面到底發生了什麼事?

我們會用一顆自己設計的教學用處理器 UC8(8 位元、32 格記憶體、10 條指令)一步一步看。

儲存程式的由來

ENIAC(1946 年公開)是早期著名的電子計算機,算得很快,但它沒有「把程式存起來」的地方。 換一個問題,工作人員要重新拔插電纜、撥動開關,把程式「接」出來,往往要花上好幾天。

ENIAC 的團隊在設計下一台機器 EDVAC 時,討論出另一種做法:既然記憶體可以存數字,那就把指令也編成數字,和資料一起存進記憶體。 1945 年 6 月 30 日,數學家馮紐曼(John von Neumann)寫的〈EDVAC 報告初稿〉(First Draft of a Report on the EDVAC)開始流傳, 第一次有系統地描述了這種設計,「馮紐曼架構」這個名稱就是從這份報告來的。

這個名稱有爭議:報告只署名馮紐曼,但儲存程式的想法來自整個團隊的討論,ENIAC 的設計者 Eckert 與 Mauchly 也有重要貢獻。

1948 年 6 月 21 日,英國曼徹斯特大學的實驗機器 Manchester Baby 執行了存在自己記憶體裡的程式, 通常被認為是第一台執行儲存程式的電子計算機。從此以後,換程式只要把新的位元載入記憶體,不必再重新接線。

馮紐曼架構的組成

EDVAC 報告把電腦分成幾個主要部分,對應到今天的說法:

部分 做什麼 UC8 裡的對應
運算單元(ALU,算術邏輯單元) 加、減、比較等計算 ALU 與累加器 ACC
控制單元(control unit) 決定下一步做什麼:擷取指令、解讀指令、指揮其他部分 PC、IR、解碼
記憶體(memory) 存放程式和資料,每一格有一個位址 32 格,每格 8 位元
輸入(input) 把外界的資料送進來 輸入裝置(IN 指令)
輸出(output) 把結果送出去 輸出裝置(OUT 指令)

運算單元和控制單元合起來就是 CPU(中央處理器)。CPU 和記憶體之間靠匯流排(bus)連接,可以想成三組電線:

  • 位址匯流排:CPU 告訴記憶體「我要第幾格」
  • 資料匯流排:真正搬運內容(指令或資料)
  • 控制訊號:說明這次是「讀取」還是「寫入」
        ┌───────────── CPU ─────────────┐
輸入 ──▶│  控制單元(PC、IR)   ALU(ACC)│──▶ 輸出
        └──────────────┬────────────────┘
          位址匯流排 / 資料匯流排 / 控制訊號
        ┌──────────────┴────────────────┐
        │   記憶體:程式和資料放在一起    │
        └───────────────────────────────┘

指令週期:擷取、解碼、執行

CPU 一生只做一件事,不斷重複這個指令週期(instruction cycle):

  1. 擷取(fetch):照 PC(程式計數器)指的位址,從記憶體把一格內容搬進 IR(指令暫存器),然後 PC 加 1,指向下一格
  2. 解碼(decode):控制單元看 IR 的位元,判斷這是哪一條指令、要用哪個位址
  3. 執行(execute):真的去做,例如從記憶體讀一個數、讓 ALU 做加法、把結果寫回記憶體

CPU 裡的幾個暫存器(register)是 CPU 內部的小儲存格,速度比記憶體快很多:

暫存器 全名 放什麼
PC 程式計數器(program counter) 下一條要擷取的指令位址
IR 指令暫存器(instruction register) 正在執行的指令
MAR 記憶體位址暫存器 要存取的記憶體位址,經位址匯流排送出
MDR 記憶體資料暫存器 從記憶體讀進來、或要寫出去的內容
ACC 累加器(accumulator) 計算的結果

UC8 的每條指令是 8 個位元:前 3 位元是運算碼(要做什麼),後 5 位元是位址(對哪一格做)。例如:

001 00101   →  001 是 LDA(載入),00101 是位址 5   →  LDA 5:ACC ← 記憶體[5]

下面的模擬器把每個階段再切成幾個微步驟,你可以看到值在匯流排上怎麼流動。

互動練習:一步一步看指令週期

記憶體裡已經放好一個五條指令的程式(位址 0~4)和三個資料(位址 5~7)。先按「下一個微步驟」三次,看 PC 的值走上位址匯流排、指令沿資料匯流排搬進 IR;回答 PC 的問題後,繼續單步走完 ADD y,看 ALU 怎麼算出 ACC;最後按「執行到停止」跑完程式,回答 STA sum 時匯流排上是什麼。上方的任務清單會依序打勾;記憶體格子可以點開,看同一格內容當成指令和當成數字各是什麼。

用 Python 寫出指令週期

同樣的指令週期,用幾行 Python 就能模擬:memory 是一串數字,while 迴圈每一圈就是一個指令週期。注意三件事:ir = memory[pc] 之後 pc 馬上加 1;>> 和 & 把 8 個位元拆成運算碼和位址;程式和資料都在同一個 memory 串列裡。

程式就是資料

馮紐曼架構最重要的後果是:記憶體裡的位元沒有標記「我是指令」或「我是資料」。

同一格 001 00101,PC 指到它時,CPU 把它當成指令 LDA 5;用 LDA 把它讀進 ACC 時,它就是數字 37。 CPU 不會檢查,它只照 PC 去擷取、照指令去讀寫。這帶來兩種結果:

  • 好處:程式可以被載入、複製、下載、修改,就像處理一般資料。作業系統把 App 從儲存裝置載入記憶體、編譯器產生新的程式,都靠這一點。 早期一些電腦沒有專門走訪陣列的硬體,程式設計師會讓程式改寫自己指令裡的位址,一格一格處理資料。
  • 風險:如果 PC 跑到資料區,CPU 會把資料當成指令執行;如果有人把惡意資料寫進記憶體再讓 CPU 跳過去執行,就是一種攻擊手法。 所以現代作業系統會把放資料的記憶體區域標成「不可執行」。

下面的程式會改寫自己的第一條指令:每輸出一個數,就把位址 0 的 LDA list 加 1,讓它下一次讀下一格。

互動練習:會改寫自己的程式

這個情境有四個任務:先按「執行到停止」看程式輸出哪三個數,回答位址 0 最後變成什麼;再按「重新載入程式」還原,點位址 08 的格子,把 HLT 改成 OUT 後按「寫入這一格」,然後執行到停止,看 CPU 衝進資料區之後發生什麼事,最後回答位址 09 被當成指令時做了什麼。把記憶體顯示切到「當成指令讀」,可以看到每一格的位元被解讀成哪一條指令。

哈佛架構與馮紐曼瓶頸

馮紐曼架構不是唯一的做法。另一種設計把指令和資料放在分開的記憶體,各走各的通道,通常稱為哈佛架構(Harvard architecture)。 這個名稱來自 1944 年啟用的哈佛 Mark I:它從打孔紙帶一條一條讀指令,資料則存在機器內部,兩者是分開的。 (「哈佛架構」這個說法是後來才出現的分類名稱,Mark I 當時並沒有這樣稱呼自己。)

馮紐曼架構 哈佛架構
指令與資料 放在同一個記憶體 放在分開的記憶體
通道 共用一組匯流排,一次只能拿指令或資料其中一個 指令和資料可以同時傳送
彈性 程式可以被當成資料載入、修改 程式區和資料區分得清楚,不容易誤把資料當指令
常見於 一般電腦的整體設計 許多微控制器、數位訊號處理器

馮紐曼瓶頸(von Neumann bottleneck):CPU 算得再快,每條指令和每筆資料都要經過同一組匯流排從記憶體搬過來, 搬運速度就成了限制。這個詞因電腦科學家 John Backus 在 1977 年圖靈獎演講〈程式設計能從馮紐曼風格中解放出來嗎?〉而廣為人知。

今天的電腦其實混用兩種想法:主記憶體裡程式和資料放在一起(馮紐曼), 但 CPU 內部的快取(cache)常分成「指令快取」和「資料快取」兩份,讓指令和資料能同時取得(哈佛的精神),通常稱為修改式哈佛架構。 快取會在第 12 課「記憶體階層與快取」細談。

想一想:馮紐曼架構

1.

「儲存程式」這個想法的核心是什麼?

2.

下列哪一個不是馮紐曼架構描述的電腦主要組成部分?

3.

哈佛架構和馮紐曼架構最主要的差別是?

第 1 次作答

想一想:指令週期與 UC8 程式

1.

下面這段 UC8 程式執行到 HLT,會輸出什麼?

00  LDA x
01  SUB y
02  JN neg     ; 結果是負數就跳到 neg
03  OUT
04  HLT
05  neg: LDA y
06  OUT
07  HLT
08  x: DATA 3
09  y: DATA 8
2.

為什麼 PC 跑進資料區時,CPU 會把資料當成指令執行?

第 1 次作答

重點整理

  • 儲存程式:指令編成數字,和資料一起存在記憶體裡;換程式只要換位元。1945 年的〈EDVAC 報告初稿〉有系統地描述了這種設計,後來稱為馮紐曼架構。
  • 電腦的組成:運算單元、控制單元(合稱 CPU)、記憶體、輸入、輸出;CPU 和記憶體之間用位址匯流排、資料匯流排、控制訊號連接。
  • 指令週期不斷重複:擷取(PC → MAR → 記憶體 → MDR → IR,PC 加 1)、解碼(看運算碼和位址)、執行。
  • 暫存器各有分工:PC 記下一條指令在哪、IR 放正在執行的指令、MAR/MDR 負責和記憶體交換、ACC 放計算結果。
  • 記憶體裡的位元沒有標記是指令還是資料:程式可以修改自己,PC 跑錯地方也會把資料當成指令執行。
  • 哈佛架構把指令和資料的記憶體分開;馮紐曼瓶頸指 CPU 和記憶體之間的搬運速度成了限制。現代 CPU 的快取把指令和資料分開,混用兩種想法。

下一課:UC8 的 10 條指令怎麼設計?組合語言怎麼變成機器碼?我們會用這些指令自己寫程式:相加、倒數迴圈、找出較大的數。

這一課完成了!
Next lesson:CPU 與指令執行
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。