MCM6830L7は型番のプリフィックスから想像できるようにMotorola社製のメモリICで、具体的には1 KByteの容量のマスク ROMです。マスクROMですから、普通は量産用の装置以外には縁がなかったはずですが、型番の末尾に7が付いているMCM6830L7は、Motorola製のモニタプログラムが書き込まれていて、アマチュアやプロの教材として、あるいは自作機の最初に動かすプログラムとして、単体で売られていましたし、実際よく使われていました。
これは久我様よりいただいたもの。1976年製の旧式パッケージでハンダ封止もあやうい感じがします。
単なるMASK ROMとしてのMCM6830については、次のようなピン配置の、少しチップセレクトが多い普通のROMです。
GND 1 24 A0 D0 2 23 A1 D1 3 22 A2 D2 4 21 A3 D3 5 20 A4 D4 6 19 A5 D5 7 18 A6 D6 8 17 A7 D7 9 16 A8 CS0 10 15 A9 CS1 11 14 CS3 VCC 12 13 CS2
5 V単一電源で、チップセレクト端子が4本あります。チップセレクトはすべて正論理で書いてありますが、正負どちらかの論理にプログラマブルとなっています。
アクセスタイムは最悪575 nsで、一見中途半端な数値ですね。これは、MC6800に標準的な1 MHzクロックを加えたときに必要となるアクセスタイムの最悪値に一致しています。MC6800専用というか、かなり意識した設計であることは確かです。ちなみに、そのアクセスタイム条件では、MC6800のアドレスバスにバッファを挿入しただけでも規定外になりそうですけよね。実際には、バッファを挿入すれば規定の負荷条件より軽くなるはずで、負荷条件によって遅延時間が大幅に変化する当時のMOSプロセスの性質を考えれば、問題が発生する可能性はなさそうです。
さて、MCM6830L7の中身について考えていきましょう。
このROMの内容には独立した3要素が詰め込まれています。ひとつはMC6820をI/Oとして利用するMIKBUGモニタプログラム、さらにMC6850をI/Oとして利用するMINIBUGモニタプログラム、最後の要素はプログラムでなくて単なるテストパターンデータです。
ROM内での配置は次の表のようになっています。
先頭アドレス | サイズ | 内容 |
$000 | 512 Byte | MIKBUG |
$200 | 256 Byte | MINIBUG |
$300 | 256 Byte | テストパターン |
上の表の先頭アドレス欄は、あくまでROM内でのアドレス配置を示すものです。MC6800に接続したときのアドレスとは直接関係ありません。
MCM6830L7の4本のチップセレクトの論理はすべて正論理にプログラムされています。
MIKBUGはMC6820 PIAをI/Oポートとして使用し、外部にテレタイプライタ(TTY)かRS-232Cでインターフェースされる端末を接続して入出力を行うモニタプログラムです。次のような機能があります。
モニタプログラムでピンとこなければ、ものすごく簡単なデバッガといえばわかるでしょうか。
MIKBUGを利用する際に必要となるメモリマップは次のようになっています。
重要なのは3要素、MIKBUG自体を格納したROMと、MIKBUGの作業領域やスタック領域のために128 ByteのRWM、さらにI/OポートとしてのMC6820だけです。それ以外のメモリやI/OポートはMIKBUGのために必要ありません。もちろん、ターゲットプログラムの都合ではるかに大きなメモリやI/Oが必要とされるかもしれませんが、MIKBUGからはコマンドで特にアクセスしようとしなければ、使用されることはありません。
MIKBUGではTTYかRS-232Cで接続される端末を入出力に使用します。PIAのポートの使用状況を表にすると、こうなります。
ポート | 入出力 | 用途 |
PA0 | 出力 | シリアル出力 |
PA7 | 入力 | シリアル入力 |
CB2 | 出力 | テープリーダー制御 |
PB0 | 出力 | タイマリセット |
PB2 | 出力 | タイマA入力 |
PB6 | 入力 | 通信速度選択入力 |
PB7 | 入力 | タイマ出力 |
PA0, PA7がシリアル入出力で、RS-232Cの制御信号のようなものはいっさいサポートしない3線式のインターフェースです。ただし、TTYを接続する場合にはCB2でテープリーダー制御が可能となっています。もちろんPIAのポートの先にRS-232Cへの電圧レベル変換回路やTTYへの電流ループインターフェースを接続する必要があります。PB0, PB2, PB7はシリアル通信速度を管理するための外付けタイマICを接続する端子です。MC14536を接続することになっています。ソフトウェアでシリアル通信を行うというと、命令実行クロック数を数えて時間管理を行うことが多いと思いますが、MIKBUGではタイマICの出力を監視することによって時間管理を行っています。MIKBUGが実行されるシステムのクロック周波数を1 MHzというふうに決め打ちすることが時代的にできなかったはずで、ある意味当たり前の対策かもしれません。なにしろMC6800が発表された当時の入手しやすいメモリICのアクセスタイムが1 usくらいだったりして、最高クロック周波数の1 MHzでMC6800を動かさずに600 kHzくらいで動作させることもよくありましたから。PB6にはスイッチを接続して、300 bpsのRS-232Cの通信速度を指定するか、110 bpsのTTY標準の通信速度で入出力を行うかMIKBUGに通知することになっています。しかし、スイッチで切り替えるついでにタイマの発振周波数を微妙に調整しないと、正しい通信速度にならないかもしれません。
RWMは、正確には$A000から$A049までをMIKBUGで使用します。$A000から$A013までが作業領域、$A014から$A042までがスタック領域、$A043から$A049までが内部レジスタ退避領域として使われます。スタック領域にはSWI命令やIRQ割り込み時に内部レジスタが退避される分も含まれています。
MIKBUG自身は$E000よりの512 Byteを占有します。そのためにMCM6830L7のアドレス信号A9をLレベルにした上でA0からA8をMC6800のA0からA8に接続し、CS0 - CS3に適切なアドレスデコード信号を与えることになります。
さて、このメモリマップで気になることがあると思います。MC6800はリセット時に$FFFEのアドレスからベクタを読み出して、そのアドレスから命令読み出しを行います。ところが、上記のメモリマップでは、そのベクタ領域には何もありません。つまり、厳密に上記のメモリマップ通りのハードウェアを作製してUnusedのところに何もデバイスを割り当てないと、リセット直後から暴走することになります。いったいなぜ、このようになっているのでしょうか。
当時、最初からMIKBUGを利用するつもりでコンピュータを製作することもあったでしょうが、先にそれなりのMC6800を中心にしたコンピュータを作製して後からMIKBUGを追加することもよく行われました。ミニコンピュータタイプの、パネルのトグルスイッチからRWMにプログラムを書き込んでちょっとしたプログラムを走らせるようなコンピュータです。その場合、M6800アーキテクチャの都合上、アドレス$FF00 - $FFFFあたりと$0000から始まる領域にRWMを配置するのが普通です。このようなコンピュータに後からMIKBUGを増設することを考えれば、それ以前のアドレス割り当てを変更しないですむように、上記のメモリマップを仮定するのは現実的です。その場合、まずパネルからベクタ領域に適切なスターとアドレスや割り込みルーチンの先頭アドレスを書き込んでおいてからリセットして、MIKBUGを起動させます。なぜ最初からモニタROMの利用を考えずにコンピュータを作ってみたりするのか、当時の状況を知らないと理解しにくいでしょうけど。まぁROMに自由にプログラムを書き込める環境の方が珍しく、ROMを使わないシステムを自作することも多かったということで。
さて、元の問題に戻りますが、逆に最初からMIKBUGを利用するつもりでコンピュータを製作した場合、どうすればよいのでしょうか。ベクタ領域の$FFF8 - $FFFFを含む$FF00 - $FFFFくらいの領域にROMを配置すれば問題は解決です。しかし、そんなふうにROMを簡単に利用できないからこそMCM6830L7なんてマスクROMに納められたMIKBUGを使いたいわけです。で、そのベクタ問題を解決するために、MCM6830L7のアドレスで$1F8 - $1FF、MC6800から見たアドレスで$E1F8 - $#1FFに相当する部分に適切なベクタが書き込まれています。したがって、アドレスデコードをうまく省略して$FFF8 - $FFFFに$E1F8 - $E1FFのアドレスの内容が現れるようにすれば、ベクタ問題を解決できます。簡単に行うには、CS信号をA15 - A13がすべて1という条件で生成し、A12 - A9を無視して残りのA8 - A0をMCM6830L7のアドレス端子に接続すればよいでしょう。すると$E000から$FFFFまで、繰り返しMIKBUG部分のROMの内容が現れることになります。
MIKBUGのコマンドには次の5種類があります。
MIKBUGの内部ルーチンで利用可能なものをいくつか示します。
ラベル | アドレス | 動作 |
INEEE | $E1AC | 端末から1文字読み取ってAに入れる |
OUTEEE | $E1D1 | Aに入っている文字を端末に出力する |
OUT2H | $E0BF | (X)のメモリの内容を16進数2桁で出力 |
OUT4HS | $E0C8 | (X), (X+1)の内容を16進数4桁で出力し後にスペースを出力 |
OUT2HS | $E0CA | (X)の内容を16進数2桁で出力し後にスペースを出力 |
まぁ、最低限INEEEとOUTEEEだけあれば、端末との入出力を行えます。
MINIBUGはMC6850を用いてTTYやRS-232Cインターフェースで接続される端末と入出力を行うモニタプログラムです。サイズはMIKBUGの半分の256 Byteですから、いくらソフトウェアでシリアルインターフェースを実現する必要がないとはいえ、MIKBUGより機能も削られています。次の4点だけです。
紙テープにパンチされたSフォーマット形式のコードをメモリにロードする機能はありましたが、逆にメモリの内容をパンチする機能はありません。それでは困りそうなものですが、パンチ出力を行う小さなプログラムを「メモリ内容の表示と変更」機能を用いてコンピュータに入力して、そのプログラムを含むメモリ領域を対象にしてそのプログラムを実行します。するとパンチ出力を行う小さなプログラムの紙テープができますから、パンチ出力したいときには「メモリローダ」機能でその紙テープから読み込んで実行することでMINIBUGの機能にないパンチ出力を代用できます。
MINIBUGのメモリマップは、このようになっています。
MIKBUGと異なり、I/Oも含めて$FC00 - $FFFFの間にコンパクトに配置されています。
ただし、256 Byteの制限のため、リセット時のベクタがROMの中にありません。したがって、少なくとも$FFFEと$FFFFにリセット時のベクタを提供する回路が必要となります。小容量のROMを配置するか、8 bitバッファを2個用意してベクタアドレスがMC6800から出力されたときにそのバッファから適切なベクタアドレスを供給する必要があります。
RWMは$FF00 - $FF35までMINIBUGで使用します。
MINIBUG ROMは$FE00 - $FEFFの256 Byteを、1 Byteの余りもなく使用しています。
MINIBUGのコマンドには次の4種類があります。
なお、レジスタの保存領域については次の表のようになっていますから、Mコマンドで変更することができます。
アドレス | レジスタ |
$FF29 | CCR |
$FF2A | B |
$FF2B | A |
$FF2C | X |
$FF2E | PC |