アドレッシングモード

アドレッシングモード("Addressing Mode")は、CPUの命令セットアーキテクチャ(ISA)において、命令のオペランド部（演算の対象となるデータのこと）を表すための方法のことである。一般に、プロセッサの命令において、オペランドとその結果を出力する場所が必要である。アドレッシングモードは、結果を出力する場所をオペランドと同じ場所とし、オペランドの領域に結果を書き戻す方法である。これによって、命令での場所の指定が最小限に抑えられる。そのため、狭義のアドレッシングモードでは、オペランドとして使用すべきメモリ領域を指定する。しかし、広義には、レジスタを指定したり、値が命令のオペランドとして直接与えられたりする場合も含まれる。
プログラミングの観点では、アドレッシングモードはコンパイラ開発を行う時やアセンブリ言語を利用する際に重視される。
アドレッシングモードの複雑さ.
コンピュータ・アーキテクチャが異なれば、それぞれに独自のアドレッシングモードが存在する。複雑なアドレッシングモードには、使用する命令数やレジスタの削減といった利点がある。一方、単純なアドレッシングモードだけにすることには、CPUの命令パイプラインの設計が容易になるという利点があるとされる。
RISCでは一般にアドレッシングモードが少なく単純だが、DECのVAXなどのCISCでは1ダース以上のアドレッシングモードを備え、その一部は非常に複雑である。IBM System/360 は3種類のアドレッシングモードしか持たなかったが、System/390ではいくつか追加された。
アドレッシングモードが少ない場合（例えばRISCや IBM System/390）、命令コード側にオペランドの意味を規定する情報が含まれている。しかしアドレッシングモードが豊富なアーキテクチャでは命令フォーマット内に命令コードとは別にアドレッシングモードを指定するフィールドが存在する。DEC VAX はほとんど全ての命令で複数のメモリオペランドを指定でき、オペランド指定フィールドの先頭数ビットで、そのオペランドのアドレッシングモードを指定することになっている。アドレッシングモードを指定するビット列をオペコードから分離した命令セットは「直交性が高い」と言われる。
豊富なアドレッシングモードを持つコンピュータであっても、実際のプログラムは、90%は単純なアドレッシングモードで構成される。これは高水準言語のコンパイラが生成したコードを調査した結果であり、コンパイラ自体の限界を反映したものである。
構成要素.
アドレッシングモードは様々なものがISA毎に存在するが、共通の名称は存在しない。したがって、本項目で便宜的に採用している呼び方があらゆる場面で通用するわけではない。アドレッシングモードとは、単にアクセスすべきアドレスを指定する方法を意味するのではなく、命令のオペランドの記述方法そのものである。addressing とは「演算対象を指定する」ことを意味する。したがって、アドレッシングモードにはメモリアドレスの指定方法だけでなく、レジスタそのものや演算にそのまま使われるイミディエイト値も含まれる。アドレッシングモードを構成する要素として以下のようなものがある。
なお、インデックスレジスタはその性格上、必ずしもメモリアドレス全体を表せるビット幅を持つ必要はないが、一般的にはアドレス全体を表すことができるため、ベースポインタとの役割分担があいまいとなっている。
CISCの例.
CISCアーキテクチャでは、分岐命令やメモリアクセス（ロード/ストア）命令だけでなく、演算命令などでもメモリアクセスを行うことができる。CISCの命令セットの設計思想はアドレッシングモードを豊富に用意して、ある処理を実現するのに必要となる命令数を減らすことが大きな目標となっていた。このため、現在では使われなくなった複雑なアドレッシングモードを用意したCPUも存在する（VAXが有名。日本では日本電気のV60などは豊富なアドレッシングモードを誇っていた）。
右図は、現在最も多く使われているCISCであるx86アーキテクチャでのアドレッシングモードを示している。実効アドレス（実際にアクセスすべきメモリアドレス）はセグメント内のアドレスであり、セグメントレジスタと組み合わせることでリニアアドレスと呼ばれる一種の論理アドレスに変換されるが、この部分はメモリ管理に関わるものでアドレッシングモードには含まれない。実効アドレスは、ベースレジスタ、インデックスレジスタ、ディスプレースメントを加算することで得られるが、これらの要素は省略可能である。したがって、以下のようなアドレッシングモードが存在する。
x86では、ロード・ストア命令以外でもメモリアクセスが可能である。例えば加算の場合「A ← A + B」という形式であるため、A にメモリを指すようなアドレッシングモードを使用すると一命令で「ロード→加算→ストア」と二回のメモリアクセスを行うことになる。なお、MOV命令でメモリからメモリへの転送はできない。
RISCの例.
RISCアーキテクチャでは、メモリアクセスを減らすことが設計思想にあるため、ロード/ストア命令と命令フェッチ以外ではメモリにアクセスしないのが一般的である。また、ロード/ストア命令も一命令でのメモリアクセスが一回というのが原則であり、CISCに存在したメモリ間接モードは存在しない。以下では、PowerPCアーキテクチャでのアドレッシングモードを例として説明する。
一般命令のアドレッシングは、レジスタかイミディエイト値のみである。
既に使われなくなったアドレッシングモード.
以下に挙げるのは、1980年代ごろまで使われていたアドレッシングモードであるが、現在では使われていない。これが全てを網羅しているものではなく、時に応じて様々なアドレッシングモードが使われてきた。例えば、直接アドレス値に複数のインデックスレジスタの論理和を加算するなどといったものもあった。
初期のコンピュータ.
EDSACなどは、主記憶装置の容量が小さいため、アドレス指定は全て直接であった（命令内にアドレスが書かれていた）。しかし、これでは配列の各要素に同じ演算をするようなループをコーディングすることが困難である。というのは、ループにしたとき毎回違う配列要素にアクセスするには命令を書き換えなければならなかったからである（実際、命令を書き換えてループさせていた）。これに対してManchester Mark Iではインデックスレジスタを実装して命令を書き換えなくても済むようにした。
別の解決方法として、次の命令のオペランドを修飾する命令を持ったマシンも存在した。エリオット・ブラザーズの Elliott 503 や Elliott 803、アポロ誘導コンピュータなどは絶対アドレッシングしか持たず、インデックスレジスタも持っていなかった。従って間接アドレッシングによる分岐やレジスタを使った分岐は命令セットに存在しない。その代わりとして「指定したメモリワードの内容を次の命令に加える」という命令がある。例えば次の命令が codice_1 だった場合、メモリから読み込んだ値が 20 だったとすると codice_2 に書き換えられる。これによってインデックス付きの分岐命令と同等の効果を得る。なお、命令は実行時に更新されるのであって、メモリ上の内容は書き換えられない。したがってこれは自己書き換えコードではない。指定したメモリ位置の内容が大きい場合、オペランド（アドレス）だけでなく命令コードまで変更することができる。
多重メモリ間接.
何らかの実効アドレスがメモリ上の領域を示していて、そこに別のメモリ領域のアドレスが格納されていて、さらにその先にまでたどってメモリの内容をとってくるような場合を多重メモリ間接という。例えばMC68020などは二重メモリ間接までは実装していた。その際、いったんメモリアクセスして取ってきたアドレス値にさらにインデックスレジスタやディスプレースメントを加算して第二の実行アドレスを計算するモードが存在した。
TRONCHIPでは「多段間接モード」を持つ。1段の間接参照操作の中で、インデックスレジスタのスケーリングと加算、オフセットの加算、メモリの間接参照、の3動作を行い、これを任意の段数反復することが可能であった。
DEC の PDP-10では、アドレスが18ビット幅でワード長が36ビットであるため、ワード内にポインタとフラグを含めることができる。メモリに格納するワードの中の、間接メモリ参照を許可するフラグを設定することによって自動的に多重メモリ間接が可能であった。この場合、ポインタがループを形成していると永久にループをたどり続けるため、注意が必要である。一般にワード長がアドレス長より長い場合、このような多重間接が可能で、他にも IBM 1620、データゼネラルNovaなどがある。Novaの多重メモリ間接から間接スレッデッドコードの発想が生まれた。
メモリマップド・レジスタ.
DEC PDP-10 などは、レジスタがメモリの先頭アドレス部分（0番地付近）を使って実現されていた（つまり、レジスタがメモリ空間にマップされていた）。これを活用すると、小さなループを構成する命令（機械語）をレジスタに並べておくと、高速にループを実行することができた。
後のPDP-11シリーズではレジスタを入出力エリアにマッピングしていたが、これは遠隔診断を意図したものである。
自動インクリメント付きメモリ間接.
PDP-8などの初期のミニコンピュータでは、特別なメモリアドレスがいくつかあり、そこにメモリ間接でアクセスすると、メモリの内容をアクセス後に自動インクリメントしたり、自動デクリメントしたりする（アドレスによって異なる）。これを使うとレジスタを使わずにループを実行することが容易になる。
ゼロページとダイレクトページ.
Data General Nova、MC6800ファミリ、MOS 6502 ファミリなどは内蔵レジスタ数が非常に少ないアーキテクチャである。そのため、多くの算術命令をメモリ上の値に対して行う。普通にアドレスを指定すると16ビット必要とし、コードの中でアドレス指定に要するメモリ量がかなり大きくなる。
そのため、プロセッサ設計者は「ゼロページ」アドレッシングと呼ばれる緩和手段を実装した。メモリ空間の先頭256バイト（$0000 - $00FF; これがすなわちページ "0" である）を1バイトで指定できるアドレッシングモードを用意したのである。インデックス付きもある。これによって命令長が1バイト短縮され、クロックサイクルも1サイクル短縮される。結果としてゼロページはレジスタファイルのような使い方をされた。
6502を発展させた WDC 65816 や 、MC6809などでゼロページ・アドレッシングが強化され、「ダイレクトページ」アドレッシングとなった。これは、256バイトのゼロページの開始アドレスを専用レジスタで自由に設定できるようにしたもので、それによって複数のソフトウェアがダイレクトページを切り換えて使えるようになった。
ワードを任意サイズのバイトで分けて指定.
PDP-10は36ビットのワード長で、1ビットから36ビットまでの任意サイズのバイト単位でメモリを指定する特殊なアドレッシングモードを持つ。18ビットのワードアドレス、ワード内のビット位置、バイトのサイズを指定する1ワードの記述子を使用する。
この記述子を使ってバイト単位でロード・ストアする命令が存在し、記述子が次のバイトを指すようインクリメントする（バイトはワード境界をまたがない）。DECのソフトウェアでは1バイトを7ビット（ASCII）とし、1ワードを5バイトと未使用の1ビットにする記述子を使うことが多かった。C言語では、"int" 型が "char" 型の整数倍であるという前提で malloc 関数が成り立っていたため、1バイトを9ビットとし、1ワードを4バイトちょうどにする必要があった。実際何倍なのかはコンパイル時の演算子であるsizeofで決まる。