2026-11-01
前回に引き続き、『コンピュータシステムの理論と実装』(通称 nand2tetris)を読み進めています。 今回は第2章「ブール算術」で出てきた、CPUの中で計算を担当する ALU について学んだことをまとめてみました。
ALU(Arithmetic Logic Unit、算術論理演算装置)は、CPUの中で計算を担当している部品のことです。
JavaScriptで例えると、ALUは「計算の種類を引数で選べる関数」のようなものです。
x と y という2つの値と「どの計算をするか」を受け取って、結果を1つ返します。nand2tetrisのALUでは、この「計算の種類」で全部で18種類の計算を選べます。
18種類の計算ができると言いましたが、実はALUが本当にできるのは 「足し算」と「And」の2つだけ です。
足し算はそのままですが、Andができると次のようなことができます。
たとえば x & 1 とすると一番右のビットだけが取り出せるので、結果が 1 なら奇数、0 なら偶数だと分かります。
では、この2つだけでどうやって18種類の計算をするのかというと、計算する前に入力を「下ごしらえ」する ことで実現しています。
下ごしらえは次の流れで行います。
x と y に分ける(5 + 3 でいう 5 と 3 のこと)x と y をそれぞれ4通りに下ごしらえする(4 × 4 通り)x の下ごしらえは、zx と nx という2つのフラグ(ON/OFFのスイッチ)で決まります。
zx(zero x): x を0にするかどうかnx(negate x): x のビットを反転するかどうかこの2つの組み合わせで、x は次の4つのどれかに変わります(x = 5 = 0101 の例。実際のALUは16ビットですが、ここでは分かりやすく4ビットで書いています)。
| zx | nx | 何をする? | 出てくるもの |
|---|---|---|---|
| 0 | 0 | 何もしない | 0101(x) |
| 0 | 1 | 反転だけ | 1010(!x) |
| 1 | 0 | 0 にするだけ | 0000(0) |
| 1 | 1 | 0 にしてから反転 | 1111(-1) |
1111 が -1 になるのは、コンピュータでは負の数を 2の補数(全ビットを反転して1を足す表現)で表すためです。0001(1)を反転すると 1110、そこに1を足すと 1111 になるので、1111 は -1 を表します。
y も同じように、zy と ny の2つのフラグで y、!y、0、-1 の4通りになります。
下ごしらえした x と y に対して、f というフラグで「足し算」と「And」のどちらをするかを選びます。さらに no というフラグで、最後に結果を反転するかどうかを選べます。
この組み合わせで、たとえば引き算 x - y は次のように作れます。
x を反転して !x にする(nx = 1)!x + y を計算する(f = 1)no = 1)2の補数では !a = -a - 1 なので、!(!x + y) = -((-x - 1) + y) - 1 = x - y となり、足し算と反転だけで引き算ができてしまいます。
引き算という専用の機能を持たなくても、入力と出力をひっくり返す組み合わせだけで別の計算が作れるのは面白いなと感じました。
ALUは計算結果の out に加えて、結果がどういう状態かを表す2つの出力も返します。
zr(zero): out が0なら1ng(negative): out が負の数なら1ng は、2の補数では一番左のビット(最上位ビット)が1なら負の数になるので、そのビットを見るだけで判定できます。zr は第1章で作った Or8Way を使って「どれか1ビットでも1があるか」を調べ、それをひっくり返すことで判定できます。
この2つは、後の章で「結果が0ならジャンプする」といった条件分岐に使われます。
ALUは18種類の計算ができる部品ですが、中身は「足し算」と「And」の2つだけで、残りは入力を0にしたり反転したりする下ごしらえの組み合わせで作られていました。 第1章で作ったMuxやNotが、この「0にする/しない」「反転する/しない」を選ぶところでそのまま使われているのも、つながりが見えて良かったです。