MC6800

Motorola社は電話など通信機器の大メーカーとして有名ですが、携帯電話などの最終製品だけでなく、アメリカの企業としては珍しく半導体まで開発販売しています。Intel社が当時としては実用的で使いやすい8 bitマイクロプロセッサ8080Aを発表して数ヶ月後、Motorola社は第2の8 bitマイクロプロセッサ、MC6800を発表します。特徴的なのは、最初からMC6800に接続して使うことを前提にした周辺LSIを用意していたことで、マイクロプロセッサのファミリ展開をリードしていたといえるでしょう。IntelとMotorolaは、マイクロプロセッサの業界で広く使われるプロセッサの系譜を初期から作ってきましたが、当時の企業規模を比較すると、巨大企業のMotorolaとふけば飛ぶようなベンチャー企業のIntelという構図になります。
MC6800は6 umシリコンゲートn-MOSプロセスで約5000トランジスタを集積しています。単一5 V電源で標準1 MHzクロックで動作し(1.5 MHz, 2 MHzで動作する高速版も後に出荷)、そのクロックがそのままバスサイクルを表し、バスのバンド幅は1 MByte/sになります。最大64 KByteのアドレス空間を持ち、その中にI/Oを配置するメモリマップ式のI/Oとなっています。8 bitのアキュムレータを2本と16 bitのインデックスレジスタとスタックポインタをそれぞれ1本、16 bitのプログラムカウンタと8 bit幅のコンデションコードレジスタが内蔵されています。割り込み入力はマスク可能なものとマスク不能なものの2種類が用意され、割り込みによってスタックポインタ以外のすべての内部レジスタが自動的にスタックに保存されるなど洗練されています。

比較的初期の(とはいえ1977年製)石の写真を下に示します。1.5 MHz版と2 MHz版の高速品を開発する際に1 MHz版も同様に改良されたと思われます。初期の1975年のデータシートと1980年頃のデータシートと比べると、DC特性からクロックタイミングやクロック端子入力容量、はてはバスサイクルタイミングまで変更されていて、改良が加えられていることがわかります。このMC6800L2という型番の末尾の2は改良後の製品であることを示しているのではないかと思いますが、正確なことはわかりません。MEK6800Dに付属のMC6800は、ちょうど1年前の76年製で、マーキングはMC6800L PK7603Jとなっていました。Lの後に2という数字はありません。おそらく、この間に切り替わったのでしょう。
MC6800

MC6800は、PDP-11のようなミニコンピュータを徹底的に簡略化して1個のICの中につめ込んだという面が強く、インデックス修飾などのアドレッシングモードが考慮された命令体系になっていました。まぁ、徹底的に簡略化ってとこが問題で、子供がまたがって動かすことのできる自動車のおもちゃは本物のスポーツカーの子供に不要な部分を省略して徹底的に簡略化したものだといえるかどうか、そこらへんの感覚がどうかってなところですが。いえ、別にMC6800が子供のおもちゃだという気はないんですが、ミニコンピュータ風だからプログラミングがしやすいって想像してしまうと期待はずれで悲しい思いをしそうですけどね。
ハードウェアの面からは、5 V単一電源で動作し、比較的簡単な回路だけで周辺LSIばかりか標準的なメモリも接続できるなど、8080Aに比べて簡単になっています(ただし、信号タイミングの問題で、バッファを外付けして強化したバスに多数のモジュールを接続するような大規模な応用では、バッファ制御などがすごく面倒になったりします)。
ハードウェア面では10 - 20個程度のICで応用システムを作ろうとすればMC6800が有利でそれ以上の規模や凝ったことをしようとすれば8080Aが有利かなぁという面はありますが、ほぼ互角。ソフトウェア面でも、MC6800が整った体系といっても下記のようにインデックスレジスタが1本のためにプログラムが書きにくいところがあり、一見アドレッシングモードが貧弱に見える8080Aでも複数のポインタやテンポラリレジスタが使えるため意外にプログラミングしやすい場面があったりして、事実上は互角だったといえます。つまりは論理的な決着なんて付けられないわけで、当時のマイクロコンピュータをテーマにした雑誌の読者のページなんかではどちらが有利かなんて論争が延々と続けられていました。

レジスタ構成はこうなっています。MCS6502MC6809のレジスタ構成と比較してみるのもおもしろいでしょう。
MC6800 registers
このように、8 bitのアキュムレータとしてAレジスタとBレジスタ、16 bit幅のインデックスレジスタが1個にスタックポインタとプログラムカウンタがあり、外部メモリをスタックとして使える普通のアーキテクチャでした。フラグ類はコンデションコードレジスタ(CCR)に集められています。Cはキャリー、Vはオーバーフローフラグ、Zはゼロフラグ、Nはネガティブフラグ、Iは割り込みマスク、Hはハーフキャリーです。演算は原則的に二つのアキュムレータのどちらかとメモリの間で8 bit単位で行います。インデックスレジスタへの演算はインクリメントとデクリメント、例外的に比較が可能になっていますが、加減算など16 bit演算はできません。

アドレッシングモードは16 bit直接アドレッシングのエクステンドアドレッシング、8 bit直接でゼロページ内を指定するダイレクトアドレッシング、インデックスレジスタに8 bitオフセットを加えるインデックスアドレッシングなどが可能で、条件分岐命令はプログラムカウンタ相対アドレッシングになっています。インデックスアドレッシングは、インデックスレジスタに定数の8 bitオフセットを加えるモードしかなく、16 bitオフセットやレジスタオフセットは使えません。レジスタセットがこのように貧弱なので、メモリ内のブロックコピーをするだけでも、転送元をインデックスアドレッシングでアキュムレータにロードした後、インデックスレジスタの内容をどこかに退避して、別のどこかにしまってあった転送先のアドレスをインデックスレジスタに入れて、アキュムレータの内容をストアし、再びインデックスレジスタの内容を入れ替えるという手順を踏まなければならず、面倒なものになってしまいました。このようなとき、スタックポインタをメモリ転送用のアドレスポインタとして使う裏わざもありましたが、もちろんコピーを行っている間は割り込みを禁止する必要があり、使い方に制約がありました。

これからMC6800の命令を、いくつかにグループわけして説明していきます。レジスタ構成の図で上から下へ、関連した命令をグループにしてみます。最初にアキュムレータを中心とする8 bit単位のデータ操作のグループ。次にインデックスレジスタやスタックポインタへの操作。さらに分岐などプログラムカウンタ関係の操作。最後にCCR回りの操作グループという順にしましょう。
アキュムレータ関係の命令はこのくらいあります。

意味            ニーモニック IMMED  DIRECT INDEX  EXTEND IMPLIED 動作
Add                    ADDA  8B 2 2 9B 3 2 AB 5 2 BB 4 3         A + M -> A
                       ADDB  CB 2 2 DB 3 2 EB 5 2 FB 4 3         B + M -> B
Add Accumulators       ABA                               1B 2 1  A + B -> A
Add with Carry         ADCA  89 2 2 99 3 2 A9 5 2 B9 4 3         A + M + C -> A
                       ADCB  C9 2 2 D9 3 2 E9 5 2 F9 4 3         B + M + C -> B
And                    ANDA  84 2 2 94 3 2 A4 5 2 B4 4 3         A & M -> A
                       ANDB  C4 2 2 D4 3 2 E4 5 2 F4 4 3         B & M -> B
Bit Test               BITA  85 2 2 95 3 2 A5 5 2 B5 4 3         A & M
                       BITB  C5 2 2 D5 3 2 E5 5 2 F5 4 3         B & M
Clear                  CLR                 6F 7 2 7F 6 3         0 -> M
                       CLRA                              4F 2 1  0 -> A
                       CLRB                              5F 2 1  0 -> B
Compare                CMPA  81 2 2 91 3 2 A1 5 2 B1 4 3         A - M
                       CMPB  C1 2 2 D1 3 2 E1 5 2 F1 4 3         B - M
Compare Accumulators   CBA                               11 2 1  A - B
Complement             COM                 63 7 2 73 6 3         not M -> M
                       COMA                              43 2 1  not A -> A
                       COMB                              53 2 1  not B -> B
Negate                 NEG                 60 7 2 70 6 3         0 - M -> M
                       NEGA                              40 2 1  0 - A -> A
                       NEGB                              50 2 1  0 - B -> B
Decimal Adjust         DAA                               19 2 1  BCD補正
Decrement              DEC                 6A 7 2 7A 6 3         M - 1 -> M
                       DECA                              4A 2 1  A - 1 -> A
                       DECB                              5A 2 1  B - 1 -> B
Exclusive OR           EORA  88 2 2 98 3 2 A8 5 2 B8 4 3         A eor M -> A
                       EORB  C8 2 2 D8 3 2 E8 5 2 F8 4 3         B eor M -> B
Increment              INC                 6C 7 2 7C 6 3         M + 1 -> M
                       INCA                              4C 2 1  A + 1 -> A
                       INCB                              5C 2 1  B + 1 -> B
Load Accumulator       LDAA  86 2 2 96 3 2 A6 5 2 B6 4 3         M -> A
                       LDAB  C6 2 2 D6 3 2 E6 5 2 F6 4 3         M -> B
Or                     ORAA  8A 2 2 9A 3 2 AA 5 2 BA 4 3         A or M -> A
                       ORAB  CA 2 2 DA 3 2 EA 5 2 FA 4 3         B or M -> B
Push Data              PSHA                              36 4 1  A -> M(SP--)
                       PSHB                              37 4 1  B -> M(SP--)
Pull Data              PULA                              32 4 1  M(++SP) -> A
                       PULB                              33 4 1  M(++SP) -> B
Rotate Left            ROL                 69 7 2 79 6 3         ROL(M)
                       ROLA                              49 2 1  ROL(A)
                       ROLB                              59 2 1  ROL(B)
Rotate Right           ROR                 66 7 2 76 6 3         ROR(M)
                       RORA                              46 2 1  ROR(A)
                       RORB                              56 2 1  ROR(B)
Shift Left Arithmetic  ASL                 68 7 2 78 6 3         ASL(M)
                       ASLA                              48 2 1  ASL(A)
                       ASLB                              58 2 1  ASL(B)
Shift Right Arithmetic ASR                 67 7 2 77 6 3         ASR(M)
                       ASRA                              47 2 1  ASR(A)
                       ASRB                              57 2 1  ASR(B)
Shift Right Logic      LSR                 64 7 2 74 6 3         LSR(M)
                       LSRA                              44 2 1  LSR(A)
                       LSRB                              54 2 1  LSR(B)
Store Accumulator      STAA         97 4 2 A7 6 2 B7 5 3         A -> M
                       STAB         D7 4 2 E7 6 2 F7 5 3         B -> M
Subtract               SUBA  80 2 2 90 3 2 A0 5 2 B0 4 3         A - M -> A
                       SUBB  C0 2 2 D0 3 2 E0 5 2 F0 4 3         B - M -> B
Subtract Accumulators  SBA                               10 2 1  A - B -> A
Subtract with Carry    SBCA  82 2 2 92 3 2 A2 5 2 B2 4 3         A - M - C -> A
                       SBCB  C2 2 2 D2 3 2 E2 5 2 F2 4 3         B - M - C -> B
Transfer Accumulator   TAB                               16 2 1  A -> B
                       TBA                               17 2 1  B -> A
Test Zero or Minus     TST                 6D 7 2 7D 6 3         M - 0
                       TSTA                              4D 2 1  A - 0
                       TSTB                              5D 2 1  B - 0

この表で、ニーモニックの欄はアセンブラで使われるニーモニックを示します。この後の欄は数字3組の欄が五つ続いていますが、それぞれがアドレッシングモードに対応しています。数字3組のうち、最初の2桁の16進数が、その命令のオペコードです。次の1桁の数字が命令実行に必要なクロック数、最後の1桁がその命令全体のバイト数です。この数字が2や3になっている命令には、アドレス修飾に必要なバイトが1ないし2 Byteだけオペコードの後に続きます。
では、この3組の数字が並んだ5欄について左から順に説明すると、最初の欄がイミディエートアドレッシングです。次がダイレクトアドレッシングで、真ん中がインデックスアドレッシング、その次がエクステンドアドレッシングです。最後のがインプライドアドレッシングで、命令自体の中に操作対象が内包されているものを指します。オペコードなどが書き込まれていない空欄の場所は、その命令について該当アドレッシングモードが禁止されていることを意味します。たとえば、TST命令ではダイレクトアドレッシングは使えないのです。
では、命令の各論に入ります。一応、この表ではMotorolaのデータシートと同じように、アキュムレータが演算対象の場合にはニーモニックの末尾にアキュムレータを示す1文字が直接続いています。以下の説明ではアキュムレータ指定部分を省略して表記することもありますから、注意してください。つまり、ADDA命令とADDB命令に共通の話をする場合にはADD命令と表記してしまいます。実は、オリジナルのMotorolaのアセンブリ言語の仕様ではデリミタがスペースで、しかもスペースを省略しても判別できる場合にはスペースを省略してもよいことになっていました。本来のニーモニックはADDAとかADDBでなくて、ADDだったのです。現にMIKBUGのソースのように初期のMotorola社が提示しているアセンブリ言語のソースリストでも、ADD B #$10のような形で、ADDとレジスタ指定の間にスペースが入っています。Motorolaのニーモニックは、他の命令もすべて3文字に統一されていましたから、3文字を読み込んだだけでニーモニックの判別を行ってしまい、レジスタ指定が必要な命令と判定されたら、4文字目以降から探しはじめていたのですね。こういったスペースの仕様はなんだか旧式のFORTRANみたいですが、昔の不便なソースコード編集環境では多少便利なこともあったということでしょう。アセンブラのリスト出力では、スペースの個数を自動的に調整して、レジスタや他のオペランドのカラム位置が揃う清書機能が付けられていました。
一般に、アキュムレータAとBには同等の操作が可能ですが、ABA, CBA, DAA, SBAに限っては、Aが優先的なレジスタになっています。他に後で出てくるTAP命令とTPA命令でAが特別扱いされています。それ以外の命令では完全にAとBは同等です。
ADD, ADC, AND, EOR, ORA, SUB, SBCの2項演算命令は意味のあるアドレッシングモードがすべて使えるようになっています。演算の意味も自明でしょう。ADD命令とADC命令では割り込みマスクを除くすべてのフラグが変化します。論理演算命令やSUB, SBC命令では割り込みマスクの他、ハーフキャリーフラグも変化しません。ですからDAA命令でBCD補正が可能なのは、加算系だけで、減算についてはBCD補正が効きません。
BIT, CMP, TSTは、アキュムレータやメモリの内容をテストするための命令です。BITはAND命令で結果をアキュムレータに書き込まないタイプです。CMP命令はSUB命令の変形です。TST命令は0との比較と考えられます。アキュムレータの特定のビットが1か0かを確かめるには、そのビットを1にした値をイミディエート指定してBIT命令を実行すればよいわけですね。逆にメモリ内容の特定のビットを調べる場合には、アキュムレータにテスト用のデータを入れて、ANDかBIT命令を実行します。TST命令だけはダイレクトアドレッシングができないことに注意しないといけません。
CLR, COM, NEG, DEC, INC, ROL, ROR, ASL, ASR, LSRの単項演算命令もダイレクトアドレッシングができません。CLR命令と他のINC命令などの実行クロック数が同一であることにも注意してください。CLR命令でメモリの内容を0にする場合も、実行制御回路を簡単にするためか、INC命令と同じように、先に操作対象のメモリ内容を読み出してから0を書き込みます。一般のメモリに対しては問題になりませんが、オートハンドシェーク機能などのために読み出しただけで状態が変化するI/Oポートに対してのCLR命令の使用には注意すべきです。
ローテート・シフト系の命令の具体的動作については、表の動作欄に書き込めませんでしたので、ここで説明します。ROLとRORのローテート命令については、8 bitデータのビット0とビット7の間にキャリーフラグを挟んで、全体を回転させます。つまりROL命令ではキャリーフラグの内容がビット0に入り、ビット7の内容がキャリーフラグに入ります。ビット7の内容がNフラグに反映され、ZフラグやVフラグも変化します。ASLでは左シフトを行いますが、ビット7からあふれた内容がキャリーフラグに入ります。新しいビット0には0が入ります。単純に操作対象の内容が2倍されたと解釈できます。逆にLSRでは右シフトではみ出したビット0がキャリーフラグに入り、ビット7には0が入ります。ASRは少し異なり、右シフトではみ出したビット0がキャリーフラグに入るのは同一ですが、ビット7には直前のビット7の内容がそのまま残ります。ASRでは内容を2の補数と解釈したときの符号が保存された状態で値が1/2にされたことになるわけです。ですから算術的右シフトと言われるわけです。
PSHとPULの対象になるのは二つのアキュムレータだけです。インデックスレジスタに関する命令は、この後で説明しますが、インデックスレジスタをPSHしたりPULしたりはできません。もちろん、定数やメモリの内容をPSHすることもできません。このアキュムレータグループの命令全体で、PSHとPULを除いた全命令の実行にともなって、何らかのフラグが影響を受けますから、注意してください。単にLDAでアキュムレータにデータを移動しただけでもNフラグやZフラグが変化します。この点が8080などの命令体系と異なっています。

次にインデックスレジスタやスタックポインタの16 bit単位のデータ操作グループです。

意味            ニーモニック IMMED  DIRECT INDEX  EXTEND IMPLIED 動作
Compare Index Reg.     CPX   8C 3 3 9C 4 2 AC 6 2 BC 5 3         X - M
Decrement Index Reg.   DEX                               09 4 1  X - 1 -> X
Decrement SP           DES                               34 4 1  SP - 1 -> SP
Increment Index Reg.   INX                               08 4 1  X + 1 -> X
Increment SP           INS                               31 4 1  SP + 1 -> SP
Load Index Reg.        LDX   CE 3 3 DE 4 2 EE 6 2 FE 5 3         M -> X
Load SP                LDS   8E 3 3 9E 4 2 AE 6 2 BE 5 3         M -> SP
Store Index Reg.       STX          DF 5 2 EF 7 2 FF 6 3         X -> M
Store SP               STS          9F 5 2 AF 7 2 BF 6 3         SP -> M
Transfer Index to SP   TXS                               35 4 1  X - 1 -> SP
Transfer SP to Index   TSX                               30 4 1  SP + 1 -> X

以上です。
CPX, DEX, INX, LDX, LDS, STX, STSの各命令ではZフラグが影響を受けます。また、この中のDEX, INXを除く5命令ではNフラグが変化したり、Vフラグも影響を受けます。具体的にはデータシートを参照して戴くとして、DEXとINXでZフラグが変化するのはプログラミングで使えそうです。DESやINSではフラグが変化しないようになっているのも、ポインタレジスタの使い分けを意識して設計されたと推測できますね。SPの比較命令がありませんから、スタックオーバーフローの検出は面倒になっています。まぁ、スタック消費量もプログラマがすべて自分で管理できるようなプログラム量とプログラム開発技法を期待されていた時代で、細かいことはプログラマが考えずに計算機の方で自動的に安全性も確保しようなんて考えはありませんでしたしね。
この命令グループでは16 bitデータを扱いますが、そのメモリの格納順序は、アドレスの小さい方に上位バイトでアドレスの大きい方に下位バイトが来ます。8080やMCS6502と逆ですから注意してください。
TXS命令とTSX命令は、データをレジスタ間で転送するだけの命令に見えますが、同時に演算も行っていることに注意してください。こうすることで、BSR命令やJSR命令の直後に定数を配置して、呼び出されたサブルーチン側で定数を操作するプログラミングが簡単になります。しかし、うっかり単なる転送命令だと理解してしまうと、気付きにくいバグの原因になることでしょう。TXS命令とTSX命令ではフラグも変化しないなど、少々例外的な命令です。
すでに触れましたが、インデックスレジスタをPSHしたりPULすることはできません。しかもインデックスレジスタが1本しかないため、データ転送やある種の文字列操作など、複数のポインタ操作が必要なプログラムを作成する場合には、頻繁にインデックスレジスタを入れ替える必要があります。通常は、ゼロページにインデックスレジスタの保存場所を確保して、ダイレクトアドレッシングでインデックスレジスタの保存や復帰を行います。ただ、こうすると再帰呼び出しやリエントラント可能なコードになりません。MC6800の命令体系でその種のプログラミングテクニックを実現するためには、相当の手間とコードと実行時間が必要となります。

次はプログラムカウンタ関係の命令ですね。このグループはプログラムカウンタ相対アドレッシングしか許されないブランチ系の命令と、それ以外に分けて表にします。

意味              ニーモニック   REL   条件
Branch Always            BRA   20 4 2  常に分岐
Branch If Carry Clear    BCC   24 4 2  C = 0
Branch If Carry Set      BCS   25 4 2  C = 1
Branch If = Zero         BEQ   27 4 2  Z = 1
Branch If >= Zero        BGE   2C 4 2  N eor V = 0
Branch If > Zero         BGT   2E 4 2  Z + (N eor V) = 0
Branch If Higher         BHI   22 4 2  C + Z = 0
Branch If <= Zero        BLE   2F 4 2  Z + (N eor V) = 1
Branch If Lower or Same  BLS   23 4 2  C + Z = 1
Branch If < Zero         BLT   2D 4 2  N eor V = 1
Branch If Minus          BMI   2B 4 2  N = 1
Branch If Not Equal Zero BNE   26 4 2  Z = 0
Branch If Overflow Clear BVC   28 4 2  V = 0
Branch If Overflow Set   BVS   29 4 2  V = 1
Branch If Plus           BPL   2A 4 2  N = 0
Branch to Subroutine     BSR   8D 8 2  動作: PC -> (SP--), PC += offset

最後のだけがサブルーチン呼び出しで特別な動作をしますが、他は(無条件も条件のうちと考えて)条件分岐命令です。オペコードの他にオフセットデータとして1 Byteの符号付き2進数データを持ち、条件が成立した場合にPCにその値を加えます。注意すべきことは、命令をフェッチした後にPCが自動的にインクリメントされているため、オペコードのあるアドレスから+2だけPCが進んでいるということです。つまり、自分自身への分岐を行う無限ループ、アセンブラでHERE: BRA HEREというような命令のバイナリコードは、20 FEとなるわけです。20 00ではないので注意してください。
条件分岐命令は条件判定に使われるわけですから、近傍に分岐する可能性が高いため、オフセットを1 Byteにして、コードサイズを節約できるようにしています。MC6800の命令体系では、バイナリコードを完全にリロケータブルにはできないので、コードをリロケータブルにするというよりは、1 Byteの節約だけを考えたのでしょう。当時のメモリは現在の100000倍以上高価であったのですから。そのため、-128から+127の範囲にない領域に条件分岐する場合は、条件分岐できる範囲に中継用のJMP命令を配置して、そこへと条件分岐しなくてはなりません。メモリ空間の任意の位置に条件分岐するための命令はありません。
ところで、BGTとBHIは、どこが違うんだと思われるかもしれません。比較対象が符号付きの整数か無符号の整数かの違いです。比較に使用する分岐命令を表にまとめてみました。

条件 無符号正数 符号付き整数
Acc < M BCS BLT
Acc <= M BLS BLE
Acc >= M BCC BGE
Acc > M BHI BGT
Acc = M BEQ BEQ
Acc != M BNE BNE

8080には複数のフラグが関与した条件分岐命令がなく、符号付き2進数の比較を正しく行うのは面倒でした。まぁ、このへんはPDP-11っぽいかなとも思えますね。LSI-11/23の命令と比較してみるのもおもしろいかもしれません。

その他のプログラムカウンタ回りの命令には、このようなものがあります。

意味            ニーモニック INDEX  EXTEND IMPLIED 動作
Jump                   JMP   6E 4 2 7E 3 3         Addr -> PC
Jump To Subroutine     JSR   AD 8 2 BD 9 3         PC -> (SP--), Addr -> PC
No Operation           NOP                 01 2 1  Do nothing
Return From Interrupt  RTI                 3B 10 1 後述
Return From Subroutine RTS                 39 5 1  (++SP) -> PC
Software Interrupt     SWI                 3F 12 1 後述
Wait for Interrupt     WAI                 3E 9 1  後述

JMPとJSR命令は説明がいらないでしょう。NOP命令は、単にプログラムカウンタを+1するだけの命令ということで、このグループに入っています。RTS命令はサブルーチンからの復帰で、リターンすべきアドレスをスタックから取り出してPCに入れます。NOP命令が01であって00でないってのが、8080に慣れた目からすると、ちょっといやかな。00というオペコードは未定義命令になっているのにね。UVEPROMの性質として、消去したときにオール1になって、0になるビットを書き込んでいくというのがあるので、00がNOPならUVEPROMのすでに書き込まれたバイトを00に上書きしてNOPにしてしまえるのに、そういう使い方ができません。ちなみにUVEPROMの消去パターンであるFFはSTXのエクステンドアドレッシングの命令と解釈されてしまいます。ここら辺を押さえておくと、暴走パターンの理解に役立つかもしれません。
残りのRTI, SWI, WAI命令は、割り込みに関係しています。RTIは割り込み時に保存されたレジスタ状態をすべて復元して割り込みで中断された命令列に復帰するための命令で、SWIはソフトウェアで割り込みと同じ動作を行うもの。WAIは割り込み時に保存されることになっているレジスタ類をすべてスタックに先に保存して、高速で割り込みに応答できる状態にしておいてプログラム実行を一時停止する命令です。これらの詳細は、MC6800の割り込みメカニズムの説明を行うときにまとめて説明しようと思います。

最後に残ったのがCCR、フラグ関係の命令ですね。これには、次の8命令が含まれます。

意味            ニーモニック IMPLIED 動作
Clear Carry            CLC   0C 2 1  0 -> C
Clear Interrupt Mask   CLI   0E 2 1  0 -> I
Clear Overflow         CLV   0A 2 1  0 -> V
Set Carry              SEC   0D 2 1  1 -> C
Set Interrupt Mask     SEI   0F 2 1  1 -> I
Set Overflow           SEV   0B 2 1  1 -> V
Transfer A to CCR      TAP   06 2 1  A -> CCR
Transfer CCR to A      TPA   07 2 1  CCR -> A

NフラグやZフラグはデータを操作した瞬間に変化してしまうためか、個別にセット・リセットする命令はありません。また、TAP命令やTPA命令はアキュムレータA専用で、アキュムレータBに対応する命令はありません。割り込みマスクに関しては0で割り込み許可、1で割り込み禁止という意味になります。1977年11月以前に製造されたMC6800には(あ、最初の写真のMC6800も含まれる)、CLI命令の後にWAI命令を続けて実行する場合、この直前の命令コードが偶数の場合に正しく動作しないという不具合があります。該当するMC6800に関してはCLI命令やSEI命令の直前にNOP(01)を配置するよう、Motorolaは勧告しています。

ピン配置はこんなふうです。MCS6502と比べてみてください。

VSS    1      40 RESET*
HALT*  2      39 TSC
CK1    3      38 NC
IRQ*   4      37 CK2
VMA    5      36 DBE
NMI*   6      35 NC
BA     7      34 R/W*
VCC    8      33 D0
A0     9      32 D1
A1    10      31 D2
A2    11      30 D3
A3    12      29 D4
A4    13      28 D5
A5    14      27 D6
A6    15      26 D7
A7    16      25 A15
A8    17      24 A14
A9    18      23 A13
A10   19      22 A12
A11   20      21 VSS

NCは使用されていない端子です。VSSが1番ピン21番ピンの2ヶ所にありますが、安定に動作させるために少しは有効でしょう。VCCに+5 Vを電源として供給します。A0 - A15がアドレスバスでD0 - D7がデータバスです。
CK1とCK2がクロック信号で、互いに反転した信号でかまわないのですが、同時にHになる時間があってはいけないことになっています。ほぼ5 Vフルスイングする振幅が必要で、特殊なドライブ回路が必要です。クロック専用ICを使うのが手軽ですが、フリップフロップで50 %デューティの2相信号を発生させてからオープンコレクタのバッファにプルアップ抵抗でHレベルを確保してクロック端子を駆動するということもできます。オープンコレクタのバッファにプルアップ抵抗を接続した場合、LからHになる時間がHからLに変化する時間の数倍かかってしまうため、同時にHになってはいけないという条件がおそらく満たされます。DBE信号はデータバスイネーブルで、データバスの駆動を行うために必要な信号ですが、ダイナミック回路を使用しているためか、Hレベルに固定することはできません。バスサイクルをできるだけ有利にする場合はCK1の立ち上がりから150 nsだけLレベルにして残りの時間はHにするのがよいのですが、回路を簡単にしたい場合にはCK2と同じ信号を与えることもできます。
HALT*, BA, TSCがDMAに関する信号です。TSCはトライステートコントロール信号で、バスをハイインピーダンスにすることができますが、この信号を使う場合には同時にCK1とCK2を停止するなど、制御が難しいこともあって、あまり使用されません。HALT*信号をLにすると、命令実行の区切りでMC6800がバスを開放してDMAが可能になります。DMAが可能になったのを示す出力信号がBA信号です。ただし、1命令を実行し終わってからですから、SWI命令の場合には最悪12クロック後にDMAが許可されることになります。ちょっとした命令でも5クロックくらいは消費しますから、あまり応答性が高くありません。どうしても2 us以内にDMAを行いたいという場合には、CK1とCK2を一時停止してDMAを使う方法か、CK2がLの時間にCPUがバスを使用しないことを利用して、その間にメモリを読み出すようなハードウェア設計を行います。ダイナミックメモリのリフレッシュを行う場合にも、このどちらかが使用される場合が多かったですね。
VMA, R/W*, 重複しますがCK2信号の3本がバスサイクルで特に重要な信号です。CK2信号はシステム全体のタイミングを規定する信号で、Hの間はMC6800からのアドレスが確定していることを表し、データの読み込みはCK2がHからLになるタイミングで規定されています。データの書き込みも、同じタイミングでメモリやI/Oがデータを取り込むことになっています。CK2はCPUの内部動作にも使用され、普通は停止することができない信号ですが、CPUが内部動作だけ行ってバスとデータ転送を行わないクロックサイクルというのも存在します。バスに出力されているメモリアドレスが有効かどうか、つまりバスサイクルをMC6800が行っているのか行わないクロックサイクルかを示すのが、VMA信号です。
最後に残ったIRQ*, NMI*, RESET*は、割り込み・例外関係の信号ですね。IRQ*はマスク可能な割り込みで、NMI*はマスク不能な割り込み要求信号です。IRQ*はレベルで受け付けられますが、NMI*はネガティブエッジで受け付けられます。RESET*はリセット信号で、割り込み要求信号と異なり、レジスタの退避も行われなければ、リセット前の状態に復帰することもできませんが、ベクタメカニズムが同一なので、まとめて説明します。MC6800では割り込みサービスルーチンのアドレスを決定するのにベクタを用いています。とはいえ、Z80や8086やMC68000のように、割り込み要求を出したデバイスからベクタコードを読み出して、そのコードを用いて表を引いてアドレスを求めるようなことはしていません。IRQ*ならFFF8から、NMI*ならFFFCから、2 Byteを読み出して、それをPCにロードします。つまり割り込み信号別にベクタアドレスが最初から決まっています。ベクタアドレスを表にしてみました。

割り込み要因 ベクタアドレス
RESET FFFE, FFFF
NMI FFFC, FFFD
SWI FFFA, FFFB
IRQ FFF8, FFF9

ベクタに納められるサービスルーチンのアドレスも、他の16 bitデータと同じように上位バイトが小さなアドレスの方に配置されます。
RESET*信号がLにされて規定の時間が経過後にHにされると、アドレスFFFEとFFFFから16 bitデータを読み出して、それをPCにロードしてから、通常の命令実行モードに入ります。すなわち、リセット時にはFFFFやその前のアドレスにベクタデータが読み出せなくてはなりませんから、MC6800システムではこのアドレスに必ずメモリが必要です。しかも、電源投入直後から何かしらの動作を開始する通常のシステムでは、この付近にROMがなくてはなりません。MC6800システムでは、ダイレクトアドレッシングの都合からアドレス0000からRWMを配置して、この割り込みベクタの都合でアドレス空間最上位のFFFFの付近がROMを配置するように設計するのが普通です。I/Oはメモリマップですから、ROMでもRWMでもない場所に配置すればよいのですが、小規模の組み込み用の場合にはゼロページの一部に確保してプログラムを短くできるようにすることが多く、大規模なパーソナルコンピュータ的な使用法の場合にはRWMをできるだけ連続して広く取りたいのでROMの近傍に配置するのが普通です。
NMIやIRQ、さらにSWI命令の実行によって、通常の割り込みシーケンスが起動します。これらは独立のベクタが割り当てられています。ただし、複数のデバイスからIRQ*を受け付けるような場合、MC6800では一般的にソフトウェアで割り込み要因を調べます。ただし、特別なハードウェアを用意して、プロセッサがIRQのベクタアドレスFFF8とFFF9の内容を読み出す際に、割り込み要求信号を出しているデバイスの種類をハードウェアで検出して、その要因に応じてアドレスを外部回路で変換してしまって多数のベクタアドレスを付加してしまうようなシステムも存在します。
割り込みシーケンスでは、PC, X, A, B, CCRを、この順にスタックにプッシュして、CCRの割り込みマスクIをセットしてから、ベクタを読み出して、割り込みサービスルーチンにジャンプします。全レジスタの退避を、すべて自動で行います。ソフトウェアの関与は一切必要ありません。また、割り込みサービスルーチンからの復帰は、RTI命令ひとつで確実に行えます。RTI命令の実行によって、CCR, B, A, X, PCをこの順にスタックからプルして、割り込みされた命令列の実行を再開します。CCRもスタックに保存されていますから、割り込みマスクの状態も自動的に復元されます。
MC6800の割り込みシーケンスでは、常に全レジスタの状態を自動退避することになっているため、最短でも12クロック分の時間が割り込みサービスルーチン実行に先駆けて必要とされます。まぁ、本来は割り込みサービスルーチンの内部でソフトウェアで行わなければならないはずの作業ですから、ソフトウェアに任せるよりも効率的になっているはずですが、場合によっては時間がかかりすぎて使えない場面もあるでしょう。その問題をある程度解決して割り込み応答時間を稼ぐために、MC6800にはWAI命令が用意されています。WAI命令では、割り込みが発生したときと同じように、先に内部レジスタをスタックにプッシュしてしまいます。その後でPCのインクリメントを停止し、つまり命令の実行を中断して、割り込み信号が与えられるのを待ち続けます。割り込みが発生すると、内部レジスタのプッシュは終わっていますから、内部の同期とベクタの読み出しに必要な分、4クロックサイクルだけで、割り込みサービスルーチンを開始できます。スタックに退避されるPCの値はWAI命令の次のアドレスを指していますから、RTI命令で割り込みサービスルーチンから復帰すると、WAI命令の次の命令からプログラム実行を再開します。入出力デバイスの完了割り込みが発生するまでCPUが何もする必要がない場合などにWAI命令を使用すれば、最高のスループットで処理を行うことができます。

8080AにはNECが機能を追加したuPD8080Aというバリエーションが存在します。MC6800にはそのようなものがないかといえば、実はあります。富士通が製造していたMB8861がそれです。

採用したコンピュータ製品

Motorora MEK6800D, MEK6800D-II, MEK6800D-IIB
日立 H68/TR, ベーシックマスターシリーズ(レベル2まで)
SWTPC 6800

Returnto IC Collection.