← SEARCHABLE ARCHIVE
Nand2Tetris · 2026-05-23

Nand2Tetris 韓文教材 — 完整路線圖

同時連結 12 個章節,從邏輯閘到作業系統

INTERACTIVE READING MODE →

Nand2Tetris 韓文講座資料

該部落格上撰寫的文章是出於教學目的而創建的。 另外,文章中的資訊可能不正確,請謹慎。

Nand2Tetris 是從單一 NAND 閘開始創建電腦、編譯器和作業系統的過程。 如果單獨看每一章,它看起來像是 HDL 程式碼或 Python 程式碼的集合,但實際上,上一章的結果成為下一章的材料。

晚安。 在本文中,我們將第 1 章到第 12 章的現有程式碼連結成一個流程。

全流

NAND
  ↓
邏輯閘
  ↓
加法器和ALU
  ↓
暫存器和記憶體
  ↓
破解CPU和計算機
  ↓
彙編器
  ↓
虛擬機器翻譯器
  ↓
傑克編譯器
  ↓
傑克作業系統

第 1-5 章創建硬件, 第 6-8 章創建了一個低階轉換器。 第 9-12 章介紹了高階語言、編譯器和作業系統。

第 1 章 布林邏輯與基本閘

目標

  • 僅使用 NAND 建立另一個邏輯閘。
  • 查看真值表並思考 HDL 連結。
  • 了解 Mux 和 DMux 如何選擇和分發資料。

只有當兩個輸入均為 1 時,NAND 才會輸出 0。 這可能看起來很簡單,但將輸入連接到同一行會建立 NOT,再次組合 NOT 可以建立 AND 和 OR。

Not(a) = Nand(a, a)
And(a, b) = Not(Nand(a, b))
Or(a, b) = Nand(Not(a), Not(b))

多工器是sel根據情況選擇 a 或 b。 另一方面,DMux 將一個輸入傳送到 a 或 b。

【第一章查看程式碼】(#post/120001/ko)

驗證問題

  1. 當我在 NAND 的兩個輸入上輸入相同的值時,為什麼不會發生?
  2. 讓我們來解釋一下 Mux 和 DMux 在資料方向上的差異。
  3. Mux16與 1 位元複用器有何相同之處?

第 2 章布林運算和 ALU

目標

  • 了解半加法器和全加法器的差異。
  • 我們來看看多位加法進位的過程。
  • 了解 ALU,它使用控制位執行多種操作。

半加法器將兩個位元相加以建立和和進位。 全加器接收來自前一位置的進位作為輸入。

HalfAdder: a + b
FullAdder: a + b + carry-in
Add16:連接到FullAdder的16位元加法器

ALU 的關鍵不是為每個操作創建單獨的電路。 zx, nx, zy, ny, f, no透過改變訊號的輸入和輸出,一個電路可以有多種用途。

第二章查看程式碼

驗證問題

  1. 為什麼用XOR作為加法之和?
  2. 如果在 16 位元加法中丟棄最後一個進位會發生什麼事?
  3. 算術邏輯單元zr, ng下一章中輸出將用於什麼功能?

第 3 章 時序邏輯與內存

目標

  • 了解組合邏輯和時序邏輯之間的差異。
  • 我理解DFF是儲存時間的最小單位。
  • 了解位元、暫存器、RAM 和 PC 如何擴充。

在第 1 章和第 2 章的電路中,輸出僅由電流輸入決定。 然而,記憶體必須記住前一個時鐘的值。

DFF的輸出不是目前的輸入,而是前一個時間點的輸入。 透過在此處附加一個 Mux,您可以建立一個僅在負載為 1 時儲存新值的位元。

DFF → Bit → Register → RAM8 → RAM64 → RAM512 → RAM4K → RAM16K

電腦是reset, load, inc優先事項很重要。 通常reset是最強的,然後是load,最後是inc。

【第三章查看程式碼】(#post/120003/ko)

驗證問題

  1. 讓我們用 Mux 來解釋一下當負載為 0 時,一個位元保持其現有值的過程。
  2. 為什麼 RAM8 中需要 DMux 和 Mux?
  3. 如果PC的控制訊號優先權顛倒,會出現什麼樣的bug?

第 4 章 Hack 機器語言

目標

  • 區分 A 指令和 C 指令。
  • 了解A、D、M暫存器的作用。
  • 了解分支和循環如何在彙編中表達。

A 指令將一個值放入 A 暫存器中。

@10

C 指令在一行中表達計算、儲存位置和跳躍條件。

D=M+1;JGT

M不是一個單獨的暫存器。RAM[A]方法。 如果你忽略了這一點,很容易混淆 A 暫存器是用作值還是位址。

【第四章查看程式碼】(#post/120004/ko)

實踐

  1. RAM[2] = RAM[0] + RAM[1]寫 。
  2. 寫一個從 1 到 10 相加的循環。
  3. 檢查Fill代碼中為什麼SCREEN地址是16384。

第 5 章破解電腦體系結構

目標

  • 將CPU、記憶體和ROM32K連接到一台電腦上。
  • 了解指令位如何控制 ALU 和暫存器。
  • 我們看到一個重複獲取和執行的結構。

CPU 解釋目前指令並決定將 ALU 結果儲存在哪裡:A、D 或 M。 如果跳轉條件為真,則將A暫存器的值插入PC,否則移至下一指令。

對於內存,根據位址範圍選擇 RAM16K、螢幕和鍵盤。 也就是說,只要讀寫記憶體位址就可以操作螢幕和鍵盤。

第五章代碼檢視

驗證問題

  1. instruction[15]為什麼 A/C 指令要除以 ?
  2. writeM當為1時,該值實際儲存於哪個位址?
  3. 為什麼鍵盤不需要負載訊號?

第 6 章駭客彙編器

目標

  • .asm16位元文件.hack轉換為檔案。
  • 過程標籤和變數符號。
  • 理解為什麼需要讀兩遍。

標籤不是實際指令,不應增加 ROM 位址。 所以在第一遍中(LOOP)收集相同標籤的位址,並在第二遍中翻譯實際指令。

第一次:標籤→ROM位址
第二遍:A/C指令→16位元代碼
變數符號:從RAM[16]開始依序分配

【第六章查看程式碼】(#post/120006/ko)

實踐

  1. 編寫一個預處理函數來刪除空格和註釋。
  2. 即使同一個變數出現多次,也要檢查該位址是否只分配了一次。
  3. dest, comp, jump當遇到表中沒有的輸入時,會輸出錯誤。

第 7 章 VM 轉換器 I

目標

  • 了解基於堆疊的虛擬機器。
  • 將算術指令和記憶體段轉換為 Hack 彙編。
  • 了解為什麼比較操作需要唯一的標籤。

大多數VM指令從堆疊中取得值,計算它們,然後將結果放回。

push constant 7
push constant 8
add

local, argument, this, that跟隨基底地址, temp, pointer, static每個都使用自己設定的地址規則。

【第七章查看程式碼】(#post/120007/ko)

驗證問題

  1. 為什麼push和pop改變SP的順序不同?
  2. eq, gt, lt如果您不為每個標籤建立唯一的標籤,會發生什麼情況?
  3. 為什麼靜態變數名應該包含檔名?

第 8 章 VM 轉換器 II

目標

  • Label、goto 和 if-goto 在函數範圍內處理。
  • 了解函數、呼叫和傳回的堆疊框架。
  • 了解引導程式碼的作用。

呼叫函數時,必須儲存返回位址和目前幀狀態。

return-address
LCL
ARG
THIS
THAT

返回是FRAME = LCL, RET = *(FRAME - 5)首先保存呼叫者的段,然後恢復它。 由於LCL在恢復期間發生變化,因此必須先保存RET。

【第八章查看程式碼】(#post/120008/ko)

實踐

  1. 檢查遞歸函數呼叫中的返回標籤是否不重疊。
  2. 一些.vm檢查文件的靜態段沒有衝突。
  3. 在引導程式中,將 SP 設定為 256 並Sys.init稱呼 。

第 9 章 Jack 高階語言

目標

  • 區分 Jack 的類別、建構函式、方法和函數。
  • 了解物件和陣列如何儲存在記憶體中。
  • 使用作業系統 API 處理輸入和輸出。

Jack看起來和Java很相似,但它的功能簡單得多。 物件的欄位儲存在堆中,目前物件的位址儲存在方法中。this就變成了。

建構函數分配所需大小的內存,然後this返回。 數組也更接近連續的記憶體區塊,而不是特殊的資料結構。

【第九章查看程式碼】(#post/120009/ko)

實踐

  1. 建立兩個 Counter 物件並確保值保持獨立。
  2. 連續按下按鍵輸入時防止重複處理。
  3. 解釋為什麼對於已使用的物件需要進行處理。

第 10 章 Jack 解析器

目標

  • 了解標記器將原始程式碼劃分為標記的過程。
  • Jack 語法是作為遞歸下降解析器實現的。
  • 將解析樹輸出為 XML。

字串內部的符號和註解外部的符號必須以不同的方式處理。 因此,簡單地按空格分割不會創建正確的分詞器。

解析器查看目前標記並決定呼叫哪個語法函數。

class
 ├─ classVarDec
 ├─ subroutineDec
 └─ statements

第10章代碼查看

驗證問題

  1. 在字串中//為什麼我不能用評論刪除它?
  2. 將表達式和術語分開有什麼方便?
  3. 在使用令牌之前檢查預期類型有什麼好處?

第 11 章 Jack 編譯器

目標

  • 將解析樹轉換為 VM 指令。
  • 區分類作用域和子程式作用域符號。
  • 了解方法呼叫和建構函式呼叫的隱藏行為。

符號表不僅僅儲存名稱。 類型、類型和索引儲存在一起以決定要使用哪個VM 段。

static   → static
field    → this
argument → argument
var      → local

此方法接收目前物件作為第一個參數。pointer 0連接到 構造函數的數量與字段的數量一樣多。Memory.alloc呼叫後返回地址為pointer 0把它放進去。

第11章代碼查看

實踐

  1. 檢查當同名的局部變數遮蓋欄位時選擇哪個符號。
  2. 在數組賦值中,我們組織地址和值在堆疊上儲存的順序。
  3. do查詢回傳值temp 0解釋一下丟棄的原因。

第 12 章 Jack 作業系統

目標

  • 直接實作了Jack程式使用的基礎函式庫。
  • 將數學、字串、陣列和記憶體的職責分開。
  • 它填補了硬體和高階語言之間最後的空白。

作業系統並不是以巨大的核心啟動的。 關鍵是用Jack語言實作Jack程式所期望的功能。

  • 數學:乘法、除法、絕對值
  • String:字元儲存、長度、輸出轉換
  • 數組:連續的記憶體分配
  • 記憶體:堆分配和釋放
  • 螢幕:像素和形狀輸出
  • 鍵盤:按鍵輸入
  • 輸出:輸出字母和數字
  • 系統:初始化、待機、關閉

第十二章代碼查看

驗證問題

  1. 為什麼不用CPU指令就可以實作乘法和除法?
  2. 為什麼 String 物件有單獨的長度和容量?
  3. 如果不釋放內存,Jack程式會出現什麼問題?

推薦學習順序

最好按以下順序閱讀每一章。

  1. 在查看完整的程式碼之前,請先寫下輸入/輸出和真值表。
  2. 首先測試小零件。
  3. 如果測試通過,則將其用作下一階段的組件。
  4. 如果失敗,不要只看輸出,還要找出值在哪一層發生了變化。
  5. 最後,將現有部落格程式碼與您自己的程式碼進行比較。

如果您按原樣輸入正確的代碼,該項目將很快完成。 但在 Nand2Tetris 中重要的是理解答案本身下面的一層如何支持當前層。

一旦我們看到 NAND 通往作業系統的流程,電腦似乎就不再神奇了。