コンピュータのしくみ

INPUT · スライド

CPU が命令を動かす順

01 / 11

まず、装置は5つしかない

コンピュータの中身は複雑そうに見えるけれど、役割で分けると装置は5つしかないよ。

  • 入力装置 … キーボードやタッチパネル。外から取りこむ
  • 出力装置 … 画面やプリンタ。外へ出す
  • 記憶装置 … プログラムとデータを置いておく
  • 制御装置 … 命令を読んで、ほかの装置に指示を出す
  • 演算装置 … 計算と比較をする

この5つを 5大装置 と呼ぶ。そして大事なのは、制御装置と演算装置のふたつをまとめたものが CPU(中央処理装置)だということ。

つまり CPU がやっているのは「指示を出す」と「計算する」の2つだけだよ。データを覚えるのも、外とやりとりするのも、CPU の外側の仕事なんだ。

入力 → [ CPU ] → 出力        制御装置        演算装置        記憶装置

02 / 11

CPU の中を開けてみる

では CPU の中には何が入っているんだろう。3種類だよ。

  • 制御装置 … 命令を解読して、各部に「こう動け」と指示を出す司令塔
  • 演算装置(ALU)… 足し算・引き算・比較・論理演算を実際にやる場所
  • レジスタ … CPU の中にある、いちばん速くていちばん小さい置き場

レジスタは用途ごとに名前が分かれている。ここが試験でよく問われるところだよ。

  • プログラムカウンタ(命令アドレスレジスタ)… 次に実行する命令が置かれている番地を持つ
  • 命令レジスタいま取り出してきた命令そのものを持つ
  • 汎用レジスタ累算器 … 計算に使うデータを持つ
  • 指標レジスタ基底レジスタ … アドレスの計算に使う値を持つ
  • 状態レジスタ(フラグレジスタ)… 演算結果のようす(0になった、あふれた、負になった)を持つ。条件分岐はここを見て進む先を決める

名前が似ている2つを取りちがえないこと。持っているのが番地ならプログラムカウンタ、命令なら命令レジスタだよ。

プログラムカウンタ  次の命令の番地命令レジスタ  取り出した命令状態レジスタ  演算結果のようす

03 / 11

命令は3拍子で動く

プログラムは、動かす前に主記憶へ置かれる。そこから CPU が順に読み出しながら実行していく。この方式を プログラム格納方式(ノイマン型)というよ。いまのコンピュータはほぼ全部これだ。

読み出しから実行までは、いつも同じ3拍子をくり返している。

  • 取り出し(フェッチ)… プログラムカウンタが指す番地から命令を読んで、命令レジスタに入れる
  • 解読(デコード)… 制御装置が「何をする命令か」を読み取る
  • 実行 … 演算装置が動いて、結果をレジスタや主記憶に書く

ここで気持ちよくできているのが、取り出しが終わった時点でプログラムカウンタが自動的に次を指すこと。だから何もしなければ、命令は書いた順に上から下へ進んでいく。

順番を変えたいときだけ、分岐命令がプログラムカウンタを書きかえるiffor が実現されているのは、この1手だよ。

1 取り出し   PC の番地の命令を   命令レジスタへ2 解読   何をする命令か3 実行   演算装置が動くPC は自動で次へ進む

04 / 11

オペランドの読み方 ― 即値・直接・間接

1つの命令は、何をするかどこの値を使うかの2つでできている。前者を 命令部(オペコード)、後者を アドレス部(オペランド)と呼ぶよ。

このアドレス部の読み方が何通りもある。それが アドレス指定方式 だ。まずは3つ。

  • 即値アドレス指定 … アドレス部に書いてある値が、そのままデータ。番地を見に行かない。いちばん速い
  • 直接アドレス指定 … アドレス部の値が番地。その番地にあるデータを使う
  • 間接アドレス指定 … アドレス部の番地には別の番地が入っている。2回たどってようやくデータに届く

違いはたどる回数だよ。即値は0回、直接は1回、間接は2回。回数が増えるほど遅くなるけれど、そのぶん融通がきくようになる。

即値 その値がデータ直接 その値は番地間接 番地の先にまた番地

05 / 11

足して決める ― 指標・基底・相対

残りの3つは、アドレス部にレジスタの値を足して番地を決める方式だよ。足した結果、実際に読み書きしにいく番地のことを 実効アドレス と呼ぶ。

  • 指標アドレス指定(インデックス)… アドレス部 + 指標レジスタ。配列の n 番目を取り出すのに使う。レジスタの値を1つ増やせば隣の要素になる
  • 基底アドレス指定(ベース)… アドレス部 + 基底レジスタ。プログラムの先頭番地を入れておけば、主記憶のどこに置いても同じ命令が動く
  • 相対アドレス指定 … アドレス部 + プログラムカウンタ。いまの命令から数えて何個先か、という指し方

3つとも足し算をしているので、見分けるには何を足しているかを見ればいい。指標なら要素をずらすため、基底なら置き場所を変えるため、相対ならいまの位置から数えるためだよ。

実効アドレス =  アドレス部 + 何か指標 + 指標レジスタ基底 + 基底レジスタ相対 + PC

06 / 11

クロックが刻む速さ

CPU は好きなときに動いているわけじゃない。クロック という一定のリズムに合わせて、1拍ごとに少しずつ処理を進めている。

1秒あたりの拍数が クロック周波数 で、単位は Hz(ヘルツ)。1拍にかかる時間が クロックサイクル時間 で、周波数の逆数だよ。

数字を入れてみよう。1GHz は1秒に10億拍。だから1拍は 1 ÷ 10億 = 1ナノ秒2GHz なら1秒に20億拍で、1拍は 0.5ナノ秒。周波数が2倍になると、1拍の時間は半分になる。

ここで勘違いしやすいのが2つある。1つめ、周波数の逆数は1拍の時間であって、1命令の時間ではない。1命令に何拍かかるかは別の話だよ。

2つめ、周波数を2倍にしても、システム全体の性能は2倍にならない。主記憶やバスは CPU とは別のクロックで動いているので、CPU だけ速くしても待たされる時間が残るんだ。

1 GHz = 1秒に 10億拍 → 1拍 = 1ナノ秒2 GHz → 1拍 = 0.5ナノ秒

07 / 11

1命令に何拍か ― CPI と MIPS

1命令を終えるのに必要なクロック数を CPI(Cycles Per Instruction)というよ。ここまでそろえば、速さは式で出せる。

  • 平均命令実行時間 = CPI × クロックサイクル時間
  • 1秒間に実行できる命令数 = クロック周波数 ÷ CPI

この命令数を 100万命令/秒 の単位で書き直したものが MIPS だ。1億命令/秒なら 100 MIPS だよ。

数字でやってみよう。1GHz で CPI が 0.8 のとき、命令数は 10億 ÷ 0.8 = 12.5億命令/秒。ここで 割るのがポイントで、掛けてしまうと 8億になって合わない。

逆向きの問われ方もある。平均命令実行時間が 20ナノ秒なら、1秒 ÷ 20ナノ秒 = 5000万命令/秒。100万で割って 50 MIPS だよ。

CPI が 1 より小さいこともある。あとで出てくるパイプラインやスーパスカラを使うと、1拍あたり1命令より速く仕上がるからだ。

命令/秒 = 周波数 ÷ CPI1GHz ÷ 0.8 = 12.5億命令/秒20ナノ秒/命令 → 1 ÷ 20n = 5千万 = 50 MIPS

08 / 11

命令ミックスで平均を出す

実際の CPU では、命令の種類によって必要なクロック数が違う。レジスタどうしの足し算は速いけれど、主記憶を触る命令は遅い。

そこで、どの命令がどれくらいの割合で出てくるか(出現率)で重みをつけて平均を出す。この考え方を 命令ミックス というよ。

平均 CPI = Σ(その命令の CPI × その出現率)

700MHz の CPU で、こんな内訳だったとしよう。

  • レジスタ間演算 … 4クロック、出現率 30%
  • メモリ・レジスタ間演算 … 8クロック、出現率 60%
  • 無条件分岐 … 10クロック、出現率 10%

平均 CPI は 4 × 0.3 + 8 × 0.6 + 10 × 0.1 = 1.2 + 4.8 + 1.0 = 7クロック。あとはさっきの式に入れるだけで、700MHz ÷ 7 = 1億命令/秒 = 100 MIPS だよ。

出現率を使わずにただ平均してはいけない。この問題の落とし穴はそこだけだ。

4×0.3 = 1.28×0.6 = 4.810×0.1 = 1.0平均 CPI = 7700M ÷ 7 = 100M → 100 MIPS

09 / 11

パイプライン ― 流れ作業にする

取り出し・解読・実行を1命令ずつ順にやると、実行しているあいだ取り出しの回路は遊んでいる。もったいないよね。

そこで、命令の処理を段(ステージ)に細かく分けて、前の命令が次の段に進んだら空いた段に次の命令を入れる。工場の流れ作業と同じで、これが パイプライン処理 だよ。

大事なのは、1命令にかかる時間は短くなっていないこと。速くなっているのは単位時間に仕上がる命令の数だ。ここを取りちがえた選択肢が必ず出る。

RISC の教科書的な5段だと、こう並ぶ。

  • ① 命令フェッチ → ② 命令デコードとレジスタファイル読出し → ③ 実行とアドレス生成 → ④ メモリアクセス → ⑤ 書込み

弱点もある。分岐命令だ。次にどの命令が来るか決まる前に、後ろの命令をもう流しこんでしまっているので、予想が外れたら流した分をぜんぶ捨てることになる。この乱れを パイプラインハザード と呼ぶよ。

対策が 分岐予測投機実行。「たぶんこっちに分岐する」と予測して、分岐先が確定する前にその命令を実行し始める。当たれば丸もうけ、外れたら捨てるだけだ。

命令1 取 解 実命令2    取 解 実命令3       取 解 実1つ終わるまで待たない

10 / 11

もっと並べる ― スーパスカラとマルチコア

パイプラインで味をしめたら、次は並べる数を増やす方向に進む。名前がたくさん出てくるので、何を増やしているかで整理しよう。

  • スーパスカラ … パイプラインを何本も並べる。同じ段を複数の命令が同時に通れるので、1クロックで複数の命令を仕上げられる。どの演算器を使うかは実行のときに動的に決める
  • スーパパイプライン段をもっと細かく分けて、1段あたりの時間を短くする
  • VLIW … どの命令をどの演算器で同時に実行するかを、コンパイラが前もって割り振っておく
  • アウトオブオーダ実行 … 依存関係のない命令を、書かれた順と関係なく先に実行する
  • 同時マルチスレッディング … パイプラインの空き時間に別のスレッドを流し、1つのコアを2つに見せる
  • マルチコア … CPU の中に演算の中核(コア)を複数積む
  • GPU … 浮動小数点の演算器を大量に並べたプロセッサ。3D 演算や画像処理のように、同じ計算を大量のデータに掛ける仕事が得意

マルチコアには、覚えておきたい良さと限界がある。良さは、1つのコアのクロックを上げるより消費電力を抑えたまま性能を上げやすいこと。限界は、コアを n 倍にしても性能が n 倍にはならないこと。コアどうしが主記憶などの共有資源を取り合うので、そこで待ちが生まれるんだ。

スーパスカラ  同じ段を2命令ずつマルチコア  コアを複数積むGPU  演算器を大量に並べる

11 / 11

CISC と RISC ― 命令の作り方が逆

最後に、CPU の設計そのものの考え方を2つ。命令を豪華にするか、簡素にするかの違いだよ。

CISC は、1つの命令で複雑なことをさせる方向。命令の種類が多く、長さもばらばらで、1命令に何クロックもかかる。中では命令をマイクロ命令という細かい単位に分解して実行していて、これを マイクロプログラム制御 と呼ぶ。

RISC は逆に、命令を単純なものだけに絞る方向。長さがそろっていて、1命令が1クロックに近い時間で終わる。回路で直接動かすので ワイヤードロジック制御 という。

どちらが偉いという話ではないけれど、RISC はパイプラインと相性がいい。命令の長さと段数がそろっていると、段をずらして流しこむのがきれいに決まるからだよ。だからパイプラインの問題に RISC が出てくることが多いんだ。

CISC  命令は多くて複雑  1命令に何クロックもRISC  命令は少なく単純  段をずらしやすい