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言語のローカル変数を作るためです。ローカル変数は一般にスタック上に取られるため、そのための命令を用意しているのです。 - 条件分岐・ジャンプ命令
- 条件分岐は、いわゆる「IF」に相当するものです。この概念がないプログラム言語はありえないほど、コンピューターにとって重要な命令です。
それに対し、ジャンプは「GOTO」や「GOSUB」です。最近の言語では関数呼び出しもこれに当たると考えてよいでしょうか。こちらも、コンピューターにとっては不可欠な概念です。
CPUのコマンドとしては、一般に分岐はジャンプよりも高速に動作します。また、ジャンプとは異なりアドレスを相対位置で示す分岐命令では、プログラムをメモリ上のどこに配置しても同じように動作するというメリットもあります。
8086系のCPUでは分岐命令の「相対指定」の距離が短い(8bit)ため、実際のプログラムではジャンプ命令と組み合わせて使うことが必要です。
しかし、68000では条件分岐命令の有効距離が非常に長く(16bit)、分岐条件のなかに「必ず」というものがあるために、通常のプログラムのジャンプは分岐命令だけで書くことが出来ます。
68000の分岐命令にはデータレジスタを引き数にとるものがあり、その場合は条件をチェックした後、条件を満たさない場合はデータレジスタをデクリメントし、結果が正の場合だけジャンプします(条件を満たすか規定回数回るまでのループ、というのは結構使われるプログラムです)。
68000にはもちろんジャンプ命令もあり、こちらは32bitのアドレスすべてをカバーしています。
また、サブルーチンを呼び出すのにも分岐とジャンプの両方が使えますが、この場合の分岐命令にはフラグをチェックする機能はありません。 - 例外処理命令
- 例外処理とは割り込みのことです。普通は外部からの信号で割り込みがかかるのですが、ソフトウェアで割り込みを発生することも出来ます。
一つの方法は「割り込み命令」を使う正統派の方法でもう一つは未実装命令を使う方法です。
未実装命令とは、命令としては無意味だけどそのコードを呼んでも動作が保証されるというもので、その保証される動作とは「割り込みルーチンに移ること」です。
(もっとも、保証されない命令を使っても「不当命令割り込み」という割り込みルーチンに移るのだが)
未実装命令には16bitの命令コードのうち上位4bitが F のものと A のものがあり、それ以下の12bitには何を設定しても構いません。また、割り込みルーチン内で戻り先アドレスを適切に操作してくれれば、後ろにデータをつけても構いません。
つまり、68000はCPUの命令をユーザーが追加できるのです。ここまで基本的な命令を説明しましたが、プログラム上良く使うルーチンなどは命令にしてしまい、快適にプログラムを組んだりすることが可能です。
通常、未実装命令はOSが使用して、サービスルーチンの呼び出しなどに使っています(だって、それが一番「良く使うルーチン」だもの)。
メモリ保護
68000はUNIXを動かすために設計されているため、マルチユーザー下での安定性を確 保するための工夫がなされています。それが端的に現われているのがメモリ保護です。
68000はプログラムの実行をスーパーバイザーモードかユーザーモードかのいずれかでおこないま す。スーパーバイザーのプログラムがユーザーに移行することはできますが、その逆はできません。
そして、メモリはハード設計時にスーパーバイザーメモリとユーザーメモリにわけられ、ユーザーモードでスーパーバイザーメモリをアクセスしようとすると、例外処理が発生し、アクセスできません。
この特徴をいかし、OSやI/Oをスーパーバイザーメモリに置き、ユーザーに直接触らせ ないことで危険な状況を回避できます。
この場合、OSのファンクション呼び出しなどは割り込みをつかって処理します。割りこみプログラムはスーパーバイザーモードで走りますので、こうすることで間接的にユーザーモードからスーパーバイザーメモリにアクセスできます。
ところで、、スタックエリアはどちらに置くのでしょう。スタックはプログラムの実行に重要なものなのでユーザーエリアに置くのは危険ですし、かといってスーパーバイザーエリアに置いてしまえばユーザーモードでスタックが使えなくなってしまいます。
この問題を解決するため、68000は2つのスタックポインタをもちます。それはどちらもa7レジスタとして表現されますが、内部では2本のレジスタもち、実行モードによってどちらを見せるか切り替えているのです。
メモリ保護とはちがいますが、奇数アドレスから16bit、32bitをアクセスした場合にも例外が発生します。これにより、暴走したプログラムも結構な割合でとまってくれました。
(Macintoshでプログラムが暴走すると爆弾が出たりするのは、この割り込みを使用しています。)
このように、68000は効率的なプログラムが作れるようにレジスタや命令を工夫するとともに、「プログラムとは暴走するものだ」という前提に立ってその対策を講じています。
しかしUNIXワークステーションはともかく、パソコン用のCPUとしては、いささか先進的過ぎたかもしれません。メモリ保護機能などは多くのパソコンで無視され、アプリケーションもスーパーバイザーモードで動かしたり(Macintosh)、ユーザープログラムが簡単にスーパーバイザーに変身できたり(X68000)するOSがほとんどのようです。
68000はこの後も進化を続け、バグを取った68010、外部バスも32bitにした68020、さらにバグを取った68030、パイプラインを導入して大幅に高速化した68040、そして最新の(最近発売されたばかりの)68060とシリーズ化されています。
ところで余談なのですが、68000の普及は意外なところで進んだというデータがあります。
1986年ごろ、68000の総出荷数は70万個程度でした(おそらく、ほとんどの用途がMacintoshでしょう)。
しかしこの頃、家庭用ゲーム機のメガドライブ(セガ社)が68000をCPUに選び、コストを抑えるために100万個を発注しました。総出荷数よりも多い数を一度に注文した、というので当時は多くのパソコン雑誌で話題になりました。
結局このゲーム機は2200万台を売り上げ、量産効果で68000はかなり安価になりました。昔は組み込み機器などには安価なZ80が使用されていましたが、最近は組み込みでも68000が使われることが多くなったと聞きます。
最近は同じ理由で、一番売れているRISC CPUはRシリーズでも PowerPCでもなく、なんとSHシリーズなんだそうです。
これも、最初の原因は同じくセが社の「セガサターン」で、1台に2つのSH2と1つのSH1が使われていたからのようです。しかし、量産効果で値段の下がったSHシリーズはその後もいろいろなところで使用され、今では定番の組み込みチップの一つとなっています。
最近では ARMチップも良く使われる、という話もちらほら聞きます。ARMはやはり松下のゲーム機「3DO REAL」やAppleの「Newton Message Pad」に使われていたCPUですが、爆発的に売れたのはヨーロッパの携帯電話で標準CPUとして採用されて以降だとか。
いずれにせよ、CPUの売れ行きを決めるのが実は「パソコン」ではなく、それ以外の製品だというのが興味深いところです。
(ページ作成 1997-04-06)(最終更新 2002-05-02)
このページの誤字脱字発見・情報提供・意見などありましたら、下の一行掲示板へどうぞ。樫樹の広場から全体を見ることも出来ます。
