マイクロプログラム方式
マイクロプログラム方式(マイクロプログラムほうしき、マイクロプログラミング、英:microprogramming)は、プロセッサの制御装置の実装手法のひとつであり、CPU内のマイクロプログラム(マイクロコード)を使用して、複雑な命令を比較的容易に実装する。
利点としては、オペレーティングシステムを含めたソフトウェアから見た場合のハードウェア(命令セットアーキテクチャ、ISA)を、容易に追加・拡張したり、あるいはプロセッサ間で標準化して互換性を高める、更には異なる命令セットのCPUのエミュレートにも応用可能である(仮想化技術のひとつともいえる)。
反面、複雑な命令の増加はパイプラインの効果が薄れる結果ともなりやすい。
一般にROM (Read Only Memory) またはPLA(プログラマブル・ロジック・アレイ)、またはそれらを組み合わせたものに格納される。コントロールストアをRAMで構成すると、動的にプログラマブル可能にできるが起動時に読み込みが必要である。ROMにすれば読み込みは必要ないが、動的にプログラム可能という利点がなくなる。
マイクロプログラム方式は、主にCISCのCPUで採用されている。
マイクロプログラム方式に対し、論理ゲートとフリップフロップを配線でつなぎあわせて直接実装する方式はワイヤードロジック(布線論理)と呼ばれる。RISCは原則としてはワイヤードロジックで構築される。
「マイクロ」という用語は英語の小さいという一般的な意味として使われている。このため、マイクロプロセッサやマイクロコンピュータやマイクロコントローラやその他「マイクロ」と付く物とは関連性は無い。
IBMなどのベンダーではマイクロコードという語を「ファームウェア」の同義として使うことがあり、周辺機器に格納されるマイクロプログラムも機械語プログラムもまとめてマイクロコードと呼ぶことがある。
マイクロプログラム (Microprogram) は非常に特殊なコンピュータプログラムであり、あるコンピュータアーキテクチャ上でより複雑なアーキテクチャをエミュレートするものである。マイクロプログラムは一般的なプログラムに比較して非常に小さいため、マイクロプログラムと呼ばれる。可能な限り実行速度を上げるよう注意深く最適化して設計される。
他のコンピュータプログラムと同様、マイクロプログラムはマイクロ命令の列からなる。マイクロ命令はコンピュータのCPUを最も基本的なレベルで制御するものである。
例えば典型的なマイクロ命令は以下のような処理を行う。
レジスタ1をALUの入力"A"に接続する
レジスタ7をALUの入力"B"に接続する
フラグレジスタ ("condition codes") をALUのステータスフラグ ("Negative", "Zero", "Overflow", "Carry") にしたがってセットする
このような処理を並列して行うため、マイクロ命令は非常に大きな幅となることが多い。例えば56ビット(8ビットx7命令)やそれ以上になる。
マイクロプログラムはCPUのマイクロコードとしても知られている。マイクロコードはCPUの各マイクロ命令を1つの状態とした、状態遷移表をメモリであらわしたものと捉えることができる。
マイクロコードは(ファームウェアの一部として)ROMに格納されていることもあるし、CPUの初期化の一環としてRAMにロードされることもある。このため広義には、CPU以外を含むファームウェア全般をマイクロコードと呼ぶ場合もある。
コンピュータの電源投入時に、マイクロコードをロードする過程をIML(イニシャル・マイクロコード・ローダー)とも呼ぶ。またマイクロコードが格納されているメモリをコントロールストアと呼ぶ。
初期のコンピュータのCPUの制御回路は行き当たりばったりの方法で設計されていた。最も単純なものとしてはコンピュータの制御ロジックの順序制御のためにフリップフロップのリングを使っていた。
1947年、Whirlwindの開発でコントロールストアを使って設計を単純化させるという概念が導入された。この際のコントロールストアはダイオードの2次元格子回路である。CPUクロックから "pulse distributor" で8個のタイミングパルスを生成し、それぞれが格子の異なる列を活性化させるようになっている。そのタイミングパルスに同期して制御信号でその中の一列を選択すると、それぞれの交点がCPUの各部を制御する信号を発するようになっていた。
コントロールストアから発せられる信号群は、自動ピアノのピアノロールのような役割を果たす。すなわち、それぞれのビットがそれぞれの部分を制御するようになっている。ただし、コントロールストアの奏でる曲は短く、しかも繰り返し演奏される。
1951年、モーリス・ウィルクスがそれを発展させ、マイクロプログラムに「条件付実行」の概念、すなわちコンピュータプログラムにおけるif文を追加した。ウィルクスの当初の実装は、ダイオード格子回路を2つ使うもので、1つ目はWhirlwindのコントロールストアと同じように制御信号を生成し、もう1つの格子回路で次に実行すべき列(1つ目の格子回路に格納されたマイクロ命令)を選択する。条件判断は、1つ目の格子回路で選択した列の一部のビット群の値で2つ目の格子回路の列を選択できるようにすることで実装した。これを従来の単純なコントロールストアを区別するため、「マイクロプログラム方式」と名付けた。
1958年、IBM 709はマイクロコードによる商用初の別アーキテクチャのエミュレータを提供した。
1964年 IBM System/360は、マイクロコードによる上位互換の確立(標準化)により、コンピュータ・アーキテクチャを確立した
初期のマイクロプロセッサの命令セットはそれほど複雑なものではなかったが、命令デコード部の回路設計を単純化するためにプログラマブル・ロジック・アレイやROMを使用してCPU内の制御を行っていた。例えば MOS 6502 はPLAを使用して命令デコードと制御を行っていた。
マイクロプログラム方式のプロセッサのハードウェアの実装は一般のプログラマから見えるものとは違っていて、よりシンプルである。このシンプルなアーキテクチャ(マイクロアーキテクチャ)上で、プログラマに見せるアーキテクチャをエミュレートするマイクロプログラムが実行される。このマイクロアーキテクチャはプログラマに見えているアーキテクチャと固定的な関係である必要は全くない。これを利用すれば、様々なマイクロアーキテクチャのハードウェア上に任意の(プログラマから見える)アーキテクチャを実装することができる。
例えば、IBMのSystem/360は32ビットアーキテクチャで16本の汎用レジスタを持っている。しかしSystem/360の実際のハードウェアの実装ではもっと単純なマイクロアーキテクチャが実装されている。最も下位の機種である360 Model 30は8ビットのマイクロアーキテクチャでハードウェアのレジスタも少ない。プログラマが見ているものは全てマイクロプログラムがエミュレートしたものである。より上位の機種は16ビットや32ビットのマイクロアーキテクチャになっていて、プログラマから見えるアーキテクチャに近くなっているため、より高速に動作できる。
この方法により、IBMは様々なハードウェアを使用してコストと性能を勘案しバラエティに富んだSystem/360の機種をそろえ、それらを全て命令セット互換にすることができる。これにより機種別に書かなければならないシステムソフトウェア(OSなど)を劇的に減らすことが出来る。
全く同じ方法がDECのVAXコンピュータファミリでも採用された。下位機種では4ビットの2901ビットスライスプロセッサを膨大なマイクロコードとともに使用している。上位機種では大きな浮動小数点数を直接扱えるように128ビットデータパスを採用している。
マイクロプログラミングはプロセッサのバグの修正も容易にする。多くのバグはマイクロプログラムの修正で間に合い、ハードウェアのロジックや配線を修正する必要がない。
マイクロプログラム方式は原理的に1命令の実行にクロック数が多く必要になるために、ワイヤードロジック方式に比べて実行速度は遅い。
一方で、コンピュータの初期から主記憶装置はCPUに比べて相対的に遅く、複雑な処理(例えば浮動小数点数演算や文字列処理、多項式の計算)は、主記憶に記憶させた命令の組み合わせで実現するよりも、複雑な処理をする命令をCPU内部でマイクロプログラムで実現したほうがメモリへのアクセスが少なくなる分だけ短時間で処理できた。
半導体技術の進歩によって主記憶装置のビット単位の単価が劇的に下がるまでは、主記憶装置は高価であり、大型のメインフレームでも主記憶装置の容量は限られていた。そのため、より少ないビット数でより多くの機能を実行する命令セットが必要とされた。また、コンパイラ技術が未発達の段階では、高級言語の命令を単純な命令の組み合わせに置き換える事よりも、高級言語の命令に直接対応するような命令が必要とされた。
これらの多機能な命令を実装するにはマイクロプログラム方式が適していた。
マイクロプログラム方式により、のちにCISCと呼ばれるような複雑な命令(セット)が可能になった。IBMのSystem/360やDECのVAXファミリーは複雑なマイクロプログラムを使用している。
その後、キャッシュメモリの活用や、複雑な命令を排除してその分をレジスタに充てることでより高性能にできるという考えが生まれ、マイクロプログラムによる複雑な命令を廃したRISCにつながる。
IBM 801など初期のRISCではコンパイラは複雑な命令を活用できない、という観察から命令の単純化、という発想が生まれ、後にコンパイラ技術の進歩によりコンパイラがより高性能な、単純な命令を組み合わせたコードを生成できるように命令セットも工夫された。一方でTRONCHIPなど、コンパイラが活用しやすいような複雑な命令を揃えるという方向もあった。
ただし、CISCであるインテルのx86系CPUも、i486以後でワイヤードロジックなどRISCの技術を徐々に取り入れた。またRISCであるサン・マイクロシステムズのSPARC、IBMのPOWERも必要に応じて命令セットの追加を繰り返しているため、現在ではCISC、RISCという分類の意義は薄れている。
マイクロコードを使用したCPUは一般にひとつの命令を実行するのに数クロックサイクルを要する。クロックサイクル毎にその命令を実現するマイクロプログラムの1ステップを実行するのである。このためCISCプロセッサの中には非常に長い時間のかかる命令が存在するものもある。そのような命令実行時間の長さはパイプラインや割り込み遅延に影響する。
マイクロプログラム(マイクロコード)はプログラムの一種として、一般のプログラムと同様に著作権で保護されるものと判示されている。インテルとAMD間の互換CPUに関する争いではマイクロコードのライセンスも争点になっている。尚、ワイヤードロジックの場合、パターンが回路配置利用権で保護される。
チャールズ・バベッジの解析機関は一連のカムで演算を制御する方式で、それらが言わばリードオンリーのコントロールストアである。そのため、世界初のマイクロプログラム方式の設計ともいわれる。
EMIDEC 1100は、フェライトコア群に導線を通す形の固定結線のコントロールストアを採用しており、それを 'the laces' と呼んだ。
IBM System/360 シリーズの多くの機種はマイクロプログラム方式である。
モデル25は中でも独特で、主記憶である磁気コアメモリの先頭16kバイトにマイクロプログラムを格納していた。2025は16ビットのマイクロアーキテクチャで、マイクロ命令は7ワードで構成されている。電源投入時やシステムリセット時にカードリーダーからマイクロコードを読み込む方式だった。IBM 1410 のエミュレーションも同じ方式でロードする。
モデル30は8ビットのマイクロアーキテクチャでハードウェアで実装したレジスタ数も少ない。プログラマから見たアーキテクチャはマイクロプログラムでエミュレートされたものである。このモデルでも専用パンチカードリーダーからマイクロコードを読み込み、CROS (Capacitor Read-Only Storage) と呼ばれる専用記憶装置に格納する。
モデル40は56ビットのマイクロ命令を使用する。CROSによく似たTROS (Transformer Read-only Store) にマイクロプログラムを格納する。
モデル50には2つのデータパスがあり、それらが並行動作する。32ビットのデータパスは算術演算に使われ、8ビットのデータパスは論理演算に使われる。コントロールストアは90ビットのマイクロ命令を使用する。
モデル85では高速化のために命令フェッチ機構 (I-unit) と実行機構 (E-unit) を分離している。I-unit はワイヤードロジックでの制御で、E-unit はマイクロプログラム方式である。マイクロ命令は基本構成では108ビットで、エミュレータ機能を実装した場合はさらに幅広くなる。
NCR 315はフェライトコア群を手作業で結線したコントロールストアを使っている。
DECのPDP-11は、PDP-11/20以外はマイクロプログラム方式だった。
バロースの多くのシステムはマイクロプログラム方式だった。
B700は、主記憶に格納された16ビットのマイクロプログラムを使用し、アプリケーションレベルの機械語を実行する。各マイクロ命令はそのままレジスタロード命令として実行されるか、ROMに格納された56ビットの「ナノコード」にマッピングされる。これによってハードウェアが単純化され、メインフレームの周辺プロセッサとしてもスタンドアロンのコンピュータとしても使用できる。
バロース B1700は主記憶がビット単位にアドレス指定できる独特のハードウェアだが、B700と同様の階層構成になっている。オペレーティングシステムは、必要な言語のインタプリタを事前ロードする。それらインタプリタはCOBOLやFORTRANなど向けの仮想機械として機能する。
Microdataは、ユーザーがアクセス可能なマイクロプログラムを備えたコンピュータを生産していた。そのためユーザーは独自の機械語命令を実装可能だった。MicrodataのOSもこの機能を多用していた。
NINTENDO64のGPU兼オーディオプロセッサ Reality Co-Processor は、マイクロプログラム方式である。そのマイクロプログラムは書き換え可能で、必要な出力が得られるエフェクトを実装可能である。独自マイクロコードを使ったゲームの例として、ファクター5の Indiana Jones and the Infernal Machine、「スター・ウォーズ 出撃! ローグ中隊」、Star Wars: Battle for Naboo などがある。
ソニー・コンピュータエンタテインメント PlayStation 2 の Emotion Engine のVU0とVU1というベクトル演算ユニットはマイクロプログラム可能である。VU1は初期のSDKではマイクロプログラム経由でしかアクセスできなかった。
nanodata QM-1 は、マイクロプログラムが2段階になっており、マイクロコードがハードウェアを制御するのではなく、マイクロコードはナノプログラムによって解釈され、ナノプログラムがハードウェアを制御していた。
マイクロプログラム方式では、(コンピュータの構成要素である)プロセッサ自体を、さらに小さな制御装置や記憶装置や命令セットから成る小さなコンピュータであるとみなして考えることが多い。このとき、この「さらに小さな〜」などそういったものを「マイクロ〜」と呼ぶ。簡単に類推可能なので以下では特に説明せずそのような用語を使う。
マイクロプログラムはCPUを制御するビット列となる。根本的な進歩はCPU制御がコンピュータプログラムになったことである。つまり、複雑な電気回路の設計変更(すなわち従来のCPUの制御)がプログラムの変更に転換されたのである。
以下、コンピュータ内部をいくつかに分けて解説する。
マイクロシーケンサがコントロールストアの次のワードを取り出す。シーケンサとはカウンタのようなもので、コントロールストアの一部のデータにしたがってジャンプする(つまり値をカウントアップして指し示す場所を変化させる)が、場合によっては命令レジスタの内容にしたがってジャンプする。最も単純なシーケンサはコントロールストアの数ビットをロードするレジスタである。
レジスタはCPUのデータを保持する高速なメモリである。レジスタにはプログラムカウンタ、スタックポインタなどアプリケーションプログラマが簡単にはアクセスできないものも含まれる。ほとんどのレジスタファイルは3つのポートを持つ。すなわち同時にふたつのレジスタを読んで、ひとつのレジスタに書き込むのである(レジスタ間の基本的な演算命令を想起されたい:add r1,r2,r3 (r1 ← r2 + r3))。
ALUは計算を行う。加算、論理否定、右シフト、論理積、論理和などである。ALUでさらに他の機能を実現することもある。
これらは全て実行ユニットの構成要素である。最近のCPUは複数の実行ユニットを持つ。単純なコンピュータでもひとつの実行ユニットをメモリの読み書きに使用し、もうひとつの実行ユニットをユーザコードの実行に使用する。
これらの要素をひとつのチップに組み込むこともある。このチップが実行ユニットのスライスを構成し、これをビットスライスチップと呼ぶ。例えば AMD Am2900 ファミリがある。
実行ユニットの各構成要素や実行ユニット同士は複数のワイヤで結線される。これをバスと呼ぶ。
プログラマはマイクロプログラムを作成する。その際の基本ツールもソフトウェアであり、マイクロアセンブラを使ってビットテーブルをシンボリックに定義する。シミュレータでそのビットを電気回路と同じように実行してみてマイクロプログラムをデバッグする。
マイクロプログラムの設計には水平型と垂直型の2つの方向性がある。ただし、明確に分類できるものではなく、実装により中間的なもの、曖昧なものもある。水平型はマイクロ命令が直接CPU各部の制御を行う方式で、垂直型はマイクロ命令を論理回路で解釈(デコード)して実行する方式である。結果として水平型のマイクロ命令の方がビット幅が大きく、垂直型よりも多くの格納領域を必要とする。以下それぞれ説明する。
水平型の制御ワードには、相応の幅のビット列があって、CPU内の各部を制御する。56ビット以上ということも珍しくない。例えば簡単なフィールドの配置例は以下の通りである。
このタイプのマイクロマシンでジャンプ先アドレスを即値としてジャンプ命令オペコードの次に与えるジャンプ命令を実装する場合、マイクロアセンブリ言語は以下のようになる。
# シャープ記号ではじまる行はコメント
# これは単なるラベル。アセンブラにシンボリックにアドレスを指定する
# 一般的な方法である
InstructionJUMP:
# 次の命令に備えて、命令デコードのマイクロコードがプログラムカウンタを
# メモリアドレスレジスタ(MAR)にすでに格納して、次の命令と思われる内容を
# メモリデータレジスタ(MDR)にロードする。これが実はジャンプ命令の
# オペコードの次のワードであり、ジャンプ先アドレスになっている。
# そのためにMDRをMARにコピーする。
# シーケンサには"NEXT"命令を与えてコントロールストアの次の命令を取り出すよう
# 指示する。
MDR, NONE, MAR, COPY, NEXT, NONE
# この命令で、次の命令アドレスをプログラムカウンタ(PC)に格納する。
# これにより、メモリシステムに1クロックサイクルの余裕を与えて、前の
# マイクロ命令で開始されたフェッチを終了させる。
# シーケンサには命令デコードマイクロプログラムの先頭にジャンプすることを指示。
MAR, 1, PC, ADD, JMP, InstructionDecode
# 命令デコードはエミュレートするプロセッサに依存していて非常にきたない
# コードになるのでここでは示さない。この例は非常に単純化したものである。
# 多くのCPUはジャンプ先を示すにも様々な方法を用意している。
# つまり、ジャンプ命令も一種類ではない。
CPU制御のあらゆる部分を各クロックサイクル毎に記述してシーケンサを動作させるものである。
水平型のマイクロコードでは、必要ならプロセッサの各部を同時に働かせる指示ができる利点があるが、半面、多数の操作を同時にできない場合にはNOPとなるフィールドが多くならざるをえないことに注意。
垂直型は、前述のNOPのコストを削減する。ある種の垂直型マイクロコードは非常に単純なコンピュータで複雑なコンピュータをエミュレートしているようなものである。この技術はPDP-8のころは一般的だった。垂直型マイクロコードはふたつのフィールドを持つ。
「フィールドセレクト」はこのワードで制御対象としているCPU内の構成要素を指示する。「フィールドバリュー」はその構成要素を実際に制御する。このタイプのマイクロコードでは、設計者は明示的にコストを優先してCPU性能を犠牲にしていると言える。複雑さを排除することでCPUのクロック周波数を上げることができるかもしれないが、1命令あたりにかかるクロックサイクル数が増えるので効果が相殺される。
トランジスタが安価になり、水平型マイクロコードが主流となった。2000年代初頭、垂直型マイクロコードは一般のコンピュータ上で他のアーキテクチャをエミュレートするエミュレータソフトウェア以外では使われなくなった。
マイクロプログラムが完成してテストされた後、これを論理回路生成プログラムの入力データとして使用する場合もある。完璧に最適化された論理回路を生成できるプログラムは存在しないが、それなりにできのよい論理回路を使うことでコントロールストアのためのROMに使うトランジスタを減らすことができ、結果として全体のトランジスタ数を減らすことができる。これによりCPUのコストと消費電力を減らすことが出来る。
書き換え可能なマイクロコードを使っているコンピュータもある。つまり、マイクロコードをROMに格納しているのではなく、WCS (Writable Control Store) と呼ばれるRAMに格納している。そのようなコンピュータをWISC (Writable Instruction Set Computer) と呼ぶこともある。多くの場合、それらのマシンは実験用プロトタイプであったが、商用マシンでも書き換え可能なマイクロコードを採用したものがあった。初期のXeroxワークステーションやDECのVAX 8800(ノーチラス)ファミリ、シンボリックスのLISPマシンの一部、IBMのSystem/360とSystem/370のいくつかの機種、DEC PDP-10 の一部機種、データゼネラルの Eclipse MV/8000 などである。オプションとして書き換え可能なコントロールストアを用意していたマシンはさらに多い(たとえばHP HP 2100 や DEC PDP-11/60 ミニコンピュータ)。IBM System/370 ではそのためのファシリティとして IML (Initial-Microprogram Load, IMPL) を用意し、電源投入時にコンソールから起動したり、密結合マルチプロセッサシステムでもう一方のシステムから起動したりできた。
IBM 360/85 などの商用マシンでは、リードオンリーと書き換え可能の両方のコントロールストアを備えていた。
WCSの利点はマイクロプログラムに対するパッチを可能にするだけでなく、ある年代のハードウェアにとってはROMよりも高速なアクセスができるという利点もあった。ユーザがプログラム可能なWCSは、特定用途向けにマシンを最適化することができる。
インテルのx86アーキテクチャのCPUでもWCSを使っているものがある。これにより Intel Core 2 や Intel Xeon のマイクロコードのバグ修正をソフトウェアのみで実施できた。
1960年代に入ると、マイクロプログラム方式で複雑な命令を実装するという設計が増えていき、その傾向が1980年代中ごろまで続いた。そしてRISC設計哲学が登場し、盛んになっていった。
マイクロプログラム方式のCPUでは、1命令の実行に数クロックサイクルかかり、1クロックサイクルはマイクロプログラムの各ステップの実行に対応している。一部のCISCプロセッサは実行に非常に多大なクロック数のかかる命令を持っている。そのような性質は割り込みレイテンシやパイプライン処理に悪影響を及ぼす。
新たにプロセッサを設計する際、RISCのワイヤードロジックによる制御装置は、CISCのマイクロプログラム方式に比べて次のような利点がある。
アセンブリ言語でのプログラミングは主流ではなくなったため、複雑な高機能命令を実装して生産性を上げることは重要ではなくなった。
より単純な命令はハードウェアで直接実行でき、マイクロコード実行による性能低下を防ぐことができる。
分析によれば、複雑な命令は滅多に使われず、結果としてハードウェア資源の浪費につながる。
複雑な命令の実装に使われていたハードウェア資源を、単純で一般的な命令の性能向上のために使うことができる。
マイクロコードによる複雑な命令は実行に多大なクロック数を必要とし、しかも命令によって必要なクロック数が異なる場合がある。それにより、性能向上のためのパイプライン処理が難しくなる。
逆にマイクロプログラム方式にも利点はある。
マイクロプログラム方式で複雑な命令を実装したとしても、コントロールストアが大きくなるだけで他のハードウェア資源は節約できることもある。例えば、1つのALUで実効アドレスの計算と通常の演算命令の計算を兼ねることが多い(Z80、8086など)。
非RISC命令セットでは、(平均すると)1命令でより多くのことを実行できるため、同じプログラムを書いたとき命令数が少なくて済み、メモリ使用量が低減されキャッシュの効果も大きくなる。
x86系の設計では、命令をデコードした結果(マイクロ命令列)を動的なバッファに出力し、それに対して動的な並べ替え(アウトオブオーダー実行)を行う。静的なマイクロプログラム方式は自動反復命令やFPUの超越関数などの複雑な命令で使用している。
現代的なCISCアーキテクチャでは、単純な命令は直接ハードウェアで実行する設計になっていることもある。
多くのRISCおよびVLIWプロセッサは全ての命令を(その命令がキャッシュ上にある限り)1サイクルで実行する。これはマイクロコードを持つCPUがマイクロ命令を1サイクルにひとつ実行するのとよく似ている。VLIWは水平型マイクロコードのような非常に長い命令を使う。一方RISCはもっと小さい垂直型マイクロコードのような命令を使用する。
マイクロプログラム方式はネットワークプロセッサなどの特定用途向けのプロセッサで今もよく使われている。