アドレッシングモード
出典: フリー百科事典『ウィキペディア(Wikipedia)』
アドレッシングモード(Addressing Mode)は、CPUの命令セットアーキテクチャ(ISA)の一部を構成する。プロセッサの命令には操作対象をオペランドで指定するものがあり、その指定方法の詳細がアドレッシングモードと呼ばれるものである。したがって、広義のアドレッシングモードにはレジスタを指定する場合も、値が命令のオペランドとして直接与えられている場合も含まれるが、狭義のアドレッシングモードはオペランドとして使用すべきメモリ領域を指定するものとみなされる。
アドレッシングモードに関心があるのはコンパイラを開発する人とアセンブリ言語を直接使用する人であろう。アドレッシングモードは様々なものがISA毎に存在するが、共通の名称は存在しない。したがって、本項目で便宜的に採用している呼び方があらゆる場面で通用するわけではない。アドレッシングモードの具体的な指定方法もISAによって異なる。例えば、DECのVAXでは、オペランドであらゆるアドレッシングモードを指定している。したがって MOV 命令は一種類だけでレジスタ間の転送もレジスタ・メモリ間の転送もメモリ間の転送も行うようになっている。それに対してRISCアーキテクチャでは命令コード側にオペランドの意味を規定する情報が含まれている。例えばMIPSアーキテクチャのロード命令は転送サイズごとに命令コードがあり、メモリ→レジスタという転送だけを扱う。
目次 |
[編集] 構成要素
アドレッシングモードとは、単にアクセスすべきアドレスを指定する方法を意味するのではなく、命令のオペランドの記述方法そのものである。addressing とは「演算対象を指定する」ことを意味する。したがって、アドレッシングモードにはメモリアドレスの指定方法だけでなく、レジスタそのものや演算にそのまま使われるイミディエイト値も含まれる。アドレッシングモードを構成する要素として以下のようなものがある。
- レジスタ
- 命令のオペランドとしてレジスタそのものを指定する場合と、指定されたレジスタの内容をメモリアドレス指定に使用する場合がある。以下に列挙するのはアドレッシングモードでメモリアドレス指定に使われるレジスタであるが、あくまでもアドレッシングモードでの役割名であり、下記の名称のレジスタが必ず存在するわけではない。
- ベースポインタ(BP)/ベースレジスタ(BR)
- アクセスすべきメモリアドレスを格納するレジスタ。さらにメモリブロック(例えばC言語の構造体など)の先頭アドレスを保持して、ディスプレースメント(後述)を使用してメモリブロック内の任意のアドレスを指定するのにも使われる。
- インデックスレジスタ(IX)
- 配列のインデックスに相当する値を保持するレジスタ。単独で使われることはなく、ディスプレースメントの変数化したものと捉えることができる。
- プログラムカウンタ(PC)
- 実行中の命令のアドレス(あるいは一般に次に実行予定の命令のアドレス)を保持するレジスタ。アドレッシングモードの文脈では、プログラムの流れを制御する際(分岐命令など)に使われる特殊なベースポインタである。
- イミディエイト/即値
- 命令内に直接書かれている値を意味する。演算命令などのオペランドとしてそのまま使われる。以下に列挙するものは命令内に直接書かれアドレッシングモードでメモリアドレス指定に使われる値である。
- 直接アドレス
- アドレスを命令内で直接指定する場合に使われる。例えば大域変数のアドレスやライブラリ関数のアドレスなどは直接アドレスで指定されることが多い(ただし、ダイナミックリンクされるライブラリのアドレス指定はその限りではない)。
- ディスプレースメント/オフセット
- 何らかのベースアドレスからのオフセットを示す値である。
なお、インデックスレジスタはその性格上、必ずしもメモリアドレス全体を表せるビット幅を持つ必要はないが、一般的にはアドレス全体を表すことができるため、ベースポインタとの役割分担があいまいとなっている。
[編集] CISCのアドレッシングモード
CISCアーキテクチャでは、分岐命令やメモリアクセス(ロード/ストア)命令だけでなく、演算命令などでもメモリアクセスを行うことができる。CISCの命令セットの設計思想はアドレッシングモードを豊富に用意して、ある処理を実現するのに必要となる命令数を減らすことが大きな目標となっていた。このため、現在では使われなくなった複雑なアドレッシングモードを用意したCPUも存在する(VAXが有名。日本では日本電気のV60などは豊富なアドレッシングモードを誇っていた)。
右図は、現在最も多く使われているCISCであるx86アーキテクチャでのアドレッシングモードを示している。実効アドレス(実際にアクセスすべきメモリアドレス)はセグメント内のアドレスであり、セグメントレジスタと組み合わせることでリニアアドレスと呼ばれる一種の論理アドレスに変換されるが、この部分はメモリ管理に関わるものでアドレッシングモードには含まれない。実効アドレスは、ベースレジスタ、インデックスレジスタ、ディスプレースメントを加算することで得られるが、これらの要素は省略可能である。したがって、以下のようなアドレッシングモードが存在する。
- レジスタ間接
- ベースレジスタがアクセスすべきメモリアドレスを保持している。また、ベースレジスタを省略してインデックスレジスタだけを使う場合もこれにあたる。
- レジスタ間接・インデックス付き
- ベースレジスタにインデックスレジスタの値を加算した値がアクセスすべきメモリアドレスとなる。インデックスレジスタの値は加算する前に2倍、4倍、8倍とスケーリングすることができる。これは例えば 32ビットのデータの配列のインデックスをインデックスレジスタに保持している場合に、4倍にスケールアップすることで配列先頭からのオフセット(アドレスの差分)に変換されるような場合に使われる。
- レジスタ間接・ディスプレースメント付き
- ベースレジスタ(またはインデックスレジスタ)に命令内に直接書かれたディスプレースメントを加算した値がアクセスすべきメモリアドレスとなる。
- レジスタ間接・インデックス付き・ディスプレースメント付き
- 全部を使用した指定方法
- 直接アドレス
- ディスプレースメントのみを使用した場合。
x86では、ロード・ストア命令以外でもメモリアクセスが可能である。例えば加算の場合「A ← A + B」という形式であるため、A にメモリを指すようなアドレッシングモードを使用すると一命令で「ロード→加算→ストア」と二回のメモリアクセスを行うことになる。
[編集] RISCのアドレッシングモード
RISCアーキテクチャでは、メモリアクセスを減らすことが設計思想にあるため、ロード/ストア命令と命令フェッチ以外ではメモリにアクセスしないのが一般的である。また、ロード/ストア命令も一命令でのメモリアクセスが一回というのが原則であり、CISCに存在したメモリ間接モードは存在しない。以下では、PowerPCアーキテクチャでのアドレッシングモードを例として説明する。
- 命令アドレス指定
-
- PC相対ディスプレースメント付き
- 現在の命令アドレス(PowerPCなど命令パイプラインを持つスーパースケーラプロセッサでは複数の命令が並行して処理されているためプログラムカウンタは仮想的に現在の命令を指しているものとして扱われる)に命令内で指定されたディスプレースメントを加算して実効アドレスを求める。ディスプレースメントは符号拡張されて加算される。
- 直接アドレス
- 実際にはPC相対ディスプレースメント付きでPCを考慮しないフラグが指定されている場合、この形式となる。ディスプレースメントで指定できる範囲は全アドレス空間をカバーできない。
- レジスタ間接
- レジスタの内容を実効アドレスとして使用する。ただし、アドレス指定に使えるレジスタは2本(リンクレジスタとカウントレジスタ)に限定されている。一般的なRISCアーキテクチャでは全ての汎用レジスタが使用できるのが普通であるが、PowerPC では条件付き分岐命令にして、さらにサブルーチンからの復帰命令を同じ命令にしているため、このような制限がある。
- ロード/ストアアドレス指定
- レジスタ間接を基本として、ディスプレースメントで修飾するか、インデックスレジスタで修飾する。この場合のベースレジスタは汎用レジスタであり、分岐命令のような制限はない。また、配列などの連続した領域へのアクセスを高速化するためにアップデート形式と呼ばれるものがあり、実効アドレスへアクセスした後でベースレジスタに実効アドレスを書きこむ命令もある。アドレス指定という意味ではこれだけの形式しかないが、PowerPCは、バイト順番を逆転させるロード/ストア命令(エンディアンを考慮しなければならない場合に便利)、汎用レジスタを連続で複数本ロード/ストアする命令(コンテキストスイッチなどに便利)、複数の汎用レジスタを連続したバイト列としてロード/ストアを行う命令がある。
一般命令のアドレッシングは、レジスタかイミディエイト値のみである。
[編集] 既に使われなくなったアドレッシングモード
以下に挙げるのは、1980年代ごろまで使われていたアドレッシングモードであるが、現在では使われていない。これが全てを網羅しているものではなく、時に応じて様々なアドレッシングモードが使われてきた。例えば、直接アドレス値に複数のインデックスレジスタの論理和を加算するなどといったものもあった。
[編集] 初期のコンピュータ
EDSACなどは、主記憶装置の容量が小さいため、アドレス指定は全て直接であった(命令内にアドレスが書かれていた)。しかし、これでは配列の各要素に同じ演算をするようなループをコーディングすることが困難である。というのは、ループにしたとき毎回違う配列要素にアクセスするには命令を書き換えなければならなかったからである(実際、命令を書き換えてループさせていた)。これに対してManchester Mark Iではインデックスレジスタを実装して命令を書き換えなくても済むようにした。
別の解決方法として、次の命令のオペランドを修飾する命令を持ったマシン(Elliott 503)も存在した。つまり、メモリ上のある位置に加算すべき値を書き込んでおき、その値を読み込んで次の命令のメモリアクセスの実効アドレスを修飾するのである。
[編集] 多重メモリ間接
何らかの実効アドレスがメモリ上の領域を示していて、そこに別のメモリ領域のアドレスが格納されていて、さらにその先にまでたどってメモリの内容をとってくるような場合を多重メモリ間接という。例えばMC68020などは二重メモリ間接までは実装していた。その際、いったんメモリアクセスして取ってきたアドレス値にさらにインデックスレジスタやディスプレースメントを加算して第二の実行アドレスを計算するモードが存在した。
TRONCHIPでは「多段間接モード」を持つ。1段の間接参照操作の中で、インデックスレジスタのスケーリングと加算、オフセットの加算、メモリの間接参照、の3動作を行い、これを任意の段数反復することが可能であった。
DEC の PDP-10では、アドレスが18ビット幅でワード長が36ビットであるため、ワード内にポインタとフラグを含めることができる。メモリに格納するワードの中の、間接メモリ参照を許可するフラグを設定することによって自動的に多重メモリ間接が可能であった。この場合、ポインタがループを形成していると永久にループをたどり続けるため、注意が必要である。
[編集] メモリマップド・レジスタ
DEC PDP-10 などは、レジスタがメモリの先頭アドレス部分(0番地付近)を使って実現されていた(つまり、レジスタがメモリ空間にマップされていた)。これを活用すると、小さなループを構成する命令(機械語)をレジスタに並べておくと、高速にループを実行することができた。

