命令セット
命令セット(めいれいせっと、instruction set)は、コンピュータのハードウェアに対して命令を伝えるための言葉の語彙[1]。
目次
命令セットアーキテクチャ
コンピュータのアーキテクチャとは、もともとは、入出力インタフェースを含むコンピュータシステムのハードウェア全体(周辺機器自体は含まない)の、ユーザー(プログラマ、OSを設計するプログラマも含む)から見たソフトウェアインタフェースの定義である。具体的には使用できるレジスタの構成、命令 (コンピュータ)とデータ型、アドレッシングモード、メモリマネジメント、割り込みと例外処理、さらに(もしあれば)入出力などである。このインターフェースの違いがコンピュータ・アーキテクチャの違いであり、実装方法をマイクロアーキテクチャといい、このマイクロアーキテクチャ上に各種命令を構築した体系が命令セットアーキテクチャ (instruction set architecture, ISA) である。
マイクロアーキテクチャはプロセッサを設計する上での技術であり、マイクロコード、パイプライン、キャッシュシステムなどを含み、一般的にはアーキテクチャが異なればISAも異なるが、同じ命令セットを持つこともできる。後者の例としては、インテルのPentiumとAMDのAthlonとがある。これらは実装しているx86命令セットはほとんど同じだが内部設計は全く異なっている。
ISAは、プロセッサに実装された命令形式を二進数のコード(オペコード)のセットで表現する。オペコードのセットは、機械語とも呼ばれる。
この概念を拡大したユニークなISAとしてTIMI (Technology-Independent Machine Interface) があり、これはシステム/38とAS/400で使われている。TIMIは最近では仮想機械として知られるソフトウェアで実現されている。これはプラットフォームとそこで動作するアプリケーションの寿命を延ばすために設計されたもので、プラットフォーム全体を全く異なるハードウェアに移行してもTIMI自身だけを移植すれば、その上のオペレーティングシステムもアプリケーションもそのまま動作する。このためIBMはAS/400のハードウェアを古いCISCからPOWERに移行させたが、オペレーティングシステム (OS) を含めたソフトウェアは全く変更せずに済んだ。
命令セットの設計
マイクロアーキテクチャを設計するとき、技術者はRegister Transfer Language(コンパイラの中間形式と同じ名前だが直接の関係はない)を使って ISAの各命令の処理を定義する。
ISAをプロセッサとして実装する方法が歴史的に大きく2つ存在している。この記事は実装についての記事ではないので深くは扱わない。詳細はCPU設計などの記事を参照のこと。
この他、エミュレータや仮想機械などインタプリタ型のソフトウェアによる実装や、ハードウェア記述言語などでFPGAなどのプログラマブルロジックデバイスのコンフィギュレーションとして記述されたソフトプロセッサがある。
今日、新たなISA(あるいはマイクロアーキテクチャ)を開発しようとするベンダーはソフトウェアエミュレータを作って、ハードウェアが完成する前にソフトウェア開発者が開発に取り掛かることができるようにするのが一般的である。
命令セットの設計では、一部のオペコードをソフトウェア割り込みに利用する。例えば、6502では0x00、Z80では0xFF[2]など、68000では0xA000から0xAFFFがソフトウェア割り込みに使われた。
PopekとGoldbergの仮想化要件に適合した命令セットでは、高速な仮想機械の実装が容易になる。
複数プロセッサを搭載するシステムでは、命令セットでフェッチ・アンド・アッド、LL/SC、コンペア・アンド・スワップなどの機能をサポートすることで排他制御の実装が容易になる。
コード密度
初期のコンピュータでは、メモリは高価で容量が少なかったため、メモリ上のプログラムのサイズを削減することが重要な課題であった。そのため、ある作業をするのに要する命令列のサイズを「コード密度; code density」と呼び、命令セットの重要な特性の1つとしていた。コード密度の高い命令セットでは、1つの命令で一度にいくつもの機能を実行できるようになっている。そのような複雑な命令セットを持つコンピュータ (CISC) では、基本的な操作(加算、乗算、サブルーチンへの分岐など)に加えて、メモリアクセス、レジスタのインクリメントといった操作を同時に行う。ソフトウェア実装の命令セットではさらに複雑な命令も存在する。
RISCは、メモリの低価格化に伴って登場した考え方であり、命令セットを単純化することでコード密度は低下する。RISCでは、各命令はレジスタ同士の加算などといった単純な操作しか行わない。
MISC (Minimal Instruction Set Computer) はスタックマシンの一種であり、命令数は非常に少なく(16から64種)、1ワードに複数の命令を格納可能となっている。MISCの実装にはチップ面積はごく小さくて済み、FPGA やマルチコアでの実装に適している。コード密度はRISCと同程度である(メモリ当たりの命令密度は増加しているが、命令数が少ないため、より多くの命令実行を必要とする)。例えば、FORTH言語を実装したチップがある[1]。
命令セットの分類方法として、最も複雑な命令のオペランド数で分類する方法がある(以下で、a、b、c はメモリアドレス、reg1 などはレジスタを意味する)。
- 0オペランド(ゼロアドレスマシン) - スタックマシンとも呼ばれ、全てのオペランドをスタックから取り出して使用する。2つの数を加算する処理は4命令 (push a, push b, add, pop c) で行われる。
- 1オペランド - 初期のコンピュータでよく使われたモデルで、1つのオペランドを使って処理をし、結果をアキュムレータに格納する。2つの数を加算する処理は3命令 (load a, add b, store c) で行われる。
- 2オペランド - RISCマシンのほとんどはここに分類される。CISCマシンもここに分類されるものが多い。RISCの場合、2つの数を加算する処理は4命令 (load a,reg1, load b,reg2, add reg1,reg2, store reg2,b) で行われる。
- 3オペランド - 一部のCISCと、ごく一部の RISC がここに分類される。CISCの場合、2つの数を加算する処理は1命令 (add a,b,c) で行われるか、より一般的には(3つのオペランドがあっても、メモリを指定できるのはそのうち2つであることが多いため)2命令 (move a,reg1, add reg1,b,c) で行われる。RISCの場合、オペランドが3つであってもメモリアクセスと加算は別命令となるため、さらにロード命令とストア命令が必要になる。レジスタが32本なら、3つのオペランドを指定するのに15ビット必要となり、必然的に命令サイズは32ビットかそれ以上でなければならない。
- 4以上 - 一部のCISCでは3つ以上のレジスタを指定してメモリアクセスを行う命令が存在する。
コード密度を改善する機構として実行ファイル圧縮が研究されてきた。関連する数学上の概念としてコルモゴロフ複雑性がある。
機械語
機械語は個々の命令から構成される。アーキテクチャにもよるが、命令は通常、以下のいずれか(あるいは複数)を指定する。
- 算術演算、アドレス指定、制御用途にレジスタを指定する。
- メモリ位置やオフセットを指定する。
- オペランドを解釈するためのアドレッシングモードを指定する。
このような単純な命令を組み合わせてより複雑な操作を構築し、(ノイマン型であれば)これを逐次的に実行したり、制御フロー命令で順序を変えたりする。
多くの命令セットに共通な操作として、以下のものがある。
- 移動(コピー)
- レジスタに固定の定数値を格納する。
- あるメモリ位置からレジスタにデータを移動する(または逆方向)。そのデータに対して後から何らかの計算を行い、結果をメモリに格納する。
- ハードウェア機器からデータを読み込んだり、逆にデータを書き込んだりする。
- 計算
- 加算、減算、乗算、除算。2つのレジスタの内容についてそれら演算を行い、結果をレジスタに格納する。
- ビット演算。2つのレジスタのビット位置毎の論理和や論理積を計算したり、1つのレジスタのビット毎の否定を計算する。
- 2つのレジスタの値の比較(等しいかどうか、どちらが大きいかなど)
- 制御フローの変更
- プログラム内の別の位置にジャンプし、そこの命令を実行する。
- ある条件が成り立つときだけ別の位置にジャンプする。
- 別の位置にジャンプするが、その際にジャンプ元の次の命令の位置を記憶しておき、後でそこに戻る(サブルーチン)
コンピュータによっては命令セット内に複雑な命令を持っている。通常ならいくつもの命令を使わなければならないような操作を1つの命令で実現している。一般にそのような命令は内部で複数のステップに分解され、複数の実行ユニットを使って実現される。さもなくば、プロセッサの回路規模が大きくなりすぎることになる。そのような複雑な命令として以下のようなものがある。
- 複数のレジスタを一度にスタック上にセーブする。(コンテキストスイッチ)
- メモリを大きなブロックで移動する。
- 複雑な浮動小数点演算(三角関数、平方根など)
- テスト・アンド・セット命令などの不可分操作を実行する。
- ALUへの入力にレジスタではなく、メモリ位置を指定する命令。つまり、メモリからの移動と計算が1つの命令で行われる。
最近普通に実装されるようになった複雑な命令として、SIMD (Single-Instruction Stream Multiple-Data Stream) 命令またはベクター命令がある。これは、同じ演算操作を複数のデータに同時に行うものである。SIMD によって大きなベクトルや行列の操作を短時間で行うことが可能となる。また、音声、画像、動画などの並列化されたアルゴリズムを高速に実行できる。SIMD の実装には様々なマーケティング上の名称がつけられている(MMX、3DNow!、AltiVecなど)。
命令セットの設計は複雑な問題である。マイクロプロセッサの歴史は命令セットの設計で2つの段階に分けられる。当初、CISC すなわち複雑な命令セットが実装されていた。1970年代、IBMなどで研究が行われ、多くの命令が省略可能であることが判明した。その結果 RISC すなわち縮小された命令セットが登場した。命令セットが縮小されることで、クロックを高速化でき、プロセッサのサイズを小さくでき、電力消費を低減させることが可能となった。極端なRISCでなくとも、典型的な操作を最適化し、メモリやキャッシュの効率を向上させ、プログラミングを単純化させることができる。
ISA一覧
この一覧は完全ではない。古いものは省かれていて、新しいものはこれからも出てくるだろう。 商用のマイクロプロセッサやマイクロコントローラは様々なISAを実装している。 ISAのカスタマイズも非常によく見られる。
ハードウェアで実装されたISA
- DEC Alpha
- ARMアーキテクチャ
- IA-64
- MIPSアーキテクチャ
- 68000
- PA-RISC
- POWER
- SPARC
- SuperH
- System/360
- Tricore (Infineon)
- トランスピュータ (STMicroelectronics)
- VAX (DEC)
- x86
- バロース B5000
- PDP-11 (DEC)
ハードウェアでも実装されたが一般にはソフトウェアで実装されているISA
- p-Code (UCSD p-System Version III / ウェスタン・デジタルのPascal Micro-Engine)
- Java仮想マシン (ARM Jazelle, PicoJava)
- FORTH
ハードウェアに実装されていないISA
- SECDマシン
- ALGOL Object Code
- MMIX - ドナルド・クヌースの The Art of Computer Programming で使われている教育用途のマシン
関連項目
ISAのカテゴリー
特殊な命令セットの利用例
何らかのISAを実装しているハードウェア
その他
- コンピュータ・アーキテクチャ
- CPU設計
- エミュレータ
- 仮想機械
- Atmel AVR
- ABI
- HAL
- Streaming SIMD Extensions (SSE) 命令セット
参考文献
脚注
- ↑ パターソン&ヘネシー(上) p.44
- ↑ Ganssle, Jack. "Proactive Debugging". 2001年2月26日