CPUはZ80 CPUで、I/OポートにZ80 PIOを用いています。スペックは、
CPU: Z80 CPU 2.5 MHz clockというようなものです。TK-80のように1 KbitのRWMではなくて4 KbitのRWMを採用しているため、さすがにメモリ容量も大きいですね。
RWM: 1 KByte標準実装(最大4 KByte)
ROM: 1 KByteモニタROM標準実装(最大3 KByte)
出力装置: 6桁LED(アドレス4桁、データ2桁)
入力装置: キースイッチ25個(ファンクションキー9個を含む)
補助記憶装置: コンパクトカセットテープレコーダインターフェース1200 bps
カレントループシリアル通信インターフェース装備
基板サイズは180 mm×147 mmで、PC-9801のC-Bus拡張基板よりほんの少し大きいだけ、TK-80の基板の半分以下のサイズです。
以前の所有者が勉強のためかZ80 CPUとZ80 PIOにピンの名称を印刷したシートを両面テープで貼り付けていました。剥がしてみると、CPUはNECのuPD780Cで、PIOはSGSロゴの付いたZ80A
PIOでした。CPUの方はオリジナルでしょうが、PIOは破損して交換したのかオリジナルと異なる比較的新しいものです。
すぐにわかるように、1と5のキートップが紛失しています。実は6のキートップも破損があります。なにかにぶつけたみたいで、タクトスイッチとのはめ込み部分のキートップ側が壊れているので、1と5のキートップも同様に破損して脱落、紛失したものと思われます。
さらに、以前の所有者が、カードエッジコネクタ部に直接ハンダ付けして電源ケーブルを取り付けています。カードエッジコネクタの裏側の端子にもハンダ付け跡があったりして、悪い状態です。
あと、RWMがオプションの分も含め、フル実装されています。標準は1 KByteですが、これは4
KByte使えます。
まず電源を用意します。電源は5 V ±5 %で最大0.9 A流せるものが必要です。RWMを最大まで増設した状態で、実測値で0.81
Aとなっています(LEDに8888 88と表示させた状態)。ちなみにLEDを消した状態では0.68
Aでした。余裕をみて最大1 Aまで取りだせる5 V電源を用意すればよいでしょう。5
V単一電源です。他の電源電圧は不要です。Z80 CPUを使用しているから当たり前のように思えるかもしれませんが、ROMが2708で、これは+12
Vと- 5 Vも必要とします。しかし、内部で+ 5 Vから変換していますから、単一電源で済んでいます。
この電源を、カードエッジコネクタから供給します。写真のように、直接基板にハンダ付けしないで、コネクタから供給すべきでしょうね。カードエッジコネクタには、カセットテープレコーダへの入出力端子なども引き出されていますから、後で載せる予定のコネクタ端子表をもとに、必要なコネクタの取り付けや配線を前もって済ましておく方がよいでしょう。
カードエッジコネクタのすぐそばにDIPスイッチがあります。後述しますが、電源投入前にすべてOFF側に設定しておいてください。特に、2番スイッチに関しては必ずOFFにしてください。これがONだとTTY/タイピュータ用モニタを自動起動しようとしますが、そのTTY/タイピュータ用モニタは別売で標準実装されていませんから、暴走することになります。
以上で、電源投入前の準備は終わりです。CRC-80を絶縁板の上に置いて、電源を投入してください。この基板には、4隅に固定用の穴が空いていませんし、裏にゴム足を付けられるようなちょうどよいスペースもありませんから、置くときに注意してください。古雑誌の類の上に置くのが、滑らずに机に傷もつかずに適当でしょう。さて、電源を投入しても、LED表示が消えていたり、へんなパターンが表示されていたら、電源電圧が規定の電圧になるまでの時間や変化のしかたの影響でパワーオンリセット回路がうまく働いていない可能性がありますから、キースイッチの右上RESボタンを押して、手動リセットしてください。表示用LEDの6桁になんらかの16進数が表示されていれば、正常動作しています。ただし、データ表示の2桁分に関しては、後述しますが、ちらちらとデータが頻繁にでたらめに変化している場合があるかもしれません。しかし、それはメモリを実装していないアドレスのデータを表示しようとしているためで、おそらく正常です。リセット直後、特定のメモリアドレスを表示するように初期化する機能はありません。作業用メモリの偶然の初期値によって決まりますから、たまに異なる数値が表示されても気にしないでください。
これからの操作は、基板右側のキーボードとLEDによって行います。
6桁あるLEDの左側4桁は原則としてアドレスを表し、その右側の2桁のLEDはアドレスLEDに表示されているメモリアドレスに記録されているデータを常に表示しています。
16個の16進数キーは数字を入力するのに使用します。それ以外の9個のファンクションキーで、必要な操作を行います。以降に、そのファンクションキーの使い方をひとつずつ説明します。
RESキーはシステムをリセットします。ハードウェアのRESET*信号に直接接続されているため、システムがどんな状態でも確実にリセットできます。後で出てくるLDキーを誤って押してテープからの信号待ちになってしまい他の操作ができないような場面でも、RESキーで復帰できます。ただし、RESキーを押している間は常にRESET*信号が発生しているため、外部にダイナミックメモリを用いたメモリシステムを拡張して、その回路がZ80
CPUの発生するRFSH*信号をもとにしてリフレッシュを行っていると、RESキーを押している間はRFSH*信号が発生しませんから、記憶内容が変化する可能性があります。
INCキーは、LEDに表示されているアドレスをインクリメントします。そうして、インクリメントされたアドレスに含まれるデータが、データ表示LEDに表示されます。
DECキーは、INCキーと逆でアドレスのデクリメントを行います。やはりデータ表示も切り替わります。それ以外の機能はありません。
DAキーとADキーは、16進数キーの入力モードを切り替えるのに使われます。入力モードには2種類あります。アドレス入力モードとデータ入力モードです。
ADキーを押すとアドレス入力モードになります。DAキーを押すとデータ入力モードになります。リセット後のモードは不定です。アドレス入力モードでは、16進数キーを押すたびに、アドレス表示が1桁左にずれて、押したキーの数値がアドレス表示の最下位桁に入力されます。そうして、新たに確定した4桁のアドレスで指されたメモリからデータを読み出して、データ表示用LEDに表示します。この動作は、DAキーが押されてデータ入力モードになるまで、16進数キーを押すたびにくり返されます。これは、RESキーを含む他のファンクションキーが押された場合にも同じで、入力モードが変化することはありません。たとえば、89ABというアドレスを設定するためにADキーを押してアドレス入力モードにして、8,
9と入力した後、誤って9をもう一度押してしまったなら、あわてずに最初から8,
9, A, Bの順に押しなおせば良いのです。
DAキーを押すとデータ入力モードになります。データ入力モードで16進数キーを押すと、アドレス表示LEDに表示されているアドレスが指しているメモリ内容を1桁左にずらして押したキーの表す数値を下位桁に入れた数値を、同じアドレスのメモリに書き込みます。そうして、さらに同じアドレスからデータを読み出して表示します。データ表示LEDに表示されているのは、常にメモリの内容です。したがって、アドレスの指すメモリがROMであったりメモリが実装されていなかったりして、データを書き込めない場合、16進数キーをいくら押しても表示内容が変化することはありません。書き込み可能なら、データ入力モードで16進数キーを押せば、必ずメモリ内容が変化してしまいます。押した後でキャンセルすることはできません。注意してください。一度データ入力モードに入れば、次にADキーを押すまではリセットをしようが何をしようが、モードが変化することはありません。
メモリに格納されたデータを確認するだけなら、ADキーでアドレス入力モードに切り替えてアドレス設定した後、INCキーやDECキーでメモリの内容を順番に確認していくのが良いでしょう。これなら、操作の最中に誤って16進数キーに触れてしまっても、アドレスが変化してしまうだけで、データの内容が書き変わってしまうことがありません。データ入力モードにしてしまうと、INCキーを押した直後にうっかりFキーにでも触れてしまえば、メモリ内容が書き換えられてしまい、実際にどんなデータが入っていたかわからなくなってしまいます。
GOキーはメモリ上の命令列を実行させるためのキーです。GOキーが押されると、後述のモニタROMの作業領域マップの中のレジスタ保存用領域からCPUの内部レジスタに内容が移されて、アドレス表示LEDに表示されているアドレスから命令を実行します。DIPSWの1番がOFFになっていると、1命令実行ごとにNMI*が発生し、モニタの作業領域のブレークポイント関係にあらかじめ設定しておけば、そのブレークポイントアドレスでプログラムの実行を中断させることができます。ただし、1命令ごとに割込みが生じるのでプログラムの実行速度はかなり遅くなります。DIPSWの1番をONにしておけば、NMI*が生じませんので、本来の速度でプログラムを実行することができます。
ブレークポイントを設定するには、83ECHからの2 Byteにブレークポイント対象アドレス、83EEHからの1
Byteにブレークポイントの実行何回目で中断させるか、その回数から1を引いたものを書き込んでおきます。たとえば、83ECHに8200H,
83EEHに3を書き込めば、8200Hの命令を4回目に実行する直前でプログラムが中断されます。83EEHが0なら、初めて実行される直前で中断されます。なお、ブレークポイントアドレスは命令の第1
Byte目でなくてはなりません。また、モニタROM以外の全アドレス空間の命令をブレークポイントに設定できます。逆にいえばモニタROMの内部にブレークポイントを設定することはできません。ブレークポイントを無効にするには、DIPSWの1番をOFFにするか、ブレークポイントアドレスにモニタROMのアドレス範囲、つまり0000Hから03FFHまでの数値を書き込むことになります。DIPSWの1番をONにすればプログラムが本来の速度で実行されるので、こちらの方がお勧めです。あと、そのアドレスの命令が実行される直前というのも注意してください。ブレークポイントの命令まで実行させたいなら、そのままの状態でSTPキーを押すか、最初からブレークポイントを次の命令アドレスに設定するしかありません。
STPキーはプログラムのステップ実行を行わせるためのキーで、GOコマンドとほぼ同様ですが、1命令実行後に再びモニタに戻ってきます。その際、モニタROMの作業領域マップに示したレジスタ保存用領域にレジスタの内容を記録しますので、ADキーやINC/DECキーなどを使ってその領域を調べることによって、レジスタの内容を確認したり変更することもできます。また、1命令実行後のプログラムカウンタの値は、制御がモニタに戻ってきた直後にアドレス表示LEDに表示されています。単純に1命令ずつ続けてステップ実行する場合、STPキーを何回も繰り替えし押すだけでプログラムカウンタが変化していくのがLEDに表示されて読み取れます。ただし、ハードウェア割り込みを使用してステップ制御を行っている都合上、DIPSWの1番がOFFでないとステップ動作を実現できません。DIPSWの1番がONなら、単なるGOコマンドと同じ動作を行い、プログラムは最高速で動作します。また、モニタプログラム内のルーチンをステップ実行させることもできません。
STキーはオーディオカセットテープにメモリの内容を保存するためのコマンドです。保存するメモリ領域の先頭アドレスは、後述のモニタROM作業領域マップでもわかりますが、83E8Hから始まる2
Byteに前もって書き込んでおきます。また保存すべきメモリ領域のサイズも同じように83EAHから始まる2
Byteに前もって書き込んでおきます。それにしたがって、テープへ記録するためのオーディオ出力が行われます。まず15秒ほどのヘッダが送出され、その後で先頭アドレスと記録長が出力され、それからメモリの内容が連続して出力されて、最後にチェックサムが1
Byte書き込まれます。1 Byteのデータにはスタートビットとストップビットが1
bitずつ付加されて10 bitにして書き込まれ、1200 bpsの速度で記録が行われます。したがって、標準1
KByteを書き込むのにヘッダ部分も含めて24秒ほど、4 KByteで50秒必要となりますから、まずまず手ごろな速度と考えられるでしょう。テープレコーダを録音状態にしてからSTキーを押すようにすると良いでしょう。
LDキーはSTの逆で、オーディオカセットテープからデータを読み込みます。メモリのどこにロードするかなどは、テープの側に記録されているので前もって手で設定する必要はありません。テープレコーダを再生状態にして、ピーという音が出力されている状態でLDキーを押すと良いでしょう。LDキーを押すとLEDの表示が消えます。正常にロードされると再びモニタに戻ってきて通常のLED表示がなされます。ロード中にエラーが発生すると、アドレス表示LEDにEE01,
EE02, EE03のいずれかのエラーコードを表示します。チェックサムエラーでEE01、スタートビットに異常を検出するとEE02、ストップビットに異常を検出するとEE03というエラー表示が行われるようになっています。
STコマンドとLDコマンドでオーディオカセットテープレコーダを接続する端子については、後でエッジカードコネクタのピン割り当てを紹介するときに説明します。一般に録音用出力はマイク入力に接続するには大きすぎるので、アッテネータを入れるかライン入力を備えたレコーダを使用すると良いでしょう。
品名 | コメント |
Z80 CPU | 8 bitマイクロプロセッサ2.5 MHzクロック |
Z80 PIO | パラレルI/O, LED表示やキー入力、シリアル入出力として使用
シリアル入出力はソフトウェア支援による |
2114 * 2 (Max 8) | 4 Kbit S-RWM
標準1 KByte、最大4 KByteまで増設可能 |
2708 * 1 (Max 3) | 8 Kbit UV-EPROM
標準1 KByte、最大3 KByteまで増設可能 モニタプログラム書き込み済みのものが標準実装 TTY/タイピュータ用モニタ別売増設可 |
SN7438 | TTY/タイピュータインターフェース |
SN7445 | LED/KEY SWスキャン |
SN7493 | クロック分周 |
SN74LS00 | アドレスデコーダ、ステップ実行制御 |
SN74LS04 * 2 | LEDセグメントドライバ、クロック発振回路など |
SN74LS32 | アドレスデコーダ、ステップ実行制御 |
SN74LS155 | アドレスデコーダ |
TL497A | +12 V, -5 V電源 |
MC1741 | コンパクトカセットインターフェース |
トランジスタ2個 | TTYインターフェース |
ダイオード3個 | TL497Aと共に電源回路 |
7セグメントLED 6個 | アドレス・データ表示用 |
以下に調査して作成したカードエッジコネクタの端子表を掲載します。ただし、これは現物を独自に調べた結果であるため、誤っている可能性があります。特に、NC(未接続)になっている端子でランド付きの場所は、実際にはジャンパ線を用いてCPUの信号などを取り出すためにあったものかもしれません。組み立てマニュアルで、たとえば部品面15番端子にINT*信号を接続するように書かれていたとしても、以前の所有者が配線を行っていない場合、私には単なるNCであるとしかわからないためです。カードエッジコネクタへのジャンパ配線は(仮に存在したとして)、他の基板と接続する場合にだけ必要で、単体で使用するのにはまったく必要ありませんから、組み立てた時に必要を感じなかった結果、配線されなかっただけという可能性も捨てきれません。
また、番号をどのように割り振るか、現物からはコネクタ番号のシルク印刷もなかったので、本来の振り方はわかりませんでした。とりあえず、上の全体写真で一番上の端子を1番、一番下の端子を36番として、表(部品面)と裏(ハンダ面)で独立して番号を振りました。これも、マニュアルなどで公開されている情報と異なっている可能性があります。番号は暫定的なものとして考えてください。
部品面のエッジコネクタ端子表です。
番号 | 略号 | コメント |
1 | GND | -- |
2 | GND | -- |
3 | + 5 V | 電源供給 |
4 | NC | -- |
5 | M1 | TU LSTTL 1 + MOS 2 |
6 | MINH* | I LSTTL 1 + 4.7 kohm |
7 | RD* | TU LSTTL 1 + MOS 2 |
8 | MREQ* | TU LSTTL 1 + MOS 1 |
9 | CLK | O 7493 Qout + 330 ohmプルアップ |
10 | NC | ランド付き |
11 | A9 | TU MOS 12 |
12 | A11 | TU LSTTL 1 + MOS 1 |
13 | A12 | TU MOS 1 |
14 | A15 | TU LSTTL 2 + MOS 1 |
15 | NC | ランド付き |
16 | NC | ランド付き |
17 | NC | ランド付き |
18 | D1 | TU MOS 9 |
19 | D2 | TU MOS 9 |
20 | D5 | TU MOS 9 |
21 | D7 | TU MOS 9 |
22 | ハンダ面の22へ | |
23 | A1 | TU MOS 13 |
24 | A3 | TU MOS 12 |
25 | A5 | TU MOS 12 |
26 | A7 | TU MOS 12 |
27 | NC | ランド付き |
28 | TTLSI | I 7438 in, 330 // 390 ohm |
29 | PIO-B5 | IU 330 // 390 ohm 終端抵抗付き。シリアル入力の送信停止要求信号として使用か。 |
30 | NC | ランド付き |
31 | CurrO+ | O 20 mA current loop簡易シリアル出力 |
32 | CurrIN+ | I + 5 Vへ330 ohmでプルアップのみ |
33 | NC | ランド付き |
34 | NC | -- |
35 | NC | -- |
36 | GND | -- |
ハンダ面のエッジコネクタ端子表です。
番号 | 略号 | コメント |
1 | GND | -- |
2 | GND | -- |
3 | + 5 V | 電源供給 |
4 | NC | -- |
5 | IORQ* | TU LSTTL 1 + MOS 1 |
6 | PIOINH* | LSTTL 1 + 4.7 kohm |
7 | WR* | TU MOS 9 |
8 | RFSH* | TU MOS 1 |
9 | NC | -- |
10 | NC | -- |
11 | A8 | TU MOS 12 |
12 | A10 | TU LSTTL 1 + MOS 1 |
13 | A13 | TU MOS 1 |
14 | A14 | TU MOS 1 |
15 | NC | -- |
16 | NC | -- |
17 | NC | -- |
18 | D0 | TU MOS 9 |
19 | D3 | TU MOS 9 |
20 | D4 | TU MOS 9 |
21 | D6 | TU MOS 9 |
22 | 部品面の22へ | |
23 | A0 | TU MOS 13 |
24 | A2 | TU MOS 12 |
25 | A4 | TU MOS 12 |
26 | A6 | TU MOS 12 |
27 | NC | -- |
28 | TTLSO | O 7438 out 330 // 390 ohm |
29 | 7445-3O | O 7445 out 330 // 390 ohm |
30 | NC | -- |
31 | GND | CurrO-側か |
32 | CurrIN- | I 20 mA current loop簡易入力 |
33 | NC | -- |
34 | AudioOUT | O テープレコーダのREC INへ |
35 | AudioIN | I テープレコーダのスピーカ出力へ |
36 | GND | -- |
コメント欄の記号ですが、欄の最初にIと書いてあるのはCRC-80から見て入力端子であることを意味します。Oは出力、Tはトライステート入出力の意味です。UはLSIの端子がバッファリングされずに引き出されていることを意味します。端子の負荷がわかっているところにはコメントに記載してあります。標準的なLSTTLの入力端子1本に相当する負荷にはLSTTL
1と、MOS入力1回路分に相当する負荷にはMOS 1という表記が使われています。ただし、MOS負荷にはCPUの端子も含まれています。たとえばA13という信号はCPUからの出力がそのままカードエッジコネクタに引き出されているだけで、内部ではまったく使われていませんが、CPUの分の負荷として1回路分を数えています。
TTLSI, CurrIN+, CurrIN-, AudioINは、異なるバッファ処理をされたあとで、1本のシリアル入力信号となるように合成されています。TTLSO,
CurrO+, CurrO-, AudioOUTについては1本のシリアル出力信号を異なるバッファ処理をして端子に引き出してあります。相互に影響しあう可能性があるため、たとえばTTLSIを使用するときにはCurrIN-には何かを接続してはいけません。
部品面とハンダ面のそれぞれ6番には、MINH*信号とPIOINH*信号があります。これは、それぞれCRC-80上のメモリとI/Oを切り離す信号です。つまり、MINH*信号がアサートされると、CRC-80に搭載されているROMもRWMもアクセスできなくなります。ROMは最大3
KByte、RWMは最大4 KByteで、Z80 CPUのメモリ空間の64 KByteの一部しか占有しないはずですが、アドレスデコーダに使用する回路を節約しているため、ほとんどすべてのアドレス空間にROMやRWMのイメージが見えます。これでは外部にメモリを拡張する際に困ったことになるので、外部回路にメモリを増設した場合に、その増設メモリへのアクセスが確定した時点でMINH*信号をアサートします。すると、CRC-80側のメモリはデータの読み書きを行わないので、正しく外部増設メモリの読み書きが遂行されます。PIOINH*信号はI/Oポートアドレス空間に対して同じことを行います。CRC-80上に1個搭載されているPIOは4
Byte分のI/Oアドレスしか消費しませんが、CRC-80には256 Byteの全I/O空間にイメージがあらわれます。そこで、外部にI/Oを増設する場合、そのI/Oアクセスを行うアドレスが出力されたら、それを検出してPIOINH*信号をアサートします。これでI/Oの増設が初めて可能になります。共にオープンコレクタ出力のゲートで駆動すれば、バス上でワイアードORが行われて正しく動作します。2.5
MHzクロックのZ80 CPUですから、オープンコレクタ駆動の遅延や外部アドレスデコーダの遅延が多少あっても、トラブルの原因になることはないでしょう。
それ以外の、部品面ハンダ面両面の1から27番端子までは、電源かNCかZ80
CPUの端子そのものが引き出されています。バッファなどは挿入されていません。そのままのMOS入出力です。28から35番端子までは、I/O関係の信号が割り当てられています。
TTLSI信号はTTLレベルのシリアル入力信号で、TTLSO信号は同じくTTLレベルのシリアル出力信号です。PIO-B5はTTLレベルの入力信号で、シリアルの送信停止要求に使われているようですが、詳細はわかりません。PIOのBポートの第5ビットの入出力端子に抵抗負荷を付けて、直接カードエッジコネクタに引き出されています。
7445-3O信号も用途は不明で、7445の第3出力にプルアップ抵抗を付けて引き出してあります。
CurrO+, CurrO-は20 mAカレントループインターフェースの出力端子です。簡易インターフェース回路になっているため、厳密にはカレントループの規格を満足しないでしょうが、実際にはなんとか接続できるでしょう。
CurrIN+, CurrIN-も20 mAカレントループインターフェースで入力端子です。これも同じく簡易インターフェース回路になっています。
AudioOUTとAudioINはそれぞれオーディオカセットテープインターフェースの出力端子と入力端子で、すでに記述した通りです。
以上で、カードエッジコネクタの信号についての解説を終わりにします。
メモリマップを表にまとめました。
アドレス | 用途 |
0000 - 03FF | モニタROM |
0400 - 07FF | 拡張ROM1(TTYモニタ) |
0800 - 0BFF | 拡張ROM2 |
0C00 - 0FFF | 未実装 |
1000 - 7FFF | 未実装だが0000 - 0FFFのイメージあり |
8000 - 839F | 標準実装RWM(ユーザ領域) |
83A0 - 83FF | 標準実装RWM(モニタ作業領域) |
8400 - 87FF | 拡張RWM1 |
8800 - 8BFF | 拡張RWM2 |
8C00 - 8FFF | 拡張RWM3 |
9000 - FFFF | 未実装だが8000 - 8FFFのイメージあり |
I/Oアドレス空間の割り当てはこうなっています。
アドレス | 用途 |
00 - 03 | PIO |
04 - FF | 未実装だが00 - 03のイメージあり |
PIO周辺について詳細に見ていきましょう。まず、写真。
7セグメントLEDに16進数を表示したものを見たことがないってな方も増えてきたでしょうから、ABCDEFと表示したものを撮影してみました。BとDはbとdに近い小文字風の表現になっていますね。普通の数字については電卓などで使われるのと似たようなものです。
LEDの文字表示の高さは4 mm足らず、かなり小さなものを使用しています。左の縦長に配置された40ピンのLSIがZ80
CPUで、中央下寄りに横長に配置された40ピンLSIがZ80 PIOです。Z80 PIOのすぐ上にあるふたつのTTL
ICは、左からSN7445とSN74LS04です。LEDはZ80 PIOを通してソフトウェアでダイナミックスキャンで点灯させていますが、この手の回路でよく見られる、桁駆動用のトランジスタの類のバッファも、LEDへの電流制限用抵抗もいっさい見当たりません。このCRC-80では、カソードコモンのLEDを使用して、桁駆動用にSN7445の出力をそのまま使用しています。SN7445はオープンコレクタ出力のBCD
to DECIMAL Decoder/Driverで、Volが0.9 Vになってもよいのなら80 mA吸い込むことができます。したがって、LEDが小型であり、セグメントあたり10
mA程度の少ない電流でも充分な輝度が得られるなら、確かにSN7445を桁駆動に使用できます。そうなると、PNPトランジスタでバッファしたセグメント駆動回路を、普通なら使用するはずです。ところがCRC-80ではそんなものはありません。どのようにLEDのセグメントを駆動しているかというと、SN74LS04の流れ出し電流をそのまま使用しています。つまりSN74LS04の出力をそのままLEDの各セグメント端子に接続しているのです。SN74LS04は、このような使い方を本来は想定されていません。Vohを保証できるのは0.4
mA以下の流れ出しと規格上は規定されています。しかし、そんなことを無視して、SN7445のVolとLEDのVFを加算した電圧までVohが低下したときにSN74LS04の内部回路で制限される流れ出し電流をそのままLEDの駆動に使用しています。セグメントあたり約15
mAくらいでしょうか。部品数削減とコストダウンのために、ずいぶんと思いきった回路にしています。なお、SN74LS04は6個のインバータが入っていて、7セグメントLED(と小数点)の駆動に必要な8回路には2個足りません。その分はキーボード左側のクロック発振回路に使用しているもうひとつのSN74LS04に割り当てています。
SN7445はBCD表示の信号4本を入力して、10本の出力端子のうち、その入力された数値に対応する信号だけをLにするICです。で、10本の出力端子のうちの6本をLEDの桁駆動に使用しています。残りの4本の出力端子のうちの3本を、キーボードマトリクスの駆動に使用しています。最後に残った1本は、カードエッジコネクタに引き出されて、タイピュータインターフェースの一部として使われているらしいのですが、詳細は不明です。
具体的にZ80 PIOのI/Oポートの使用状況をまとめてみました。
Z80 PIOはA, B両ポートともビット制御モードで使われています。そのため、ストローブ信号などは使用されず、16本の入出力ピンだけが利用可能です。
まずはポートBの使われかたですが、下位4 bitはSN7445のデコーダに接続されてLEDとキースキャンの制御に、上位4
bitはビット単位でシリアル入出力関係の信号に使われています。
信号 | 用途 |
PIO-B7 | シリアル入力(TTY、タイピュータ、オーディオカセット兼用) |
PIO-B6 | シリアル出力(TTY、タイピュータ、オーディオカセット兼用) |
PIO-B5 | タイピュータ制御? |
PIO-B4 | LEDモニタ/TTYモニタ切り替え(DIPSW 2) |
PIO-B3 | SN7445-D |
PIO-B2 | SN7445-C |
PIO-B1 | SN7445-B |
PIO-B0 | SN7445-A |
シリアル入力は単なる1 bit入力端子として扱われて、ソフトウェアによってシリアル・パラレル変換を行っています。シリアル出力も1 bitの出力端子を同じように扱っています。ポートBの第4ビットはモニタの切り替え入力として使用しています。このビットはリセット時だけでなく、シングルステップ処理時などに参照していますから、電源投入後にスイッチを切り替えると暴走の原因になるかもしれません。
SN7445の出力の用途はこのようになっています。
信号 | 用途 |
SN7445-9 | LED1(一番左側) |
SN7445-8 | LED2 |
SN7445-7 | LED3 |
SN7445-6 | LED4 |
SN7445-5 | LED5 |
SN7445-4 | LED6(一番右側) |
SN7445-3 | ??? タイピュータ関係? |
SN7445-2 | K2 (8 - F key) |
SN7445-1 | K1 (0 - 7 key) |
SN7445-0 | K0 (command key) |
ポートAはSN7445が何を出力しているかによって、用途が変わることに注意しなくてはなりません。多目的の信号です。
SN7445出力 | LED1 - LED6 | K0 | K1 | K2 |
PIO-A7 | dp | STP | 7 | F |
PIO-A6 | g | ST | 6 | E |
PIO-A5 | f | LD | 5 | D |
PIO-A4 | e | DEC | 4 | C |
PIO-A3 | d | INC | 3 | B |
PIO-A2 | c | AD | 2 | A |
PIO-A1 | b | DA | 1 | 9 |
PIO-A0 | a | GO | 0 | 8 |
SN7445がLED1からLED6までの桁駆動信号を出力する場合、ポートAはセグメント駆動出力信号として使われます。表には、7セグメントのどのセグメントを駆動するか書きました。0を出力したセグメントが点灯し、1を出力したセグメントは消灯します。たとえば、0C0Hを出力すれば、セグメントaからfまでの6セグメントが点灯し、結果として0表示が行われます。ついでですから、16進数表示に使われるビットパターンを掲載しましょうか。こうなります。
数値 | 出力 | 数値 | 出力 | 数値 | 出力 | 数値 | 出力 |
0 | 0C0H | 4 | 099H | 8 | 080H | C | 0C6H |
1 | 0F9H | 5 | 092H | 9 | 090H | D | 0A1H |
2 | 0A4H | 6 | 082H | A | 088H | E | 086H |
3 | 0B0H | 7 | 0F8H | B | 083H | F | 08EH |
もちろん、LEDはダイナミックスキャン方式の回路で駆動されていますから、たとえばSN7445の出力がLED1で、ポートAに0C0Hを出力しただけなら、左端のLEDが明るく0の形に光って、他のLEDは消えたままになってしまいます。すべてのLEDになんらかの表示を行いたければ、短時間LED1を光らせた後、次にLED2を光らせて、という具合に、高速で順番に各LEDを駆動しなくてはなりません。点灯する時間がばらつくと、明るさにムラができたり、ちらつきが目立ったりしますから、手間と注意が必要です。モニタプログラムでは4
ms単位で点灯するLEDを切り替えています。
SN7445がK0, K1, K2を出力している場合はポートAが入力として使われます。そのとき、キーが押されていない信号は1が、押されている信号は0が読み込まれます。ただし、キーの複数同時押しはサポートされていません。同時に押すことのできるキーはただひとつだけです。LEDを駆動している最中に複数のキーを押すと、ポートAの信号出力間でショートが起きる可能性があり、Z80
PIO外部にその保護回路などはありません。これもコストダウンのための簡略化でしょうか。とにかく、0が読み込まれたところが押されているキーです。たとえば、K0を出力している状態で0FEHが読み込まれたらGOキーが、0BFHが読み込まれたらSTキーが、押されています。同じ条件で0FFHが読み込まれたのなら何もキーが押されていません。
このキー入力用の回路には、チャタリング防止回路とかの類は一切用意されていませんから、すべてソフトウェアで処理することになります。よくあるパターンとしては、10
ms間隔くらいでキーの状態を読み取り、何も押されていなかった状態から何か押された状態へ変化したら、それをキー入力として処理するというものです。前回、なにかキーが押されていたら、そのキーが離されるまでは新たなキー入力が検出されなかったと判定しなくてはなりません。モニタプログラムでは約4
ms間隔でキースキャンサブルーチンを呼び出しています。
アドレスデコーダとシングルステップ制御には3個のTTL ICを使用しています。下に写真を掲載します。全体写真では基板の左上の縦長の部分ですが、掲載スペースの都合で時計周りに90度寝かせた形にしました。
使用されているICは左から順にSN74LS155, SN74LS00, SN74LS32です。
アドレスデコーダの回路を論理式のようなもので表示してみます。まずROM全体を選択する信号ROMSELとRWM全体を選択する信号RWMSELは、このように書けます。
ROMSEL := (MINH* = H) & (MREQ* = L) & (A15 = L)そうして、次のような条件で、ROM0, ROM1, ROM2, RWM0, RWM1, RWM2, RWM3が選択されます。
RWMSEL := (MINH* = H) & (MREQ* = L) & (A15 = H)
選択信号 | ROMSEL = TRUE | RWMSEL = TRUE |
(A10 = L) & (A11 = L) | ROM0 | RWM0 |
(A10 = H) & (A11 = L) | ROM1 | RWM1 |
(A10 = L) & (A11 = H) | ROM2 | RWM2 |
(A10 = H) & (A11 = H) | 無選択 | RWM3 |
NMI := (DIPSW1 = OFF) & (M1* = L) & (RD* = L) & (ROMCS0* = H)ここでROMCS0というのはROM0のチップ選択信号で、すぐ上の表のROM0の選択信号です。つまり、この式を解釈すると、DIPSW1がOFFの位置にあって、モニタROM以外から命令をフェッチするとNMI*が有効になるということです。モニタROMの中に納められた命令を実行する限りは割り込みが起きません。
次にクロック生成回路について。これが写真です。全体写真ではキーマトリックスのすぐ左にあります。
上のTTL ICがSN74LS04で下がSN7493です。ふたつのTTL ICの間に10.000と印刷された水晶振動子が見えますね。
CRC-80ではシステムクロックとして2.5 MHzを用いていますが、水晶振動子で発振させている周波数は4倍の10
MHzです。これは、水晶自体のサイズが2.5 MHzでは大きめで10 MHzよりもコスト高になりがちなのと、50
%デューティのクロック信号を保証するために高い周波数の信号を1/2とか1/4に分周して使用する必要があるための、ふたつの要因の兼ね合いでしょう。
発振回路は、最近のCMOSインバータを利用した、1個のインバータに抵抗で負帰還をかけてアナログ反転増幅器として動作させ、無調整水晶発振回路と同じ構成にしたものではありません。2個のインバータをアナログ動作するようにそれぞれ抵抗で負帰還をかけたものをリング状に結合する際、一方の結合点にはコンデンサを挿入し、もう一方には水晶振動子を挿入した回路になっています。TTL
IC全盛期にはよく見られた発振回路です。1段バッファとしてインバータを挿入した後、SN7493で分周されています。
SN7493には1/2分周回路と1/8分周回路が1組ずつ内蔵されていますが、CRC-80ではそのふたつの分周回路を直列に接続し、1/16分周回路となるようにして使用しています。そのため、10
MHz, 5 MHz, 2.5 MHz, 1.25 MHz, 0.625 MHzの周波数の信号を同時に利用できます。ただし、SN7493の2.5
MHz出力を330 ohmでプルアップしたもので直接Z80 CPUやZ80 PIOのクロック端子を駆動しています。バッファ類は入っていません。しかも同じ信号がカードエッジコネクタにまで引き出されています。SN7493は内部分周フリップフロップの出力がそのまま出力端子になっているため、負荷が重いと(特に容量性負荷)分周動作が不安定になります。したがって、この回路だとカードエッジコネクタの先に接続された拡張基板で重い負荷がかけられると、システムクロックが不安定になる可能性があるため、扱いに注意しなくてはなりません。なお330
ohmのプルアップがなされているのは、Z80 CPUの要求するクロック信号のHレベル確保と立ち上がり時間改善のためです、
最後に電源部について簡単に触れます。全体写真ではクロック生成回路のさらに左、オプションのROMの下あたりにあります。
中央にあるのがTL497Aです。ひところ、2716とか2764などのROMにデータを書き込むROM
Writerなんかの製作記事でもよく使われていました。え、私?uA78S40を使う方が多かったかな。
TL497Aは昇圧チョッパとして使われています。写真右上のトロイダルコイルにエネルギーを溜め込み、+5
Vから+12 Vへの電圧変換を行っています。-5 Vも生成していますが、これはチョッピングされている信号波形をコンデンサ結合で交流分だけ取り出し、それを倍電圧整流した後で100
ohmの抵抗と5 Vのゼナーダイオードで-5 Vに安定化しています。
+12 Vと-5 Vが必要なのはROMの2708(とオーディオカセットインターフェースに使われているオペアンプ)だけですが、+12
Vも- 5 Vも結構な電流を消費するため、本格的なチョッパレギュレータを使用しています。おそらくROMに5
V単一電源の2716を採用できれば、こんな回路は付加しなかったでしょうが、開発当時は2716が極めて高価だったために2708にするしかなかったのでしょう。
アドレス | サイズ | コメント |
83A0 | ?? | ユーザプログラム用のスタックポインタ初期値 |
-- | ?? | モニタプログラムスタック領域 |
83C8 | ?? | モニタプログラム用スタックポインタ初期値 |
-- | ?? | -- |
83CD | 2 | シリアル送信用ループカウンタ |
83CF | 2 | 同上? |
83D1 | 2* | AF save area |
83D3 | 2* | BC save area |
83D5 | 2* | DE save area |
83D7 | 2* | HL save area |
83D9 | 2* | AF' save area |
83DB | 2* | BC' save area |
83DD | 2* | DE' save area |
83DF | 2* | HL' save area |
83E1 | 2* | IX save area |
83E3 | 2* | IY save area |
83E5 | 3* | RST 38H vector |
83E8 | 2* | ST start address |
83EA | 2* | ST Byte count |
83EC | 2* | Break point address (Init: 0000H) |
83EE | 1* | Break point counter |
83EF | 2 | -- |
83F1 | 2 | レジスタ保存領域のアドレス(Init: 83D1H) |
83F3 | 1 | LED表示用桁カウンタ(Init: 9) 9, 8, 7, ..., 4と変化 |
83F4 | 2 | -- |
83F6 | 1 | 直前のキー状態(Init: 0) |
83F7 | 2 | GOコマンド内部作業領域 |
83F9 | 1 | Address/Data入力モード(Data: 0, Address: 1) |
83FA | 1+ | Data LED表示データ |
83FB | 2+ | Address LED表示データ |
83FD | 1 | Single stepモード(Off: 0, On: others) (Init: 00H) |
83FE | 2* | SP save area (Init: 83A0H) |
ユーザが読み出したり書き換えたりする意味のある場所には、サイズの項目に*マークを入れておきました。同じ場所に+マークがついているのは、ユーザプログラムからモニタROM内サブルーチンを利用する際に書き換える意味のありそうな場所です。詳細は後述します。
83D1Hから83E4Hおよび83FEHからの2 Byteが、ユーザプログラムを実行する際にレジスタにロードされる値の格納領域です。また、シングルステップ動作やブレークポイント動作でユーザプログラムが中断された場合、ユーザプログラムの使用していたレジスタの値が保存されている場所でもあります。したがって、シングルステップ動作させながらレジスタの内容を確認する場合、STPキーを押した後で毎回これらのレジスタ保存領域の内容を調べる操作を行うことになります。
Z80 CPUには、RST命令というのがあって、1 Byteの機械語命令で特定アドレスのサブルーチンを呼び出せるようになっています。しかし、そのサブルーチンのアドレスは0000Hから0038Hの間の8
Byteおきの固定アドレスで、しかもリセット時に0000HからCPUが命令を読み込んで実行する都合上、一般にはROM領域になってしまいます。そのため、RST命令で呼び出されるROM内のアドレスにはJMP
XXXXという命令を書き込んでおいて、RWM上の適当なアドレスに制御を移すようにして、ユーザがRST命令を利用しやすくするのが普通です。さて、CRC-80では、RST
0はリセットと同じというのはしかたがないとして、RST 8HからRST 30Hまでは、とくに何もせずRET命令が実行されて、ただちにリターンしてしまいます。唯一RST
38H命令だけは、JMP 83E5Hが実行されて、83E5Hに制御が移ります。したがって、RST
38Hをユーザが利用するには、83E5Hから始まる3 Byteの中に、実行したいサブルーチンへのジャンプ命令を書き込むようにします。モード1割り込みを使用する場合には、割り込み時に自動的にRST
38H命令が実行されますので、やはり83E5Hに割り込みハンドラへのジャンプ命令を書き込むことになります。
83E8Hからの4 Byteはオーディオカセットテープへメモリの内容を書き込むSTコマンドで使用されます。これはモニタコマンドの項で書きましたので、省略します。
さらに83ECHからの3 Byteもブレークポイント実行のために使われる領域で、同じ理由で省略します。
次にモニタROM内で利用可能なサブルーチン類について説明します。
アドレス | 動作 | 使用レジスタ |
0081 | LEDダイナミックスキャン | AF, B, HL |
00C2 | 4 msウエイトループ | AF, HL |
0136 | キースキャン | AF, B |
01D7 | LEDセグメントテーブル | |
01E7 | テープストア | AF, BC, DE, HL |
021B | テープ1 Byteストア | AF, BC |
0256 | テープロード | AF, BC, DE, HL, BC', DE' |
027B | テープ1 Byteロード | AF, BC, BC', DE' |
02E7 | シリアル通信送信 | すべて保存 |
031E | シリアル通信受信 | AF |
だいたいこんなものでしょうか。入出力条件などは表に書かずに、この後で細かく解説します。TTYモニタから呼び出して使用するシリアル通信用サブルーチン以外は、モニタプログラムで必要最小限のルーチン仕様になっていて、ユーザから呼び出されることをあまり考えていないようです。LEDに任意のパターンを表示させるルーチンはありませんし、キースキャンルーチンも解釈が簡単なキーコードまで変換して値を返すことはなく、PIOのポートから読み込んだだけのビットパターンを返しています。
アドレス0081HからのLED表示用サブルーチンは、レジスタ渡しのパラメータはありません。入力パラメータは、メモリの83FAHからの3
Byteの固定領域に置きます。このサブルーチンを呼び出すと、この3 Byteのうちの4
bit分をLEDの1桁に16進数表示パターンに変換して、表示し、4 ms待って戻ります。1回の呼び出しで1桁分だけの表示が行われ、6桁すべてを表示するには6回呼び出さなくてはならないし、それで約24
ms分の一瞬の表示になるだけです。ですから、普通に表示を続けるには、1桁分表示するためにこのサブルーチンを呼び出した後、ごく短い作業を行って、再びこのサブルーチンを呼び出すということを、常にくり返さなくてはなりません。この表示ルーチンの間に挿入するルーチンの実行時間がばらついていると、各桁の明るさがばらついたり、ちらついた表示になる原因となります。また、このルーチンでは16進数表示以外のパターンを表示することはできません。任意のパターンを表示するためには、独自のルーチンを開発しなくてはなりません。なお、このルーチンで使用する4
bit数値を16進数表示用パターンに変換するテーブルが01D7Hから始まる16 Byteにあります。
00C2Hから始まるルーチンはLED表示用のコードの一部で、4 msの時間待ちループとして使えます。入力パラメータはなく、このアドレスを呼び出せば、4
msだけ時間をつぶしてくれます。
0136Hからはキースキャンルーチンが配置されています。正確には、キースキャンの一部を構成するルーチンというべきで、かなり不完全なものです。キーの状態を調べて、それをレジスタに反映させてただちに戻ってきます。このルーチンから戻ってきたとき、Zフラグがセットされているとキーは何も押されていません。Zフラグがクリアされていればキーが何か押されています。その場合、BレジスタにK0,
K1, K2を表すコード(それぞれ0, 1, 2)が入り、Aレジスタには押されているキーが1になっているZ80
PIO Port Aのビットパターンが入ります。具体的にはハードウェアの項のPort
Aの使い方の表を参照してください。たとえば、'4'のキーだけが押されていると、Zフラグがクリアで、Aに10H、Bに01Hが入って戻ります。さて、この戻り値はキーの状態を表していて、遷移を表していません。'4'のキーが押し続けられている時に、くり返しこのルーチンを呼び出すと、毎回同じビットパターンを返します。ですから、前回、このルーチンを呼び出したときに押されていたキーを記録しておいて、別のキーが押されたときにのみ、新たなキー入力があったとして処理しなくてはなりません。24個のキーですから、5
bitのキーコードで符号化できるはずですが、そのようなコードへ変換するルーチンもありません。実際にはモニタプログラムでコマンドキーなどの解釈ルーチンの中でそれを行っていますが、独立したサブルーチンになっていないで、長いコードの一部に埋め込まれているため、ユーザから利用できなくなっています。あと、チャタリング対策もしていないため、4
msから10 ms間隔でこのルーチンを呼び出してキーチェックを行うようにします。数msでチャタリングが納まるので、このようにしてキーの状態遷移を検出するようにすれば、チャタリングを無視できます。
これから先はシリアル入出力関係です。01E7Hからのルーチンと0256Hからのルーチンは、それぞれモニタプログラムの動作時にSTキーやLDキーを押したときに呼ばれるルーチンそのものです。レジスタ渡しのパラメータはなく、83E8H,
83EAHで指定された領域をテープに記録したり、テープに記録されたデータをロードします。プログラム中でデータをテープに記録することもあるのではないかと、表に載せました。ただし0256Hのテープロードルーチンは、ロードするアドレスがテープに記録されているものを使うため、誤って別のテープを再生して読み込ませると、プログラムの一部を上書きしてしまう危険もあります。
そのため、独自のテープ入出力ルーチンを作成する場合、021BHと027BHの1
Byte入出力ルーチンが役に立ちます。
021BHの1 Byteテープ出力ルーチンでは、Cレジスタに出力すべきデータ、Bレジスタにそれまでのチェックサムを渡すことになっています。出力ルーチンの内部で、チェックサムの更新も行われます。DE,
HLレジスタペアは使われていないので、ストアすべきデータを指すポインタとして、これらレジスタを利用できます。なお録音する信号のタイミングもすべてソフトウェアで作成しているため、この出力ルーチンを呼び出す側ではポインタの指すメモリからデータを読み出してポインタをインクリメントする程度以上のことをすべきではありません。仮に数ms必要な演算などを行ってしまうと、バイト単位のデータの間に変な無音期間というか音の高さの変わった部分ができてしまって、うまく読み込めないかもしれません。チェックサムを利用する場合には、最初に出力ルーチンを呼び出す前にBレジスタを0クリアして初期設定しておきます。そうして、最後にBレジスタの内容の符号反転したものをCレジスタに入れて、テープ出力ルーチンを呼び出し、チェックサムを記録するとよいでしょう。このほか、一連のデータを出力する前に1の連続データをヘッダとして記録するべきですが、それはモニタプログラムの01E7Hから01F2Hまでのコードを参考にするのがよいでしょう。
027BHからは1 Byteのテープ入力ルーチンがあります。Bレジスタにそれまでのチェックサムを入れて、このルーチンを呼び出すと、Cレジスタに入力データ、Bレジスタに更新されたチェックサムを入れて、戻ります。なお、チェックサムが0になっているとZフラグがセットされていますから、最後にチェックサムを記録したデータの場合には、それを読み出した直後にZフラグをテストしてチェックサムエラーを検出できます。チェックサムを利用する場合、最初に入力ルーチンを呼び出す前にBレジスタを0クリアしておきます。出力ルーチンと同じく、この入力ルーチンを続けて呼び出す側は、呼び出す間に時間のかかる作業を入れるとタイミングが狂って正しく読み込めませんから注意が必要です。さらにヘッダを読み飛ばすには、027BHからの入力ルーチンの代わりに、02AAHのヘッダ読み飛ばし機能付き入力ルーチンを最初に1回だけ利用します。入出力条件は同一です。
02E7Hと031EHからのシリアル入出力ルーチンは、タイピュータやTTYとの入出力を行うためのルーチンです。ビットレートの設定方法など、ちょっとまだ解読しきれていないとこがありますので、詳細は説明しません。気合いのある人は02E7Hから03A7Hまでを丹念に読むとよいでしょう。
以上でモニタプログラム内ルーチンの解説を終わりにします。あまり流用できるルーチンはありませんが、LEDのダイナミックスキャンルーチンやキースキャンルーチンは、一度逆アセンブルして解読すると、応用プログラムを作成しやすくなるでしょう。
Return to IC Collection