シリーズ「コンピュータの記憶のしくみ」 第7

回路が「ずらす」とは?

隣に、つなぐ

前回の最後に、こう問いかけた。 覚えている数を、クロックが来るたびに 1 桁ずつ横へ送るには、どうすればいいだろうか。

答えから書いてしまおう。

  1. 各桁のフリップフロップの値 D を、隣の桁の出力 Q につなぐ。
  2. 端の桁の D だけは、外から値を入れる「入口」にする。
  3. クロックの線は、今までどおり 1 本を全員に配る。

これだけである。 新しい部品は、今回も 1 つも要らない。 前回までと違うのは、線をどこにつなぐかだけだ。

こうして、クロックが来るたびに覚えている値を隣へ送っていくレジスタを、シフトレジスタという。 シフト(shift)は「ずらす」という意味だ。

まずは、触ってみてほしい。

シフトレジスタ シミュレータ

各桁の値 D は、右隣の桁の出力 Q につないであります。右端の「入口」だけは、スイッチで選べます

1 の位1DQ2 の位0DQ4 の位0DQ8 の位0DQこぼれる入口0クロック0

箱は第5回と同じ D フリップフロップ。値は右から左へ流れる

覚えている数0001= 1

「クロックを入れる」を押してください。1 の位の 1 が、どこへ行くかを見てください

図の「クロック」の丸を押すと、1 にしたままにできる(もう一度押すと 0 に落ちる)

押して、確かめる

箱が横に 4 つ並んでいる。左端が 8 の位、右端が 1 の位だ。 0001 と書いたときの並びと同じである。

箱の中身は、どれも第5回と同じ D フリップフロップだ。 箱の右辺に値 D、左辺に出力 Q がある。 右隣の箱の Q が、まっすぐ左隣の箱の D へ入っている。 右端の丸が入口で、1 の位の D につながっている。

いまは 1 の位だけが 1。0001 を覚えている。 「クロックを入れる」を押してほしい。

1 の位にあった 1 が、2 の位へ移った。

もう一度押すと 4 の位へ、もう一度で 8 の位へ。 押すたびに、1 が 1 桁ずつ左へ歩いていく。 入口は 0 なので、空いた 1 の位には 0 が入る。

8 の位まで来た 1 は、次のクロックでどうなるか。 左隣には、もう箱が無い。 1 は左端からこぼれて、消える。 覚えている数は 0000 になる。

今度は入口を 1 にして、何回か押してみてほしい。 右から 1 が次々に入ってきて、左へ流れていく。 入口を 1 と 0 に切り替えながら押せば、好きなパターンを流し込める。

電光掲示板の文字が、右から現れて左へ流れていくのと、よく似た動きだ。

文字が流れている電光掲示板

右から入って、左へ抜ける

第5回では、桁を縦に積んで描いた。 横に並べると、隣どうしがつながった鎖に見えてしまうからだった。 あの回の話は「桁どうしは、つながっていない」だったので、鎖に見えては困ったのだ。

今回は、その鎖こそが主役である。だから横に並べた。

玉突きに、ならないのか

ここで、少し引っかかってほしい。

クロックが来ると、1 の位は入口の値を受け取る。 2 の位は、1 の位の値を受け取る。

けれど 1 の位の値は、たったいま入口の値に書き換わったところではないか。 それなら 2 の位が受け取るのは、書き換わったあとの値、つまり入口の値になりそうだ。

同じ理屈で、4 の位も 8 の位も、入口の値を受け取ってしまいそうに思える。 玉突き事故のように、値が端から端まで一気に走り抜けて、全部が同じ値になる。 そう考えるほうが、むしろ自然である。

ところが、シミュレータではそうならなかった。 1 回のクロックで、値はきっちり 1 桁だけ進んだ。

何が、玉突きを止めているのだろうか。

ラッチで、作ってみる

試しに、同じ配線を第3回の D ラッチ で組んでみよう。 クロックの線は、ラッチの書き込み E につなぐ。クロックが 1 のあいだ、ラッチは開いている。

上がラッチで作った鎖、下がフリップフロップで作った鎖だ。 どちらも 0000 から始めて、入口は 1 にしてある。 配線はまったく同じである。

ラッチとフリップフロップ シミュレータ

上下とも配線は同じで、入口は 1 です。長さを選んで押すと、毎回 0000 から、上と下が同時に動きます

第3回の D ラッチで作った鎖(0000

1 の位0DQ2 の位0DQ4 の位0DQ8 の位0DQこぼれる入口1クロック0

第4回の D フリップフロップで作った鎖(0000

1 の位0DQ2 の位0DQ4 の位0DQ8 の位0DQこぼれる入口1クロック0
クロックを 1 にしておく長さ(ステップ数)

長さを「3」にして、「両方にクロックを入れる」を押してほしい。 上も下も 0001 になる。1 の位にだけ 1 が入った。ここまでは同じだ。

では、長さを「6」「9」「12」と長くしてみてほしい。

  • 上(ラッチ)001101111111 と、1 が奥まで走り込んでいく。
  • 下(フリップフロップ) … 何度やっても 0001

長さ 12 で、上は 1111 になった。 さきほど心配した玉突きが、ラッチでは本当に起きる。

第3回で見たとおり、ラッチは開いているあいだ、D を素通しにする。 入口の 1 は、1 の位のラッチを素通しで抜けて、2 の位のラッチの D に届く。 2 の位のラッチも開いているので、そこも素通しで抜けて、4 の位へ。 1 桁抜けるのに 3 ステップほどかかるので、開いている時間が長いほど、奥まで走る。

第3回では、D ラッチの出力を「+1」して D に戻したら、値が何周も回ってしまった。 開けておく長さで、答えが変わった。 今回は輪ではなく一列だが、起きていることは同じである。 あのとき「透過」と呼んだ性質が、ここでは悪さをする側に回っている。

長さ 3 のように短ければ、ラッチでも 1 桁で止まる。 けれど第4回で見たとおり、「ちょうどいい短さ」はゲートの速さしだいで、作る前には決められない。 その道が行き止まりなのは、もう知っている。

直前の値を、受け取る

では、フリップフロップは、なぜ走り抜けないのか。 中身を開いて見てみよう。

各桁のフリップフロップを、第4回と同じく、前のラッチ(上の段)と後ろのラッチ(下の段)に分けて描いた。 後ろのラッチの出力が、すきまを上って、左隣の前のラッチの D へ入っている。

シフトレジスタ シミュレータ

各桁の値 D は、右隣の桁の出力 Q につないであります。右端の「入口」だけは、スイッチで選べます

1D後ろ1Q0D後ろ0Q0D後ろ0Q0D後ろ0Qこぼれる入口0クロック0

上の段が前のラッチ、下の段が後ろのラッチ(第4回)。後ろの出力が、左隣の前へ入る

前のラッチ0001= 1
覚えている数0001= 1

「クロックを入れる」を押してください。1 の位の 1 が、どこへ行くかを見てください

図の「クロック」の丸を押すと、1 にしたままにできる(もう一度押すと 0 に落ちる)

図の左下の「クロック」の丸を押して、1 にしたままにしてほしい。

上の段の「前」が、4 つともになる。 開いた前のラッチは、右隣の「後ろ」の値を受け取る。 2 の位の前には 1 の位の後ろの 1 が入り、1 の位の前には入口の値が入る。

このとき、下の段の「後ろ」は 4 つともだ。 前のラッチが受け取った値は、そこで止まる。 後ろのラッチは、クロックを 1 にする直前の値を、そのまま持ちつづけている。

しばらく待ってほしい。何ステップたっても、どこも動かない。 前のラッチが受け取っている相手は、閉じている後ろのラッチだからだ。 受け取った相手が動かないので、走り抜けようがない。

もう一度丸を押して、クロックを 0 に落としてほしい。

今度は前が閉じ、後ろが開く。 4 つの後ろのラッチがいっせいに、自分の前のラッチの値を受け取る。 覚えている数が、1 桁ずれた。

けれど、このとき前のラッチはもう閉じている。 ずれた値が、さらに左隣へ走り込むことはない。

1 回のクロックでやっていることは、2 段階に分かれている。

  1. クロックが 1 のあいだ … 全員が、隣の直前の値を、前のラッチに受け取っておく。まだ渡さない。
  2. クロックが 0 に落ちた瞬間 … 全員が、受け取っておいた値を同時に出す。

荷物を手から手へ渡していく、バケツリレーを思い浮かべてほしい。 ただし、全員が合図に合わせて動く、少し変わったバケツリレーだ。

1 人 1 人は、隣から受け取る手と、隣へ渡す手を、別々に持っている。 合図の前半で、隣が差し出している荷物を、受け取る手でつかむ。自分の荷物は、まだ渡す手に持ったままだ。 合図の後半で、つかんだ荷物を渡す手に持ちかえて、反対側の隣へ差し出す。

受け取る手と渡す手が分かれているから、全員が同時に動いても、荷物は 1 人ぶんずつしか進まない。 1 つの荷物が、列の端まで一気に飛んでいくことはない。

箱を手渡しで運ぶバケツリレー

1 人ぶんずつ、先へ

前のラッチが受け取る手、後ろのラッチが渡す手である。 第4回で、2 つの扉が同時に開かない閘門のたとえを出した。あれと同じことを、隣どうしでやっている。

隣から受け取りながら、同時に隣へ渡せるのは、書き込みが一瞬だからだ。 ラッチで作れば、値は端まで走り抜けてしまう。

第4回では、フリップフロップなら出力を自分の入力に戻せることを確かめた。 何度やっても、1 回しか進まなかった。 今回はそれが、隣どうしのあいだで起きている。 自分の出力を隣へ渡し、隣の出力を自分が受け取る。 全員が一度にそうしても、全員がちょうど 1 桁ずつ進む。

ずらすと、2 倍

ここで、覚えている数のほうに目を移したい。

最初のシミュレータで、0001001001001000 と進んだ。 10 進法で読むと、1、2、4、8 である。 クロックを入れるたびに、2 倍になっていた。

計算シリーズの第6回で書いたとおり、2 進法で 1 桁左へずらすのは、2 倍することだった。 では、逆向きにずらすとどうなるか。

つなぐ向きを逆にしたシフトレジスタを用意した。 上は左へずらす。下は右へずらす。右へずらすほうは、入口が左端、こぼれるのが右端になる。 上下とも、同じ数を入れてある。クロックは 1 本を両方に配っている。

2 倍と半分 シミュレータ

上は左へ、下は右へずらすレジスタ。クロックは 1 本を両方に配っています

1 の位0DQ1 の位0DQ2 の位1DQ2 の位1DQ4 の位1DQ4 の位1DQ8 の位0DQ8 の位0DQ左へずらすこぼれる← 0右へずらす0 →こぼれるクロック0

はじめの数は、端の入口から 1 桁ずつ流し込んでおいた。いまは入口から 0 が入る

上(左へ)0110= 6
下(右へ)0110= 6

上と下に、同じ 60110)が入っています。「クロックを入れる」を押してください

はじめの数

6(0110)のまま、「クロックを入れる」を押してほしい。

上は 1100、12。2 倍だ。 下は 0011、3。半分になった。

もう一度押すと、上は 1000、8 になる。 24 になるはずだが、16 の桁が左端からこぼれた。前回見た「15 の次は 0」と同じ話である。

下は 0001、1 になる。 3 の半分は 1.5 だが、右端からこぼれた 0.5 の桁は、どこにも残らない。 計算シリーズの第11回で見た、切り捨てそのものだ。 はじめの数を 5 にしても、同じことが起きる。5 の半分は、2 になる。

ここで、回路は掛け算も割り算もしていない。 やったのは、各桁の値を隣へ移しただけだ。

それを 2 倍や半分と読んでいるのは、桁に貼った名札のほうである。 8、4、2、1 の名札は、1 つ左へ行くたびにちょうど 2 倍になり、1 つ右へ行くたびにちょうど半分になる。 だから全員が 1 つずつ隣の席へ移れば、全体も 2 倍(半分)になる。 桁に名札を貼っているのは、回路ではなく読む側だ。計算シリーズの第4回から、ずっと言ってきたことである。

計算シリーズの第6回では、ずらすのはタダだった。 線を 1 つ隣へつなぎ替えるだけで済んだ。 前回の最後で、それはもうタダではなくなった。 クロックに合わせて、覚えている数そのものを動かさなければならない。

その代わりに、手に入れたものがある。 ずらすこと自体が、2 倍と半分という計算になっている。

3 × 5 を、回路で

材料がそろった。前回の最後に出した表を、もう一度見てほしい。 今回は、その回までにずらしてきた被乗数も書き足しておく。

何回目見る桁被乗数 → 足すもの合計
11 の位(1)00110011(3)3
22 の位(0)01100000(0)3
34 の位(1)11001100(12)15
48 の位(0)10000000(0)15

矢印の左が、ずらしてきた被乗数だ。 見る桁が 1 なら、それがそのまま足すものになる。0 なら、0000 に置き換わる。 2 回目は、被乗数が 0110(6)になっていても、足されるのは 0000 だ。

4 回目の 1000 は、0011 を 3 桁ずらしたものだ。 いちばん上の 1 は 4 桁からはみ出して、左端からこぼれている。 どのみち 0000 に置き換わるので、答えには効かない。

この表を、そのまま回路にする。

  • 被乗数 0011 は、左へずらすシフトレジスタに入れる。 クロックのたびに 01101100 と 2 倍になっていく。表の矢印の左で、ずれていく 3 である。
  • 乗数 0101 は、右へずらすシフトレジスタに入れる。 クロックのたびに右へずれるので、右端の 1 の位を見ていれば、1 の位・2 の位・4 の位・8 の位を順に見られる。表の「見る桁」だ。
  • 合計は、前回のアキュムレータ。表の「合計」の列そのものである。

残るのは、「見る桁が 1 なら被乗数を足し、0 なら足さない」ところだ。

足さない、はどうすればいいか。前回の自動販売機で、答えはもう出ている。 0 を足せばいい。

見る桁が 1 なら被乗数をそのまま、0 なら 0000 を出す。 これは計算シリーズ第6回の「2 進法の九九」、つまり AND そのものだ。 被乗数の 4 桁それぞれと、見る桁とを AND に入れる。AND を 4 個並べればいい。

シフト加算 シミュレータ

被乗数・乗数・合計の 3 つのレジスタを、同じクロック 1 本で動かします。「クロックを入れる」を 4 回押してください

11100100足すもの(AND)0011 = 3乗数の1の位合計(アキュムレータ)0000 = 0被乗数(左へずらす)← 0乗数(右へずらす)0 →クロック0

「足すもの」は AND 4 個(計算シリーズ第6回)。「合計」は第6回のアキュムレータ。はじめの数は、シミュレータが直接書き込んだ

被乗数0011= 3
乗数0101= 5
足すもの0011= 3
合計0000= 0

乗数の 1 の位は 1。だから「足すもの」は 被乗数をそのまま写した 3。「クロックを入れる」で、これが合計に足される

掛け算
何回目見る桁被乗数 → 足すもの合計
1
2
3
4

表は第6回の締めの表に、ずらしてきた被乗数を書き足したもの。見る桁が 0 の回は、被乗数が 0000 に置き換わる

「クロックを入れる」を、4 回押してほしい。 下の表が 1 行ずつ埋まり、4 回目で合計が 15 になる。

前回の表が、そのまま回路の上で動いた。

1 回ごとに、図の中で何が起きているかも見てほしい。 クロックが落ちた瞬間、3 つのことが同時に起きている。

  • 合計が、「足すもの」を足し込む。
  • 被乗数が、左へ 1 桁ずれる。
  • 乗数が、右へ 1 桁ずれる。

ここで、合計が足し込んだのは、ずれる前の被乗数だ。 同じ瞬間に被乗数がずれて、「足すもの」も変わる。 それでも合計は、もう受け取り終えている。 合計の前のラッチが受け取るのは、クロックが落ちる直前の値だからだ。 さきほどのバケツリレーが、ここでも効いている。

3 つのレジスタは、互いに何も相談していない。 クロック 1 本を分け合っているだけで、表の 1 行ぶんの仕事が、そろって 1 つ進む。

最初の 3 と 5 は、どこから入れたのか

ひとつ、白状しておかなければならない。

このシミュレータの被乗数 0011 と乗数 0101 は、シミュレータが直接書き込んだものだ。 回路のほうには、最初の数を入れる口が無い。

シフトレジスタの値 D は、どの桁も隣の出力でふさがっている。 空いているのは、端の入口 1 つだけだ。 最初のシミュレータで入口から流し込んだように、1 桁ずつなら入る。 けれど 4 桁を一度に入れることはできない。 しかも、流し込んでいるあいだにもクロックは来るので、合計のほうは勝手に足し込んでしまう。

前回、アキュムレータの入口が加算器でふさがっていて、覚えている数を取り替えられなかった。 同じ問題が、今回はもっと強く出ている。

「隣の値を受け取る」ときと、「外から新しい数を受け取る」ときで、入口を切り替えられればいい。 その「選ぶ仕組み」は、次回の宿題にしておこう。

部品と、時間

計算シリーズの第6回で、2 つの方式を比べた表があった。 あの表では、シフト加算方式の「覚えておく場所」を、「要る」とだけ書いていた。

いまなら、その中身を数えられる。 フリップフロップ 1 個は、第4回のとおりゲート 9 個として数える。 時間は、このサイトのシミュレータと同じく、ゲートを 1 つ通るのを 1 ステップとして数えた。

アレイ方式シフト加算方式
AND16 個4 個
全加算器12 個4 個
フリップフロップなし12 個
ゲートの数76 個132 個
答えが出るまで17 ステップ52 ステップ(13 ステップ × 4 回)

時間は、予想どおりシフト加算方式のほうがかかる。3 倍ほどだ。 1 回のクロックに要る 13 ステップは、前回のカウンタで数えたのと同じ長さである。

ところが、ゲートの数もシフト加算方式のほうが多い。 AND と全加算器は減った。 けれど覚えておく場所のフリップフロップが 12 個、ゲートにして 108 個も増えたからだ。

覚える回路は、タダではない。 4 桁では、かえって高くつく。

では、桁を増やすとどうなるか。32 桁どうしの掛け算で数えてみる。

  • アレイ方式 … AND が 32 × 32 で 1024 個。32 桁の加算器が 31 個。ゲートにして、約 6000 個。
  • シフト加算方式 … AND が 32 個。32 桁の加算器が 1 つ。フリップフロップが 96 個。ゲートにして、約 1050 個。

今度は逆転して、シフト加算方式は 6 分の 1 ほどで済む。 アレイ方式の部品は、桁数の 2 乗で増えていく。 シフト加算方式の部品は、桁数に比例してしか増えない。 数えてみると、7 桁あたりで入れ替わる。 その代わり、シフト加算方式は 32 回ぶんクロックを待たなければならない。

このシミュレータの作りでは、合計に残るのは 4 桁ぶんだけだ。4 桁どうしの積は、本当は 8 桁になる。 8 桁ぶん残すには、ずらす向きを工夫する作り方がある。フリップフロップの数はほとんど変わらないが、ここでは踏み込まない。

前回、覚える回路を手に入れて、回路は「時間」を使えるようになった、と書いた。 今回、それがはっきりした形になった。

部品を並べて一度に通り抜けるか、少ない部品に時間をかけて何度も通すか。 覚えておく場所のぶんを払っても、桁が大きくなるほど、時間で払うほうが得になる。 回路を作ることは、部品と時間の払い分けを決めることになった。

順番にしか、たどれない

最後に、シフトレジスタが苦手なことを見ておきたい。

シフトレジスタは、隣へ順番に送ることしかできない。 4 桁なら、8 の位の値を 1 の位まで運んでくるのに、クロックが 3 回要る。 32 桁なら、31 回だ。

もっと長い列を作って、たくさんの値を並べて覚えておいたとしよう。 10 個先の値が欲しくなったら、どうするか。 10 回クロックを入れて、手元まで流れてくるのを待つしかない。

カセットテープを思い出してほしい。 曲は、テープの上に順番に並んでいる。 5 曲目を聴きたければ、早送りして、テープが 5 曲目の頭まで流れてくるのを待つしかない。 これを頭出しという。

カセットデッキにカセットテープを入れる手元

5 曲目は、4 曲ぶん先にある

テープに並べておくぶんには、いくらでも覚えられる。 けれど欲しい場所へは、順番にたどっていくしかない。

たくさんの値を覚えておいて、そのうちの欲しい場所へ、一足飛びに行きたい。 10 個先の値を、10 回待たずに取り出したい。

さきほどの白状も思い出してほしい。 入れるときも、端から順番に流し込むのではなく、入れたい場所へ直接入れたい。

欲しいのは、「どこから読むか」「どこへ書くか」を選ぶ仕組みだ。

次回は、それを考えてみよう。

参考文献

シリーズ「コンピュータの記憶のしくみ