Nand to Tetris(nand2tetris)は、NANDゲートという1種類の論理素子だけを出発点に、16ビットCPU・アセンブラ・コンパイラ・OSまでを自分の手で組み上げる教材です。名前の印象からテトリスを作る講座だと思われがちですが、実際に作るのはテトリスが動く土台のコンピュータそのもので、提出課題は12本のプロジェクトに分かれています。この記事では公式サイトと公式配布リポジトリの内容をもとに、12プロジェクトの中身、書籍『コンピュータシステムの理論と実装 第2版』との対応、実際に書くHDL・アセンブリ・VMコードの形、そして多くの学習者が止まる工程までを整理します。
まとめ:Nand to Tetrisの全体像と着手前に押さえる要点
- 提出課題は12プロジェクト。公式サイトは「The complete Nand to Tetris journey spans 12 projects, divided into two parts.」と明記し、Part I(ハードウェア)がプロジェクト1〜6、Part II(ソフトウェア)がプロジェクト7〜12です。
- 書籍は全13章。プロジェクト数(12)と章数(13)は一致しません。13章「さらなる冒険へ」に対応する提出課題は無く、公式リポジトリの
projects/13に入っているのはmore fun to go.txtという案内テキスト1本だけです。 - NANDゲート自体は作りません。プロジェクト1で実装するのは Not から DMux8Way までの15チップで、Nandは組み込み済みの原始素子として与えられます。
- 環境構築は不要になりました。公式のWeb版IDEがブラウザだけで動きます。デスクトップ版はJavaプログラムなので、Javaランタイムが無い端末ではWeb版一択です。
- 詰まる場所はほぼ決まっています。プロジェクト5(CPU)とプロジェクト8(VMの関数呼び出し)は、複数の制御状態を扱うため工程が複雑です。ここだけは時間を厚く見積もってください。
以降で、12プロジェクトの中身と、各段階で実際に書くコードの形を順に見ていきます。
Nand to Tetrisの全体像:12プロジェクトで完成するHackコンピュータ
Nand to Tetris は Noam Nisan 氏と Shimon Schocken 氏による教材で、テキストはMIT Pressから出ています。定めるゴールは、Hack という名前の16ビットコンピュータを、論理ゲートの一段目からOSまで通しで作り切ること。抽象化の階層を上から説明するのではなく、下から順に積み上げて「なぜその層が必要なのか」を手を動かして確かめさせる構成です。
コースの12プロジェクトと書籍13章の対応関係
公式サイトのコースページに載っている12プロジェクトと、邦訳書『コンピュータシステムの理論と実装 第2版』の章立ての対応は次のとおりです。
| 区分 | プロジェクト | 課題名 | 書籍の章 |
|---|---|---|---|
| Part I ハードウェア | 1 | Boolean Logic | 1章 ブール論理 |
| Part I ハードウェア | 2 | Boolean Arithmetic | 2章 ブール算術 |
| Part I ハードウェア | 3 | Memory | 3章 メモリ |
| Part I ハードウェア | 4 | Machine Language | 4章 機械語 |
| Part I ハードウェア | 5 | Computer Architecture | 5章 コンピュータアーキテクチャ |
| Part I ハードウェア | 6 | Assembler | 6章 アセンブラ |
| Part II ソフトウェア | 7 | VM I: Stack Arithmetic | 7章 仮想マシン1 |
| Part II ソフトウェア | 8 | VM II: Program Control | 8章 仮想マシン2 |
| Part II ソフトウェア | 9 | High-Level Language | 9章 高水準言語 |
| Part II ソフトウェア | 10 | Compiler I: Parsing | 10章 コンパイラ1 |
| Part II ソフトウェア | 11 | Compiler II: Code Generation | 11章 コンパイラ2 |
| Part II ソフトウェア | 12 | Operating System | 12章 OS |
| (課題なし) | - | - | 13章 さらなる冒険へ |
解説記事でしばしば「全12章」と書かれますが、書籍は13章構成です。ずれるのは13章が読み物で、提出物を伴わないからです。公式GitHubリポジトリ nand2tetris/projects を見ると projects/01 から projects/13 までディレクトリは並んでいるものの、13だけは more fun to go.txt しか置かれていません。学習計画を立てるときは「12本の課題+読み物1章」と数えるのが実態に合います。
完成するHackコンピュータの仕様とメモリマップ
作るコンピュータの仕様は最初から固定されていて、途中で設計を選ぶ余地はほとんどありません。Hackは16ビットのマシンで、命令メモリは ROM32K、データメモリは RAM16K です。公式が配布する Memory.hdl のヘッダコメントが、アドレス空間の規約をそのまま書いています。使われるのは 16K+8K+1 ワード。0x4000(10進16384)から 0x5FFF がスクリーンのメモリマップ、0x6000(同24576)がキーボードで、0x6000 を超えるアクセスは不正です。画面は512列×256行の白黒で、8Kワードがそのまま画素のビット列に対応します。
CPU側も同様で、CPU.hdl のヘッダは「ALU、AとDという2本のレジスタ、PCという名前のプログラムカウンタから構成される」と定義しています。Hack CPUのALUはDレジスタと、Aレジスタまたは Memory[A] を入力に取り、結果をA・D・Memory[A]へ格納できます。プロジェクト7・8では、高水準言語とHack機械語の中間層として、スタック方式のVMとVM変換器を実装します。画面出力もメモリ書き込みだけで完結するので、割り込みもデバイスドライバも登場しません。FPGAとは何か?フィールドプログラマブルゲートアレイの定義と基本原理を解説で扱うような実チップの制約は入らない、教育用に絞り込んだ設計です。
ハードウェア編:NAND 1種類から15チップを組み上げる(プロジェクト1〜5)
Part I では、論理ゲートから始めて動くCPUまでを作ります。記述言語は教材専用のHDLで、VerilogでもVHDLでもありません。文法は付録Bにまとまる程度の小ささで、覚えることはほとんどありません。
プロジェクト1で実装する15チップとHDLの書き方
プロジェクト1で作るのは Not、And、Or、Xor、Mux、DMux、Not16、And16、Or16、Mux16、Or8Way、Mux4Way16、Mux8Way16、DMux4Way、DMux8Way の15チップです。Nandは対象外で、公式ページは「except for the Nand chip, which is considered primitive, and thus there is no need to implement it.」と明記しています。NANDだけは天から与えられ、そこから先は全部自分で作るというのがこの教材の設計思想です。
配布される .hdl ファイルは、入出力の宣言だけが書かれた骨組みです。たとえば Mux.hdl は次の状態で渡されます。
CHIP Mux {
IN a, b, sel;
OUT out;
PARTS:
// Put your code here:
}
学習者は PARTS: の下に、部品チップの結線を1行ずつ書き足します。チップは1つにつき1つの .hdl ファイルで、Not.hdl には Not だけを書きます。
ここに完成コードは載せません。公式ライセンスが「don’t post solutions publicly on the web, e.g. in blogs, forums, or Github-like places.」と、解答をブログ等へ公開しないよう明示的に求めているためです。代わりに考え方だけ示します。Not は NAND の両端に同じ信号を入れれば得られます。And はその Not を NAND の出力に重ねる形、Or はド・モルガンの法則から両入力を反転して NAND に通す形、Xor は Not・And・Or を部品として組み合わせる形になります。
Xor から先で重要なのは、いま作ったチップをそのまま部品として呼べる点です。1段前に作ったものが次の段の語彙になるという積み上げが、12プロジェクトを通して最後まで続きます。答え合わせは自分の手元で、次に説明するテストスクリプトが自動でやってくれます。
.tstと.cmpで進める合否判定の流れ
実装したHDLは、付属のハードウェアシミュレータにテストスクリプトを読ませて検証します。プロジェクトごとに .tst(テスト手順)と .cmp(期待出力)が最初から配られているので、答え合わせは自動です。Not.tst の中身はこうなっています。
load Not.hdl,
output-file Not.out,
compare-to Not.cmp,
output-list in%B3.1.3 out%B3.1.3;
set in 0,
eval,
output;
set in 1,
eval,
output;
対応する Not.cmp は次の3行です。
| in | out |
| 0 | 1 |
| 1 | 0 |
シミュレータが生成した .out と .cmp は空白文字の違いを無視して比較され、値や列が異なると不一致として止まります。採点基準が数値で固定されているので、「たぶん動いた」で先へ進めません。この仕組みのおかげで独学が成立します。なお .hdl ファイルを置いていないチップは、シミュレータが組み込み実装で肩代わりします。プロジェクト2以降で詰まったときも、上流のチップは組み込み版に任せて先に進めます。
プロジェクト2〜5:ALU・記憶素子・CPUの組み立て
プロジェクト2で作るのは HalfAdder、FullAdder、Add16、Inc16、ALU の5チップです。半加算器から積み上げて、最後にALUへ到達します。プロジェクト3で扱うのは記憶素子で、D型フリップフロップ(DFF)はシミュレータ側の組み込みチップとして与えられ、そこから Bit、Register、RAM8、RAM64、RAM512、RAM4K、RAM16K、PC の順にアドレス幅を広げていきます。プロジェクト4はハードウェアを離れ、Hack機械語でプログラムを2本書く回です。R0とR1の積を求める Mult.asm と、キー入力に応じて画面を白黒反転させる Fill.asm の2本で、後者で初めてスクリーンのメモリマップを直接叩きます。
山はプロジェクト5です。作るチップは Memory.hdl、CPU.hdl、Computer.hdl の3本しかありませんが、CPUは命令のデコード・ALUへの入力選択・ジャンプ判定・PCの更新を1枚のHDLに詰め込むことになります。公式のFigure 5.9で命令ビットと制御線の対応を確認してから着手すると、配線ミスを切り分けやすくなります。チップ数が少ない回ほど重いと考えてください。
機械語とアセンブラ:A命令とC命令を16ビットへ翻訳する(プロジェクト4・6)
Hack機械語の命令は2種類だけです。@値 と書くA命令のビット構成は 0vvvvvvvvvvvvvvv で、先頭が0、残り15ビットに値かアドレスがそのまま入ります。計算を指示するC命令は 111accccccdddjjj で、先頭3ビットが 111、続く7ビット(aを含む comp)が演算内容、3ビットの dest が格納先、3ビットの jump が分岐条件です。命令形式が2種類に絞られており、公式はシンボルなしの変換とシンボル対応の2段階で実装する方法を示しています。
プロジェクト6で最初に通す公式サンプル Add.asm は、RAM[0] に 2+3 を書き込むだけのプログラムです。
// Computes R0 = 2 + 3 (R0 refers to RAM[0])
@2
D=A
@3
D=D+A
@0
M=D
これを仕様どおりに符号化すると、次の6ワードになります。
| アセンブリ | 機械語(2進16ビット) | 種別 |
|---|---|---|
| @2 | 0000000000000010 | A命令 |
| D=A | 1110110000010000 | C命令 |
| @3 | 0000000000000011 | A命令 |
| D=D+A | 1110000010010000 | C命令 |
| @0 | 0000000000000000 | A命令 |
| M=D | 1110001100001000 | C命令 |
C命令の3行目を分解すると、先頭 111、a ビットが 0(Aレジスタを参照)、comp が 000010(D+A)、dest が 010(Dへ格納)、jump が 000(分岐なし)です。6命令を実行し終えた時点で RAM[0] は 5 になります。アセンブラの実装で本当に手間がかかるのはこの符号化ではなく、シンボル解決のほうです。ラベル定義を集める1パス目と、命令を出力する2パス目に分けないと、前方参照のジャンプで破綻します。
命令列を生成して実行するという構図は、実行時に機械語を吐く現代の処理系と同じです。仕組みの違いはJITコンパイラとは?仕組み・種類とAOT・インタプリタの違いをわかりやすく解説で整理しています。
ソフトウェア編:VM変換器・コンパイラ・OS(プロジェクト7〜12)
ここから先が Part II です。VM変換器・コンパイラ・OSを扱う区間で、分量としてはこちらのほうが重くなります。
プロジェクト7・8:スタックマシン方式のVM変換器
Hack CPU にはレジスタが2本しかないため、高水準言語を直接機械語へ落とすと式の評価で行き詰まります。そこで中間層としてスタックマシンのVMを挟みます。プロジェクト7では push/pop/算術命令を扱い、プロジェクト8で分岐と関数呼び出しの命令を追加します。公式サンプル SimpleAdd.vm は3行で終わります。
// Pushes and adds two constants.
push constant 7
push constant 8
add
これを検証する SimpleAdd.tst は実行前に set RAM[0] 256 でスタックポインタを初期化し、期待値ファイル SimpleAdd.cmp は RAM[0]=257、RAM[256]=15 を要求します。定数を2つ積んで加算した結果、スタックの底に15が残りポインタが1つだけ進んでいる、という状態を数値で突き合わせる仕組みです。
プロジェクト7は算術とメモリセグメントまでで、比較的素直に進みます。難所はプロジェクト8の関数呼び出しです。call/function/return を実装するには、戻りアドレス・呼び出し元のLCL・ARG・THIS・THAT をスタックに退避し、return で正しい順序に復元する必要があります。ここでフレームの復元順を間違えると、誤りが後続の命令を実行した段階で表面化することがあります。CPUエミュレータのステップ実行に加え、生成したASMの確認と、公式テストプログラムによる段階的な検証が有効です。
プロジェクト9〜11:Jack言語とコンパイラ
プロジェクト9で扱う Jack は、教材専用のオブジェクト指向言語です。Java風の文法を持ちながら、仕様は大胆に削られています。公式Web IDEに含まれるJackの文法定義を読むと、型は int・char・boolean・クラス名の4種類しか許されず、式は「項と演算子の並び」を平坦に受けるだけで演算子の優先順位が定義されていません。2 + 3 * 4 は左から順に評価され、Jackでは20になります。この割り切りは学習者の都合ではなく、コンパイラを自力で書き切れるようにするための設計です。プロジェクト9自体は Jack でアプリを1本書くだけの回で、提出物はコンパイラではありません。
プロジェクト10は構文解析器を作り、Jackのソースを構文木のXMLとして出力させます。プロジェクト11でそのXML出力をVMコード生成に差し替え、シンボルテーブルでスコープと変数の割り当てを管理します。10と11が分かれているのは、構文解析の正しさを先に確定させてからコード生成に進ませるためで、この順を飛ばして一気に書こうとすると、構文の誤りとコード生成の誤りが混ざって切り分け不能になります。
プロジェクト12:Jack OSの8クラス
最後のプロジェクト12は、Jack言語で書かれた標準ライブラリの実装です。公式リポジトリの projects/12 に置かれている実装対象は8クラスで、Math、Memory、Screen、Output、Keyboard、String、Array、Sys が並びます。
内容は現代のOSが持つ機能とはかなり違います。プロセス管理もファイルシステムもスケジューラも無く、実装するのは演算とI/Oの土台です。Math では multiply・divide・sqrt を書きます(Jackの * と / はコンパイラがこの関数呼び出しへ変換するため、掛け算すら自分の実装に依存します)。Memory は32,768ワードのRAMに対する peek・poke と、ヒープの alloc・deAlloc を担当します。Screen は256行×512ピクセルの画面に対する直線・矩形・円の描画で、円は半径181以下という制限付きです。ここでいうOSは標準ライブラリの意味で、カーネルは登場しません。実際のOSの中核が何を担うかはカーネルとは?OSの中核が担う役割と仕組みを実装目線で解説【2026年版】と読み比べると差がはっきりします。8クラスすべてを自作の実装に差し替えたうえで、Pong や Tetris のような Jack アプリが動けば完走です。
教材の入手と学習環境:Web IDE・書籍第2版・オンライン講座の選び方
教材本体は nand2tetris.org で公開されています。講義資料、プロジェクトのひな形ファイル、テストスクリプト、期待値ファイル、シミュレータのすべてが対象で、費用をかけずに最後まで進められます。ただし無料・オープンソースでの提供は非営利目的での利用を条件としているので、社内研修に転用する場合はこの条件を確認してください。
ツールの入手方法は2通りあります。公式サイトは Web版について「This new Integrated Development Environment is web-based, meaning that you don’t have to download anything.」と説明しており、ブラウザだけで HDL の編集からテスト実行まで完結します。デスクトップ版は「The tools are implemented as Java programs that run on your local PC」とあるとおりJavaプログラムなので、Javaランタイムを入れていない端末では動きません。特別な理由がなければWeb版を選んでください。バージョン差による起動トラブルを丸ごと回避できます。
日本語で読みたい場合は邦訳書があります。『コンピュータシステムの理論と実装 第2版 モダンなコンピュータの作り方』(オライリー・ジャパン、2024年12月2日発行、472ページ、ISBN 978-4-8144-0087-4、斎藤康毅 訳)が現行版です。第1版は2015年3月25日発行の416ページで、どちらも本編は13章構成ですが、付録が第1版のA〜Cの3本から第2版ではA〜Gの7本に増え、「オンラインIDEの使い方」が加わりました。Web版ツールを前提に学ぶなら第2版を選ぶことになります。
講義形式で進めたい場合は Coursera に「Build a Modern Computer from First Principles: From Nand to Tetris (Project-Centered Course)」とその続編「Nand to Tetris Part II」があります。扱うプロジェクトの範囲は公式サイトの配布物と同じなので、講義動画と受講証明が必要かどうかで判断すれば足ります。
詰まりやすい工程と、着手を見送るべきケース
12プロジェクトは難易度が均等ではありません。時間配分を誤ると、山の手前で息切れします。
最初の関門はプロジェクト5のCPUです。ここまでは仕様書に書かれた真理値表をHDLに写せば通りますが、CPUだけは16ビットの命令語をどう制御線へ配るかを自分で設計します。公式はCPUをFigure 5.9の提案実装に沿って構成し、MemoryとCPUを単体テストしてからComputerへ進むよう勧めています。二つ目の関門がプロジェクト8の関数呼び出しで、スタックフレームの退避と復元を実装します。バグが表面化する場所と原因の場所が離れるため、机上のデバッグが効きません。
一方で、着手を見送ったほうがよいケースもはっきりしています。業務で使うスキルを最短で得たい人には向きません。作るのは実在しない教育用アーキテクチャで、Verilogも書かず、x86やArmの命令セットも扱わず、成果物をそのまま業務へ持ち込むことはできません。実チップの設計フローを学びたいならOpenLane2とは何か?RTLからGDSIIまで対応する新世代オープンソースEDAフロー基盤の概要と特徴で扱うRTLからGDSIIまでの流れを追うほうが目的に合います。
逆に、抽象化の各層を一つの環境で実装し、その接続を確かめたい人には目的の合う教材です。判断の分かれ目は「何かを作れるようになりたいのか、仕組みを納得したいのか」です。後者ならやる価値があります。
進め方としては、Part I を通しで終えてから Part II に入るより、プロジェクト6のアセンブラを好きな言語で書く段階で一度立ち止まることを勧めます。ここまでで「回路→機械語」の往復が閉じるので、区切りとして自然です。Part II は言語処理系の実装が主題になり、必要な体力の質が変わります。
よくある質問
Nand to Tetris は日本語で学べますか?
教材本体(公式サイト・シミュレータ・課題ファイル)は英語のみですが、テキストは邦訳されています。『コンピュータシステムの理論と実装 第2版』(オライリー・ジャパン、2024年12月2日発行、472ページ、斎藤康毅 訳)が現行版で、13章すべてと付録A〜Gが日本語で読めます。課題ファイル内のコメントやテストスクリプトは英語のままですが、書式が定型なので読解の負担は小さいです。
『コンピュータシステムの理論と実装』第2版は第1版と何が違いますか?
本編は第1版・第2版とも13章構成で、扱うプロジェクトの範囲も変わりません。差が出るのは分量と付録で、第1版が416ページ・付録A〜Cの3本だったのに対し、第2版は472ページ・付録A〜Gの7本に増えています。第2版で加わった付録には「オンラインIDEの使い方」が含まれ、ブラウザ版ツールを前提とした説明になっています。章タイトルも一部が改められ、3章は「順序回路」から「メモリ」へ、13章は「さらに先へ」から「さらなる冒険へ」へ変わりました。
NANDゲートだけであらゆる論理演算を作れるのはなぜですか?
NANDは機能的完全性を持つ演算だからです。両入力に同じ信号を入れた NAND は NOT として働き(NAND(x, x) = NOT x)、NOT が作れれば NAND の出力を反転して AND が得られます。OR はド・モルガンの法則から、両入力を反転して NAND に通せば求まります。AND・OR・NOT がそろえば任意の論理関数を構成できるため、NANDひとつを原始素子に置けば足ります。Nand to Tetris のプロジェクト1は、この性質を15チップの実装で確かめる回です。
プログラミング未経験でもCPUを自作できますか?
プロジェクト1〜5までは、HDLで結線を書くだけなので未経験でも進められます。ただしプロジェクト6以降は、アセンブラ・VM変換器・コンパイラを好きな言語で自分で実装する課題になります。少なくとも、選んだ言語でテキストファイルを読み、仕様に沿って解析・変換するプログラムを書けることが必要です。未経験から始めるなら、Part I を終えた時点で一度プログラミング言語の学習に戻るのが現実的です。
テトリスは自分で作るのですか?
いいえ。12プロジェクトの提出物にテトリスの実装は含まれません。名前が示しているのは「NANDゲートから出発してテトリスが動くところまで到達する」という射程で、作るのはテトリスを動かす側のコンピュータです。完成したプラットフォーム上では、Jack で書かれた Pong などのサンプルアプリを動かせます。自作のゲームを載せたい場合は、プロジェクト9の課題として Jack で書くことになります。