シリーズ「コンピュータの CPU のしくみ」 第2回

回路が「命令を見分ける」とは?

届いた、パターン

前回は、手順を配線ではなく、メモリの中のパターンとして置いた。

メモリには 16 語ぶんの場所があり、0 から 15 までの番地が付いている。 番地のカウンタがクロックのたびに 1 つずつ進み、その番地の語を命令の置き場に運ぶ。 1 語は 8 桁。命令として読むときは、上 4 桁が「何をするか」、下 4 桁が「どの番地か」だった。

前回の終わりに、命令の置き場には 0010 1111 が届いていた。 人間が読めば「15 番地の数を、足す」。

けれど、回路にとっては、8 本の線のうち 4 本が 1 になっているだけだ。 「足す」という言葉を、回路は知らない。

回路は、命令をどうやって見分けるのか。

上 4 桁で、決める

まず、上 4 桁のどのパターンを、どの命令にするかを決めておこう。

前回の 3 + 5 のプログラムで使った命令は、4 つだった。

上 4 桁名前(英語の略)すること
0001持ってくる(LOAD)番地の数を、手元に置く
0010足す(ADD)番地の数を、手元の数に足す
0011書き込む(STORE)手元の数を、番地に書き込む
1111止まる(HALT)止まる

「番地」は、どれも下 4 桁が指す番地だ。止まるだけは、下 4 桁を使わない。 英語の略は、本物の CPU の説明でよく見る書き方だ。このシリーズでは、日本語の名前で進める。

0010 が「足す」なのは、そう決めたからだ。 0010 というパターンの中に、足し算らしさがあるわけではない。 0111 を「足す」にしてもよかった。 大事なのは、決めたら変えないこと。プログラムを書く人と回路を作る人が、同じ約束を守ればいい。

このシリーズでは、3 + 5 でやる順番どおり、持ってくる・足す・書き込むを 0001・0010・0011 にした。 止まるは、全部 1 の 1111 にした。

1 本だけ、1 にする

命令の置き場の上 4 桁は、4 本の線だ。 この 4 本を見て、「足す」のときに動かす箱、「書き込む」のときに動かす箱、と動かし分けたい。

4 桁のパターンは、0000 から 1111 まで、16 通りある。 そこで、4 本の線から、16 本の線を作る。 16 本には 1 本ずつパターンを受け持たせ、上 4 桁がそのパターンのときだけ、その線が 1 になるようにする。

作り方はこうだ。 0010 の線は、「8 の位が 0、4 の位が 0、2 の位が 1、1 の位が 0」のときだけ 1 になればいい。 0 であってほしい桁は NOT を通してから、4 本まとめて AND に入れる。 AND は、4 本全部が 1 のときだけ 1 を出す。

線8 の位4 の位2 の位1 の位
0001NOTNOTNOT―
0010NOTNOT―NOT
0011NOTNOT――
1111――――

表の 1 行が、AND 1 個だ。「NOT」の桁は NOT を通してから、「―」の桁はそのまま入れる。行ごとに違うのは、それだけである。

ほかの 12 本も、同じように作る。 どのパターンも、16 本のうちちょうど 1 本の AND にだけ当てはまる。 だから、1 になる線は、いつも 1 本だけだ。

4 桁のパターンを、16 本の線にほどき直すこの箱を、デコーダという。

『記憶のしくみ』を読んだ人は、第8回のデコーダを思い出してほしい。あちらは番地 2 桁から 4 本の線を作っていた。今回は 4 桁から 16 本で、作り方はまったく同じだ。

じつは、前回のメモリの中にも、同じ形のデコーダが入っている。 番地 4 桁から 16 本の線を作り、16 語のうち 1 語だけを選んでいた。 同じ箱を、今度は命令の置き場の上 4 桁につなぐ。

押して、確かめる

デコーダをつないだ回路を、押して確かめてみよう。

命令を見分ける シミュレータ

命令の置き場の左の 4 マス(上 4 桁)を押して、パターンを切り替えてみてください

命令の置き場デコーダ0000000100100011010001010110011110001001101010111100110111101111メモリ → A の箱閉加算器 → A の箱開A の箱 → メモリ閉クロックを止める閉上 4 桁(押せる)下 4 桁(この回は使わない)00101111

デコーダの線の名前は、その線が 1 になる上 4 桁のパターン。緑の「開」が、いま開いている入口

上 4 桁は 0010。デコーダの 16 本のうち、0010 の線だけが 1 になった。その先の「加算器 → A の箱」の入口が開いた。(人間は、このパターンを「足す」と呼んでいる)

試したパターン:1 / 16

  • 0000何もしない
  • 0001持ってくる
  • 0010足す
  • 0011書き込む
  • 0100(空き)
  • 0101(空き)
  • 0110(空き)
  • 0111(空き)
  • 1000(空き)
  • 1001(空き)
  • 1010(空き)
  • 1011(空き)
  • 1100(空き)
  • 1101(空き)
  • 1110(空き)
  • 1111止まる

いちばん上が、命令の置き場の 8 マス。 左の 4 つが上 4 桁で、押して切り替えられる。右の 4 つ(下 4 桁)は 1111 に決めてある。 いまは、前回の終わりと同じ 0010 1111 だ。

その下の縦長の箱がデコーダ。右の辺から 16 本の線が出ていて、それぞれの線の名前は、その線が 1 になるパターンである。 いま緑になっているのは、0010 の線だけだ。 その線の先にある「加算器 → A の箱」の入口に、「開」の字が出ている。

上 4 桁の右端(1 の位)を押して、0011 にしてほしい。

0010 の線が消えて、0011 の線だけが 1 になった。 開いている入口も、「A の箱 → メモリ」に移った。

続けて、0001 と 1111 も作ってみてほしい。 0001 では「メモリ → A の箱」が、1111 では「クロックを止める」が開く。

では、0101 ではどうだろう。 0101 の線は、ちゃんと 1 になる。 けれど、その先には何もつながっていない。短い切れ端が緑になるだけで、どの入口も開かない。

下の「試したパターン」を見ながら、16 通り全部を試してみてほしい。 どのパターンでも、1 になる線は、ちょうど 1 本だ。 2 本光ることも、1 本も光らないことも、ない。

入口が、開く

開いた入口の先で、何が起きるのかを見ておこう。

前回、3 + 5 のプログラムを読むのに、計算の途中の数を置いておく場所を「手元」と呼んだ。 ここで、それを箱にする。

4 桁の数を 1 つ覚えておける箱だ。このシリーズでは、A の箱と呼ぶ。 入ってくる数を次々に足し込んでいくこういう箱を、アキュムレータという。 『記憶のしくみ』を読んだ人は、第6回で硬貨の金額を足し込んでいったアキュムレータを思い出してほしい。A の箱は、あれと同じものだ。

持ってくる(0001)は、メモリから出てきた数を、A の箱に入れる命令だ。 足す(0010)は、加算器の答え(A の箱の数 + メモリから出てきた数)を、A の箱に入れる命令だ。

どちらも、A の箱が受け取る。 けれど、A の箱の入口は 1 つしかない。 メモリからの数と、加算器の答えを、両方つないだら混ざってしまう。

そこで、入口の手前に「通すか、0 にするか」を 2 つ置く。

  • 「メモリ → A の箱」は、0001 の線が 1 のときだけ、メモリからの数を通す
  • 「加算器 → A の箱」は、0010 の線が 1 のときだけ、加算器の答えを通す

デコーダの線は 1 本しか 1 にならないので、通るのはいつも、どちらか一方だけになる。 2 つを合流させて A の箱の入口につなげば、命令に合ったほうの数が届く。 『記憶のしくみ』を読んだ人は、第8回の「入口を、選ぶ」を思い出してほしい。アキュムレータの入口で、加算器の答えか、外から来た新しい数かを選んだ。あのときの選ぶ線を、ここではデコーダの線が引き受けている。

書き込む(0011)では、「A の箱 → メモリ」が開く。 これはメモリの書き込みの合図だ。合図が来ると、A の箱の数が、下 4 桁の番地に書き込まれる。

止まる(1111)では、「クロックを止める」が開く。 クロックが届かなくなれば、どの箱も、もう何も受け取らない。回路は止まる。

このシミュレータでは、まだ入口の合図だけを見せている。 入口を通って運ばれる数(A の箱の中身や加算器の答え)は、次回つなぐ。

意味を、知らない

さて、回路は命令を見分けたのだろうか。

0010 が届くと、0010 の AND の 4 本の入力が全部 1 になり、その出力が 1 になる。 その線が、「加算器 → A の箱」の入口につながっている。 起きたのは、それだけだ。

回路は、「足す」という言葉を、どこにも持っていない。 もし 0010 の線を「A の箱 → メモリ」の入口につなぎ替えたら、0010 は今日から「書き込む」になる。 回路にとっては、配線が変わっただけである。

前回のメモリの表の「読み方」の欄を、灰色にしておいたのを覚えているだろうか。 「足す 15 番地」は、人間のためのメモだった。 このシミュレータでも、「足す」「書き込む」という名前は、お知らせの欄と下のマスにしか書いていない。回路図の中には、どこにも無い。

『計算のしくみ』を読んだ人は、第1回を思い出してほしい。XOR と AND を並べただけの回路は、足し算を理解していないのに、答えは合っていた。ここでも同じことが起きている。

命令の上 4 桁をデコーダに通すと、動かす箱の入口が 1 つだけ開く。回路は命令の意味を知らない。どの線が 1 になるかがあるだけだ。

「見分ける」というと、何か考えているように聞こえる。 けれど、デコーダがしているのは、パターンごとに決まった 1 本の線を 1 にすることだけだ。 その線をどこにつなぐかを決めた時点で、命令の意味は、配線の中に置かれている。

使っていない、パターン

上 4 桁のパターンは 16 通りある。 いま入口につないだのは、そのうち 4 つだけだ。

残りの 12 本は、1 になっても、どこにもつながっていない。 どの入口も開かず、何も起きない。

このうち 0000 を、このシリーズでは「何もしない」と呼ぶことにする。 何も書いていない番地は 0000 0000 だから、命令として読んでも、何もしない。 14 番地や 15 番地に置いた数も、上 4 桁は 0000 だ。

ほかの 11 本は、空いている。 あとの回で、新しい命令を足したくなったら、空いている線に新しい入口をつなげばいい。 デコーダは作り直さなくていい。16 本は、はじめからそろっている。

前回の 4004 も、命令は 8 桁だった。 インテルの資料の命令の表は、8 桁を OPR と OPA という 4 桁ずつに分けて書いている。 命令は全部で 45 種類。何もしない命令は、どちらの 4 桁も 0000、つまり 0000 0000 である。

開いたら、いつ

入口は開くようになった。 けれど、まだ大事なことが決まっていない。

いつ、受け取るのか。

命令の置き場に 0010 が入った瞬間から、「加算器 → A の箱」は開いている。 A の箱は、次のクロックで受け取ればいいように思える。

ところが、次のクロックは、命令の置き場が次の命令を受け取るクロックでもある。 前回のシミュレータを思い出してほしい。メモリの箱からは、いつも、番地のカウンタが指している次の語が出てきていた。 そのクロックで A の箱も受け取れば、加算器に入るのは 15 番地の数 5 ではなく、次の命令のパターン 0011 1101 だ。 A の箱は、数ではなく、命令を足してしまう。

読むことと、こなすことを、同じクロックでやろうとしたのが間違いなのだ。

読むのとこなすのを、どう順番にすればいいか。

次回は、クロックに 2 つの役目を交互に持たせて、3 + 5 を最後まで動かしてみる。

参考文献