マイクロアーキテクチャ

マイクロアーキテクチャとは、用語の生まれた当初としてはマイクロプログラム方式におけるコンピュータ・アーキテクチャという意味であった。内容は実質的には変わらないが、マイクロプログラム方式をとらないプロセッサも増えた現在では、命令セットアーキテクチャより下位の、実装におけるアーキテクチャ、を指してそう呼んでいる。

具体的にはCPU、DSPなどのハードウェアの動作を完全に記述できるような電子回路の設計や実装を指す。学術的用語には「コンピュータ構成」もあるが、プロセッサ業界ではマイクロアーキテクチャという用語がよく使われる。

マイクロアーキテクチャと命令セットアーキテクチャは共にコンピュータ設計の一部である。インテルは命令セットを「アーキテクチャ」、各マイクロプロセッサの設計を「マイクロアーキテクチャ」と呼ぶ場合が多い。

1. 歴史
-----

1950年代から1970年代にかけて作られた多くのコンピューターはコンピューターの命令列をデコードし実行するための制御ロジックをマイクロプログラム方式によって実現していた。マイクロプログラムのワード内のビットは、実際に計算を行うユニットを制御する電気信号であった。この時代、マイクロアーキテクチャという用語はマイクロプログラムのワードによって制御されるユニットについて記述するために用いられた。

2. 命令セットアーキテクチャとの関係
-------------------

マイクロアーキテクチャとコンピュータの命令セットアーキテクチャははっきり区別される。命令セットアーキテクチャは機械語プログラマから見たコンピュータシステムの抽象的なイメージであり、命令セット、メモリアドレス指定のモードや、レジスタ、アドレスやデータのフォーマットなどを含むものである。コンピュータ構成とはISAよりももっと低いレベルで具体的にシステムを記述したものである。

コンピュータの構成は、システムを形作る要素と、アーキテクチャの仕様を実現するためにそれらがどのように接続され、相互作用するかを示す 。

異なるマシンが同じ命令セットアーキテクチャをもつ場合もあり、すなわち同じプログラムを実行可能であるが、異なるマイクロアーキテクチャを持つ場合がある。こうした異なるマイクロアーキテクチャは新しい世代のプロセッサが以前の世代に較べ高い性能レベルを発揮するといったことを可能にしている。理論的には、ひとつのマイクロアーキテクチャは、異なった2つの制御記憶をプログラムすることで2つの異なる命令セットを実現するために用いることができる。

マシンのマイクロアーキテクチャは通常、マシンのレジスタ、バス、機能ブロックの接続を示すブロック図で表現される。図にはいくつもの実行ユニット、CPUは結果として命令を大幅に早く片付けることができ、より高いクロック速度で動作することができる。

RISCでは各ステージをきれいに分割し、同じ長さの時間、すなわち1サイクルかかるようにすることで、パイプラインをより小さく、より簡単に構築できるようにする。プロセッサは結果として製造ラインのように、命令が片方から来て反対側から出て行くように動作する。複雑さを抑えた伝統的なRISCパイプラインにより、パイプライン化されたコアと命令キャッシュを、CISCであればコアのみしか入らないようなダイに両方搭載できるようになった。これがRISCが高速な理由であった。SPARCやMIPSのような初期の設計では、同クロック・同じ値段の インテル や モトローラ のCISCチップに対してしばしば10倍以上高速に動作した。

パイプラインはRISCの設計に限定したものではまったくない。1986までにVAXの最上位機種  はかなりパイプライン化された設計で、MIPSとSPARCの最初の商業的な設計にわずかに早かった。今日ではほとんどのCPUがいまやパイプライン化されており、パイプライン化されていないマイクロコードのCPUは面積に制約がある組み込み用プロセッサでしか見られない。VAX 8800から現代の Pentium 4 と Athlon にいたる大規模なCISCマシンはマイクロコードとパイプラインの両方を使って実装されている。パイプラインとキャッシュの進歩が、マイクロアーキテクチャの進歩のうちもっとも重要なもので、プロセッサのパフォーマンスを製造技術の進歩とともに、高いペースでの性能向上の割合を保つことを可能にした。

2.1. キャッシュ
----------

チップ製造技術の向上によってダイにより多くの回路を詰め込むことができるようになり、設計者がその使い道を探すようになったのはそれほど昔のことではなかった。もっともありふれた方法はダイにキャッシュをどんどん追加していくことだった。キャッシュは単純に高速なメモリであり、メインメモリと通信するのにかかる「長い」サイクルに対して数サイクルでアクセスすることができる。CPUはキャッシュの読み書きを自動化するキャッシュコントローラを搭載し、データがキャッシュ内に存在すればすぐに読み出すことができ、なければキャッシュコントローラが読み込む間プロセッサはストールする。

1980年代の中盤から後半に、RISCの設計でキャッシュを追加していくことが始まった。たいていは全体で4KBのみであった。この数字は時代を経て増え続け、今や典型的なCPUは約512KBのキャッシュを搭載し、よりパワフルなCPUは、1～2MBあるいは4～8MBさえ搭載し、複数のレベルのメモリ階層が構成されている。一般的にいえば、大容量のキャッシュは高速化につながる。

キャッシュとパイプラインはお互いにとって完璧な組み合わせであった。それまでは、チップ外のメモリのレイテンシより高速に動作するパイプラインを作ってもあまり意味はなかった。オンチップのキャッシュメモリを使用することは、パイプラインがキャッシュのレイテンシ、すなわちより短い時間で動作できることを意味した。これによりプロセッサの動作周波数を、チップ外のメモリの速度の向上よりもかなり早いペースで向上させることができた。

2.2. 分岐予測
---------

命令レベルの並列化により高い性能を実現する上で障壁となるのが、分岐によるパイプラインのストールとフラッシュである。通常、条件分岐が発生するかどうかは、レジスタの演算結果に依存するためパイプラインの後段にならないと分からない。プロセッサの命令デコーダが条件分岐命令に出会った時点から、問題となるレジスタの値が読み出せるようになるまでの時間、パイプラインは数サイクル停止する可能性がある。平均的には、命令の五分の一は分岐であり、つまり高い頻度でストールが発生する。実際に分岐が行われると事態はより深刻で、パイプラインにあった以降すべての命令を廃棄する必要がある。

分岐予測や投機実行などの手法が分岐によるペナルティを軽減させるために用いられる。分岐予測はハードウェアがある特定の分岐が起こるかどうかを推測する。推測により、プリフェッチ命令はレジスタの読み出しを待たなくてもよくなる。投機実行はこれを大きく発展させたもので、予測された経路のコードを、分岐が発生するかどうかがわかる前に実行してしまうものである。

2.3. スーパースカラー
-------------

これまで述べてきたような方法を実装すると複雑さやゲート数が増大するのだが、半導体製造技術の向上により、すぐに多くのゲートが搭載できるようになってしまう。

上記に述べた方法では、プロセッサは一度に1つの命令の一部を実行する。もし複数の命令が同時に実行できれば、コンピュータのプログラムはより高速に動作するはずである。これがスーパースカラーの実現するもので、そのためにALUなどの機能ユニットを複数個搭載する。機能ユニットを複数搭載することは、シングルイシューのプロセッサのダイサイズが安定して生産できるダイサイズについていかなくなって初めて意味がある。1980年代の後半までには、スーパースケーラの設計が市場に登場し始めた。

現代的な設計では、ロードユニットを二つ、ストアユニットを1つ、2つ以上の整数演算ユニットと浮動小数点ユニット、何らかのSIMDユニットがよく見られる。命令発行のロジックはメモリから膨大な命令列を読み込み、その時点でアイドルになっている実行ユニットに引き渡すため複雑さが増大する。処理の結果は最後に集められ、並べ替えられる。

2.4. アウトオブオーダー
--------------

キャッシュの導入により、ストールの頻度やメモリ階層からのフェッチ待ちの時間を減少させることができるが、ストールを完全に排除できる訳ではない。初期の設計では、キャッシュミスがキャッシュコントローラにプロセッサを停止させ待機させるようになっていた。もちろん、その時点でプログラム内にキャッシュのデータが利用可能な別の命令が存在する可能性がある。アウトオブオーダー実行は、実行可能な命令が、以前の命令がキャッシュ待ちになっている間に処理できるようにし、すべてがプログラムされた順序で発生したかのように結果を並び替えることを可能にする。

2.5. 投機実行
---------

命令パイプラインの問題点の一つは、実行が継続できる前に進む方向が完全に決まっていなければならないような類の命令である。具体的には、条件分岐は、どちらの分岐に進むべきかを決定する前に、先行する命令の結果を知る必要がある。たとえば、「xが5より大きければこの処理、そうでなければこの処理」といった命令は、後続の命令をフェッチしてよいかを判断する前に、x の結果を待たなければならない。

簡単な4段パイプラインでは、遅延が最大3サイクルで、依然デコードを実行できる。しかし、クロック速度が向上すると、それにともなってパイプラインの段数が増え、現代のプロセッサでは20ステージ以上に達している。この場合、そうした命令が現れるたびにサイクルの大半CPUが停止してしまう。

解決方法、あるいはその一つは、投機実行、別名分岐予測である。分岐のどちらに進むは、実際には片方に偏っており、単純に処理を進めて 「xはおそらく5より小さいので、こちらの処理を開始」のようにして問題ない。予測の結果が正しければ、かなりの時間が節約できる。近代的な設計はさらに複雑な予測機構を持っており、過去の分岐の結果を監視して未来の分岐方向をかなりの精度で予測する。

2.6. マルチプロセッシングとマルチスレッディング
--------------------------

コンピュータのアーキテクトたちは、CPUの動作周波数とDRAMのアクセス時間との乖離に悩まされてきた。1つのプログラム内の命令レベルの並列化を利用した手法はいずれも、メインメモリからデータをフェッチする場合には長いストールを発生させる可能性がある。さらに、高度な命令レベル並列化のための膨大な数のトランジスタと高い動作周波数により発生する熱は、もはや安価に冷却できるレベルではなくなった。こうした理由により、新しい世代のコンピュータは、1つのプログラムやスレッドの範囲を超えたより高い次元の並列化手法を用い始めた。

このトレンドは「スループットコンピューティング」としても知られる。この考え方は、もともとはメインフレームの市場でオンライントランザクション処理が1トランザクションの速度ではなく、膨大な数のトランザクションを処理できる能力を強調したことに由来する。ネットワークのルーティングやWebサーバなどのこの10年で急速に増加したトランザクション的なアプリケーションに対して、コンピュータ業界は再び容量とスループットの問題を強調してきている。

並列性を実現する方法の一つはマルチプロセッシング、つまり複数のCPUを搭載したシステムを用いることである。かつてはハイエンドのメインフレームやスーパーコンピュータのためのものであったが、小規模の2-8個のマイクロプロセッサを搭載したサーバはスモールビジネスの市場で一般的になっていた。大企業では、大規模のものが一般的である。さらに複数のCPUを搭載したパーソナルコンピュータが1990年代に登場した。

半導体技術の進歩によってもたらされる、さらなるトランジスタサイズの減少はさらに進み、複数のCPUが同じシリコンチップ上に実装されたマルチコアCPUが登場している。はじめは組み込み市場をターゲットとし、シンプルで小さなCPUのみ1つのシリコン上に実装可能であった。2005年までに、半導体技術の進歩によりハイエンドのデスクトップCPUを二つ搭載した CMPチップを大量生産することが可能となった。サンマイクロシステムズの UltraSPARC T1 のように、単純な設計を踏襲し、1つのシリコンにより多くのプロセッサを詰め込む事を選択したものもある。

また、最近よく用いられるようになった技術としてマルチスレッディングがある。マルチスレッディングでは、プロセッサが低速なシステムのメモリからデータをフェッチする際、データの到着のためにストールする代わりに、プロセッサは実行可能な別のプログラムあるいはスレッドに切り替えを行う。これは特定のプログラムやスレッドの動作を高速化するものではないが、CPUのアイドル時間を減少させることで全体的なシステムのスループットを向上させる。

概念的には、マルチスレッディングはオペレーティングシステムレベルのコンテキストスイッチと等価である。違いは、マルチスレッド化されたCPUが通常のコンテキストスイッチが必要とする数百から数千のCPUサイクルを1サイクルで行ってしまうという点である。これはCPUの状態ハードウェアをアクティブなスレッドごとに持つことにより実現される。

さらなる改善方法として、同時マルチスレッディングがある。この技術は、スーパースケーラCPUに異なるプログラムの命令を同じCPUサイクルで複数実行させるものである。

History of general purpose CPUsの記事に、CPUの設計に影響を与えている研究分野のトピックが述べられている。

3. 関連項目
-------

CPU年表
マイクロプロセッサ
マイクロコントローラ
デジタルシグナルプロセッサ
CPU設計
ハードウェア記述言語
ハードウェアアーキテクチャ
ハーバードアーキテクチャ
フォンノイマンアーキテクチャ
マルチコア
データパス
データフローアーキテクチャ
VLSI
VHDL
Verilog
ストリームプロセッシング

4. 参考文献
-------

5. 読書案内
-------

[1]
[2]