うんちく:アドレッシングモードの色々

 

1.様々なアドレッシングモード

テキスト中では、アドレッシングモード、つまりメモリの番地を示す方法としては、アキュムレータマシンで直接指定を、POCOでレジスタ間接指定を紹介したが、他には触れなかった。ここではもっと他の方法を紹介しよう。ここではEAを実効アドレス、raと書いた場合、レジスタraの中身を指す。

 

ディスプレースメント付(オフセット付)レジスタ間接指定

LD rd, disp(ra):  EA= ra+disp 

radisplacementで記した数値を加えたものがアドレスとなる。もちろんdispは負の数も取ることができる。この方法は実はほとんどのRISCで用いており、disp=0ならばレジスタ間接指定と同じである。また、多くの32bit RISCではr0の値は常に0なので、r0を指定すれば直接指定となる。つまり、テキストで紹介した二つの方法を兼ねている二度美味しい方式である。この方式の問題点は、直接方式同様にdispに指定できるアドレスではCPUの全アドレス空間をカバーできないことにある。したがって、アドレスの基点はraに入れておき、dispは細かい所の調整に使うのが普通である。このテキストでは紹介できなかったが、ループアンローリングを行うためにはこの指定は不可欠と言ってよく、これにより、この方式は現在のアドレッシングモードの主流となっている。

 

ポストインクリメント付レジスタ間接指定

LD rd,(ra)+:  EA=ra, ra++

 実効アドレスは、raでレジスタ間接指定と同じだが、データを移動した後にraの値を増やす。ここで、移動したデータ分だけ増やしてやって、ちょうど次のデータを指すようにするのがミソ。つまり、バイトアドレッシングを使っている場合、8ビットデータを移動すると+1、16ビッドデータでは+2、32ビットならば+4、64ビットならば+8される。サイズを考えないでよいため、昔アセンブラでプログラムを書いた際は実に重宝だった。raをスタックポインタとすると、ポップ操作に相当する。

 

プリデクリメント付レジスタ間接指定

LD rd,-(ra):   ra--, EA=ra

  raをデータサイズ分減らしてから、データを読み出す。ポストインクリメントとはまったく逆の操作を行う。プリデクリメント付とポストインクリメント付を組み合わせるとスタックが簡単にできる。raをスタックポインタとすると、プッシュ操作に相当する。

 

インデックス付レジスタ間接指定

LD rd, (ra,rx): EA=ra+rx

 raの他にインデックスレジスタrxを指定し、この両者を足した値が実効アドレスとなる。さらに、これにディスプレースメントも組み合わせたものもある

LD rd,disp(ra,rx): EA=disp+ra+rx

 この方式では実効アドレスはra,rx,dispの全てを足したものになる。後に説明するように、この方式は、インデックスレジスタという専用の特殊レジスタから生まれたが、汎用レジスタマシンでは、どのレジスタでもインデックスレジスタの役割ができるようになった。

 

スケールド

LD rd,disp(ra,rs) : EA=disp+ra+rs*size

 この方式はディスプレースメント及びインデックス付間接レジスタと似ているのが、rsに移動するデータサイズ(バイトで計る)を掛けたものが足される点が違う。つまりこれは露骨に配列アクセス用であり配列X[i]のアドレスを与える場合、irsに設定し、配列の先頭Xdisp+raで表せば良い。この方式はFORTRANの高速実行を念頭に置いて設計されたDEC社のVAX-11に使われ、世に広まった。

 

メモリ間接

LD rd,@A : EA=(A)

 Aで指定したアドレスに格納されたデータをアドレスとして考えてメモリからデータを読み出す。つまり、二回メモリを参照することになる。これにレジスタ間接を組み合わせた方式も考えられる。

 

レジスタ間接付メモリ間接

LD rd,@(ra) EA= @(ra)

 raの中身で指定したアドレスに格納されたデータをアドレスとして考えてメモリからデータを読み出す。つまり、まずレジスタから値を読み出し、これをアドレスとして使って、メモリを読み出し、さらに読み出した値をアドレスとしてデータを読み出す。ややこしいが、メモリ内の値をポインタとして用いることができる。

 

2. アドレッシングモードの一般化:インデックス修飾

 レジスタ間接指定は様々であるが、インデックス修飾という形である程度一般化できる。すなわち、指定したアドレスに、インデックスレジスタrxを加算して実効アドレスとすることを、インデックス修飾と呼ぶ。この考え方だと。

何もしないでインデックス修飾→ レジスタ間接指定

直接指定にインデックス修飾 → ディスプレースメント付レジスタ間接指定

レジスタ間接にインデックス修飾 → インデックスレジスタ付レジスタ間接指定

などである。この考え方は古いタイプのコンピュータでかなり広く使われたため、今でも「インデックス修飾」という言葉は残っている。昔は、この役割を果たす専用のインデックスレジスタを使っていた。

 

3.      さらなる一般化:汎用レジスタをPCにしたら?

 汎用レジスタの一つをプログラムカウンタ(PC)にすることで、アドレッシングモードをさらに一般化することができる。今、命令がオプコード1バイトとオペランド1バイトに分かれているとしよう(オペランドは小さすぎるがここでは説明のためお許しを)。ここで、以下の二つのモードを設けておく。

@     レジスタ間接指定 (rx)

A     レジスタ間接付メモリ間接指定 @(rx)

ここで、プログラムカウンタPCを汎用レジスタの一つとしてみよう。PCのレジスタ間接指定(PC)は、プログラムカウンタが指している命令を示すことになる。ここで、PCがオプコードをアクセスするとすぐ先に進む場合(そのように実装するのが普通だった)、PCが指しているのはまさしくオペランドそのものになる。つまり、(pc)は、オペランドそのものが扱う対象となるイミーディエイト指定に相当する。

 さらに、@(PC)は、PCの指す命令中のオペランドのさらに指し示す内容が実効アドレスになるモード、すなわち直接指定である。まとめると、

(PC) → イミーディエイト指定

@(PC)→ 直接指定 となる。

もちろんPC以外のレジスタを使えば、普通にレジスタ間接指定とメモリ間接指定が可能である。これにインデックス修飾を許すようにすれば、ポストインクリメント、プリデクリメントを除いて、ほとんどありとあらゆるアドレッシングモードがカバーできてしまう。この方式はPDP-8以来DECの特許であり、その美しさが数多くのアーキテクトを魅了した。後にRISCの登場によってメモリ間接指定という考え方自体が性能を悪化させる要因として排除されるようになり、今ではこの考え方を知る者も少ない。ただ、本来アドレッシングモードの中には入るべきではないイミーディエイト指定が、多くのテキストや解説でなんとなくアドレッシングモードの仲間に入っているのは、この方式のなごりであろう。