シリーズ「コンピュータの CPU のしくみ」 第6回
回路が「繰り返す」とは?
足し算しか、できない
ここまでの 5 回を、短く振り返っておこう。
手順を 0 と 1 のパターンにしてメモリに並べ、上 4 桁をデコーダに通して入口を開き、「読む拍」と「こなす拍」を交互に回した(第1〜3回)。 番地のカウンタに命令の下 4 桁を書き込めば飛べる(第4回)。 引き算のあとのランプ C は「引く前の数が、その数以上」を覚えていて、そのランプで飛ぶかどうかを選べた(第5回)。
前回の終わりに、こう書いた。
飛ぶとランプなら飛ぶを組み合わせると、同じ命令を何度も通り、決めたところで抜ける道が作れる。 けれど、この回路にできる計算は、足すと引くだけだ。
足し算しかできない回路に、掛け算をさせられないか。
掛け算の回路を新しく作る、という手もある。 けれど、この回はゲートを 1 つも足さない。 前回と同じ回路のまま、メモリの中のパターンだけで、掛け算をさせてみる。
足し算を、繰り返す
3 × 5 は、3 を 5 回足すことだ。
0 から始めて、3、6、9、12、15。 5 回足したら、やめる。
人間なら、指を折って数える。 回路には指が無いので、数えるのも、メモリに置いた数でやる。
メモリに置くものは、2 つ。
- 答え … 0 から始めて、3 ずつ増えていく
- 残りの回数 … 5 から始めて、1 回足すたびに 1 ずつ減らす
残りの回数が 0 になったら、やめればいい。
では、「0 になった」は、どうやって知るか。 この回路が見られるのは、ランプ C だけだ。
ここで前回の引き算が効いてくる。 残りの回数から 1 を引くと、ランプ C は「引く前の回数が、1 以上」のときに点く。 つまり、まだ足す回数が残っていれば点き、もう 0 だったら消える。
ランプが点いていれば、続ける。消えていれば、止まる。 数えることも、やめどきを知ることも、前回までの命令でできる。
ただ、順番には気をつけたい。 「数えてから足す」と「足してから数える」。どちらでもよさそうに見える。
下の図で、回数 N を押して比べてみてほしい。掛けられる数は 3 にしてある。
回数 N(掛けられる数は 3)
数えてから足す(この回のプログラム)
- 残り 5・点く
- +3 → 3
- 残り 4・点く
- +3 → 6
- 残り 3・点く
- +3 → 9
- 残り 2・点く
- +3 → 12
- 残り 1・点く
- +3 → 15
- 残り 0・消える
- 止まる
足した回数 5 回 → 9 番地は 15(3 × 5 = 15)合う
足してから数える
- +3 → 3
- 残り 5・点く
- +3 → 6
- 残り 4・点く
- +3 → 9
- 残り 3・点く
- +3 → 12
- 残り 2・点く
- +3 → 15
- 残り 1・点く
- +3 → 2
- 残り 0・消える
- 止まる
足した回数 6 回 → 9 番地は 2(3 × 6 = 18 の下 4 桁で 2)1 回多い
足してから数えるほうは、いつも 1 回多く足す。 3 × 5 なら、3 を 6 回足して 18。4 桁に収まらず、残るのは 2 だ。 回数を 0 にしても、見る前に 1 回足してしまうので、答えは 3 になる。
原因は、ランプの意味にある。 最後の 1 回、残りの回数を 1 から 0 にするときも、引く前は 1 なので、ランプは点く。 足してから数えるほうは、そのランプを見て、もう 1 周してしまう。
だから、先に数えて、足すのはそのあとにする。 残りの回数から 1 を引いてみて、ランプが点いたら(まだ残っていたら)、1 回足す。
プログラムを、読む
この順番で書いたのが、下のプログラムだ。13 語ある。
| 番地 | 中身 | 読み方 |
|---|---|---|
| 0 | 0001 1011 | 持ってくる 11 番地 |
| 1 | 0100 1100 | 引く 12 番地 |
| 2 | 0110 0100 | ランプなら飛ぶ 4 番地 |
| 3 | 1111 0000 | 止まる |
| 4 | 0011 1011 | 書き込む 11 番地 |
| 5 | 0001 1001 | 持ってくる 9 番地 |
| 6 | 0010 1010 | 足す 10 番地 |
| 7 | 0011 1001 | 書き込む 9 番地 |
| 8 | 0101 0000 | 飛ぶ 0 番地 |
| 9 | 0000 0000 | 答えを置く場所 |
| 10 | 0000 0011 | 数 3(掛けられる数) |
| 11 | 0000 0101 | 数 5(残りの回数) |
| 12 | 0000 0001 | 数 1(回数から引く 1) |
上から、4 つのまとまりに分けて読める。
- 0〜3 番地:回数を確かめる。 残りの回数を持ってきて、1 を引く。ランプ C が点いていれば 4 番地へ飛ぶ。消えていれば、そのまま 3 番地の止まるに進む
- 4 番地:回数を書き戻す。 1 減らした回数を、11 番地に書き込む
- 5〜7 番地:答えに足す。 答えを持ってきて、3 を足し、9 番地に書き込む
- 8 番地:戻る。 0 番地へ飛んで、また回数を確かめる
計算するたびに、持ってきて、計算して、書き戻している。 A の箱は 1 つしかないからだ。 回数を減らすときも、答えに足すときも、A の箱を使う。だから、使い終わったらメモリに返しておく。
12 番地の 1 は、「1 を引く」ためだけに置いた数だ。 この回路の引くは、いつも「その番地の数」を引く。1 を引きたければ、1 をどこかの番地に置いておくしかない。
もう 1 つ、細かいところ。 答えが 15 を超えると、6 番地の足すでランプ C が点く(4 桁からあふれた)。 けれど、そのランプを見る 2 番地の前に、1 番地の引くが、ランプ C を「引く前の回数が 1 以上か」で上書きする。 だから、あふれのランプを、続けるかどうかと取り違えることはない。
押して、確かめる
繰り返す シミュレータ
「自動で進める」を押して、9 番地の答えと 11 番地の残りの回数がどう変わるかを見てください
回路は前回とまったく同じ(1900 ゲート)。変わったのは、メモリの中のパターンだけ。「次の番地を選ぶ」の大きな文字が、いま通しているほう
はじめは読む拍。番地のカウンタは 0。次の番地を選ぶ箱は、いつもは「+1」を通している。クロックを入れると、0 番地の語が命令の置き場に届く。
拍ごとの記録
| 拍 | 段階 | 番地 | 起きたこと |
|---|---|---|---|
| まだクロックを入れていない | |||
| 番地 | 中身 | 読み方(人間のメモ) |
|---|---|---|
| 0000(0) | 持ってくる 11 番地 | |
| 0001(1) | 引く 12 番地 | |
| 0010(2) | ランプなら飛ぶ 4 番地 | |
| 0011(3) | 止まる | |
| 0100(4) | 書き込む 11 番地 | |
| 0101(5) | 持ってくる 9 番地 | |
| 0110(6) | 足す 10 番地 | |
| 0111(7) | 書き込む 9 番地 | |
| 1000(8) | 飛ぶ 0 番地 | |
| 1001(9) | 0000 0000 | 数 0(答えを置く場所) |
| 1010(10) | 0000 | 数 3(掛けられる数) |
| 1011(11) | 0000 | 数 5(残りの回数) |
| 1100(12) | 0000 0001 | 数 1(回数から引く 1) |
| 1101(13) | 0000 0000 | |
| 1110(14) | 0000 0000 | |
| 1111(15) | 0000 0000 |
青い行は、読む拍で使う番地(番地のカウンタ)。琥珀色の行は、こなす拍で使う番地(命令の下 4 桁)。0〜8 番地は 8 桁すべてを、10・11 番地(掛けられる数と回数)は下 4 桁を、押して替えられる(替えると、はじめからやり直す)
図は、前回とまったく同じだ。ゲートは 1 つも増えていない。 変わったのは、下の表のパターンだけだ。
「クロックを入れる」で何拍か進めたら、「自動で進める」を押してほしい。 88 拍あるので、速さは「速く」にすると見やすい。
0 番地から 8 番地までを通って、0 番地に戻る。これで 1 周、8 命令・16 拍だ。 1 周するたびに、11 番地の残りの回数が 1 減り、9 番地の答えが 3 増える。
| 周 | 終わった拍 | 11 番地(残りの回数) | 9 番地(答え) |
|---|---|---|---|
| はじめ | 0 | 5 | 0 |
| 1 | 16 | 4 | 3 |
| 2 | 32 | 3 | 6 |
| 3 | 48 | 2 | 9 |
| 4 | 64 | 1 | 12 |
| 5 | 80 | 0 | 15 |
5 周したあと、もう一度 0 番地から。 残りの回数 0 から 1 を引くと、ランプ C は消える。 2 番地のランプなら飛ぶは飛ばず、3 番地の止まるを読んで、88 拍で止まる。 9 番地は 15。3 × 5 の答えだ。
止まったとき、A の箱には 1111(15)が残っている。
これは答えではない。最後に 0 − 1 を計算した残りだ。0〜15 の読み方では引ききれず、1111 になった(前回の 3 − 7 と同じ)。
3 × 5 では、たまたま答えと同じ 15 になる。答えは、あくまで 9 番地だ。
表の 10 番地と 11 番地は、押して替えられる。
10 番地を 0101(5)、11 番地を 0011(3)にして、5 × 3 を試してほしい。答えは同じ 15 なのに、56 拍で止まる。
答えが 15 を超える組では、9 番地には下 4 桁だけが残る。 たとえば 4 × 5 = 20 なら、残るのは 4。16 × 16 の 256 通りのうち、4 桁に収まるのは 76 通りだ。 どの組でも、9 番地には X × N の下 4 桁が入り、必ず止まる。
何拍、かかるか
5 × 3 のほうが速かったのは、なぜか。
1 周は、いつも 8 命令だ。足す数が 3 でも 5 でも、1 周の長さは変わらない。 変わるのは、何周するか。それを決めるのは、残りの回数 N だけだ。
そして最後に、回数を確かめて止まるまでの 4 命令(0・1・2・3 番地)がある。
こなす命令の数は、8N + 4。 1 命令は 2 拍なので、拍はその 2 倍になる。
横は回数 N、縦は止まるまでの拍の数
3 × 5 は N = 5 で 44 命令・88 拍。5 × 3 は N = 3 で 28 命令・56 拍。 N が 1 増えるたびに、16 拍ずつ伸びる。いちばん長いのは N = 15 で、248 拍だ。 1 回も足さない N = 0 でも、回数を確かめるのに 8 拍かかる。
掛け算の答えは、時間をかけないと出てこない。 しかも、掛ける回数が大きいほど、時間がかかる。
回路で解くなら
掛け算をするだけなら、別のやり方もある。
『計算のしくみ』の第6回では、掛け算の回路を作った。 2 進法の掛け算の筆算を、AND と加算器でそのまま組んだものだ。 部分積を一度に足すアレイ方式と、加算器 1 つで 1 本ずつ足すシフト加算方式を、こう比べていた。 そこに、この回のプログラムを 1 列足してみる。
| アレイ方式 | シフト加算方式 | この CPU のプログラム | |
|---|---|---|---|
| AND | 16 個 | 4 個 | 0 個(足していない) |
| 4 桁加算器 | 3 つ | 1 つ | 1 つ(もとからある) |
| 覚えておく場所 | 要らない | 要る | メモリの 4 語(もとからある) |
| かかる手順 | 1 回(通り抜けるだけ) | 4 回 | 8N + 4 命令(最大 248 拍) |
アレイ方式は、部品を並べて、一度に答える。 この CPU は、何も並べない。もとからある加算器 1 つに、同じ足し算を何度も通す。そのかわり、いちばん時間がかかる。
この箱のゲートは、1900 個ある。 けれど、掛け算のために足したゲートは、0 個だ。 足したのはメモリの中の 13 語、それも、もとからある 128 桁のどこかを 0 にするか 1 にするかを決めただけだ。
1900 個の内訳と、掛け算の回路を足した場合を並べてみよう。
合わせて 1900 個
- メモリの 128 桁を覚える1408
- メモリの語を選ぶ・書く172
- ほかの覚える箱(19 桁)209
- 加算器と反転の箱24
- そのほか(デコーダ・入口・選ぶ箱・クロック)87
1900 個のうち 1408 個は、メモリの 128 桁を覚えているフリップフロップだ。 掛け算のプログラムは、その中に住んでいる。
計算の第6回は、2 節で「足し算を繰り返せばいいのでは」と考えて、すぐにやめていた。 32 桁なら最大で約 43 億回かかる、というのが理由だった。 この CPU がしているのは、まさにそのやめたやり方だ。 4 桁なら最大 15 回で済むので、248 拍で終わる。けれど、桁が増えれば、待ち時間はどこまでも伸びる。
4 桁の CPU 4004 にも、掛け算の命令は無かった。45 種類の命令のどれも、掛け算ではない。 掛け算をしたければ、足し算などの命令を並べたプログラムを書くことになる。 そのかわり、繰り返しのための命令はあった。ISZ という命令で、レジスタに 1 を足し、0 になっていなければ飛ぶ。回数を数えて、飛ぶかどうかを決めるところまでを、1 つの命令でこなしていた。 のちの CPU、たとえば 8086 には、掛け算の命令がある。
部品か、時間か
同じ掛け算を、2 通りに解いた。
- 部品を増やして解く。 AND と加算器を並べて、一度に通り抜ける
- 手順を繰り返して解く。 もとからある加算器に、同じ足し算を何度も通す
アレイ方式の回路は、速い。けれど、掛け算しかできない。 この CPU は、遅い。けれど、掛け算のために何も作り足していない。同じ 1900 個のゲートが、配線を 1 本も変えずに、3 + 5 も、前回の「大きいほう」も、掛け算もこなす。
部品を増やして解くか、手順を繰り返して解くか。CPU は、部品を増やすかわりに時間を使う。
『記憶のしくみ』を読んだ人は、第6回の「同じ加算器を、何度も」を思い出してほしい。足す数を 3 にしてクロックを 5 回入れると、3、6、9、12、15 と、3 × 5 の答えが出た。あのとき「覚える回路を手に入れたことで、回路は時間を使えるようになった」と書いた。ただし、5 回で止めていたのは、クロックを押していた人間だった。いまは、回数を数えるのも、止めるのも、メモリの中のプログラムがやっている。
手順を繰り返すために要ったのは、3 つだけだ。
- 戻る(飛ぶ)
- やめどきを知る(引いて、ランプなら飛ぶ)
- 途中の数を覚えておく(メモリ)
どれも、前回までにそろっていた。この回で足したのは、パターンだけだ。
表を、まとめて
掛け算はできた。 では、次はこんなことを考えてみる。
3 つ、4 つの数の合計を取りたい。 たとえば、12・13・14・15 番地に並べた 4 つの数だ。
いまの命令で書くなら、こうなる。
- 足す 12 番地
- 足す 13 番地
- 足す 14 番地
- 足す 15 番地
足す命令を、数の数だけ並べる。 4 つなら 4 命令で済む。けれど、メモリは 16 語しかない。数が増えると、命令を置く場所が足りなくなる。
掛け算のときのように、1 つの「足す」を、何度も通したい。 ただ、掛け算では、毎回同じ 10 番地の 3 を足せばよかった。 今度は、1 周するたびに、足す番地を 12、13、14、15 と1 つずつずらしたい。
ところが、「足す 12 番地」の 12 は、命令の下 4 桁に書き込まれたパターンだ。 プログラムが動いているあいだ、ずっと 12 のままだ。
命令の中の番地を、1 つずつずらすことはできないか。
次回は、命令そのものを、数として眺めてみる。
参考文献
- 松下俊介 著. 基礎からわかる論理回路. 第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-19).
- Intel. "The 8086 Family User's Manual". 1979.10. https://ia801302.us.archive.org/2/items/bitsavers_intel80869lyUsersManualOct79_62967963/9800722-03_The_8086_Family_Users_Manual_Oct79.pdf, (参照 2026-10-19).