アドレッシングモード
アドレッシングモード(Addressing Mode)は、CPUの命令セットアーキテクチャ(ISA)において、命令のオペランド部(演算の対象となるデータのこと)を表すための方法のことである。一般に、プロセッサの命令において、オペランドとその結果を出力する場所が必要である。アドレッシングモードは、結果を出力する場所をオペランドと同じ場所とし、オペランドの領域に結果を書き戻す方法である。これによって、命令での場所の指定が最小限に抑えられる。そのため、狭義のアドレッシングモードでは、オペランドとして使用すべきメモリ領域を指定する。しかし、広義には、レジスタを指定したり、値が命令のオペランドとして直接与えられたりする場合も含まれる。
プログラミングの観点では、アドレッシングモードはコンパイラ開発を行う時やアセンブリ言語を利用する際に重視される。
アドレッシングモードの複雑さ
[編集]コンピュータ・アーキテクチャが異なれば、それぞれに独自のアドレッシングモードが存在する。複雑なアドレッシングモードには、使用する命令数やレジスタの削減といった利点がある。一方、単純なアドレッシングモードだけにすることには、CPUの命令パイプラインの設計が容易になるという利点があるとされる[1]。
RISCでは一般にアドレッシングモードが少なく単純だが、DECのVAXなどのCISCでは1ダース以上のアドレッシングモードを備え、その一部は非常に複雑である。IBM System/360 は3種類のアドレッシングモードしか持たなかったが、System/390ではいくつか追加された。
アドレッシングモードが少ない場合(例えばRISCや IBM System/390)、命令コード側にオペランドの意味を規定する情報が含まれている。しかしアドレッシングモードが豊富なアーキテクチャでは命令フォーマット内に命令コードとは別にアドレッシングモードを指定するフィールドが存在する。DEC VAX はほとんど全ての命令で複数のメモリオペランドを指定でき、オペランド指定フィールドの先頭数ビットで、そのオペランドのアドレッシングモードを指定することになっている。アドレッシングモードを指定するビット列をオペコードから分離した命令セットは「直交性が高い」と言われる。
豊富なアドレッシングモードを持つコンピュータであっても、実際のプログラムは、90%は単純なアドレッシングモードで構成される。これは高水準言語のコンパイラが生成したコードを調査した結果であり、コンパイラ自体の限界を反映したものである[2]。
構成要素
[編集]アドレッシングモードは様々なものがISA毎に存在するが、共通の名称は存在しない。したがって、本項目で便宜的に採用している呼び方があらゆる場面で通用するわけではない。アドレッシングモードとは、単にアクセスすべきアドレスを指定する方法を意味するのではなく、命令のオペランドの記述方法そのものである。addressing とは「演算対象を指定する」ことを意味する。したがって、アドレッシングモードにはメモリアドレスの指定方法だけでなく、レジスタそのものや演算にそのまま使われるイミディエイト値も含まれる。アドレッシングモードを構成する要素として以下のようなものがある。
- レジスタ
- 命令のオペランドとしてレジスタそのものを指定する場合と、指定されたレジスタの内容をメモリアドレス指定に使用する場合がある。以下に列挙するのはアドレッシングモードでメモリアドレス指定に使われるレジスタであるが、あくまでもアドレッシングモードでの役割名であり、下記の名称のレジスタが必ず存在するわけではない。
- ベースポインタ(BP)/ベースレジスタ(BR)
- アクセスすべきメモリアドレスを格納するレジスタ。さらにメモリブロック(例えばC言語の構造体など)の先頭アドレスを保持して、ディスプレースメント(後述)を使用してメモリブロック内の任意のアドレスを指定するのにも使われる。
- インデックスレジスタ(IX)
- 配列のインデックスに相当する値を保持するレジスタ。単独で使われることはなく、ディスプレースメントの変数化したものと捉えることができる。
- プログラムカウンタ(PC)
- 実行中の命令のアドレス(あるいは一般に次に実行予定の命令のアドレス)を保持するレジスタ。アドレッシングモードの文脈では、プログラムの流れを制御する際(分岐命令など)に使われる特殊なベースポインタである。
- イミディエイト/即値
- 命令内に直接書かれている値を意味する。演算命令などのオペランドとしてそのまま使われる。以下に列挙するものは命令内に直接書かれアドレッシングモードでメモリアドレス指定に使われる値である。
- 直接アドレス
- アドレスを命令内で直接指定する場合に使われる。例えば大域変数のアドレスやライブラリ関数のアドレスなどは直接アドレスで指定されることが多い(ただし、ダイナミックリンクされるライブラリのアドレス指定はその限りではない)。
- ディスプレースメント/オフセット
- 何らかのベースアドレスからのオフセットを示す値である。
なお、インデックスレジスタはその性格上、必ずしもメモリアドレス全体を表せるビット幅を持つ必要はないが、一般的にはアドレス全体を表すことができるため、ベースポインタとの役割分担があいまいとなっている。
命令用の単純なアドレッシングモード
[編集]- 絶対
- オペランドに直接アドレスを指定し、それを実効PCアドレスとする。修飾は特に行わない。
- PC相対
- 次の命令のアドレス(PCの内容)にオペランドとして指定したオフセット値を加えたものを実効PCアドレスとする。オフセットは負の場合もある。一般に分岐命令でよく見られる。条件分岐やループなどの制御構造は一般に比較的近いアドレスへの分岐を行うので、絶対アドレスを指定するよりも現在の命令から見た相対的な位置で十分である。実際のプログラムを調査したところ、条件分岐先の90%は8ビットから10ビットのオフセット値でカバーできるという[3]。任意のアドレスに配置可能な位置独立コードでもPC相対のアドレッシングモードを多用する。なお、条件分岐命令の条件としては、ステータスレジスタ内のビットの状態を使う場合や、レジスタを1本(例えば、reg1=0 なら分岐)または2本(例えば reg1=reg2 なら分岐)指定する場合がある。
- レジスタ間接
- オペランドとしてレジスタを指定し、そのレジスタの内容を実効PCアドレスとする。例えば、A7 レジスタの内容を指す場合、アセンブリ言語では (A7) などと表記する。例えば、ジャンプテーブルを使って分岐先を決める場合などに使われる。RISCの場合、サブルーチン呼び出しを行ったときリターンアドレスを所定のレジスタに格納する。そのため、サブルーチンからの復帰に際してレジスタ間接のアドレッシングモードを使用する。
逐次的アドレッシングモード
[編集]- 逐次的実行
- PCを意図的に変更する命令以外は、メモリ上で一般に現在実行している命令に続いている命令のアドレスをPCに設定するので、メモリ上の次の命令を逐次的に実行することになる。これは自動的に行われるため、一般にアドレッシングモードとは見なされない。例えばNOP命令は何もしないと言われるが、PCだけはインクリメントする。ほとんどの命令は逐次的に実行することになるため、CPU設計においては逐次的実行の高速化を最優先とし、分岐命令を実行すると性能が低下するような設計にすることが多い。条件分岐命令は条件によって分岐する場合と分岐しない場合があり、分岐しない場合は逐次的実行となり、分岐する場合はアドレッシングモードで指定された分岐先を使用する。最近のCPUは命令プリフェッチ、命令パイプライン、アウト・オブ・オーダー実行といった機能を備えているが、アドレッシングモードの観点からは命令を1つ実行して、完了したら次の命令を実行しているかのように振る舞う(内部の動作は異なる)。逐次的命令だけが並んでいる「基本ブロック」は、時間的にも空間的にも参照の局所性を備えている。
- プログラムカウンタ (PC) による逐次的実行を行わないCPUはほとんど存在しないが、各命令が常に次に実行すべき命令のアドレスを指定するというアーキテクチャのCPUも存在する。そのようなCPUは指定されたアドレスを保持する命令ポインタは持つが、それはカウントアップする性質はないのでプログラムカウンタではない。例えば、磁気ドラムメモリを主記憶とする一部のコンピュータ、SECDマシン、RTX 32P[4] などがある。さらにフォン・ノイマン・ボトルネックを回避するためにプログラムカウンタの代替となる機構を採用するアーキテクチャもある。
- 条件付き実行
- ARMやx86(条件付ロード命令)など一部のアーキテクチャは、分岐命令以外にも条件付きの命令を備えている。それによって分岐を不要とし、命令パイプラインが乱れるのを防ぐことができる。比較命令でステータスレジスタの条件コードを設定し、その後の命令列でその条件コードを使い、各命令を実際に実行するか否かを決定する。
- スキップ
- 比較命令の一種で、比較結果によって次の命令を実行するか否かを決定する命令を持つアーキテクチャもある。スキップ・アドレッシングは、オフセットが "+1" に固定されている特殊なPC相対アドレッシングモードと見なすことができる。条件分岐命令と同様、レジスタを1本指定する場合(reg1=0ならスキップ)や2本指定する場合(reg1=reg2ならスキップ)、ステータスレジスタの条件コードを設定する命令と条件コードを参照するスキップ命令が分かれている場合などがある。指定したレジスタの特定のビット位置が "1" か "0" かで判断する命令もある(reg12のビット7が0ならスキップ)。スキップ命令は命令パイプラインを乱さないが、スキップされた命令の実行ステージは無視され、そのサイクルは無駄になる。
データ用の単純なアドレッシングモード
[編集]- レジスタ
- オペランドとしてレジスタのみを指定する。場合によってはアドレッシングモードと見なされない。
- 「ベース+オフセット」形式とその派生
- 「ベース+ディスプレースメント」とも。ベースレジスタの内容に、オフセット値を加えた値を実効アドレスとする。オフセットは16ビットの符号付きの値で指定することが多い(i386では32ビットである)。オフセットがゼロの場合は「レジスタ間接」アドレッシングとなり、実効アドレスはベースレジスタの内容そのものとなる。RISCでは0番のレジスタは内容が常にゼロということが多く、0番のレジスタをベースレジスタとして指定した場合、一種の「絶対」アドレッシングとなる。ただし、それで表せるアドレス範囲は狭い(オフセットが16ビットなら64KBの範囲内のみ)。16ビットのオフセット値というのは、最近のメモリ容量の大きいコンピュータを考えると小さいように思われる(i386で32ビットに拡張したのもそれが理由である)。IBM System/390 ではオフセット値は符号無しの12ビットだった。しかし、参照の局所性の原則を適用すれば、あるプログラムが短時間にアクセスするデータの大部分は狭い範囲にあることが多いと言える。このアドレッシングモードは、インデックス付き絶対アドレッシングモードと深い関係がある。
- サブルーチン単位で考えた場合、重要となるデータはサブルーチンの引数と局所変数であり、それらが64KBの範囲を超えることは滅多にない。したがって、1つのベースレジスタ(フレームポインタ)で十分である。オブジェクト指向言語のメソッドの場合、(オブジェクト指向言語で this や self と呼ばれる)現在のオブジェクトのデータメンバ群を指すもう1つのベースレジスタを必要とする
- 構造体などの複合データ型のアドレスをベースレジスタに設定すれば、オフセットを使ってその構造体の特定のフィールドを指定することができる(一般にレコードや構造体といった複合データは32kBよりも小さい)。
- イミディエート/リテラル
- 演算に使用する値(定数)を直接オペランドに指定するもので、アドレッシングモードと見なさないこともある。定数は符号無しの場合と符号付きの場合がある。例えば、move.l #$FEEDABBA, D0 という命令は、"FEEDABBA" という16進の値をD0レジスタに入れる。DEC VAX では、リテラル・オペランドのサイズとして6ビット、8ビット、16ビット、32ビットがある。アンドリュー・タネンバウムは、プログラム内で使われる定数の98%が13ビットで表せることを示した。
- 暗黙のアドレッシングモード
- ある命令がアクセスするリソースが決まっているため、実効アドレスを明記せず暗黙のうちにアクセスする場合である。1970年代中ごろまでのコンピュータではよく見られた。古い典型的なコンピュータは演算対象となるレジスタが1つしかなく、それをアキュムレータと呼ぶ。アキュムレータ・マシンではほとんどの命令で暗黙のうちにアキュムレータを参照する。例えば、<a := b + c;> という処理は <load b; add c; store a;> という命令列になる。これらの命令はどれも暗黙のうちにアキュムレータにアクセスする。load 命令は b をアキュムレータにロードし、add 命令は c をアキュムレータに加算するといった具合である。store 命令はアキュムレータの内容を指定された場所に格納する。その後、複数の汎用レジスタを持つことが多くなり、算術演算の入力と出力をそれぞれ指定する必要が生じ、アドレッシングモードが複雑化していった。x86では乗除算命令などで暗黙のうちにALレジスタを使用する。
- x86など多くのアーキテクチャでは、スタックポインタという特殊なレジスタがあり、スタックにデータを置いたり、スタックからデータを取り除いたとき、自動的にインクリメントまたはデクリメントされる。また、スタックのプッシュ/ポップをする際の実効アドレスは暗黙のうちにスタックポインタに格納されているアドレスを使用する。68k、ARM、PowerPC といったアーキテクチャでは、1つ以上のレジスタをスタックポインタとして使用できる。そのため、「自動インクリメント付きレジスタ間接」などのアドレッシングモードが用意されている。
- 多くの場合、CPUモードの切り替えや割り込みマスク状態の変更には専用の命令があり、対応するビットなどを明示的に指定しない。このことはPopekとGoldbergの仮想化要件を満足させようとする場合、そのような命令をトラップしなければならないハードウェアを単純化できる。すなわち、トラップ処理はオペランド(あるいは最終的な実効アドレス)を調べる必要がなく、命令コードだけを調べればよい。
その他のアドレッシングモード
[編集]- 絶対/直接
- 命令内でアドレスをそのまま指定する。例えば、ロード命令で参照するメモリアドレスを直接指定する。この場合、命令がかなり長くなる。CISCでは命令が可変長なので、このようなアドレッシングモードを持つことが多い。x86にもある。RISCではアドレスの上位半分だけをレジスタに格納する命令を持つことがある。その命令に続いて、OR命令でアドレスの下位半分をイミディエート値で指定し、上位半分とOR演算で組合わせて、アドレスをレジスタに格納する。そうしてアドレス全体をレジスタに格納してから「レジスタ間接」または「ベース+オフセット」のアドレッシングモードでそのアドレスにアクセスする。
- インデックス付き絶対
- 命令内でアドレスをそのまま指定し、さらにインデックスレジスタを指定する。実効アドレスは絶対アドレスにインデックスレジスタの内容を加算したものになる。これも命令がかなり長くなる。絶対アドレスは配列などの先頭を指し、インデックスレジスタでその配列の特定の要素を示す。加算する前にインデックスレジスタの内容をスケーリングし、配列の添え字の値そのものをインデックスレジスタに格納しておき、スケーリングでメモリ上のオフセットに変換するアーキテクチャもある。
- 例えば、大域変数または局所定数として文字列などを定義した場合、そのアドレスは絶対アドレスとして命令に書かれる。文字列上を走査する場合、ループ変数がインデックスレジスタに格納され、このアドレッシングモードが使われる。
- ベース+インデックス
- ベースレジスタとインデックスレジスタを指定し、それぞれの内容を加算した値を実効アドレスとするアドレッシングモード。ベースレジスタは配列などの先頭アドレス、インデックスレジスタは特定の配列要素を指す。加算する前にインデックスレジスタの内容をスケーリングし、配列の添え字の値そのものをインデックスレジスタに格納しておき、スケーリングでメモリ上のオフセットに変換するアーキテクチャもある。
- ベース+インデックス+オフセット
- ベースレジスタの内容とインデックスレジスタの内容とオフセット値を加算して実効アドレスを得るアドレッシングモード。構造体やレコードの配列などで特定の構造体(レコード)の特定のフィールドを指定するといった場合に使用する。
- レジスタ間接
- ベースレジスタの内容を実効アドレスとするアドレッシングモード。通常は「ベース+オフセット」でオフセット値がゼロの場合である。
- 自動インクリメント付きレジスタ間接
- ベースレジスタの内容が実効アドレスだが、実効アドレスを求めた後、ベースレジスタをそのデータのサイズだけインクリメントする。例えば32ビットのロード命令なら、ベースレジスタに4を加える。アセンブリ言語では (A7)+ などと表記される。ループで配列の各要素を走査する場合などに使用する。
- 高水準言語では、関数は副作用がない方が理解しやすく好ましいとされることが多い。このアドレッシングモードはベースレジスタが更新されるという副作用がある。例えばこのアドレッシングモードを使った命令でページフォールトなどが発生した場合、ベースレジスタの内容が命令実行前に戻っていないと正しく復帰できない。MC68000にはそのような問題があり、MC68010で対処された。DEC VAX では最大6オペランドで自動インクリメントが可能で、命令自体が最大50バイトにもなるため、命令とデータの両方で同時にページフォールトとなる可能性があった。
- 自動デクリメント付きレジスタ間接
- ベースレジスタの内容をデータのサイズだけデクリメントしてから、その内容を実効アドレスとする。ループで配列を後ろの方から走査する場合などに使用する。自動インクリメント付きレジスタ間接のアドレッシングモードと組合わせて、スタックを実装することもできる。
- メモリ間接
- 本項で述べている各アドレッシングモードで、オプションのビットを設定することで間接アドレッシングとなるアーキテクチャもある。すなわち、それぞれの解説で実効アドレスとされているアドレス位置に真の実効アドレスが格納されているというアドレッシングモードである。間接アドレッシングは命令またはデータに使える。ポインタまたは参照の実装を容易にする効果がある。PDP-8などの初期のミニコンピュータでは、レジスタが少なくアドレス範囲も小さかった。そのため、大きなメモリを参照する唯一の手段がメモリ間接アドレッシングだった。
- PC相対
- プログラムカウンタをベースレジスタとして、オフセット値も加えてロード命令の実効アドレスとするアドレッシングモード。「ベース+オフセット」の特殊ケースである。x86-64は、位置独立コードのためにRIP(プログラムカウンタ)相対のアドレッシングをサポートしている。ARMアーキテクチャとVAXはどちらもPCが汎用レジスタファイルに含まれており、PC相対アドレッシングが可能である。これらは定数をリテラルプールと呼ばれるテキスト内の領域(サブルーチンの直前か直後)に配置し、PC相対でそれをロードするようなコードを生成する。PC相対の分岐命令はPC以外のレジスタは更新されないが、PC相対のロード命令ではデータレジスタにロード結果が格納される。
CISCの例
[編集]CISCアーキテクチャでは、分岐命令やメモリアクセス(ロード/ストア)命令だけでなく、演算命令などでもメモリアクセスを行うことができる。CISCの命令セットの設計思想はアドレッシングモードを豊富に用意して、ある処理を実現するのに必要となる命令数を減らすことが大きな目標となっていた。このため、現在では使われなくなった複雑なアドレッシングモードを用意したCPUも存在する(VAXが有名。日本では日本電気のV60などは豊富なアドレッシングモードを誇っていた)。
右図は、現在最も多く使われているCISCであるx86アーキテクチャでのアドレッシングモードを示している。実効アドレス(実際にアクセスすべきメモリアドレス)はセグメント内のアドレスであり、セグメントレジスタと組み合わせることでリニアアドレスと呼ばれる一種の論理アドレスに変換されるが、この部分はメモリ管理に関わるものでアドレッシングモードには含まれない。実効アドレスは、ベースレジスタ、インデックスレジスタ、ディスプレースメントを加算することで得られるが、これらの要素は省略可能である。したがって、以下のようなアドレッシングモードが存在する。
- レジスタ間接
- ベースレジスタがアクセスすべきメモリアドレスを保持している。また、ベースレジスタを省略してインデックスレジスタだけを使う場合もこれにあたる。
- ベース+インデックス
- ベースレジスタにインデックスレジスタの値を加算した値がアクセスすべきメモリアドレスとなる。インデックスレジスタの値は加算する前に2倍、4倍、8倍とスケーリングすることができる。これは例えば 32ビットのデータの配列のインデックスをインデックスレジスタに保持している場合に、4倍にスケールアップすることで配列先頭からのオフセット(アドレスの差分)に変換されるような場合に使われる。
- ベース+オフセット
- ベースレジスタ(またはインデックスレジスタ)に命令内に直接書かれたディスプレースメントを加算した値がアクセスすべきメモリアドレスとなる。
- ベース+インデックス+オフセット
- 全部を使用した指定方法
- 直接(絶対)アドレス
- ディスプレースメントのみを使用した場合。
x86では、ロード・ストア命令以外でもメモリアクセスが可能である。例えば加算の場合「A ← A + B」という形式であるため、A にメモリを指すようなアドレッシングモードを使用すると一命令で「ロード→加算→ストア」と二回のメモリアクセスを行うことになる。なお、MOV命令でメモリからメモリへの転送はできない。
RISCの例
[編集]RISCアーキテクチャでは、メモリアクセスを減らすことが設計思想にあるため、ロード/ストア命令と命令フェッチ以外ではメモリにアクセスしないのが一般的である。また、ロード/ストア命令も一命令でのメモリアクセスが一回というのが原則であり、CISCに存在したメモリ間接モードは存在しない。以下では、PowerPCアーキテクチャでのアドレッシングモードを例として説明する。
- 命令アドレス指定
-
- PC相対ディスプレースメント付き
- 現在の命令アドレス(PowerPCなど命令パイプラインを持つスーパースケーラプロセッサでは複数の命令が並行して処理されているためプログラムカウンタは仮想的に現在の命令を指しているものとして扱われる)に命令内で指定されたディスプレースメントを加算して実効アドレスを求める。ディスプレースメントは符号拡張されて加算される。
- 直接アドレス
- 実際にはPC相対ディスプレースメント付きでPCを考慮しないフラグが指定されている場合、この形式となる。ディスプレースメントで指定できる範囲は全アドレス空間をカバーできない。
- レジスタ間接
- レジスタの内容を実効アドレスとして使用する。ただし、アドレス指定に使えるレジスタは2本(リンクレジスタとカウントレジスタ)に限定されている。一般的なRISCアーキテクチャでは全ての汎用レジスタが使用できるのが普通であるが、PowerPC では条件付き分岐命令にして、さらにサブルーチンからの復帰命令を同じ命令にしているため、このような制限がある。
- ロード/ストアアドレス指定
- レジスタ間接を基本として、ディスプレースメントで修飾するか、インデックスレジスタで修飾する。この場合のベースレジスタは汎用レジスタであり、分岐命令のような制限はない。また、配列などの連続した領域へのアクセスを高速化するためにアップデート形式と呼ばれるものがあり、実効アドレスにアクセスした後でベースレジスタに実効アドレスを書きこむ命令もある。アドレス指定という意味ではこれだけの形式しかないが、PowerPCは、バイト順番を逆転させるロード/ストア命令(エンディアンを考慮しなければならない場合に便利)、汎用レジスタを連続で複数本ロード/ストアする命令(コンテキストスイッチなどに便利)、複数の汎用レジスタを連続したバイト列としてロード/ストアを行う命令がある。
一般命令のアドレッシングは、レジスタかイミディエイト値のみである。
既に使われなくなったアドレッシングモード
[編集]以下に挙げるのは、1980年代ごろまで使われていたアドレッシングモードであるが、現在では使われていない。これが全てを網羅しているものではなく、時に応じて様々なアドレッシングモードが使われてきた。例えば、直接アドレス値に複数のインデックスレジスタの論理和を加算するなどといったものもあった。
初期のコンピュータ
[編集]EDSACなどは、主記憶装置の容量が小さいため、アドレス指定は全て直接であった(命令内にアドレスが書かれていた)。しかし、これでは配列の各要素に同じ演算をするようなループをコーディングすることが困難である。というのは、ループにしたとき毎回違う配列要素にアクセスするには命令を書き換えなければならなかったからである(実際、命令を書き換えてループさせていた)。これに対してManchester Mark Iではインデックスレジスタを実装して命令を書き換えなくても済むようにした。
別の解決方法として、次の命令のオペランドを修飾する命令を持ったマシンも存在した。エリオット・ブラザーズの Elliott 503[5] や Elliott 803[5][6]、アポロ誘導コンピュータなどは絶対アドレッシングしか持たず、インデックスレジスタも持っていなかった。従って間接アドレッシングによる分岐やレジスタを使った分岐は命令セットに存在しない。その代わりとして「指定したメモリワードの内容を次の命令に加える」という命令がある。例えば次の命令が JUMP 0
だった場合、メモリから読み込んだ値が 20 だったとすると JUMP 20
に書き換えられる。これによってインデックス付きの分岐命令と同等の効果を得る。なお、命令は実行時に更新されるのであって、メモリ上の内容は書き換えられない。したがってこれは自己書き換えコードではない。指定したメモリ位置の内容が大きい場合、オペランド(アドレス)だけでなく命令コードまで変更することができる。
多重メモリ間接
[編集]何らかの実効アドレスがメモリ上の領域を示していて、そこに別のメモリ領域のアドレスが格納されていて、さらにその先にまでたどってメモリの内容をとってくるような場合を多重メモリ間接という。例えば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 や MOS 65CE02、MC6809などでゼロページ・アドレッシングが強化され、「ダイレクトページ」アドレッシングとなった。これは、256バイトのゼロページの開始アドレスを専用レジスタで自由に設定できるようにしたもので、それによって複数のソフトウェアがダイレクトページを切り換えて使えるようになった。
ワードを任意サイズのバイトで分けて指定
[編集]PDP-10は36ビットのワード長で、1ビットから36ビットまでの任意サイズのバイト単位でメモリを指定する特殊なアドレッシングモードを持つ。18ビットのワードアドレス、ワード内のビット位置、バイトのサイズを指定する1ワードの記述子を使用する。
この記述子を使ってバイト単位でロード・ストアする命令が存在し、記述子が次のバイトを指すようインクリメントする(バイトはワード境界をまたがない)。DECのソフトウェアでは1バイトを7ビット(ASCII)とし、1ワードを5バイトと未使用の1ビットにする記述子を使うことが多かった。C言語では、int 型が char 型の整数倍であるという前提で malloc 関数が成り立っていたため[7]、1バイトを9ビットとし、1ワードを4バイトちょうどにする必要があった。実際何倍なのかはコンパイル時の演算子であるsizeofで決まる。
脚注
[編集]- ^ "How many addressing modes are enough?" by F. Chow, S. Correll, M. Himelstein, E. Killian, L. Weber, all from MIPS Computer Systems, Inc. 1987
"An Overview of the MIPS-X-MP Project" by John L. Hennessy and Mark A. Horowitz 1986: "MIPS-X uses a single addressing mode: base register plus offset. This simple addressing mode allows the computation of the effective address to begin very early" - ^ "Instruction Set Principles: Addressing Mode Usage (Summary)" Archived 2011年9月30日, at the Wayback Machine. by Dr. Sofiène Tahar "3 programs measured on machine with all address modes (VAX)": "displacement mode" and "immediate mode" are used 75% of the time.
"Fundamentals of Computer Design"[リンク切れ] p. 112-113 "Frequency of addressing modes for TI TMS320C54x DSP. The C54x has 17 data addressing modes, not counting register access, but the four found in MIPS account for 70% of the modes. Autoincrement and autodecrement, found in some RISC architectures, account for another 25% of the usage. This data was collected form a measurement of static instructions for the C-callable library of 54 DSP routines coded in assembly language."
"Efficient and Language-Independent Mobile Programs" by Ali-Reza Adl-Tabatabai, Geoff Langdale, Steven Lucco, and Robert Wahbe 1995: "79% of all instructions executed could be replaced by RISC instructions or synthesized into RISC instructions using only basic block instruction combination." - ^ Kong and Patterson. "Instruction set design". 1995. slide 27. [1]
- ^ "Architecture of the RTX 32P" by Philip Koopman 1989
- ^ a b Dave Brooks. "Some Old Computers".
- ^ Bill Purvis. "Some details of the Elliott 803B hardware"
- ^ "C Reference: function malloc()" メモリを確保するサイズをバイト数で指定