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

回路が「別の機械になる」とは?

外の世界

ここまでの 7 回を、短く振り返っておこう。

手順を 0 と 1 のパターンにしてメモリに並べ、上 4 桁で「何をするか」、下 4 桁で「どの番地か」を表した(第1〜3回)。 番地のカウンタに数を書き込んで飛び(第4回)、引き算のあとのランプ C で飛ぶかどうかを選んだ(第5回)。 足し算を繰り返して掛け算をさせ(第6回)、命令の番地を書き換えて表の合計を取った(第7回)。

前回の終わりに、こう書いた。

使った数はどれも、はじめからメモリに置いてあった。 けれど自動販売機の硬貨は、いつ、いくら入ってくるか分からない。品物は、外へ出さないといけない。

外から数を受け取り、外へ何かを出すには、どうすればいいか。

自動販売機は、硬貨を数えて、金額が値段に届いたら品物を出す機械だ。 『記憶のしくみ』を読んだ人は、最終回で、その手順をそのまま AND と OR の配線にしたのを思い出してほしい。

この回は、同じ自動販売機を、プログラムで作る。 シリーズの最終回である。

受け取る、出す

外とやりとりするために、箱を 2 つ足す。

1 つ目は、投入口。4 桁の数を覚える箱だ。 硬貨が入ると、その硬貨の数が入る。ここでは 10 円を 1 と読むので、10 円なら 0001、50 円なら 0101。 硬貨は、クロックとは関係なく、いつでも入ってくる。

2 つ目は、出口。4 桁のランプだ。 ここに数が届いたら、品物を 1 つ落とす。そういう約束にする。

そして、命令を 2 つ足す。

  • 受け取る(0111)… 投入口の数を、A の箱に入れる。読んだら、投入口は空になる
  • 出す(1000)… A の箱の数を、出口のランプに入れる

受け取るは、こう作る。

まず、数を覚える箱のしくみを、もう一度確かめておこう。 A の箱も、命令の置き場も、数を覚える箱には、線が 2 種類つながっている。

  • 入口 … 次に覚えるパターンが届く線。ここには、いつも何かのパターンが来ている
  • 合図 … 「いま、受け取れ」と知らせる線。第1回で書いたとおり、ふだんはクロックがこの役目をしている

箱は、合図が来た瞬間にだけ、そのとき入口に来ているパターンを受け取って覚える。 それ以外のときは、入口のパターンが変わっても、覚えている数は変わらない。 カメラにたとえるなら、入口はレンズの前の景色、合図はシャッターだ。シャッターを切った瞬間の景色だけが残る。

投入口も、4 桁を覚える同じ箱だ。 では、入口には何をつなげばいいか。

自動販売機には、入ってきた硬貨を見分ける装置がある。コインメックという。 硬貨が落ちてくると、本物かどうか、何円玉かを見分ける。 ここでは、コインメックから線が出ている、と考える。

  • 「10 円が来た」線 … 10 円玉だと分かった、その一瞬だけ 1 になる
  • 「50 円が来た」線 … 50 円玉だと分かった、その一瞬だけ 1 になる
  • 「硬貨が入った」合図 … どちらかの線が 1 になっているあいだに、1 回だけ 1 → 0 と入る

お客さんが硬貨を入れなければ、どの線も 0 のままだ。

投入口の入口には、「何円が来た」線を、数のパターンに直してつなぐ。 「50 円が来た」線が 1 のあいだだけ、入口には 0101 が来る。どの線も 0 なら、入口は 0000 だ。

投入口の合図(シャッター)は、2 か所から来る。

  • 硬貨が入ったとき … 「50 円が来た」線は 1 なので、0101 を受け取る。硬貨の数を覚える
  • 受け取るをこなす拍のクロック … 硬貨はもう通り過ぎていて、どの線も 0。だから 0000 を受け取る。中身が 0000 に戻る。これを「空になる」と呼ぶ

2 か所から来る合図は、OR で 1 本にまとめて投入口に届ける。 投入口だけを切り出したのが、下の図だ。 図では、コインメックの線と合図を、1 つずつ自分で入れられるようにした。 まず「50 円が来た」(図の丸)を 1 にして、入口に 0101 が来ても、投入口の中身が変わらないことを確かめてほしい。 それから、合図を入れる。「50 円が来た」を 0 に戻す。受け取る拍のクロックを入れる。

何円が来た → 数0000 = 0投入口0000 = 0OR入口合図A の箱へ10 円が来た050 円が来た0硬貨が入った合図0受け取る拍のクロック0
まず、「50 円が来た」(図の丸)を押して 1 にしてみてほしい。

A の箱のほうには、デコーダの線 0111 で開く入口「投入口 → A の箱」を 1 つ足す。第2回で作った「メモリ → A の箱」と同じ形だ。

受け取るをこなす拍のクロックは、A の箱と投入口の両方に届く。2 つの箱は、同じクロックで同時に受け取る。 A の箱が受け取るのは、投入口が 0000 になる前の数だ。第1回で、番地のカウンタと命令の置き場が同時に受け取ったときも、命令の置き場に入ったのは、番地のカウンタが進む前の番地の語だった。それと同じである。

こうして、硬貨の数は A の箱へ移り、投入口は空になる。 次の硬貨が来るまでは、受け取るが何度読んでも、A の箱に入るのは 0 だ。

『記憶のしくみ』を読んだ人は、第6回で「1 拍のあいだだけ金額を出して、次の拍では 0 に戻るもの」が欲しい、と書いたのを思い出してほしい。この投入口は、それに近い。1 拍で消えるのではなく、受け取るに読まれるまで硬貨の数を出しておき、読まれたら 0000 に戻る。(硬貨のセンサーの信号を、クロックに合わせて整える話は、最終回でした。ここでは、硬貨が 1 枚来るたびに、コインメックの合図がちょうど 1 回入る、と思ってほしい。)

出すは、もっと簡単だ。 デコーダの線 1000 と、こなす拍のクロックの両方が 1 のときだけ、出口が A の箱の数を受け取る。 メモリの書き込みの合図(第3回)と同じ形である。

足したのは、箱 3 つ(投入口・投入口 → A の箱・出口)と、デコーダの線 2 本。 ゲートは 99 個増えて、1999 個になった。

これで、命令の表がそろった。

上 4 桁名前すること出てきた回
0000何もしない何もしない2
0001持ってくるA の箱 ← その番地の数1〜3
0010足すA の箱 ← A の箱 + その番地の数1〜3
0011書き込むその番地の下 4 桁 ← A の箱1〜3
0100引くA の箱 ← A の箱 − その番地の数5
0101飛ぶ番地のカウンタ ← 下 4 桁4
0110ランプなら飛ぶランプ C が点いていれば飛ぶ5
0111受け取るA の箱 ← 投入口(投入口は空になる)8
1000出す出口のランプ ← A の箱8
1111止まるクロックを止める1〜3

16 通りのうち、使っているのは 10 個。 受け取ると出すは、番地を使わない。下 4 桁は 0000 にしておく。

自動販売機を、書く

では、自動販売機を書こう。値段は 100 円、硬貨は 10 円と 50 円にする。 13 語ある。

番地中身読み方
00111 0000受け取る
10010 1010足す 10 番地
20011 1010書き込む 10 番地
30100 1011引く 11 番地
40110 0110ランプなら飛ぶ 6 番地
50101 0000飛ぶ 0 番地
60011 1010書き込む 10 番地
70001 1100持ってくる 12 番地
81000 0000出す
90101 0000飛ぶ 0 番地
100000 0000金額(はじめは 0)
110000 1010値段(10、つまり 100 円)
120000 0001数 1(出す数)

上から、3 つのまとまりに分けて読める。

  • 0〜2 番地:硬貨を数える。 投入口の数を受け取り、10 番地の金額に足して、書き戻す
  • 3〜5 番地:足りたかを見る。 金額から値段を引いてみる。ランプ C が消えていれば(金額が値段より小さければ)、0 番地へ戻る
  • 6〜9 番地:品物を出す。 引いた残りを金額として書き戻し、1 を出口へ出して、0 番地へ戻る

3〜5 番地は、第5回の「引いて、ランプなら飛ぶ」そのままだ。 6 番地で書き戻すのは、3 番地で引いた答えが、まだ A の箱に残っているからである。

硬貨が来ていないときは、どうなるのか。 受け取るは、空の投入口から 0 を受け取る。1 番地で、金額に 0 を足す。 金額は変わらない。値段には届かないので、0 番地へ戻って、また受け取る。

『記憶のしくみ』を読んだ人は、第6回の「止めるのではなく、0 を足す」を思い出してほしい。あのときは回路の話だったが、ここではプログラムが、同じことをしている。

そして、このプログラムには止まる命令が無い。

押して、確かめる

自動販売機 シミュレータ

「自動で進める」を押してから、硬貨を入れてください。値段に届くと、出口のランプが受け取ります

拍の状態読む拍クロックの門開次の番地を選ぶ+1+1番地のカウンタ0000 = 0命令の置き場0000 0000デコーダ001100010100001011110101011001111000番地を選ぶ0000 = 0メモリ(16 語)0111 0000メモリ → A の箱閉反転加算器 → A の箱閉A の箱0000 = 0加算器0000 = 0+1ランプ C0投入口 → A の箱閉出口0000 = 0投入口0000 = 0クロック0

新しく足したのは、下の 3 つの箱(投入口・投入口 → A の箱・出口)と、デコーダの線 0111・1000 だけ(1999 ゲート)。出口は、受け取る瞬間だけ青くなる。投入口と出口が受け取るこなす拍のクロックは、箱の中でつないである(線は省いた)

速さ

投入口は空。硬貨を入れられる

入れた金額
0 円
出てきた品物
0 個
出口のランプ 0000
金額(10 番地)
0 円
値段 100 円
拍
0
こなした命令
0

はじめは読む拍。番地のカウンタは 0。投入口は空。「自動で進める」を押してから、硬貨を入れてほしい。

読んだ番地の順:まだ読んでいない

拍ごとの記録

拍段階番地起きたこと
まだクロックを入れていない
番地中身読み方(人間のメモ)
0000(0)0111 0000受け取る
0001(1)0010 1010足す 10 番地
0010(2)0011 1010書き込む 10 番地
0011(3)0100 1011引く 11 番地
0100(4)0110 0110ランプなら飛ぶ 6 番地
0101(5)0101 0000飛ぶ 0 番地
0110(6)0011 1010書き込む 10 番地
0111(7)0001 1100持ってくる 12 番地
1000(8)1000 0000出す
1001(9)0101 0000飛ぶ 0 番地
1010(10)0000 0000数 0(金額)
1011(11)0000数 10(値段)
1100(12)0000 0001数 1(出す数)
1101(13)0000 0000
1110(14)0000 0000
1111(15)0000 0000

青い行は、読む拍で使う番地(番地のカウンタ)。琥珀色の行は、こなす拍で使う番地(命令の下 4 桁)。11 番地(値段。10 円を 1 と読む)の下 4 桁は、押して替えられる(替えると、はじめからやり直す)

図の上半分は、前の 3 回とまったく同じだ。 下に、投入口・投入口 → A の箱・出口が増えた。デコーダの右の辺から、線 0111 と 1000 が右のふちを下りてくる。

まず「自動で進める」を押してほしい。 硬貨を入れていなくても、回路は動きつづける。 読んだ番地の順は、0、1、2、3、4、5、0……。6 命令・12 拍で 1 周する。受け取っているのは、ずっと 0 だ。

そこへ「50 円を入れる」を押す。 投入口に 0101 が入り、0 番地の受け取るで A の箱へ運ばれる。投入口は空に戻る。 金額は 50 円。値段には届かないので、また 0 番地へ。

もう一度「50 円を入れる」。 金額が 100 円になる。今度は、3 番地で引いたあとランプ C が点き、4 番地から 6 番地へ飛ぶ。 8 番地の出すで、出口のランプに 0001 が入る。 品物が 1 つ出た。 金額は 0 円に戻り、また硬貨を待つ。この周は、9 命令・18 拍だ。

10 円と 50 円を、好きな順に入れてみてほしい。 ボタンの下の帳簿で、いつも

入れた金額 = 100 円 × 出てきた品物 + 金額(10 番地)

になっているはずだ。 10 円と 50 円の入れ方を、長さ 5 まで全部(62 通り)試して、出した数と残りの金額がどれも正しいことを確かめてある。

いつまで待っても、この回路は止まらない。 第4回で、飛ぶ命令を置いたら止まらなくなった。あのときは困ったことだった。 けれど、自動販売機は、止まらないのが正しい。次の客は、いつ来るか分からないのだから。

値段を、変える

表の 11 番地の下 4 桁は、押して替えられる。

0010(20 円)にしてみてほしい。 50 円を 1 枚入れると、品物が 2 つ出て、10 円が残る。 2 つ目が出るのは、次の周だ。受け取るは 0 を受け取り、金額に 0 を足す。それでも 30 円は 20 円以上なので、もう 1 つ出す。

値段を変えるのに、回路は 1 つも変えていない。 替えたのは、メモリの中の 4 桁だけだ。 記憶の最終回の自動販売機は、値段が 120 円に決めてあった。変えたければ、作り直すしかなかった。

では、その 120 円にしてみよう。11 番地を 1100(12)にする。 10 円、50 円、50 円と入れて、110 円。まだ足りない。 そこへ、もう 1 枚 50 円を入れる。

何も出てこない。金額は、0 円になる。

帳簿を見てほしい。160 円入れたのに、品物は 0 個、金額も 0 円だ。 110 円 + 50 円は、10 円を 1 と読めば 11 + 5 = 16。 16 は、4 桁には入らない。1 0000 の下 4 桁、0000 が金額に書き戻された。

1 番地の足すで、ランプ C は点いていた。あふれを、ちゃんと知らせていた。 けれど、このプログラムは、そのランプを見ていない。 すぐあとの 3 番地の引くが、ランプ C を上書きしてしまう。0 − 12 では、ランプは消える。 『計算のしくみ』を読んだ人は、第5回の「ランプを見るのは、プログラム」を思い出してほしい。

10 円と 50 円の入れ方 62 通りのうち、こうなるのは 9 通り。どれも、110 円のところへ 50 円を入れたときだ。

回路は、何も間違えていない。 11 + 5 を、いつもどおり 4 桁で足しただけだ。 間違えていたのは、プログラムを書いた人の思い込みである。「金額は、15 を超えない」。 100 円なら、足りないときの金額は 90 円まで。50 円を足しても 140 円で、たしかに超えなかった。 記憶の最終回では、ちょうどこれを避けるために、金額を 5 桁にしてあった。

手順を、変える

値段の次は、手順そのものを替えてみよう。

下のシミュレータは、上と同じ回路だ。 違うのは、メモリに入れるプログラムを選べることだけである。

入れ替える シミュレータ

メモリの中身を選んでから、「自動で進める」を押してください。回路は 1 つも変わりません

メモリの中身
拍の状態読む拍クロックの門開次の番地を選ぶ+1+1番地のカウンタ0000 = 0命令の置き場0000 0000デコーダ001100010100001011110101011001111000番地を選ぶ0000 = 0メモリ(16 語)0111 0000メモリ → A の箱閉反転加算器 → A の箱閉A の箱0000 = 0加算器0000 = 0+1ランプ C0投入口 → A の箱閉出口0000 = 0投入口0000 = 0クロック0

回路は、どのプログラムでも同じ(1999 ゲート)。変わるのは、下の表のパターンだけ

速さ

投入口は空。硬貨を入れられる

入れた金額
0 円
出てきた品物
0 個
出口のランプ 0000
金額(10 番地)
0 円
値段 100 円
拍
0
こなした命令
0

はじめは読む拍。番地のカウンタは 0。投入口は空。「自動で進める」を押してから、硬貨を入れてほしい。

読んだ番地の順:まだ読んでいない

拍ごとの記録

拍段階番地起きたこと
まだクロックを入れていない
番地中身読み方(人間のメモ)
0000(0)0111 0000受け取る
0001(1)0010 1010足す 10 番地
0010(2)0011 1010書き込む 10 番地
0011(3)0100 1011引く 11 番地
0100(4)0110 0110ランプなら飛ぶ 6 番地
0101(5)0101 0000飛ぶ 0 番地
0110(6)0011 1010書き込む 10 番地
0111(7)0001 1100持ってくる 12 番地
1000(8)1000 0000出す
1001(9)0101 0000飛ぶ 0 番地
1010(10)0000 0000数 0(金額)
1011(11)0000 1010数 10(値段)
1100(12)0000 0001数 1(出す数)
1101(13)0000 0000
1110(14)0000 0000
1111(15)0000 0000

青い行は、読む拍で使う番地(番地のカウンタ)。琥珀色の行は、こなす拍で使う番地(命令の下 4 桁)。中身は、上のボタンで選んだプログラム

「3 + 5」を選ぶと、8 拍で止まり、13 番地に 8 が入る。電卓だ。 「大きいほう」を選ぶと、2 つの数を比べて、大きいほうを残す。 「掛け算」は、足し算を繰り返して、88 拍で 3 × 5 を出す。 「合計」は、自分の命令を書き換えながら、表の 4 つの数を足す。 そして「自動販売機」に戻せば、また硬貨を待ちはじめる。

どれを選んでも、図の 1999 個のゲートは、1 つも変わらない。 クロックが来るたびに、読んで、見分けて、こなす。それしかしていない。 変わったのは、下の表のパターンだけだ。

電卓にも、比べる機械にも、掛け算の機械にも、自動販売機にもなる。 それを決めているのは、配線ではなく、メモリの中のパターンである。

回路を 1 つも変えずに、メモリの中身を替えるだけで、CPU は別の機械になる。

4 桁の、CPU

第1回の書き出しで、自動販売機も電卓も、手順は配線で決まっている、と書いた。 そして、1970 年ごろ、日本の電卓の会社がそのことに困っていた、とも。

その会社、ビジコンは、1971 年 10 月に、電卓 141-PF を売り出した。 インテルと一緒に作った 4004 を、最初に載せた製品だった。 ビジコンが求めていたのは、ハードウェアではなくソフトウェアを変えることで、注文ごとの仕様に応えられる電卓だったという。

4004 が扱える数は、一度に 4 桁。このシリーズの CPU と同じだ。 4004 の仲間では、プログラムは 4001 という読むだけのメモリに作り込む(第7回)。 機種ごとに機能を変えたければ、回路ではなく、メモリの中のパターンを替えればいい。 この回の自動販売機で、値段を替えたのと同じことだ。

自動販売機のほうも、同じ道をたどった。 飲み物の自動販売機の制御は、はじめはスイッチとリレーの配線で手順を決めていた。それがトランジスタ、IC、LSI と移り、いまはマイクロコンピュータが使われている。 第1回の書き出しの「手順は配線で決まっている」は、昔の自動販売機の話でもあったのだ。

歩いてきた道

ここで、第1回からの道のりを並べておきたい。

回足したもの使えるようになった命令ゲート
1番地のカウンタ・メモリ・命令の置き場(読むだけ)1704
2デコーダと入口(見分けるだけ)—
3拍の状態・番地を選ぶ箱・A の箱・加算器・ランプ C・クロックの門持ってくる・足す・書き込む・止まる・何もしない1876
4次の番地を選ぶ箱飛ぶ1892
5反転の箱と、ランプ C の線引く・ランプなら飛ぶ1900
6(何も足していない)—1900
7(何も足していない)—1900
8投入口・投入口 → A の箱・出口受け取る・出す1999

第6回と第7回は、ゲートを 1 つも足していない。 掛け算も、自分を書き換えることも、メモリの中のパターンだけでやってのけた。

こうして並べると、このシリーズの回路がしてきたことは、タイトルの言葉で言える。

読む。 見分ける。 こなす。 飛ぶ。 分かれる。 繰り返す。 自分を書き換える。 そして、別の機械になる。

どの回でも、回路は命令の意味を知らなかった。

書いたとおりに

第1回で、こう書いた。

手順を配線ではなくメモリの中のパターンとして置き、番地を 1 つずつ数えながら読めば、パターンが順番に並んだ手順になる。

それから 7 回かけて、その手順で足し、比べ、繰り返し、自分を書き換え、外とやりとりした。 1999 個のゲートは、どの拍でも、命令の表のとおりに動いた。どのプログラムでも、全部の拍を動作の見本と照らし合わせてある。

それでも、120 円の自動販売機は、お金をなくした。 第7回で書き込む先を 1 つ違えたプログラムは、いつまでも止まらなかった。 回路は、書いた人が何をしたかったのかを知らない。知っているのは、メモリの中のパターンだけだ。

最終回の今、こう書き足しておきたい。

回路は、一度も手順を間違えていない。それでも、書いたとおりにしか動かない。

通路に並んだ自動販売機

手順は、もう配線ではない

最後に、自動販売機の前に戻ろう。

硬貨を入れる。 金額が足りると、品物が出てくる。 外から見れば、記憶の最終回で配線した自動販売機と、何も変わらない。

けれど中で手順を決めているのは、もう配線ではない。プログラムだ。 この回の CPU なら、受け取って、足して、引いて、ランプを見て、飛んで、また受け取る。 それを、何も知らないまま、客が来ない夜のあいだも繰り返す。

次に自動販売機で何かを買ったら、少しだけ思い出してほしい。 その手順を、どこかで誰かが、パターンとして書いたことを。 そして回路は、そのとおりに、それだけを、動いていることを。

参考文献

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