MC68000とは何か
X68000ではその名前にまで使われ、他にもMacintoshやAmiga、最近ではPilotに搭載さ れるなど、多くの人に愛されてきたCPU、MC68000とは、いったいどのようなものだったのでしょう?
68000は、UNIXワークステーションでの使用を想定し、1979年にモトローラ社が開発した16bitMPU(Micro Processor Unit)です。その基本構造は伝説のミニコンとも言われるDEC社PDP-11を参考にしたといわれ、とくにC言語での使用に適した命令セットを備えています。
とてもすべての命令を紹介することはできませんが、ここではその設計思想の一部でもお伝えできればと思います。
目次
レジスタセット
68000は16bitCPUですが、その内部のレジスタは32bitで統一されています。そのため、68000を32bitだと主張する人もいます。
さて、レジスタは8本のデータレジスタと、8本のアドレスレジスタ、それにプログラムカウンタと、これだけ16bitのステータスレジスタ(フラグ)があります。
データレジスタ
データレジスタは、32bit、16bit、8bitとして使用可能なレジスタで、データ転送や計算に使われます。
ただし、当時のライバルだったi8086が16bitのレジスタを8bit2本に分割できたのに対し、68000では上位のビットは単に無視されるだけです。
アドレスレジスタ
アドレスレジスタは32bit固定ですが、実際にバスに出力されるのは24bitです。これは名前の通りアドレスようのレジスタで、豊富なアドレッシングモードと組みあわせて使用することで真価を発揮します。
8086が16bitレジスタしかもたず、メモリを16bitで表現できる64Kの積み重ねで1Mまでしかもてなかったのにたいし、24bitで直接16Mの空間を指定できるのは非常に優れた設計です。
詳しくは後に説明しますが、データレジスタは8bit、16bitとしても使用可能です。アドレスは実際には24bitしか出力されませんが、内部では32bitです。 a7レジスタは裏にもう一つのレジスタが隠れていて、システムとユーザーで切り替わります。また、ステータスレジスタも8bitづつユーザー用とシステム用にわかれています。 |
68000は「データとアドレスは別のものである」という思想が強かった時代のCPUです(現在は、それらを区別するのは工学的には無意味だと考えられています)。
ですから、このようにレジスタも厳密に分けられ、アドレスレジスタの掛け算やデータレジスタの示すメモリへの代入など、在り得ないことはできないようになっています。
データレジスタとアドレスレジスタはそれぞれ8本の使い道が自由です。構造的には、どれも対等な立場であり、使うレジスタによって使える命令が異なったりすることはありません。
ただし、アドレスレジスタの最後のレジスタ(A7レジスタ)だけは特殊で、スタックポインタとして使用されます。ユーザーが使用する場合は普通に使用される命令の組みあわせでスタックを実現しているため気になりませんが、サブルーチンコールなどでは暗黙のうちに使用されるので注意が必要です。
アドレッシング
68000には、豊富なレジスタ群を活用するために多くのアドレッシングが用意されて います。そのアドレッシングの多くがソース・ディスティネーション双方に自由な組み合せで使用でき(直交性が高い)、命令の汎用性を高めています。
アドレッシングは大きく2つにわかれ、目的とするメモリ・レジスタに直接値を設定する「直接指定」と、アドレスレジスタの示すメモリにデータを入れる「間接指定」があります。
直接指定
直値 アドレス直接 データレジスタ直接 アドレスレジスタ直接
間接指定
ポストインクリメント・アドレスレジスタ間接 プリデクリメント・アドレスレジスタ間接
ディスプレースメント付き・アドレスレジスタ間接 インデックス付き・アドレスレジスタ間接
直値
- 基本的で、ほぼ唯一の直交性例外です。このアドレッシングはソース側にしか使用できません。
アドレス直接
- 直値アドレスで示されたメモリの値を操作します。また、ジャンプ命令などでも使われます。
データレジスタ直接
- データレジスタの値を操作します。アセンブラではデータレジスタは d0〜d7の記号で示されます。
アドレスレジスタ直接
- アドレスレジスタの値を操作します。アドレスレジスタはa0〜a7の記号です。
アドレスレジスタ間接
- アドレスレジスタの示すメモリの値を操作します。 (a0)と示されます。
ポストインクリメント・アドレスレジスタ間接
- アドレスレジスタの示すメモリの値を操作した後、アドレスレジスタを増加します。
増加する値はデータ長により自動的に変更されます(1byteデータなら1増加。4byteデータなら4増加)。(a0)+ と示されます。 プリデクリメント・アドレスレジスタ間接
- ポストインクリメントの逆の動作です。 -(a0) と示します。
ポストインクリメント/プリデクリメントを使えば連続したデータ転送も簡単に行えますし、スタックの表現にも使われます( -(a7)はpush、(a7)+はpopに相当します)。
通常のプログラムでは、ここまでのアドレッシングがあれば十分なはずです。
ディスプレースメント付アドレスレジスタ間接
- アドレスレジスタの値に一定の値(ディスプレースメント)を加え、そのアドレスの示すメモリの値を操作します。
10(a0) と書かれれば、a0 に入っているアドレスの10バイト先を読むということです。なんに使うかというと、C言語でいう構造体です。 インデックス付アドレスレジスタ間接
- アドレスレジスタにディスプレースメントを加えて、さらにインデックスに示されたレジスタの値にデータ長を掛けたものを加えたアドレスのメモリの値を操作します(あぁややこしい)。
10(a0,d0) と書かれていて、これが32bit(4byte)アクセスなら、a0+d0×4+10 のアドレスを示すということです。なお、このときd0がインデックスに当たるのですが、これはデータ/アドレスどちらのレジスタでも構いません。
こんなややこしいものを何に使うのかというと、多次元配列や構造体に含まれた配列、ダイナミックなメモリ管理が行われるときの配列のハンドリングなどです。(普通、こんなことCPUレベルでサポートしないよ (^^; )
最後の2つは、アドレスレジスタの代わりにプログラムカウンタを使用することも可能です。このようにするとプログラムからの相対位置にデータを置くことが可能なので、プログラムをメモリのどこに置いても動作するように出来ます。
命令群
次に命令群を紹介しますが、68000はCISCでも円熟期に作られたものですので、と ても全部は紹介しきれません。
ここではいくつか特徴的な命令だけを紹介します。なお、命令フォーマットは2、4、6バイトのいずれかです。
命令は、主に以下のような分類になっています。
データ転送命令 算術命令 スタックフレーム命令 条件分岐・ジャンプ命令 例外処理命令
データ転送命令群
- 最も基本的なものです。データ長は命令コード内で指定できるようになっています。
スタックはデータ転送にポストインクリメント/プリデクリメント命令を組み合わせて作るため、push pop は用意されていません。
特徴的な命令として、ポストインクリメント/プリデクリメントと組み合わせたときのみ、レジスタ16本のうち好きな組み合わせをまとめて転送することが出来ます。これはルーチン呼び出しのレジスタ一括待避等のために作られた機能ですが、メモリを高速に塗りつぶすのにも使えます。 算術命令
- これも基本的ですね。特徴といえば、足し算引き算だけでなく掛け算割り算ももっていることでしょうか。
8086系では必須のインクリメント、デクリメント(INC/DEC)命令はありません。アドレスについてINC/DECを行いたいのであれば、アドレッシングモードに用意されています。
データについてINC/DECを行いたいのであれば「Quick命令」というのが用意されています。これは命令コードに3bitまでのデータを含んでしまい、1〜8の足し算/引き算を高速に行うものです。INC/DECをより使いやすくしたものだと思えばよいでしょう。 スタックフレーム命令
- アドレスレジスタを1つ使い、そのレジスタをスタックに積んだ後スタックポインタをレジスタに転送し、指定されたアドレスだけスタックポインタを進めます。逆の動作をして元に戻す命令もあります。
なんに使うかというと、C言語のローカル変数を作るためです。ローカル変数は一般にスタック上に取られるため、そのための命令を用意しているのです。 次ページ: 条件分岐・ジャンプ命令