From Nand to Tetris系列(七)

Chapter 6. Computer Architecture

Von Neumann架構

圖靈(Turing)提出的通用計算機理論,後來由馮紐曼(Von Neumann)實踐。

一個典型的馮紐曼架構中會包含下面幾個元件:

  1. CPU(裡面會有ALU與Registers)
  2. Memory

這幾個元件之間會透過匯流排(bus)進行連結,我們可以將bus上的資料分為三種信息類型:

  1. 資料(Data)
  2. 地址(Address)
  3. 控制(Control)

ALU:接收Data並輸出處理後的Data,同時ALU也需要連接Control,用來判斷運算類型或者需要控制程式執行順序(branch)。
Register:Register用於保存運算過程的資料,所以需要接收Data bus上的資料,或將Data bus上的資料保存起來。另外也需要可以設定Address,用於記憶體定址。
Memory:首先需要接收Address,指定要操作的記憶體位址,接著根據讀或寫的操作,將資料送到Data bus上。其中記憶體內還可以在分為資料記憶體(Data Memory)與程式記憶體(Program)。

擷取-執行

CPU執行的基本功能就是:從記憶體中擷取指令,然後執行,如此重複這個過程。

擷取階段:
我們通常用程式計數器(Program Counter)去指定要執行的程式位址,由於程式保存在程式記憶體(Program Memory)中,因此我們需要將下一條要被執行的指令位址放到程式記憶體的位址中,接著透過讀取記憶體內容,得到需要執行的指令。

程式計數器通常將“當前數值+1”作為下一個cycle的輸入,我們可以透過操作程式計數器來達到轉跳的目的,而其輸出的值則用來指定程式記憶體的位址,並從這個位址讀取需要被執行的指令。

執行階段:
由於指令中已經包含執行所需的相關訊息(如:要執行的運算指令、記憶體或暫存器的讀寫操作、轉跳等),透過對應的指令bit去設定Control Bus的值,就可以控制各個元件達到指令的目的。

然而,在這兩個階段中其實隱藏了一個衝突的問題:我們只有一個記憶體。
由於指令與資料都保存在記憶體中,在擷取階段我們需要讀取記憶體來取得要執行的指令;而在執行階段我們也需要讀取在記憶體中的資料。
通常我們使用Multiplexer來控制記憶體的讀寫操作。
在擷取階段,記憶體讀取指令,並存放於指令暫存器(Instruction Register);在執行階段記憶體讀取的則為資料,可以直接送到ALU中。

不過其實還有另一種更簡單的解法,稱為哈佛架構(Harvard Architecture),其直接使用兩個獨立的記憶體,分別保存指令與資料。

中央處理器CPU

CPU是整個電腦的運算核心,其包含幾個介面:

  1. inM:從Data Memory (16 bits input)
  2. instruction:從Instruction Memory (16 bits input)
  3. reset:從User來的reset (1 bit input)
  4. outM:輸出的Data (16 bits output)
  5. writeM:選擇是否寫入記憶體 (1 bit output)
  6. addressM:寫入的記憶體位址 (15 bits output)
  7. PC:指定下一個要執行的指令 (15 bits output)

我們可以簡單地使用先前課程建立的ALU、register、Mux等元件來實現CPU。

指令的擷取實現

由於我們可以透過指令的op code來辨識指令類型(A type為0開頭,C type為1開頭),因此可以使用op code作為Mux的selector訊號來控制輸入A register的內容是指令記憶體,或者ALU的output。

ALU部分的實現

ALU為組合電路,意味著任何一個時候它都會接收一個輸入,並產生一個輸出。
ALU的輸入有兩種來源:

  1. D Register
  2. A Register / M-Register

同時ALU有16 bits控制訊號,用來決定執行的運算內容。

最後ALU的輸出同時會傳到D Register、A Register與M-Register,而這3個元件會透過destination bit決定是否保存輸入的資料。

此外ALU同時也會輸出一組控制訊號:

  • ZR:代表輸出為0
  • NG:代表輸出為負數

控制訊號與PC

系統從reset訊號作為整個系統開始執行的初始,其根據控制訊號來決定程式執行的順序。
在C type指令中最後3個bits用來控制jump,由於PC用來指定下一條要執行的指令,正常狀況下PC必須不斷加一,代表執行下一條指令。
然而透過C type指令中的jump bits,結合ALU運算輸出,可以用來控制PC。

將運算邏輯寫成虛擬碼如下所示:

1
2
3
4
5
6
if (reset == 1) PC = 0
else
// current instruction
load = f(jump bits, ALU control outputs)
if (load == 1) PC = A
else PC++

From Nand to Tetris系列(七)
https://chris-suo.github.io/ChrisComplete/2024/07/22/Nand2Tetris-7/
Author
Chris Suo
Posted on
July 22, 2024
Licensed under