アドレッシングモードは、ほとんどのCPU(中央処理装置)設計における命令セットアーキテクチャの一側面です。アドレッシングモードは、そのアーキテクチャにおける機械語命令が各命令のオペランドをどのように識別するかを定義します。アドレッシングモードは、レジスタや、機械語命令内またはその他の場所に含まれる定数に保持されている情報を使用して、オペランドの実効メモリアドレスを計算する方法を指定します。
コンピュータプログラミングにおいて、アドレッシングモードは主にアセンブリ言語の開発者とコンパイラ開発者にとって重要な概念です。関連する概念として、あらゆる命令があらゆるアドレッシングモードを使用できる能力を扱う直交命令セットを参照してください。
アドレッシングモードには一般的に認められた名称はありません。異なる著者やコンピュータメーカーが同じアドレッシングモードに異なる名称を付けたり、異なるアドレッシングモードに同じ名称を付けたりすることがあります。さらに、あるアーキテクチャでは単一のアドレッシングモードとして扱われるアドレッシングモードが、別のアーキテクチャでは2つ以上のアドレッシングモードでカバーされる機能を表す場合もあります。例えば、Digital Equipment Corporation (DEC) VAXのような一部の複雑命令セットコンピュータ(CISC) アーキテクチャでは、レジスタとリテラル定数または即値定数を単なる別のアドレッシングモードとして扱います。一方、IBM System/360とその後継機、およびほとんどの縮小命令セットコンピュータ(RISC) 設計では、この情報を命令内にエンコードします。そのため、後者のマシンでは、あるレジスタから別のレジスタへのコピー、リテラル定数のレジスタへのコピー、メモリ位置の内容をレジスタへのコピーに対して、それぞれ異なる3つの命令コードがありますが、VAXには「MOV」命令が1つしかありません。さらにややこしいことに、マイクロチップ・テクノロジー社のPICマイクロコントローラなど、一部のプロセッサはレジスタとメモリを区別しない。
「アドレッシングモード」という用語自体、解釈が分かれる。「メモリアドレス計算モード」と「オペランドアクセスモード」の2つである。前者の解釈では、メモリから読み込んだりメモリに書き込んだりしない命令(例えば「リテラルをレジスタに加算する」命令)は「アドレッシングモード」を持たないとみなされる。後者の解釈では、VAXなどのマシンはオペランドモードビットを使用してレジスタまたはリテラルオペランドを指定することができる。オペランド自体ではなく、オペランドのアドレスをロードする「実効アドレスをロードする」命令などには、前者の解釈のみが適用されている。
以下に挙げるアドレッシング方式は、コードアドレッシングとデータアドレッシングに分類されます。ほとんどのコンピュータアーキテクチャはこの区別を維持していますが、あらゆる状況で(ほぼ)すべてのアドレッシング方式を使用できるアーキテクチャも存在します(または過去に存在しました)。
以下に示す手順は、アドレス指定モードを説明するためのものであり、特定のコンピュータで使用されるニーモニックを必ずしも反映するものではありません。
IBM 709、RCA 3301などの一部のコンピュータ[ 1 ]は、単一のアドレスモードフィールドを持たず、間接アドレス指定とインデックス付けのための別々のフィールドを持っています。
コンピュータのアーキテクチャは、ハードウェアで提供するアドレッシング モードの数によって大きく異なります。複雑なアドレッシング モードを排除し、1 つまたは少数のより単純なアドレッシング モードのみを使用することには、いくつかの追加命令と、場合によっては追加のレジスタが必要になりますが、いくつかの利点があります。 [2 ] [ 3 ]利用可能なアドレッシング モードが単純なものだけであれば、パイプラインCPU の設計がはるかに容易になることが 証明されています。[ 4 ] [ 5 ] [ 6 ]
ほとんどのRISCアーキテクチャは5つ程度のシンプルなアドレッシングモードしか持たないのに対し、DEC VAXなどのCISCアーキテクチャは10種類以上のアドレッシングモードを持ち、中には非常に複雑なものもある。IBM System/360アーキテクチャは4つのアドレッシングモードしか持たず、 ESA/390アーキテクチャではさらにいくつか追加された。
アドレッシング モードが少数しかない場合、必要な特定のアドレッシング モードは通常、命令コード内にエンコードされます (例: IBM System/360 とその後継機、ほとんどの RISC)。しかし、アドレッシング モードが多数ある場合、命令内で特定のフィールドが確保され、アドレッシング モードが指定されることがよくあります。DEC VAX は、ほぼすべての命令で複数のメモリ オペランドを許可していたため、各オペランド指定子の最初の数ビットが、その特定のオペランドのアドレッシング モードを示すために予約されていました。アドレッシング モード指定子のビットをオペコードの操作ビットから分離することで、直交命令セットが実現します。
多数のアドレッシングモードを備えたコンピュータであっても、実際のプログラムの測定[ 7 ]によると、以下に挙げる単純なアドレッシングモードが、使用されるすべてのアドレッシングモードの約90%以上を占めています。このような測定のほとんどは、コンパイラによって高水準言語から生成されたコードに基づいているため、これはある程度、使用されているコンパイラの制限を反映しています。[ 8 ] [ 7 ] [ 9 ]
IBM System/360とその後継機[ 10 ] Intel x86 [ 11 ]やMotorola 68000 シリーズ[ 12 ]などの命令セットアーキテクチャには、実効アドレスロード命令 があります。これは、参照先のメモリにアクセスすることなく、実効オペランドアドレスを計算してレジスタにロードします。これは、配列要素のアドレスをサブルーチンに渡す場合に役立ちます。また、1 つの命令で通常よりも多くの計算を実行する巧妙な方法にもなります。たとえば、このような命令をアドレッシングモード「base+index+offset」(後述)で使用すると、1 つの命令で 2 つのレジスタと定数を加算し、結果を 3 番目のレジスタに格納できます。[ 13 ]
Motorola 68000シリーズなどの一部の命令セットアーキテクチャには、プッシュ実効アドレス命令も備わっています。この命令は、オペランドの実効アドレスを計算し、レジスタに格納するのではなくスタックにプッシュします。これを利用して、ポインタを関数の引数として渡すことができます。
コードのアドレス指定方法の簡単な例を以下に示します。表記はプラットフォームによって異なる場合があります。
+----+------------------------------+ |ジャンプ|アドレス| +----+------------------------------+ (実効PCアドレス=アドレス)
絶対命令アドレスの実効アドレスは、アドレスパラメータ自体であり、変更は一切加えられません。
+----+------------------------------+ |ジャンプ| オフセット | 相対ジャンプ +----+------------------------------+ (実効PCアドレス=次の命令アドレス+オフセット、オフセットは負の値になる場合もある)
PC相対命令アドレスの実効アドレスは、次の命令のアドレスにオフセットパラメータを加算したものです。このオフセットは通常、命令の前後のコードを参照できるように符号付きです。[ 14 ]
これはジャンプ命令に関連して特に有用です。なぜなら、典型的なジャンプは近くの命令へのジャンプだからです(高級言語では、ほとんどのif文やwhile文は比較的短い)。実際のプログラムの測定によると、8 ビットまたは 10 ビットのオフセットは、条件付きジャンプの約 90% に対して十分な大きさです (おおよそ ±128 バイトまたは ±512 バイト)。[ 15 ] 近くにない命令へのジャンプには、他のアドレッシング モードが使用されます。
PC相対アドレッシングのもう1つの利点は、コードが位置に依存しない、つまりアドレスを調整する必要なくメモリ内のどこにでもロードできることです。
+-------+-----+ |jumpVia| reg | +-------+-----+ (実効PCアドレス=レジスタ「reg」の内容)
レジスタ間接命令の実効アドレスは、指定されたレジスタのアドレスです。たとえば、(A7) はアドレスレジスタ A7 の内容にアクセスします。
その結果、指定されたレジスタに格納されているアドレスを持つ命令に制御が移される。
多くのRISCマシン、およびCISC系のIBM System/360とその後継機には、サブルーチン呼び出し命令があり、戻りアドレスをアドレスレジスタに格納します。レジスタ間接アドレッシングモードは、そのサブルーチン呼び出しから戻るために使用されます。
+------+ | nop | 次の命令を実行します +------+ (実効PCアドレス=次の命令アドレス)
CPUは、一連の命令を実行した後、直ちに次の命令を実行します。
逐次実行は、一部のコンピュータではアドレッシングモードとはみなされない。
ほとんどのCPUアーキテクチャにおける命令の大部分は、逐次命令です。命令の大部分が逐次命令であるため、CPU設計者は、これらの逐次命令の実行速度を向上させるために、他の命令(分岐命令)のパフォーマンスを意図的に犠牲にする機能を追加することがよくあります。
条件分岐では、条件に応じて2つの可能な結果のうちの1つがプログラムカウンタ(PC)にロードされます。ほとんどのCPUアーキテクチャでは、「実行された」分岐には別のアドレッシングモードが使用され、「実行されなかった」分岐にはシーケンシャル実行が使用されます。
現代のCPUに搭載されている多くの機能(命令のプリフェッチやより複雑なパイプライン処理、アウトオブオーダー実行など)は、各命令が次の命令の開始前に完了しているという錯覚を維持し、内部的には必ずしもそうではないにもかかわらず、同じ最終結果をもたらします。
このような一連の命令の各「基本ブロック」は、時間的および空間的な参照の局所性を示します。
プログラムカウンタを使用した逐次実行を使用しないCPUは極めてまれです。一部のCPUでは、各命令が常に次の命令のアドレスを指定します。このようなCPUには、指定されたアドレスを保持する命令ポインタがありますが、インクリメントする機能がないため、プログラムカウンタではありません。このようなCPUには、IBM 650、SECDマシン、Librascope RPC 4000、RTX 32Pなどのドラムメモリコンピュータが含まれます。 [ 16 ]
水平マイクロコードで実装されたプロセッサでは、マイクロ命令に次の命令アドレスの上位ビットが含まれる場合があります。
他のコンピューティングアーキテクチャはさらに進んで、プログラムカウンタに代わるさまざまな方法を用いてフォン・ノイマン・ボトルネックを回避しようと試みている。
コンピュータアーキテクチャによっては、条件付き命令( ARMなど。ただし、64ビットモードではすべての命令に適用されるわけではない)や条件付きロード命令(x86など)があり、これらによって条件付き分岐が不要になり、命令パイプラインのフラッシュを回避できる場合があります。「比較」などの命令を使用して条件コードを設定し、後続の命令はその条件コードに対してテストを行い、命令に従うか無視するかを判断します。
+------+-----+-----+ |skipEQ| reg1| reg2| reg1=reg2 の場合、次の命令をスキップします +------+-----+-----+ (実効PCアドレス=次の命令アドレス+1)
スキップアドレッシングは、固定オフセットを持つ特殊な PC 相対アドレッシングモードとみなすことができます。[ a ] PC 相対アドレッシングと同様に、一部の CPU には、1 つのレジスタのみを参照する (「reg1=0 の場合はスキップ」) またはレジスタを参照せず、ステータスレジスタの以前に設定されたビットを暗黙的に参照するバージョンがあります。他の CPU には、テストする特定のバイトの特定のビットを選択するバージョンがあります (「reg12 のビット 7 が 0 の場合はスキップ」)。
他のすべての条件分岐とは異なり、「スキップ」命令は命令パイプラインをフラッシュする必要はありませんが、次の命令を無視させる必要がある場合があります。
データアクセスにおけるいくつかの簡単なアドレス指定方法を以下に示します。名称はプラットフォームによって異なる場合があります。
+------+-----+-----+-----+ |マル | reg1| reg2| reg3| reg1 := reg2 * reg3; +------+-----+-----+-----+
この「アドレッシングモード」には実効アドレスがなく、一部のコンピュータではアドレッシングモードとはみなされません。
この例では、すべてのオペランドがレジスタに格納され、結果もレジスタに格納されます。
これは「ベース+変位」または「切り捨て」と呼ばれることもあります。
+------+-----+-----+----------------+ | ロード | レジスタ | ベース | オフセット | レジスタ := RAM[ベース + オフセット] +------+-----+-----+----------------+ (実効アドレス=オフセット+指定されたベースレジスタの内容)
オフセットがゼロの場合、これはレジスタ間接アドレッシングの一例となり、実効アドレスはベースレジスタの値そのものになります。
多くのRISCマシンでは、レジスタ 0はゼロに固定されています。レジスタ 0をベースレジスタとして使用すると、これは絶対アドレス指定の一例となります。ただし、アクセスできるメモリ領域はごく一部に限られます。
オフセットは、現在のコンピュータのメモリ容量に比べて小さい場合が多い。しかし、参照の局所性の原理が適用される。つまり、短時間であれば、プログラムがアクセスしたいデータ項目のほとんどは互いにかなり近い位置にある。
このアドレッシング方式は、インデックス付き絶対アドレッシング方式と密接に関連している。
例1:サブルーチン内では、プログラマーは主にパラメータとローカル変数に関心を持ちますが、通常は1つの基本レジスタ(フレームポインタ)で十分です。このルーチンがオブジェクト指向言語のクラスメソッドである場合、現在のオブジェクト(一部の高級言語ではthisまたはself )の属性を指す2つ目の基本レジスタが必要になります。
例2 :ベースレジスタに複合型(レコードまたは構造体)のアドレスが含まれている場合、オフセットは通常、そのレコードからフィールドを選択するために使用できます。
+------+-----+-----+----------------+ | 追加 | reg1| reg2| 定数 | reg1 := reg2 + 定数; +------+-----+-----+----------------+
この「アドレッシングモード」には実効アドレスがなく、一部のコンピュータではアドレッシングモードとはみなされません。
定数は符号付きでも符号なしでも構いません。たとえば、move.l #$FEEDABBA, D0「FEEDABBA」の即値(16進数)をレジスタD0に移動する場合などです。
メモリからオペランドを使用する代わりに、オペランドの値は命令自体の中に保持されます。DEC VAXマシンでは、リテラルオペランドのサイズは6ビット、8ビット、16ビット、または32ビット長でした。
アンドリュー・タネンバウムは、プログラム内のすべての定数の98%が13ビットに収まることを示しました(RISC設計思想を参照)。
+-----------------+ | クリアキャリービット | +-----------------+ +-------------------+ | アキュムレータをクリア | +-------------------+
暗黙のアドレッシングモード(x86アセンブリ言語では暗黙のアドレッシングモードとも呼ばれる)では、送信元アドレスまたは宛先アドレス(あるいはその両方)の有効アドレスを明示的に指定しません。
オペコードによって、送信元(存在する場合)または宛先の実効アドレス(あるいはその両方)が暗示される。
暗黙のアドレス指定は、古いコンピュータ(1970年代半ばまで)ではごく一般的でした。こうしたコンピュータは通常、算術演算を実行できるレジスタが1つしかなく、それがアキュムレータでした。アキュムレータマシンでは、ほぼすべての命令で暗黙的にそのアキュムレータが参照されます。例えば、演算 < a := b + c; > は、< load b; add c; store a; > というシーケンスで実行できます。すべての「load」および「add」命令では、宛先(アキュムレータ)が暗黙的に指定され、すべての「store」命令では、ソース(アキュムレータ)が暗黙的に指定されます。
後のコンピュータでは、一般的に、演算のソースまたはデスティネーション、あるいはその両方として使用できる汎用レジスタまたはRAMの場所が複数存在するようになった。そのため、後のコンピュータでは、演算のソースとデスティネーションを指定するために、別のアドレス指定モードが必要となる。
x86命令の中には、オペランドまたは結果のいずれかに暗黙のレジスタを使用するものがある(乗算、除算、カウント条件付きジャンプなど)。
一部の命令セット(x86やAVRなど)には、スタックポインタと呼ばれる特殊なレジスタがあり、スタックからデータをプッシュまたはポップする際に暗黙的にインクリメントまたはデクリメントされ、ソースまたはデスティネーションの実効アドレスは(暗黙的に)そのスタックポインタに格納されているアドレスになります。
m68k 、ARM、PowerPCなどの他の命令セットには、スタックポインタとして使用できるレジスタが複数存在するため、「レジスタ自動インクリメント間接」アドレッシングモードを使用して、スタックへのデータのプッシュまたはポップ時にどのレジスタを使用するかを指定します。
現在のコンピュータ命令セット(例えば、z/ArchitectureやIA-32 / x86-64)の中には、以前の設計との後方互換性を維持するために、暗黙のオペランドを持つ命令が含まれているものがある。
一部の命令セットでは、ユーザー/システムモードビット、割り込みイネーブルビットなどを反転させる命令が、それらのビットを保持する特殊レジスタを暗黙的に指定します。これにより、PopekとGoldbergの仮想化要件を満たすためにこれらの命令をトラップするために必要なハードウェアが簡素化されます。このようなシステムでは、トラップロジックはオペランド(または最終的な実効アドレス)を参照する必要はなく、オペコードのみを参照すればよいのです。
命令セットの中には、すべての命令においてすべてのオペランドが常に暗黙的に指定されるように設計されたものもある。これらはゼロオペランドCPUと呼ばれる。
+------+-----+--------------------------------------+ | ロード | レジストレーション | アドレス | +------+-----+--------------------------------------+ (実効アドレス=指示書に記載されているアドレス)
これには、命令内にかなり大きなアドレスを格納するためのスペースが必要です。これは、 x86などの可変長命令を持つCISCマシンでよく利用できます。
一部のRISCマシンには、レジスタの上位半分に16ビットまたは20ビットの定数を配置する特別なロード上位リテラル命令があります。これは、下位16ビットまたは12ビットを供給するベースプラスオフセットアドレッシングモードのベースレジスタとして使用できます。この組み合わせにより、完全な32ビットアドレスが可能になります。
+------+-----+-----+--------------------------------+ | ロード | レジストリ | インデックス | アドレス | +------+-----+-----+--------------------------------+ (実効アドレス=アドレス+指定されたインデックスレジスタの内容)
これには、かなり大きなアドレスを格納するための命令領域が必要となります。アドレスは配列またはベクトルの開始アドレスであり、インデックスによって必要な配列要素を選択できます。プロセッサは、各配列要素のサイズに合わせてインデックスレジスタのサイズを調整する場合があります。
これは、ベースアドレス+オフセットアドレス指定モードとほぼ同じですが、この場合のオフセットは任意のメモリ位置をアドレス指定できるほど大きいという点が異なります。
例1:サブルーチン内で、プログラマは文字列をローカル定数または静的変数として定義できます。文字列のアドレスは、命令内のリテラルアドレスに格納されます。オフセット(ループのこの反復処理で使用する文字列の文字)は、インデックスレジスタに格納されます。
例2:プログラマは、複数の大きな配列をグローバル変数またはクラス変数として定義することができます。配列の先頭は、その配列を参照する命令のリテラルアドレス(再配置ローダーによってプログラムロード時に変更される場合もある)に格納されます。オフセット(ループのこの反復処理で使用する配列の要素)は、インデックスレジスタに格納されます。多くの場合、ループ内の命令は、ループカウンタと複数の配列のオフセットに同じレジスタを再利用します。
+------+-----+-----+-----+ | ロード | レジストレーション | ベース|インデックス| +------+-----+-----+-----+ (実効アドレス=指定されたベースレジスタの内容+指定されたインデックスレジスタの内容)
ベースレジスタには配列またはベクトルの開始アドレスが格納され、インデックスによって必要な特定の配列要素を選択できます。プロセッサは、各配列要素のサイズに合わせてインデックスレジスタをスケーリングできます。これは、パラメータとして渡された配列の要素にアクセスするために使用できます。
+------+-----+-----+-----+----------------+ | ロード | レジスタ | ベース|インデックス| オフセット | +------+-----+-----+-----+----------------+ (実効アドレス=オフセット+指定されたベースレジスタの内容+指定されたインデックスレジスタの内容)
ベースレジスタにはレコードの配列またはベクトルの開始アドレスが格納され、インデックスは必要な特定のレコードを選択し、オフセットはそのレコード内のフィールドを選択する。プロセッサは、各配列要素のサイズに合わせてインデックスレジスタをスケーリングすることができる。
+------+-----+-----+-----+ | ロード | レジストレーション | ベース|インデックス| +------+-----+-----+-----+ (実効アドレス=指定されたベースレジスタの内容+指定されたインデックスレジスタのスケーリングされた内容)
ベースレジスタには配列またはベクトルデータ構造の開始アドレスが格納され、インデックスには必要な特定の配列要素のオフセットが格納される。
このアドレッシングモードでは、インデックスレジスタの値が各配列要素のサイズに合わせて動的にスケーリングされます。例えば、配列要素がそれぞれ8バイトを占める倍精度浮動小数点数である場合、インデックスレジスタの値は実効アドレス計算に使用される前に8倍されます。スケーリング係数は通常2のべき乗に制限されるため、乗算ではなくシフト演算を使用できます。
+------+------+-----+ | ロード | reg1 | ベース| +------+------+-----+ (実効アドレス=ベースレジスタの内容)
一部のコンピュータでは、これを独立したアドレス指定モードとして使用しています。多くのコンピュータでは、ベースアドレスとオフセットアドレスをオフセット値0で組み合わせたアドレス指定を使用します。例えば、(A7)
+------+-----+-------+ | ロード | レジストレーション | ベース | +------+-----+-------+ (実効アドレス=ベースレジスタの内容)
実効アドレスが決定された後、ベースレジスタの値はアクセスするデータ項目のサイズ分だけインクリメントされます。例えば、(A7)+ はアドレスレジスタ A7 の内容にアクセスし、A7 のアドレスポインタを 1 (通常は 1 ワード) だけインクリメントします。ループ内では、このアドレッシングモードを使用して配列またはベクトルのすべての要素を順に処理できます。
高級言語では、結果を返す関数は副作用を持たない方が良いとよく考えられています(副作用がないと、プログラムの理解と検証がはるかに容易になります)。このアドレッシングモードには、ベースレジスタが変更されるという副作用があります。後続のメモリアクセスでエラー(ページフォルト、バスエラー、アドレスエラーなど)が発生し、割り込みが発生した場合、1つ以上のレジスタを命令開始前の状態に戻す必要があるため、命令の再開が非常に困難になります。
このアドレッシングモードを使用した場合、障害からの復旧に関して実装上の問題を抱えたコンピュータアーキテクチャが少なくとも3つ存在する。
+------+-----+-----+ | ロード | レジストレーション | ベース| +------+-----+-----+ (実効アドレス=ベースレジスタの新しい内容)
実効アドレスを決定する前に、ベースレジスタの値は、アクセスするデータ項目のサイズ分だけ減算される。
ループ内では、このアドレス指定モードを使用して、配列またはベクトルのすべての要素を逆方向に走査できます。スタックは、このモードを前のアドレス指定モード(自動インクリメント)と組み合わせて使用することで実装できます。
自動インクリメントアドレッシングモードにおける副作用に関する説明を参照してください。
この記事で言及されているアドレッシングモードのいずれにも、間接アドレッシングを示すための追加ビットが含まれる場合があります。つまり、あるモードを使用して計算されたアドレスは、実際には実効アドレスを含む場所(通常は完全なワード)のアドレスです。一部のマシンでは、間接ワードはインデックス、間接、集計[ b ]、またはそれらの組み合わせを示す場合があります。
間接アドレッシングは、コードまたはデータに使用できます。これにより、ポインタ、参照、またはハンドルの実装がはるかに容易になり、通常ではアクセスできないサブルーチンの呼び出しも容易になります。ただし、間接アドレッシングは、余分なメモリアクセスを伴うため、パフォーマンス上のペナルティが発生します。
初期のミニコンピュータ(例えば、DEC PDP-8、Data General Novaなど)は、レジスタの数が少なく、直接アドレス指定範囲も限られていた(8ビット)。そのため、メモリの間接アドレス指定を用いることが、ある程度の量のメモリを参照するほぼ唯一の方法だった。
DEC PDP-11の8つのアドレッシングモードのうち、半分は遅延アドレッシングモードです。レジスタ遅延@Rnは、上記で定義したレジスタ間接アドレッシングと同じです。プリデクリメント遅延@-(Rn)、ポストインクリメント遅延@(Rn)+、およびインデックス付き遅延@nn(Rn)モードは、パラメータのアドレスを見つけるために読み出されるメモリ内のアドレスを指します。PDP-11の遅延モードは、プログラムカウンタと組み合わせることで、絶対アドレッシングモードを提供します。
+------+------+---------+----------------+ | ロード | reg1 | ベース=PC | オフセット | +------+------+---------+----------------+ reg1 := RAM[PC + offset] (実効アドレス=PC+オフセット)
PC相対アドレッシングモードは、現在の命令から少し離れたプログラムメモリに格納されている値をレジスタにロードするために使用できます。これは、「ベース+オフセット」アドレッシングモードの特殊なケースと見なすことができ、プログラムカウンタ(PC)を「ベースレジスタ」として選択します。
PC相対データ参照をサポートするCPUはいくつか存在する。そのようなCPUには以下のようなものがある。
x86-64アーキテクチャと64ビットARMv8-Aアーキテクチャ[ 25 ]は、PC相対アドレッシングモードを備えており、x86-64では「RIP相対」、ARMv8-Aでは「リテラル」と呼ばれています。Motorola 6809もPC相対アドレッシングモードをサポートしています。
PDP -11アーキテクチャ、VAXアーキテクチャ、および32ビットARMアーキテクチャは、レジスタファイルにPC(プログラムカウンタ)を含めることで、PC相対アドレッシングをサポートしています。
IBM z/Architectureには、 汎用命令拡張機能が有効な場合、PC相対アドレッシングを使用するLoad Relative Longなどの特定の命令が含まれています。
このアドレッシングモードを使用する場合、コンパイラは通常、定数をそれらを使用するサブルーチンの直前または直後にリテラルプールに配置し、定数が誤って命令として実行されるのを防ぎます。
このアドレッシングモードは、常にメモリからデータをフェッチするか、メモリにデータを格納してから、次の命令を順次実行します(実効アドレスはデータを指します)。これは、メモリからデータをフェッチしたりメモリにデータを格納したりせず、指定されたオフセットにある別の命令に分岐する「PC相対分岐」と混同してはいけません(実効アドレスは実行可能な命令を指します)。
ここに挙げたアドレッシングモードは1950~1980年代に使用されていましたが、現在のほとんどのコンピュータでは利用できません。このリストは決して完全なものではありません。他にも、2つまたは3つのインデックスレジスタの絶対マイナス論理ORなど、興味深く独特なアドレッシングモードが時折使用されていました。[ 26 ] [ 27 ]
ワードサイズがアドレスよりも大きい場合、メモリ間接アドレッシングで参照されるワード自体に、別のメモリ間接サイクルを示す間接フラグが設定されることがあります。このフラグは間接ビットと呼ばれ、結果として得られるポインタはタグ付きポインタとなります。間接ビットは、それが直接ポインタか間接ポインタかをタグ付けします。間接アドレスの連鎖が自身を参照しないように注意が必要です。もし参照してしまうと、アドレスを解決しようとした際に無限ループに陥る可能性があります。
IBM 1620、データゼネラル Nova、およびHP 2100シリーズはいずれもこのような多段階メモリ間接アドレッシングを備えており、無限アドレス計算ループに陥る可能性があった。Nova のメモリ間接アドレッシングモードは、間接スレッドコードの発明に影響を与えた。
18ビットアドレスと36ビットワードを持つDEC PDP-10コンピュータは、各ステージでインデックスレジスタを使用する可能性もあるマルチレベル間接アドレッシングを可能にした。優先度割り込みシステムは、すべてのアドレスワードのデコード前に照会された。[ 28 ]そのため、間接アドレスループは、プリエンプティブマルチタスクスケジューラのタイムスライス期限切れハンドラ を含むデバイスサービスルーチンの実行を妨げなかった。ループ命令は、他の計算バウンドジョブと同様に扱われた。
一部のコンピュータでは、主記憶装置ではなくレジスタを参照するアドレス、またはそれらのレジスタを実装するために使用される主記憶装置を参照するアドレスがありました。初期のコンピュータの中には、アドレス範囲の上限にレジスタ アドレスを持つものもありましたが(例: IBM 650 [ 29 ] [ c ] IBM 7070 [ 30 ] [ e ])、レジスタ アドレスを 下限にのみ使用し、メモリの最初の 8 語または 16 語のみを使用する傾向がありました (例: ICL 1900、DEC PDP-6/PDP-10)。これは、個別の「レジスタからレジスタへの加算」命令は不要で、「メモリからレジスタへの加算」命令を使用するだけで済むことを意味しました。
キャッシュメモリを搭載していなかった初期のPDP-10モデルの場合、レジスタを格納するための高速回路を提供しつつ、レジスタをメモリ内にあるかのようにアドレス指定できるようにする「高速レジスタ」オプションをインストールすると、メモリの最初の数ワードにロードされたタイトな内部ループが、磁気コアメモリの場合よりもはるかに高速に動作した。
DEC PDP-11シリーズの後期モデルでは、レジスタが入出力領域のアドレスにマッピングされるようになったが、これは主にリモート診断を可能にするためのものであった。紛らわしいことに、16ビットレジスタは連続する8ビットバイトアドレスにマッピングされていた。
DEC PDP-8ミニコンピュータには、8 つの特別な場所 (アドレス 8 ~ 15) がありました。メモリ間接アドレッシングによってアクセスされると、これらの場所は使用前に自動的にインクリメントされました。[ 31 ]これにより、アキュムレータを使用してアドレスをインクリメントする必要なく、ループでメモリを簡単にステップ実行できました。
データゼネラル社のNovaミニコンピュータには、アドレス16から31に16個の特別なメモリ位置がありました。[ 32 ]メモリ間接アドレッシングでアクセスすると、16から23は使用前に自動的にインクリメントされ、24から31は使用前に自動的にデクリメントされました。
データゼネラル社のNova、モトローラ社の6800シリーズ、およびMOSテクノロジー社の6502シリーズといったプロセッサは、内部レジスタが非常に少なかった。算術演算や論理演算は、内部レジスタではなくメモリ内の値に対して実行されることが多かった。そのため、多くの命令はメモリ上の2バイト(16ビット)のアドレスを必要とした。これらのプロセッサのオペコードは1バイト(8ビット)の長さしかなかったため、メモリアドレスがコードサイズのかなりの部分を占める可能性があった。
これらのプロセッサの設計者は、「ゼロページ」アドレッシングと呼ばれる部分的な解決策を組み込んだ。最初の256バイトのメモリ($0000~$00FF、別名「ページ0」)には、1バイトの絶対アドレスまたはインデックス付きメモリアドレスを使用してアクセスできた。これにより、命令実行時間が1クロックサイクル、命令長が1バイト短縮された。頻繁に使用されるデータをこの領域に格納することで、プログラムをより小さく、より高速にすることができた。
その結果、ゼロページはレジスタファイルと同様の用途で使用されるようになった。しかし、多くのシステムでは、オペレーティングシステムやユーザープログラムによるゼロページメモリ領域の利用率が高くなり、空き容量が限られるため、その利用が制限されるという問題が生じた。
ゼロページアドレスモードは、 WDC 65816、CSG 65CE02、Motorola 6809など、いくつかの後期型8ビットプロセッサで拡張されました。この新しいモードは「ダイレクトページ」アドレッシングと呼ばれ、256バイトのゼロページメモリウィンドウをメモリの先頭(オフセットアドレス$0000)から最初の64KB のメモリ内の新しい場所に移動できるようになりました。
CSG 65CE02は、新しいベースページ(B)レジスタに8ビットのオフセット値を格納することで、ダイレクトページを メモリの最初の64KB内の任意の256バイト境界に移動できるようにしました。Motorola 6809も、ダイレクトページ(DP)レジスタで同様の操作が可能でした。WDC 65816はさらに一歩進んで、新しいダイレクト (D)レジスタに16ビットのオフセット値を格納することで、ダイレクトページをメモリの最初の64KB内の任意の位置に移動できるようにしました。
その結果、ゼロページアドレッシングモードしか搭載していなかった従来のプロセッサと比較して、より多くのプログラムが拡張された直接ページアドレッシングモードを利用できるようになりました。
これはスケーリングされたインデックスアドレッシングに似ていますが、命令に2つの追加のオペランド(通常は定数)があり、ハードウェアがインデックス値がこれらの範囲内にあるかどうかをチェックする点が異なります。
別の方法として、ベクトル記述子を使用して境界を保持する方法があります。これにより、動的に割り当てられた配列を簡単に実装でき、完全な境界チェックも実現できます。
一部のコンピュータには、ワード内のサブフィールドに対して特別な間接アドレス指定モードが備わっていた。
GE /Honeywell 600シリーズの文字アドレッシング間接ワードでは、 36ビットワード内に6ビットまたは9ビットの文字フィールドが指定されていました。
同じく36ビットのDEC PDP-10には、メモリを固定サイズのビットフィールドのシーケンスとして、または1ビットから36ビットまでの任意のサイズのバイトとして扱うことができる特殊な命令セットがあった。メモリ内の1ワードのシーケンス記述子は「バイトポインタ」と呼ばれ、シーケンス内の現在のワードアドレス、ワード内のビット位置、および各バイトのサイズを保持していた。
この記述子を介してバイトをロードおよびストアし、記述子をインクリメントして次のバイトを指すようにする命令が存在した(バイトはワード境界をまたいで分割されなかった)。多くの DEC ソフトウェアは、ワードごとに 5 つの 7 ビット バイト (プレーン ASCII 文字) を使用し、ワードごとに 1 ビットが未使用であった。C の実装では、C の 'malloc' 関数がintのサイズがcharのサイズの何らかの倍数であると想定しているため、ワードごとに 4 つの 9 ビット バイトを使用する必要があった。[ 33 ]実際の倍数は、システム依存のコンパイル時演算子sizeofによって決定される。
Elliott 503 [ 34 ]、Elliott 803 [ 34 ] [ 35 ] 、およびアポロ誘導コンピュータは絶対アドレッシングのみを使用し、インデックスレジスタは持っていませんでした。したがって、間接ジャンプ、つまりレジスタを介したジャンプは、命令セットではサポートされていませんでした。代わりに、現在のメモリワードの内容を次の命令に加算するように指示することができました。実行される次の命令に小さな値を加えると、たとえば、JUMP 0を に変更することができJUMP 20、インデックス付きジャンプの効果を生み出すことができます。命令は実行時に変更され、メモリ内では変更されないことに注意してください。つまり、自己変更コードではありません。次の命令に加算される値が十分に大きい場合、アドレスだけでなく、またはその代わりに、その命令のオペコードを変更することができました。
*p++と同様に、データを超えてアドレスをステップすること。*--pのスタックプッシュ操作と同様。... MIPS-X は、ベースレジスタとオフセットという単一のアドレッシング モードを使用します。このシンプルなアドレッシング モードにより、実効アドレスの計算を非常に早い段階で開始できます。 ...
レジスタアクセスを除いて17種類のデータアドレッシングモードがありますが、MIPSに見られる4種類が全体の70%を占めています。一部のRISCアーキテクチャに見られる自動インクリメントと自動デクリメントが、使用率のさらに25%を占めています。このデータは、アセンブリ言語で記述された54個のDSPルーチンからなるC言語呼び出し可能ライブラリの静的命令の測定から収集されました。
すべてのアドレスモード(VAX)を備えたマシンで3つのプログラムを測定... 75%の変位と即時
実行された全命令の 79% は、基本ブロック命令の組み合わせのみを使用して RISC 命令に置き換えるか、RISC 命令に合成することができました。
LEA (ロード実効アドレス) 命令は、ソース オペランドのメモリ内の実効アドレス (セグメント内のオフセット) を計算し、汎用レジスタに格納します。 この命令は、プロセッサの任意のアドレッシング モードを解釈でき、必要なインデックス付けやスケーリングを実行できます。 これは、文字列命令の実行前に ESI レジスタまたは EDI レジスタを初期化する場合、または XLAT 命令の実行前に EBX レジスタを初期化する場合に特に役立ちます。
図2-9:実効アドレス計算:テスト「PI RQ
?」