Dev Study
← コンピュータの仕組み
レッスン 4 / 13·約 12 分·第1期 コンピュータ単体の仕組み

CPUの基本サイクル — 取ってくる・読み解く・実行する

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力
  2. DNS名前→IP
  3. ルータ経路選択
  4. ロードバランサ振り分け
  5. Nginx受け口
  6. アプリ処理今ここ
  7. DB保存

前回、論理回路を並べると計算ができることを見ました。今回はその計算装置に「次は何をするか」を指示する仕組み、CPUの動作サイクルを見ます。

まず結論

CPUは「命令を取ってくる(フェッチ)→ 何の命令か読み解く(デコード)→ 実行する」を繰り返しています。

ただしこれは、すべての命令が論理的に通らねばならない段取りであって、実物のCPUが3つの段階でできているという意味ではありません。最近のx86のCPUは同じ処理を14〜19段程度に細かく刻み、しかも複数の命令を同時に流しています。

? 読む前に予測

現代のPCに入っているCPUは、1つの命令を完全に終えてから次の命令に取りかかるでしょうか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

CPUがひたすら繰り返している3つのこと

前回、論理回路を並べると足し算ができることを見ました。しかし回路だけでは、いつ何を計算するのかが決まりません。それを決めるのがCPUの動作サイクルです。

CPUは、電源が入っている間ずっと、次の3つを繰り返しています。

  1. フェッチ(取ってくる) — メモリから次の命令を読み出す
  2. デコード(読み解く) — その0と1の並びが何の命令か判定する
  3. 実行 — 実際に計算したり、メモリに書いたりする

第1レッスンで「プログラムはデータと同じメモリに置かれている」と学びました。フェッチとは、そのメモリから命令を1つ取ってくる作業です。CPUは「次にどこから取ってくるか」をプログラムカウンタという専用の記憶場所に持っていて、命令を1つ取るたびにそれを進めます。

具体実物

1つの命令が処理される流れ

具体的に「レジスタAとレジスタBを足してCに入れる」という命令が処理される様子を追います。

add c, a, b(a と b を足して c へ)が処理される流れ
フェッチプログラムカウンタが指すアドレスから命令を読む○ 0と1の並びを入手
デコードその並びを読み解く○ 「足し算」「対象はa,b」「結果はc」と判明
実行前回作った加算回路に a と b を流す○ 和が出てくる
書き戻し結果をレジスタ c に格納○ 完了
↓
プログラムカウンタを次の命令へ進めて、また1に戻る
  • ・「実行」で使われるのが、前回組み立てた加算回路(ALU)
  • ・この繰り返しだけで、あらゆるプログラムが動いている

デコードが何をしているかというと、命令の0と1の並びを、意味のある部品に切り分けているだけです。「先頭の数ビットは操作の種類」「次の数ビットは対象のレジスタ番号」というように、あらかじめ決められた区切りで読み取ります。この区切り方の取り決めが命令セット(ISA)です。

✓ ここまでの確認

CPUは「次にどの命令を実行するか」をどうやって覚えていますか。

抽象原理

ただし、3段階というのは粗い見取り図

ここで正直に補足しておきます。「CPUはフェッチ・デコード・実行の3段階でできている」という説明は、正確ではありません。

3つの段取りはどの命令も必ず通ります。その意味で嘘ではありません。しかし実物のCPUは、この処理をもっと細かく刻んでいます。

実際のパイプライン段数(Agner Fog および Lighterra の資料より)表
CPU 段数 備考
MIPS R2000/R3000 5 教科書に出る古典的な5段
Intel Skylake世代 14〜19 デコード済み再利用で14、命令から読むと19
Intel Pentium 4 20 深すぎて後に方針転換
Pentium 4 Prescott 31 歴代でも極端に深い

なぜ細かく刻むのかは次回のパイプラインで扱います。ここで押さえてほしいのは、3段階は「論理的にこれだけのことが起きる」という見取り図であって、回路の個数ではないということです。

そしてもう一点。段数を決めているのは命令セットではなく、各CPUの実装(マイクロアーキテクチャ)です。 同じx86-64という命令セットでも、Pentium 4は20段、Skylakeは14〜19段です。「x86は何段」という問いには答えがなく、「どの世代のx86か」で決まります。

具体実物

デコードが重い、という事情

上の表で、Skylakeが「14〜19段」と幅を持っているのが気になったかもしれません。この5段ぶんの差は、デコードの費用です。

x86の命令は長さが固定ではありません。1バイトで済む命令もあれば、15バイト近くになる命令もあります。どこまでが1つの命令なのかを読み解くだけで手間がかかり、さらにCPU内部で扱いやすい単純な操作(µop)に分解する必要があります。

命令長の違い表
命令セット 命令の長さ デコードの負担
x86-64 可変(1〜15バイト) 重い。µopへの分解が必要
ARM64 固定(4バイト) 軽い
RISC-V 固定(4バイト中心) 軽い

そのためSkylakeは、一度デコードした結果をµopキャッシュに貯めておき、同じ命令を再び実行するときはデコードを飛ばします。これが「14段」の経路です。デコードから始める場合が「19段」です。

ARM64やRISC-Vが命令長を固定にしているのは、このデコードの負担を根本から減らすためです。

✓ ここまでの確認

「このCPUはx86なので、パイプラインは20段です」という説明は妥当ですか。

この章のまとめ

  • CPUは「フェッチ(取ってくる)→ デコード(読み解く)→ 実行」を延々と繰り返している。
  • 次に実行する命令の場所は、プログラムカウンタが保持している。分岐はこの値の書き換えで実現される。
  • 3段階は論理的な段取りの見取り図。最近のx86のCPUは14〜19段程度に細かく刻んでいる。
  • 段数を決めるのは命令セットではなく実装(マイクロアーキテクチャ)。同じx86でも世代で全く違う。
  • x86は命令長が可変なのでデコードが重く、µopへの分解が必要。ARM64やRISC-Vは命令長を固定してこれを避けている。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 3正解: 0

「フェッチ・デコード・実行」という3段階の説明について、最も正確なのはどれですか。

用語集(5語)
フェッチ / デコード / 実行
命令を取り出す・何の命令か読み解く・実際に処理する、という命令処理の3つの論理的段取り。実物のCPUはこれをより細かい段に分割している。
クロック
CPUの動作の刻み。3.0GHzなら1秒間に30億回の刻み。1回の刻みを1サイクルと呼び、CPUの速さを測る基本単位。
命令セット (ISA)
そのCPUがどんな命令を理解するかの取り決め。x86-64、ARM64、RISC-Vなど。「何ができるか」の仕様。
マイクロアーキテクチャ
命令セットを実際にどう実装するかの設計。SkylakeやZen 3など。同じ命令セットでも実装は世代ごとに全く違う。パイプライン段数はこちらで決まる。
µop (マイクロオペレーション)
x86の複雑な命令を、CPU内部で扱いやすい単純な操作に分解したもの。デコード段でこの変換が行われる。