シリーズ「コンピュータの CPU のしくみ」 第5回
回路が「分かれる」とは?
見てから、決める
ここまでの 4 回を、短く振り返っておこう。
手順を 0 と 1 のパターンにして、メモリに並べた。1 つぶんの手順が命令で、上 4 桁が「何をするか」、下 4 桁が「どの番地か」だ(第1回)。 上 4 桁をデコーダに通すと、16 本の線のうち 1 本だけが 1 になり、その先の入口が開く(第2回)。 クロックを「読む拍」と「こなす拍」に分けて交互に回すと、命令が上から順に実行された(第3回)。 そして、番地のカウンタの入口の手前に選ぶ箱を置くと、命令の下 4 桁へ飛べるようになった(第4回)。
前回の終わりに、こう書いた。
飛ぶ命令は、そこに着いた瞬間に、飛ぶ。足し算の答えが何であっても、飛ぶ。 けれど、ランプ C は、15 + 5 のときだけ点いて、あとは消えていた。ランプ C は「計算の結果」を覚えている。
計算の結果を見て、飛ぶか飛ばないかを決められないか。
ただ、いまのランプ C が教えてくれるのは「4 桁からあふれた」ことだけだ。 本当に知りたいのは、たとえば「どちらの数が大きいか」のようなことだろう。
2 つの数を比べるには、どうすればいいか。 片方から、もう片方を引いてみればいい。
引く
この回路には、加算器しかない。引き算をする箱は無い。 けれど、新しい箱は要らない。引き算は、足し算に化けさせられる。
やり方は 2 つだけだ。
- 引く数の 4 桁を、すべて反転する(0 を 1 に、1 を 0 に)
- そのうえで、1 を足す
たとえば 7 − 3。3 は 0011。反転すると 1100(12)。
7 + 12 + 1 = 20。2 進数で 10100。
5 桁目の 1 を捨てると、0100。4 だ。 7 − 3 の答えになっている。
なぜこれでうまくいくのかは、次の節で見る。先に、回路に組み込もう。
命令に、新しい上 4 桁を割り当てる。0100、引くだ。
「引く 15 番地」は、A の箱から、15 番地の数を引いて、答えを A の箱に入れる。
デコーダの 0100 の線は、これまで、どこにもつながっていなかった。ここを 3 か所につなぐ。
- 加算器の手前に、反転の箱を置く。中身は XOR が 4 つ。線
0100が 1 のときだけ、メモリから出てきた数を反転する。0 なら素通りだ - 加算器の、いちばん下の桁の繰り上がりの入口。これまでは、いつも 0 だった。ここに線
0100をつなぐ。引くときだけ、1 が足される - 「加算器 → A の箱」の入口。足すの線
0010か、引くの線0100のどちらかが 1 なら開く。ランプ C も、足すか引くのときに受け取る
加算器の中身は、1 つも変えていない。変わったのは、入口につながる線だけだ。
反転の箱と加算器だけを、取り出してみよう。
A の箱の数は 7 に決めてある。上の 4 つのマスで引く数を、左のスイッチで線 0100 を切り替えてほしい。
線 0100 が 0 のときは、ただの足し算だ。7 + 3 = 10。
1 にすると、反転の箱が青くなって 0011 を 1100 に変え、加算器の「+1」に 1 が入る。答えは 0100、4 になる。
『計算のしくみ』を読んだ人は、第3回の「スイッチ 1 つで、両方をやる」を思い出してほしい。モードのスイッチ 1 本が、XOR の反転と、いちばん下の +1 の両方を引き受けていた。あのスイッチの役を、ここではデコーダの線 0100 が引き受けている。
5 桁目のランプ
さっきの 7 − 3 では、7 + 12 + 1 = 20 で、5 桁目に 1 があふれた。 加算器の 5 桁目は、ランプ C に入る。だから、引いたあと、ランプ C が点く。
では、3 − 7 ならどうか。
7 は 0111。反転すると 1000(8)。3 + 8 + 1 = 12。1100 で、5 桁目は 0。
ランプ C は、消える。
答えの 1100 は 12 だ。0〜15 の読み方では、3 − 7 の答えになっていない。3 から 7 は、引ききれないのだ。
どうしてこうなるのか。
4 桁の数 n を反転したものは、1111 − n、つまり 15 − n だ(1 の桁は 0 に、0 の桁は 1 に。どの桁も繰り下がらない)。
だから、引くとき加算器が計算しているのは、
A +(15 − n)+ 1 = A + 16 − n
16 は 10000、ちょうど 5 桁目の 1 だ。
- A が n 以上なら、A − n は 0 以上。A + 16 − n は 16 以上になり、5 桁目に 1 があふれる。 残った 4 桁が A − n だ
- A が n より小さいなら、A + 16 − n は 16 に届かない。5 桁目は 0 のまま
ランプ C は、引く前の A が、引く数以上かを、そのまま教えてくれる。
引く前の A と引く数の、256 通りを全部並べてみよう。緑のマスが、ランプ C が点いた引き算だ。
| A\数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | ||||||||||||||||
| 1 | ||||||||||||||||
| 2 | ||||||||||||||||
| 3 | ||||||||||||||||
| 4 | ||||||||||||||||
| 5 | ||||||||||||||||
| 6 | ||||||||||||||||
| 7 | ||||||||||||||||
| 8 | ||||||||||||||||
| 9 | ||||||||||||||||
| 10 | ||||||||||||||||
| 11 | ||||||||||||||||
| 12 | ||||||||||||||||
| 13 | ||||||||||||||||
| 14 | ||||||||||||||||
| 15 |
緑は、左下の三角形にきれいに並ぶ。どの行も、A と同じ数の列までが緑で、その右から灰色になる。 ランプ C =「A は、その数以上」。 256 通りのうち、例外は 1 つもない。
『計算のしくみ』を読んだ人は、第4回の「5 桁目のランプが教えていたこと」を思い出してほしい。引き算でランプが消えるのは、0〜15 の読み方で答えが 0 を割り込んだという知らせだった。ここで使うのは、その知らせそのものだ。
同じランプでも、足すのあとは「4 桁からあふれた」、引くのあとは「引く前の数が、その数以上」を覚えている。 ランプは、最後に加算器を使った命令の 5 桁目を覚えているだけだ。読み方を決めるのは、手順のほうだ。
ランプなら、飛ぶ
比べた結果は、ランプ C に残った。 あとは、それを見て、飛ぶかどうかを決めればいい。
命令に、もう 1 つ上 4 桁を割り当てる。0110、ランプなら飛ぶだ。
ランプ C が点いていれば、番地のカウンタを命令の下 4 桁に書き換える。消えていれば、何もしない。番地のカウンタは、いつもどおり次の番地を指したままだ。
回路に足すものは、少ない。 前回作った次の番地を選ぶ箱は、こうなっていた。
- 線
0101(飛ぶ)AND こなす拍 → 命令の下 4 桁を通す
ここに、もう 1 つ条件を足す。
- 線
0110(ランプなら飛ぶ)AND こなす拍 AND ランプ C → 命令の下 4 桁を通す
2 つを OR で合流させる。どちらかが 1 なら、下 4 桁を通す。 ランプ C の線を、1 本、選ぶ箱に引き込むだけだ。
選ぶ箱だけを取り出したのが、下の図だ。
1 を足した数は 0100(4)、命令の下 4 桁は 0110(6)にしてある。あとで動かす「3 番地の、ランプなら飛ぶ 6 番地」を読んだ場面と同じ数だ。
線 0110 とこなす拍を 1 にしても、ランプ C が 0 なら「+1」のまま。3 つとも 1 にしたときだけ「下 4 桁」に変わる。
線 0101 のほうは、前回と同じく、ランプ C に関係なく飛ぶ。
番地のカウンタが受け取る合図にも、同じ条件を足す。
- 読む拍のクロック(これまでどおり)
- 飛ぶ拍のクロック … こなす拍のクロック AND 線
0101(前回) - ランプなら飛ぶ拍のクロック … こなす拍のクロック AND 線
0110AND ランプ C
3 つを OR で合流させる。
ここで、前回と同じ落とし穴がある。条件は、どれも省けない。
選ぶ箱から「こなす拍」を外すと、飛んだ次の読む拍で困る。命令の置き場には、まだランプなら飛ぶが残っていて、ランプ C も点いたままだ。読む拍なのに下 4 桁が選ばれ、番地のカウンタは 1 進まない。前回の飛ぶと、まったく同じことが起きる。
合図から「ランプ C」を外すと、今度は飛ばないときに困る。ランプ C が消えていても、こなす拍に番地のカウンタが受け取ってしまう。そのとき選ぶ箱が通しているのは「+1 した数」だ。番地のカウンタは 1 余計に進み、次の命令を 1 つ読み飛ばす。
あとで動かすプログラムを、本物の回路と、条件を 1 つずつ外した回路で回した記録が、下の表だ。
表の数は、どれもその拍が終わったあとの値
| 拍 | 段階 | 命令の置き場 | 番地のカウンタ | 13 番地 |
|---|---|---|---|---|
| 1 | 読む | 0001 1110 | 1 | 0 |
| 2 | こなす | 0001 1110 | 1 | 0 |
| 3 | 読む | 0011 1101 | 2 | 0 |
| 4 | こなす | 0011 1101 | 2 | 7 |
| 5 | 読む | 0100 1111 | 3 | 7 |
| 6 | こなす | 0100 1111 | 3 | 7 |
| 7 | 読む | 0110 0110 | 4 | 7 |
| 8 | こなす | 0110 0110 | 6 | 7 |
| 9 | 読む | 1111 0000 | 6 | 7 |
| 10 | 止まる | 1111 0000 | 6 | 7 |
「合図から『ランプ C』を外す」のボタンで「3 と 7」を選ぶと、8 拍目に番地のカウンタが 4 ではなく 5 になる。4 番地を読み飛ばして、13 番地には 7 ではなく 12 が入ってしまう。 ランプ C は、選ぶ箱と、受け取る合図の、2 か所に要る。
押して、確かめる
2 つの数のうち、大きいほうを 13 番地に書き込むプログラムを置いた。
| 番地 | 中身 | 読み方 |
|---|---|---|
| 0 | 0001 1110 | 持ってくる 14 番地 |
| 1 | 0011 1101 | 書き込む 13 番地 |
| 2 | 0100 1111 | 引く 15 番地 |
| 3 | 0110 0110 | ランプなら飛ぶ 6 番地 |
| 4 | 0001 1111 | 持ってくる 15 番地 |
| 5 | 0011 1101 | 書き込む 13 番地 |
| 6 | 1111 0000 | 止まる |
| 13 | 0000 0000 | 大きいほうを置く場所 |
| 14 | 0000 0111 | 数 7(1 つ目) |
| 15 | 0000 0011 | 数 3(2 つ目) |
考え方は、こうだ。
- まず、1 つ目の数を、ひとまず 13 番地に書いておく(0・1 番地)
- 1 つ目から 2 つ目を引いてみる(2 番地)。ランプ C が点けば、1 つ目は 2 つ目以上だ
- 点いていれば、そのまま止まる番地へ飛ぶ(3 番地)
- 点いていなければ、2 つ目の数で 13 番地を書き直す(4・5 番地)
分かれる シミュレータ
14・15 番地の 2 つの数を替えて、13 番地に大きいほうが残るかを確かめてください
太い線は束(番地と数は 4 本、語は 8 本)。反転の箱は、引くときだけ青くなる。ランプ C の線は、右のふちを上って「次の番地を選ぶ」へ入る
はじめは読む拍。番地のカウンタは 0。次の番地を選ぶ箱は、いつもは「+1」を通している。クロックを入れると、0 番地の語が命令の置き場に届く。
拍ごとの記録
| 拍 | 段階 | 番地 | 起きたこと |
|---|---|---|---|
| まだクロックを入れていない | |||
| 番地 | 中身 | 読み方(人間のメモ) |
|---|---|---|
| 0000(0) | 持ってくる 14 番地 | |
| 0001(1) | 書き込む 13 番地 | |
| 0010(2) | 引く 15 番地 | |
| 0011(3) | ランプなら飛ぶ 6 番地 | |
| 0100(4) | 持ってくる 15 番地 | |
| 0101(5) | 書き込む 13 番地 | |
| 0110(6) | 止まる | |
| 0111(7) | 0000 0000 | |
| 1000(8) | 0000 0000 | |
| 1001(9) | 0000 0000 | |
| 1010(10) | 0000 0000 | |
| 1011(11) | 0000 0000 | |
| 1100(12) | 0000 0000 | |
| 1101(13) | 0000 0000 | 数 0(大きいほうを置く場所) |
| 1110(14) | 0000 | 数 7(1 つ目) |
| 1111(15) | 0000 | 数 3(2 つ目) |
青い行は、読む拍で使う番地(番地のカウンタ)。琥珀色の行は、こなす拍で使う番地(命令の下 4 桁)。0〜6 番地は 8 桁すべてを、14・15 番地は下 4 桁を、押して替えられる(替えると、はじめからやり直す)
第4回の図に、新しいものが 2 つ増えた。 列のあいだの細長い反転の箱と、右下のランプ C から、右のふちを上って「次の番地を選ぶ」へ入る線だ。
「クロックを入れる」を押していこう。
| 拍 | 段階 | 番地 | 何が起きたか |
|---|---|---|---|
| 1 | 読む | 0 | 0 番地の命令を読む |
| 2 | こなす | 14 | 14 番地の 7 を A の箱へ |
| 3 | 読む | 1 | 1 番地の命令を読む |
| 4 | こなす | 13 | A の箱の 7 を 13 番地へ(ひとまず) |
| 5 | 読む | 2 | 2 番地の命令を読む |
| 6 | こなす | 15 | A の箱 ← 7 − 3 = 4。ランプ C が点く |
| 7 | 読む | 3 | 3 番地の命令を読む |
| 8 | こなす | 6 | ランプ C が点いているので、番地のカウンタ ← 6 |
| 9 | 読む | 6 | 6 番地の命令を読む |
| 10 | こなす | 0 | クロックの門が閉じる |
6 拍目、反転の箱が青くなり、「加算器 → A の箱」が開く。 8 拍目、選ぶ箱の文字が「下 4 桁」に変わる。4・5 番地は読まれない。10 拍で止まり、13 番地は 7 だ。
では、表の 14 番地と 15 番地を入れ替えてみよう。14 番地を 0011(3)、15 番地を 0111(7)にする。
今度は 6 拍目に 3 − 7。A の箱は 1100(12)になり、ランプ C は消える。
8 拍目、ランプなら飛ぶの線は 1 なのに、選ぶ箱は「+1」のまま。番地のカウンタは 4 を指したままで、9 拍目に 4 番地を読む。
15 番地の 7 を持ってきて、13 番地を書き直し、14 拍で止まる。13 番地は、やはり 7 だ。
同じ手順なのに、数によって、通る道が違った。 7 と 3 なら 0、1、2、3、6 番地。3 と 7 なら 0、1、2、3、4、5、6 番地。 2 つの数を同じにすると、ランプ C は点く(その数以上だから)。飛んで、1 つ目の数が残る。
ほかの数でも試してみてほしい。16 × 16 の 256 通り、どれでも 13 番地には大きいほうが残り、必ず止まる。
この箱の中では、ゲートが 1900 個働いている。前回より 8 個増えた。
判断は、どこに
このプログラムは、外から見ると、2 つの数を比べて、大きいほうを選んでいる。 「判断」をしているように見える。
けれど、回路の中を探しても、「大きい」を知っている場所はない。
起きたのは、こういうことだけだ。
- 反転の箱と加算器が、A + 16 − n を計算した
- 5 桁目に 1 があふれるかどうかが、ランプ C に残った
- 選ぶ箱が、ランプ C の線を 1 本見て、「+1」か「下 4 桁」かを選んだ
引き算のあとの 5 桁目のランプ 1 つで、次に読む番地を選べる。それだけで、回路は「判断」をする。
回路は、比べていない。大小も知らない。ランプ C が点いた理由も知らない。 5 桁目があふれたかどうかで、次の番地が変わる。それだけだ。 「大きいほうを選ぶ」という意味は、命令をそう並べた人間の側にある。
こういう、条件によって次に読む番地が変わることを、条件分岐と呼ぶ。
『記憶のしくみ』を読んだ人は、最終回の自動販売機の「足りる」の線を思い出してほしい。金額から値段を引く加算器の、5 桁目への繰り上がりが「足りる」だった。あの回路は、その線を見て、次の段階を選んでいた。ここでは同じ線が、次に読む番地を選んでいる。
本物の CPU には、ランプ C のような印が、いくつもある。 4 桁の CPU 4004 の条件つきの飛ぶは、「A の箱(アキュムレータ)が 0」「キャリー(ランプ C にあたるもの)が 1」「外から来る TEST という線が 0」を見ることができ、条件を逆にすることもできた。 この回路は、ランプ C の 1 つだけで進む。
止められる
前回の、止まらないプログラムに戻ろう。 足して、書き込んで、0 番地へ飛ぶ。13 番地は 5、10、15、4、9……と回り続けた。
あのとき、15 + 5 でランプ C が点くのを見た。足すのランプは「4 桁からあふれた」を覚えている。 そこで、足したすぐあとに、ランプなら飛ぶを 1 つはさむ。
| 番地 | 中身 | 読み方 |
|---|---|---|
| 0 | 0010 1110 | 足す 14 番地 |
| 1 | 0110 0100 | ランプなら飛ぶ 4 番地 |
| 2 | 0011 1101 | 書き込む 13 番地 |
| 3 | 0101 0000 | 飛ぶ 0 番地 |
| 4 | 1111 0000 | 止まる |
| 13 | 0000 0000 | 合計を置く場所 |
| 14 | 0000 0101 | 数 5 |
あふれなければ、ランプなら飛ぶは何もしない。書き込んで、0 番地へ戻る。 あふれたら、書き込む前に、止まる命令へ飛ぶ。
あふれたら止まる シミュレータ
1 番地の「ランプなら飛ぶ」で、手順がいつ分かれるかを見てください
太い線は束(番地と数は 4 本、語は 8 本)。反転の箱は、引くときだけ青くなる。ランプ C の線は、右のふちを上って「次の番地を選ぶ」へ入る
はじめは読む拍。番地のカウンタは 0。次の番地を選ぶ箱は、いつもは「+1」を通している。クロックを入れると、0 番地の語が命令の置き場に届く。
拍ごとの記録
| 拍 | 段階 | 番地 | 起きたこと |
|---|---|---|---|
| まだクロックを入れていない | |||
| 番地 | 中身 | 読み方(人間のメモ) |
|---|---|---|
| 0000(0) | 足す 14 番地 | |
| 0001(1) | ランプなら飛ぶ 4 番地 | |
| 0010(2) | 書き込む 13 番地 | |
| 0011(3) | 飛ぶ 0 番地 | |
| 0100(4) | 止まる | |
| 0101(5) | 0000 0000 | |
| 0110(6) | 0000 0000 | |
| 0111(7) | 0000 0000 | |
| 1000(8) | 0000 0000 | |
| 1001(9) | 0000 0000 | |
| 1010(10) | 0000 0000 | |
| 1011(11) | 0000 0000 | |
| 1100(12) | 0000 0000 | |
| 1101(13) | 0000 0000 | 数 0(合計を置く場所) |
| 1110(14) | 0000 | 数 5 |
| 1111(15) | 0000 0000 |
青い行は、読む拍で使う番地(番地のカウンタ)。琥珀色の行は、こなす拍で使う番地(命令の下 4 桁)。0〜4 番地は 8 桁すべてを、14 番地は下 4 桁を、押して替えられる(替えると、はじめからやり直す)
「自動で進める」を押して、眺めてほしい。 読んだ番地は、0、1、2、3 を 3 周したあと、0、1、4。 13 番地には 5、10、15 と書かれ、15 + 5 であふれたところで、30 拍で止まる。 13 番地は 15 のままだ。
14 番地の数を替えても、13 番地には 15 を超えない最後の合計が残って止まる。1 にすると 15 まで数えて、126 拍。 ただし 0 にすると、いつまでもあふれないので、止まらない。
何度も、決める
いまのプログラムを、もう一度見てほしい。
0 番地から 3 番地までの 4 つの命令を、何度も通った。そして、ランプが点いたところで、抜けた。 飛ぶだけなら、止まらなかった。ランプなら飛ぶだけなら、1 回分かれて終わりだった。 2 つを組み合わせると、同じ命令を何度も通り、決めたところで抜ける道が作れる。
ここで、ふと気になる。
この回路にできる計算は、足すと引くだけだ。 掛け算は、足し算を何度も繰り返せばできる。3 × 5 は、3 を 5 回足せばいい。
足し算しかできない回路に、掛け算をさせられないか。
次回は、繰り返す回数を数えながら、プログラムで掛け算をしてみる。
参考文献
- 松下俊介 著. 基礎からわかる論理回路. 第2版, 森北出版, 2021.7. 978-4-627-82842-1. https://ndlsearch.ndl.go.jp/books/R100000002-I031573740
- ディビッド・マネー・ハリス, サラ・L・ハリス 著; 天野英晴, 鈴木貢, 中條拓伯, 永松礼夫 訳. ディジタル回路設計とコンピュータアーキテクチャ. 第2版, 翔泳社, 2017.9. 978-4-7981-4752-9. https://ndlsearch.ndl.go.jp/books/R100000002-I028478041
- 渡波郁 著. CPUの創りかた : IC10個のお手軽CPU設計超入門 : 初歩のデジタル回路動作の基本原理と製作, 毎日コミュニケーションズ, 2003.9. 4-8399-0986-5. https://ndlsearch.ndl.go.jp/books/R100000002-I000004238574
- Intel. "MCS-4 Micro Computer Set". 1971.11. https://ieeemilestones.ethw.org/w/images/2/2d/Ref2-Intel_MCS-4_DataSheet.pdf, (参照 2026-10-18).