2026-11-02
引き続き、『コンピュータシステムの理論と実装』(通称 nand2tetris)を読み進めています。 今回は第3章「メモリ」で、値を覚えておくチップ(Register や RAM)と、数を数えるチップ(PC)を作ってみて学んだことをまとめてみました。
メモリを理解するうえで、最初に出てくるのが クロック です。クロックは、コンピュータ全体が足並みを揃えるための「拍子」のようなものです。
1回の拍子(1サイクル)は、tick と tock の2つに分かれています。
in)を受け取って、中にしまうout に出すよく見る「3.5GHz」というCPUの数字は、この tick / tock のサイクルが 1秒間に35億回 来るという意味です。
第3章で一番基本になる部品が DFF(Data Flip-Flop)です。DFFは「1サイクル前の入力を、今出す」チップです。
このDFFを使って、1ビット(0か1の1つ分)を覚える Bit、それを16個並べて16ビットの数を覚える Register を作っていきます。
RAM8 は、16ビットの Register を8個並べて、そのうちの1つを選んで読み書きできるようにしたチップです。入力は次の3つです。
in[16]: 書き込む16ビットの値load: 書き換えるかどうかaddress[3]: 読み書きする位置(3ビットなので0〜7の8か所)中身は次の流れで動きます。
address で指定された Register にだけ load の印をつけるload が1の)ものだけ、次のサイクルから in の値に書き換わるaddress で指定された Register の今保存されている値を out に返すMux8Way16 は「16ビットの数8個の中から1つを選ぶ」チップです(8Way が8個の中から選ぶ、16 が1個1個が16ビットの数という意味です)。
ここで注意したいのが、書き込んだサイクルではまだ古い値が返り、新しい値が返るのは次のサイクルから という点です。
「書き込んだらすぐ新しい値が出てくればいいのに」と思ったのですが、これには理由が2つありました。
たとえば x = x + 1 を考えます。x が Register に入っていて、ALU で +1 するとします。
もし Register がすぐに書き換わると、次のようなことが起きます。
x + 1 を計算して Register に書き込む+1 を計算して Register に書き込むALUは入力が変わるたびに勝手にまた計算してしまうので、1回だけ +1 したかったのに止まらなくなってしまいます。
ALUの答えは一瞬で決まるわけではなく、サイクルの途中では正しくない答えを出していることがあります。 すぐに覚えてしまうと、この計算途中の間違った値を覚えてしまいます。サイクルの区切りまで待ってから覚えることで、確定した正しい値だけを覚えられるわけです。
「ALUは入力が変わるたびに勝手にまた計算する」というのが気になったので、もう少し調べてみました。
チップ(たとえば Nand が入った 74HC00)の中には、トランジスタ という小さな部品が入っています。トランジスタは「電気で ON/OFF するスイッチ」です。
入力の電気が変わると、どのスイッチが閉じるかが変わって、out のつながる先が切り替わります。
つまり回路は「計算している」のではなく、入力の電気でスイッチが切り替わっているだけ です。だから入力が変わるたびに、出力も勝手に変わってしまいます。
たとえば Not の中には、スイッチが2つ入っています。
out が電源(+)につながる → 1out が GND(−)につながる → 0GND は電源のマイナス側のことです。入力に応じて out を「+ につなぐか、− につなぐか」を切り替えるだけで、0 と 1 がひっくり返るんですね。
ソフトウェアの関数のように「呼ばれたら計算する」のではなく、電気が流れている限り常に入力に反応し続けている、というのが腑に落ちました。
RAM64 は、RAM8 を8個並べたチップです。address が6ビットになり、次のように分けて使います。
address[0..2]: RAM8 の中の何番目かaddress[3..5]: 何個目の RAM8 か(何階か)ビルの「何階の何号室」のようなイメージです。RAM512、RAM4K も、1つ下のRAMを8個並べるという考え方は基本同じです。 RAM16K だけは、RAM4K を8個ではなく4個並べるので、最後の部分が DMux8Way / Mux8Way16 ではなく DMux4Way / Mux4Way16 になります。
PC(Program Counter)は、数を覚えておいて、1つずつ数えるチップです。第4章で出てくる「次に何行目の命令を実行するか」を覚えておくのに使われます。
今の値(prev)から始めて、次の順に上書きしていきます。
inc が1なら、+1 した値にするload が1なら、in の値にするreset が1なら、0 にする最後に残った値(next)を Register が覚えます。後に書いたものほど優先されるので、reset > load > inc の優先順位が自然に表現できているのが面白いなと感じました。
第3章では、DFFを土台に Register、RAM、PC と、値を覚えるチップを作っていきました。 特に「書き込んだ値は次のサイクルから反映される」という仕組みは、最初は不便に感じましたが、回路が入力に反応し続けるものだと分かってからは、暴走を防いで正しい値を覚えるために必要なんだと納得できました。