命令セットアーキテクチャ(ISA)は、コンピュータのCPUのプログラマブルインターフェースを定義する抽象モデルであり、ソフトウェアがハードウェアとどのように相互作用するかを定義します。[ 1 ] ISAで記述された命令を解釈するデバイス(つまりCPU)は、そのISAの実装です。一般的に、関連するCPUデバイスのファミリーには同じISAが使用されます。
一般的に、ISA(命令セットアーキテクチャ)は、命令、データ型、レジスタ、およびアドレッシングモード、仮想メモリ、メモリ一貫性メカニズムなど、メインメモリを管理するためのプログラミングインターフェースを定義します。ISAには、プログラマブルインターフェースの入出力モデルも含まれます。
ISAは、そのISAの実装上で実行されるマシンコードの動作を、その実装の特性に依存しない形で規定し、実装間のバイナリ互換性を提供します。これにより、性能、物理的サイズ、コストなど、さまざまな特性が異なる複数のISA実装が存在しても、同じマシンコードを実行できるため、性能が低くコストも低いマシンを、ソフトウェアを交換することなく、コストが高く性能の高いマシンに置き換えることができます。また、 ISA実装のマイクロアーキテクチャの進化も可能になり、より新しく高性能なISA実装で、以前の世代の実装で動作するソフトウェアを実行できるようになります。
オペレーティングシステムが特定のISAに対して標準的で互換性のあるアプリケーションバイナリインターフェース(ABI)を維持している場合、マシンコードは将来のそのISAおよびオペレーティングシステムの実装上で動作します。ただし、ISAが複数のオペレーティングシステムの実行をサポートしている場合でも、最初のオペレーティングシステムが他のオペレーティングシステム用に作成されたマシンコードの実行をサポートしていない限り、あるオペレーティングシステム用のマシンコードが別のオペレーティングシステム上で動作することは保証されません。
ISAは、命令やその他の機能を追加したり、より大きなアドレスやデータ値のサポートを追加したりすることで拡張できます。拡張されたISAの実装は、それらの拡張機能を持たないバージョンのISAのマシンコードも実行できます。これらの拡張機能を使用するマシンコードは、それらの拡張機能をサポートする実装でのみ実行できます。
ISAが提供するバイナリ互換性は、ISAをコンピューティングにおける最も基本的な抽象化の1つにしている。
命令セットアーキテクチャは、マイクロアーキテクチャとは区別されます。マイクロアーキテクチャとは、特定のプロセッサにおいて命令セットを実装するために使用されるプロセッサ設計技術の集合です。異なるマイクロアーキテクチャを持つプロセッサでも、共通の命令セットを共有できます。例えば、Intel PentiumとAMD Athlonは、ほぼ同一のx86命令セットを実装していますが、内部設計は根本的に異なります。
特定の機械の設計とは区別されるアーキテクチャ という概念は、IBMのフレッド・ブルックスがSystem/360の設計段階で開発したものである。
NPL [System/360] 以前は、同社のコンピュータ設計者は、技術の選択だけでなく、機能面やアーキテクチャ面の改良によってもコスト目標を達成する自由があった。一方、SPREAD 互換性目標は、コストと性能の幅広い範囲にわたる 5 つのプロセッサに対して単一のアーキテクチャを前提としていた。5 つのエンジニアリング設計チームのいずれも、コストと性能目標の達成における困難を軽減する方法として、アーキテクチャ仕様の調整を行うことは期待できなかった。[ 2 ]: p.137
Smalltalk、Java仮想マシン、MicrosoftのCommon Language Runtimeなど、バイトコードをISAとしてサポートする一部の仮想マシンは、よく使用されるコードパスのバイトコードをネイティブマシンコードに変換することでこれを実現しています。さらに、これらの仮想マシンは、使用頻度の低いコードパスを解釈によって実行します(ジャストインタイムコンパイルを参照)。Transmetaは、この方法で、非常に長い命令語(VLIW)プロセッサ上でx86命令セットを実装しました。
ISAはさまざまな方法で分類できます。一般的な分類は、アーキテクチャの複雑さによるものです。複雑命令セットコンピュータ(CISC)は多くの特殊命令を持ち、その中には実際のプログラムではほとんど使用されないものもあります。縮小命令セットコンピュータ(RISC)は、プログラムで頻繁に使用される命令のみを効率的に実装することでプロセッサを簡素化し、あまり使用されない操作はサブルーチンとして実装され、その結果生じる追加のプロセッサ実行時間は使用頻度が低いことで相殺されます。[ 3 ]
その他のタイプには、 VLIWアーキテクチャ、およびそれと密接に関連するロングインストゥルメントワード(LIW)アーキテクチャと明示的並列命令コンピューティング(EPIC)アーキテクチャがあります。これらのアーキテクチャは、コンパイラに命令の発行とスケジューリングを任せることで、RISCやCISCよりも少ないハードウェアで命令レベルの並列性を活用しようとしています。[ 4 ]
さらに複雑さの少ないアーキテクチャも研究されており、最小命令セットコンピュータ(MISC)や1命令セットコンピュータ(OISC)などがある。これらは理論的には重要なタイプだが、商業化はされていない。[ 5 ] [ 6 ]
機械語は、個別のステートメントまたは命令から構成されます。処理アーキテクチャでは、特定の命令は以下を指定できます。
より複雑な操作は、これらの単純な命令を組み合わせることによって構築され、これらの命令は順次実行されるか、または制御フロー命令によって指示されたとおりに実行されます。
多くの命令セットに共通する操作の例としては、以下のようなものがある。
プロセッサは、命令セットに複雑な命令を含める場合があります。複雑な命令は、他のコンピュータでは多くの命令やサブルーチンを必要とするような処理を1つで実行します。このような命令は、複数のステップを実行したり、複数の機能ユニットを制御したり、あるいは特定のプロセッサが実装する単純な命令の大部分よりも大規模なものとして現れる命令によって特徴付けられます。複雑な命令の例としては、次のようなものがあります。
複雑な命令は RISC 命令セットよりも CISC 命令セットでより一般的ですが、RISC 命令セットにも含まれる場合があります。RISC 命令セットは一般的にメモリ オペランドを使用した ALU 演算や、大きなメモリ ブロックを移動する命令は含みませんが、ほとんどの RISC 命令セットには、複数のデータに対して同時に同じ算術演算を実行するSIMD命令またはベクトル命令が含まれています。SIMD 命令は、大きなベクトルや行列を最小限の時間で操作する能力を備えています。SIMD 命令を使用すると、音声、画像、ビデオ処理で一般的に使用されるアルゴリズムを簡単に並列化できます。さまざまな SIMD 実装が、 MMX、3DNow!、AltiVecなどの商標名で市場に投入されています。

従来のアーキテクチャでは、命令は、メモリの内容をレジスタに加算するなど、実行する操作を指定するオペコードと、レジスタ、メモリ位置、またはリテラルデータを指定する0個以上のオペランド指定子で構成されます。オペランド指定子は、その意味を決定するアドレッシングモードを持つ場合もあれば、固定フィールドにある場合もあります。多くのマイクロコードアーキテクチャを含む超長命令語(VLIW)アーキテクチャでは、 1つの命令で複数のオペコードとオペランドが同時に指定されます。
トランスポートトリガーアーキテクチャ(TTA)など、一部の特殊な命令セットにはオペコードフィールドがなく、オペランドのみが存在する。
ほとんどのスタックマシンは「0オペランド」命令セットを備えており、算術演算と論理演算にはオペランド指定子フィールドがありません。オペランドを評価スタックにプッシュする命令、またはスタックからオペランドをポップして変数に格納する命令のみがオペランド指定子を持ちます。命令セットは、ほとんどのALUアクションを、式スタックのみで動作し、データレジスタや任意のメインメモリセルでは動作しない後置記法(逆ポーランド記法)演算で実行します。これは、ほとんどの算術式を後置記法に簡単に変換できるため、高水準言語のコンパイルに非常に便利です。[ 8 ]
条件付き命令には、多くの場合、述語フィールドがあります。これは、操作を実行するかしないかを決定する特定の条件をエンコードする数ビットです。たとえば、条件分岐命令は、条件が真の場合に制御を転送し、実行をプログラムの別の部分へ進め、条件が偽の場合は制御を転送せず、実行を順次継続します。一部の命令セットには条件付き移動もあり、条件が真の場合は移動が実行され、データがターゲット場所に格納され、条件が偽の場合は移動が実行されず、ターゲット場所は変更されません。同様に、IBM z/Architecture には条件付きストア命令があります。一部の命令セットでは、すべての命令に述語フィールドが含まれています。命令に述語があることを述語化といい、SuperHなどの条件付き分岐を含めることができます。[ 9 ]bf
多くのアーキテクチャには、ループを制御するために設計された条件分岐命令があります。通常、レジスタを更新してテストします。例としては、
命令セットは、命令内で明示的に指定されるオペランドの最大数によって分類することができる。
(以下の例では、a、b、cはメモリセルを参照する(直接または計算された)アドレスであり、reg1などはマシンレジスタを参照します。)
C = A+B
push a、、、。push baddpop cC = A+B4 つの命令が必要です。[ 11 ]スタック マシンでは、「0 オペランド」と「ゼロ アドレス」という用語は算術命令に適用されますが、すべての命令に適用されるわけではありません。1 オペランドのプッシュおよびポップ命令はメモリへのアクセスに使用されます。load a左オペランド(および、存在する場合は宛先)とします。 add bstore cC = A+B3つの指示が必要です。[ 11 ]move Aへ、次にCへ。 add BC = A+B2つの命令が必要です。これは、明示的なストア命令なしで結果を効果的に「保存」します。load a,reg1ことが多い: ; add b,reg1; store reg1,c; これは、add結果が のように別の場所に格納される拡張であるか、 のようにC = A+B同じメモリ位置に格納されるかに関わらず、メモリ移動ごとにロード/ストア ペアを必要とします: A = A+B。 C = A+B3つの指示が必要です。load a,reg1; load b,reg2; add reg1,reg2; store reg2,c。 C = A+B4つの指示が必要です。add a,b,cC = A+B指示が1つ必要です。move a,reg1; add reg1,b,c; C = A+B2つの指示が必要です。load a,reg1; load b,reg2; add reg1+reg2->reg3; store reg3,c; C = A+B4つの指示が必要です。3オペランド命令の3つのレジスタをエンコードするために必要なビット数が多いため、16ビット命令を持つRISCアーキテクチャは、Atmel AVR、TI MSP430、および一部のARM Thumbバージョンなど、例外なく2オペランド設計となっています。32ビット命令を持つRISCアーキテクチャは、ARM、AVR32、MIPS、Power ISA、およびSPARCアーキテクチャなど、通常は3オペランド設計です。しかし、3オペランドRISCアーキテクチャであっても、精度向上のために、かなりのコストをかけて、必然的に4オペランドの乗算加算融合命令を持つことになります。現代の例としては、Power ISAとRISC-Vが挙げられます。
各命令は、いくつかのオペランド(レジスタ、メモリ位置、または即値)を明示的に指定します。命令によっては、スタックの最上位や暗黙のレジスタに格納されるなどして、1つまたは両方のオペランドを暗黙的に指定します。オペランドの一部が暗黙的に指定される場合、命令で指定する必要のあるオペランドの数は少なくなります。「宛先オペランド」が宛先を明示的に指定する場合は、追加のオペランドを指定する必要があります。したがって、命令にエンコードされるオペランドの数は、論理演算または算術演算に必要な引数の数(アリティ)と異なる場合があります。オペランドは、命令の「オペコード」表現にエンコードされるか、オペコードの後に値またはアドレスとして指定されます。
レジスタプレッシャーは、プログラム実行中の任意の時点での空きレジスタの利用可能性を測定します。レジスタプレッシャーは、利用可能なレジスタの多くが使用されている場合に高くなります。したがって、レジスタプレッシャーが高いほど、レジスタの内容をキャッシュまたはメモリに書き出す頻度が高くなりますが、キャッシュまたはメモリは速度が遅いため、大きなコストがかかります。アーキテクチャ内のレジスタ数を増やすとレジスタプレッシャーは低下しますが、コストは増加します。[ 13 ]
Thumbのような組み込み命令セットはレジスタセットが小さいためレジスタ負荷が非常に高いという問題を抱えているが、 MIPSやAlphaのような汎用 RISC ISA はレジスタ負荷が低い。x86-64 のような CISC ISA はレジスタセットが小さいにもかかわらずレジスタ負荷が低い。これは、CISC ISA が提供する多くのアドレッシング モードと最適化 (サブ レジスタ アドレッシング、ALU 命令のメモリ オペランド、絶対アドレッシング、PC 相対アドレッシング、レジスタ間スピルなど) によるものである。[ 14 ]
命令のサイズまたは長さは、一部のマイクロコントローラではわずか 4 ビットから、一部のVLIWシステムでは数百ビットまで、大きく異なります。パーソナル コンピュータ、メインフレーム、スーパー コンピュータで使用されるプロセッサの最小命令サイズは 8 ビットから 64 ビットです。x86 で可能な最長の命令は 15 バイト (120 ビット) です。[ 15 ]命令セット内では、異なる命令の長さが異なる場合があります。一部のアーキテクチャ、特にほとんどの縮小命令セット コンピュータ(RISC)では、命令は固定長であり、通常はそのアーキテクチャのワードサイズに対応します。他のアーキテクチャでは、命令は可変長であり、通常は1バイトまたはハーフワードの整数倍です。Thumb拡張機能を備えたARMなど、一部のアーキテクチャでは、可変エンコーディングが混在しています。これは、通常32ビットと16ビットの2つの固定エンコーディングであり、命令を自由に混在させることはできず、分岐(またはARMv8では例外境界)で切り替える必要があります。
固定長命令は、可変長命令に比べていくつかの理由(例えば、命令がキャッシュラインや仮想メモリページの境界をまたいでいるかどうかをチェックする必要がないなど)から処理が比較的容易であり、そのため速度の最適化も比較的容易です。[ 12 ]
1960年代初頭のコンピュータでは、メインメモリは高価で、メインフレームでさえ容量が非常に限られていました。限られたメモリに収まるようにプログラムのサイズを最小限に抑えることが、しばしば中心的な課題でした。そのため、特定のタスクを実行するために必要な命令のサイズ、つまりコード密度は、あらゆる命令セットの重要な特性でした。これは、当初は容量の小さいミニコンピュータやマイクロプロセッサのメモリでも重要でした。今日でも、スマートフォンアプリケーション、低速なインターネット接続を介してブラウザにダウンロードされるアプリケーション、組み込みアプリケーション用のROMなどにおいて、密度は依然として重要です。密度を高めることによるより一般的な利点は、キャッシュと命令プリフェッチの効率が向上することです。
コード密度が高いコンピュータは、プロシージャの開始、パラメータ付き戻り、ループなどのための複雑な命令を持つことが多い(そのため、後付けで複雑命令セットコンピュータ、CISCと呼ばれるようになった)。しかし、より一般的で頻繁に使用される「CISC」命令は、単に「加算」などの基本的な ALU 演算と、メモリ内の 1 つ以上のオペランドへのアクセス (直接、間接、インデックスなどのアドレッシング モードを使用) を組み合わせたものである。特定のアーキテクチャでは、2 つまたは 3 つのオペランド (結果を含む) を直接メモリに保持したり、自動ポインタインクリメントなどの機能を実行したりできる場合がある。ソフトウェアで実装された命令セットには、さらに複雑で強力な命令が含まれる場合がある。
RISC (Reduced Instruction-Set Computers )は、メモリサブシステムが急速に成長していた時期に初めて広く普及しました。RISCは、実装回路を簡素化するためにコード密度を犠牲にし、クロック周波数の向上とレジスタ数の増加によってパフォーマンスの向上を図っています。RISCの命令は通常、レジスタの「加算」やメモリ位置からレジスタへの「ロード」など、単一の操作のみを実行します。RISCの命令セットは通常、固定長の命令を持ちますが、一般的なCISCの命令セットは命令の長さが大きく異なります。しかし、RISCコンピュータは通常、特定のタスクを実行するためにより多くの、そして多くの場合より長い命令を必要とするため、バス帯域幅とキャッシュメモリの利用効率は必然的に低くなります。
ThumbやAVR32などの特定の組み込みRISC ISAは、コード圧縮と呼ばれる技術により、非常に高い密度を実現しています。この技術では、2つの16ビット命令を1つの32ビットワードにパックし、デコード段階でそれを展開して2つの命令として実行します。[ 16 ]
最小命令セットコンピュータ(MISC)は一般的にスタックマシンの一種であり、個別の命令数が少ない(8~32)ため、複数の命令を1つのマシンワードに収めることができます。これらのタイプのコアは実装に必要なシリコン量が少ないため、FPGA(フィールドプログラマブルゲートアレイ)やマルチコア形式で容易に実現できます。MISCのコード密度はRISCのコード密度と似ています。命令密度の増加は、タスクを実行するためにより多くの基本命令が必要になることで相殺されます。[ 17 ]
コード密度を向上させるメカニズムとして、実行可能ファイルの圧縮に関する研究が行われてきた。コルモゴロフ複雑性という数学は、この研究における課題と限界を説明するものである。
実際には、コード密度はコンパイラにも依存します。ほとんどの最適化コンパイラには、コード生成を実行速度重視で最適化するか、コード密度重視で最適化するかを制御するオプションがあります。例えば、GCCに-Osは、マシンコードのサイズを小さくする最適化オプションと、-O3マシンコードのサイズを大きくする代わりに実行速度を最適化するオプションがあります。
プログラムを構成する命令は、内部の数値形式(マシンコード)で指定されることはほとんどなく、プログラマがアセンブリ言語を使用して指定する場合もあれば、より一般的には、コンパイラによって高水準プログラミング言語から生成される場合もある。[ 18 ]
命令セットの設計は複雑な問題です。マイクロプロセッサの歴史には2つの段階があります。最初の段階はCISC(複雑命令セットコンピュータ)で、多くの異なる命令を持っていました。しかし、1970年代にIBMなどの企業が研究を行い、命令セット内の多くの命令を削除できることを発見しました。その結果生まれたのがRISC(縮小命令セットコンピュータ)で、より少ない命令セットを使用するアーキテクチャです。よりシンプルな命令セットは、高速化、プロセッササイズの縮小、消費電力の削減につながる可能性があります。一方、より複雑な命令セットは、一般的な操作を最適化したり、メモリとキャッシュの効率を向上させたり、プログラミングを簡素化したりする可能性があります。
命令セット設計者の中には、システムコールやソフトウェア割り込みのために 1 つ以上のオペコードを予約しているものがあります。たとえば、MOS Technology 6502 は00 Hを使用し、Zilog Z80は 8 つのコード C7、CF、D7、DF、E7、EF、F7、FF H [ 19 ]を使用し、 Motorola 68000 は4E40 H -4E4F Hの範囲のコードを使用します[ 20 ]。
命令セットがポペックとゴールドバーグの仮想化要件を満たしていれば、高速な仮想マシンははるかに簡単に実装できる。
メモリの「未プログラム」状態をNOPとして解釈すれば、免疫性を考慮したプログラミングで使用されるNOPスライドの実装がはるかに容易になります。
複数のプロセッサを搭載したシステムでは、命令セットに「フェッチアンドアッド」、「ロードリンク/ストア条件付き」(LL/SC)、または「アトミック比較アンドスワップ」などのサポートが含まれている場合、ノンブロッキング同期アルゴリズムの実装がはるかに容易になります。
特定の命令セットは、さまざまな方法で実装できます。特定の命令セットを実装するすべての方法は、同じプログラミングモデルを提供し、その命令セットのすべての実装は同じ実行可能ファイルを実行できます。命令セットを実装するさまざまな方法は、コスト、パフォーマンス、消費電力、サイズなどに関して異なるトレードオフをもたらします。
プロセッサのマイクロアーキテクチャを設計する際、エンジニアは加算器、マルチプレクサ、カウンタ、レジスタ、ALUなど、「ハードワイヤード」な電子回路ブロック(多くの場合、個別に設計される)を使用します。そして、この物理的なマイクロアーキテクチャを使用するISAの各命令のデコードとシーケンスを記述するために、何らかのレジスタ転送言語がよく用いられます。この記述を実装する制御ユニットを構築するには、大きく分けて2つの方法があります(ただし、多くの設計では中間的な方法や妥協案が用いられています)。
書き込み可能な制御ストアを備えたマイクロコードCPU設計の中には、命令セットを変更できるようにするためにそれを使用するものもある(例えば、RekursivプロセッサやImsys Cjipなど)。[ 21 ]
再構成可能なコンピューティング向けに設計されたCPUは、フィールドプログラマブルゲートアレイ(FPGA)を使用する場合があります。
ISAは、インタプリタによってソフトウェア上でエミュレートすることもできます。当然ながら、解釈のオーバーヘッドがあるため、エミュレート対象のハードウェア上でプログラムを直接実行するよりも遅くなります。ただし、エミュレータを実行するハードウェアが桁違いに高速な場合は別です。今日では、新しいISAやマイクロアーキテクチャのベンダーが、ハードウェア実装の準備が整う前にソフトウェア開発者向けにソフトウェアエミュレータを提供するのが一般的です。
多くの場合、実装の詳細が命令セットに選択される特定の命令に大きな影響を与えます。たとえば、命令パイプラインの多くの実装では、1つの命令につき1つのメモリロードまたはメモリストアしか許可されないため、ロードストアアーキテクチャ(RISC)になります。別の例として、命令パイプラインの初期の実装方法の中には、遅延スロットにつながるものもありました。
高速デジタル信号処理の要求は、逆の方向へと推し進め、命令を特定の方法で実装することを余儀なくさせている。例えば、デジタルフィルタを十分な速度で実行するには、一般的なデジタル信号プロセッサ(DSP)のMAC命令は、命令と2つのデータワードを同時にフェッチできるハーバードアーキテクチャの一種を使用する必要があり、単一サイクル乗算累積乗算器を必要とする。