ROMライタ / W-ROM 製作
秋月電子 Z80 Cコンパイラ
Z80は、1976年に発表されたイニシエのマイコンであることは確かだが、インテルからザイログに移籍した嶋正利氏がFederico Faggin氏と共に開発したCPUの中の金字塔ともいえる名品。
世界初のマイクロチップCPU i4004,i8080に続いて彼が生み出したZ80は、雨後の竹の子のように出ては消えていくあまたのプロセッサの中で、依然として世界中で現役を務めている唯一のプロセッサであることは否定できない。
Z80は、現在のPICやAVRなどのワンチップのマイクロコントローラーがRAMやプログラムメモリーだけでなく、タイマーやシリアル通信モジュールなど、ほとんどの機能を内蔵しているのに対し、これらの機能は必用に応じ、下記のようなモジュールを組み合わせて構成する。Z84C015のように、CPU,PIO,SIO,CTCなど、複数の重要なモジュールが組み込まれたチップも製造されている。
《Z80ファミリーおよび関連デバイス》
Z80CPU :中央演算処理モジュール
Z80SIO :シリアル通信モジュール
Z80CTC :カウンタータイマー・モジュール
Z80PIO :周辺入出力インターフェース・モジュール
Z80DMA :ダイレクトメモリーアクセス・モジュール
8255(PPI) :周辺入出力インターフェース・モジュール
PROM :128/256kビット ROM
RAM :128/256kビット RAM
確かにこれらのモジュールを使いこなすのは容易ではないが、例えば、多数のセンサーとステッピングモーター群を有するようなシステムを高速制御する場合、ワンチップ・マイクロコントローラーでは明らかに役不足になる場合でも、Z80の高度な割込み処理を利用することで対応可能となる可能性がある。
これらのZ80ファミリーは上位互換品を含め、HD64180、μPD9001,R800,TMPZ84C** 等々、数多くのセカンドソースが世界各国で作られ、使用されてきている。多くの高性能なCPUが消えてゆく中、もしかして、Z80はこの先もずっと残ってゆくのではないか? この名品をほっておく手はない。
Z80 Cコンパイラ
ザイログのZ80ニーモニックはインテルのニーモニックに比べ馴染み易かったこともあり、プログラムはアセンブラで記述されることも多いのですが、アセンブラでの開発は負担が大きいため、フリーCコンパイラのSDCCが使われることも多いようです。ここでは秋月のZ80
Cコンパイラ、それも「AKI-80用モニターROM&Cコンパイラセット」に付属しているCコンパイラを使ってみることにします。価格は一式で1000円。今回使うのは主役のモニターROMではなく、おまけの方のCコンパイラのCDであるが、ROM(27C256)も無論、書き換えればZ80で使うことができます。
なお、その説明書に書いてあるように、このCコンパイラは某社が開発したものであるが、秋月としてはおまけで付けているだけなので、その某社への質問等はできない。このセットについてくるガイダンスは、幾らひいき目に見ても褒められたものではなく、これでは、サイトに情報が上がってこないのもうなづける。ただしこのCコンパイラ、エディタを含む統合開発環境が使える。コンパイラやリンカのコマンドオプションに翻弄されることも、makeに惑わされなくて済むのも大きい。
しかし、C言語にすればZ80システムが簡単に使いこなせる訳ではない。Z80CTCでさえ厄介な上に、Z80SIOを前に心が折れてしまった話も耳にする。当然ながら、このページも、非力な管理人が幾日かを費やしての手探りの結果ではあるが、デバイスとコンパイラ、共に十分な資料も入手できないままのやっつけ仕事ゆえ、万全でないことは平にご容赦頂きたい。
【秋月電子/マイコン関連/各種マイコン/Z80 】 より 2023/4
Z80関連の入手
2023年の春現在、秋月電子からは、AKI-80ゴールドボード(基板単体、保守部品)、AKI-80ゴールドボード、スーパーAKI-80(基板単体、保守部品)、が販売されています。AKI-80ゴールドボードは保守品扱いにはなっていない。つまりこの先も入手可能らしい。
AKI-80ゴールドボードは、 Z84C015 (Z80CPU,PIO,SIO,CTC内蔵)とRAM(256k)、ROMソケット、Xtal(12.288MHz)がマウントされています。
スーパーAKI-80はZ84C015の他に PPI×2 、RAM(256k)、ROMソケット、Xtal(9.8304MHz)、MAX232がマウントされています。
Z80の本家ザイログからも Z84C015 という型番で東芝TMPZ84C015の互換品をネット販売しているようです。またアマゾンからは KL5C80B12CFP 始め、Z80CPU、Z80PIO、Z80CTC や、EPROMの27C128、27C256も入手することができます。
問題はEPROMにプログラムを書き込むROMライターですが、AmazonからTL866系 ライタが8千円前後で販売されているようです(2023/4月現在)。EPROMイレーザーも同じく2~3千円で販売されているようです。
私はZ80を使った年代物手作りのROMライターと、これも手作りの、デバッグ中のEPROM書き換えの手間を省くためにRAMを使ったROMエミュレーターを使っています(このページトップの「ROMライタ/W-ROM製作」参照)
それから、今時 RS232Cポート付のPCなど持っている人はいないので、シリアル-USBコンバーターが必要。USB RS232C コンバーターはAmazonでも手に入ります。XPなど32ビット対応を確認してください。
ともあれ、まずは秋月のZ80 Cコンパイラをいじってみようではないか! GAIOのCコンパイラと言わないのは敢えてジコ責任で使うから”秋月のCコンパイラ”なのである。
環境は Windows 98,2000,XP ただし私は Windows10 のVMware work station 14 player(無償版)
の上で走る仮想XP を使っています。仮想マシンに関してはtoolsを参照してください。
インストール
「AKI-80用モニターROM&Cコンパイラセット」のCDのSETUPを実行すると、C:\akiz80 フォルダにインストールされます。 スタート→プログラム にGAIO の中の「秋月Z80」の「Z80統合開発環境」が実行されるフレームワーク。表示された「Z80統合開発環境」を右クリックで押さえてドラッグして離して「ここにコピー」でアイコンを作っておくと便利です。
アンインストールはインストールしたフォルダごと直接削除できます。
下は「Z80統合開発環境」のアイコン。使うのはメモ帳とRS232Cのドライバーソフト。ドライバーは予めWindowsに入っているか、USB-RS232Cコンバーターを購入すると付いてきます。あるいは、このHPに掲載している
ComOutを使うこともできます。
新しいプロジェクトを作る
予めエクスプローラでc:\akiz80\sanpleの下、または適当なフォルダに新規プロジェクト用の作業フォルダを作っておきます。そしてそのフォルダの中にメモ帳でソースファイルの元を作っておきます。中身は下のような空っぽでかまいません。
●アセンブラによるスタートプログラムのソースファイル
ファイル名の例 " tsst.xas "
最初の中身はend文だけでokです。
END
●c言語によるソースファイル
ファイル名の例 " ts.c"
最初の中身は
main()
{
}
●「Z80統合開発環境」をスタートします。
ファイル→プロジェクトの新規作成 で アプリケーションを選び、作業フォルダの参照をクリックして作っておいたフォルダを選択しOK。
開発環境の詳細設定の画面では、リンクはリンケージマップを出力、HEXファイルは8ビットHEXフォーマットにチェックを入れOKします。
●ソースファイルの登録
ファイルリストの「ソースファイル」を右クリックして「プロジェクトへファイルを登録」を指定します。
ファイル登録画面では、ファイルの種類に、アセンブラソースな場合は「アセンブラソースファイル(*.xas) 」
Cファイルを登録する時は「cソースファイル (*.c) 」を指定してそれぞれ組み込みます。
例は、TS.c とTSST.xas が組み込まれた状態です。
●オプションパラメーターの指定
次にcプログラムとアセンブラプログラムをリンクするためのパラメーターを指定します。
「オプションファイル」欄のリスト(下図参照)をクリックし
表示されている短い中身を削除したら下のテキストをメモ帳でコピーして貼り付けます。
;-------------------------------+
; LINK 設定
;-------------------------------+
;-------------------------------+
; RAM Area |
;-------------------------------+
/ADDR=8000 ;RAMのトップアドレス
/SECT=D_*|COMM (data =_DATA)
/SECT=B_*|COMM (bss =_BSS)
/SECT=_STACK
;-------------------------------+
; ROM Area |
;-------------------------------+
/ADDR=100H ;C記述プログラムROMエリア
/SECT=C_*|CODE
/SECT=I_*
;-------------------------------+
; init data section +
;-------------------------------+
/init_section = _INIT_DATA (_DATA)
;-------------------------------+
; リンクするファイル
;-------------------------------+
/Name=TS
/entn = TSST.xao ;先頭モジュール
/modl = TSST.xao ;リンクするxasモジュール
/modl = TS.xao ;リンクするcモジュール
/SYSLIB=C:\akiz80\LIB\Z80\CS\CSZE1.XLB ;ライブラリ
なお、このオプションパラメータで配置されるメモリのセクションは
RAMエリア
D 初期化変数
B 未初期化変数
ROMエリア
C プログラムコード
I 初期化されたデータ
となります。
また、メモリーマップを確認するには、ビルド→設定 のリンクタブの一般の「リンケージマップを出力する」にチェックを入れ「セクションの割付情報をアドレス順にソート」にして、ビルドしたあと一旦統合開発環境を終了後、再立ち上げすると「その他」のファイルのmapに生成されます。
ところで、このサイトの画面をメモ帳などでコピーして、作成するZ80の開発環境へコピー&ペーストすると、行番号や余分な文字記号が混入する場合がありますから、それらは削除してください。基本的には、修正するのは一番下の部分、「リンクするファイル」の欄に表示されている先頭モジュールとリンクする
xas モジュールと c モジュール名を、作成するプロジェクトのファイル名に書き換えるだけで済むはずです。
なお、上のリンク条件文はインストールされたサンプルのままですが、super AKI-80の場合、RAMの領域は8000H~、プログラムのROMエリアは100H~の領域を指定しています。
●最低限の用意ができたら、ビルド→ビルド してみます。
下に、
Create HEX...
Success...
と表示されたらokです。エラーが表示されたら、エラー文の先頭あたりをクリックすると、対応するソース文の付近が表示されますから修正します。
●後の作業はひたすらプログラムの完成まで、少し進めてはビルドしてエラーをチェックすることです。この後に掲載するアセンブラソースとCソースの原型をコピーして使っても構いません
重要な注意事項ですが、この秋月Cコンパイラが生成する出力はobjフォルダに生成されるのですが、HEXファイルを指定しても出来上がるのは何故か xho となっています。しかし内容的にはインテルHEXになっているので、そのままROMライタに送ることができますが.HEXしか受け付けないライタの場合はリネームしてください。
●EPROMへの書き込みは、USBコンバーターを接続して、Windowsのスタートマークを右クリック→デバイスマネージャー→ポート(COMとLPT)に表示されるUSB Serial Port(COM?)のCOMポート番号を確認します。
このCOMに対して完成したHEXデータを、8ビット、パリティ無し、2stop(または1stop)、 9600bps で送信します。
8255 (PPI) (プログラマブル周辺インターフェース)
PPIはインテルで開発されたデバイスで、Z80との相性も良く、ひとつのPPIに3×8本のポートが入っているため広く使われてきましたが製造中止の方向にあるようです。
super AKI-80には2個のPPIが搭載され、次のI/Oアドレスが割付けられています。
PPI0A: 0x30 Aデータポート
PPI0B: 0x31 Bデータポート
PPI0C: 0x32 Cデータポート
PPI0W: 0x33 コントロールポート
PPI1A: 0x34 Aデータポート
PPI1B: 0x35 Bデータポート
PPI1C: 0x36 Cデータポート
PPI1W: 0x37 コントロールポート
設定はコントロールポートに、動作を決める以下のコントロールワードを書き込みます
PPIはPIOと違い、個々のビットに対して入出力を設定することはできません。
ビット7: 1
ビット6: 0
ビット5: 0
ビット4: Aポート設定 1で入力、0で出力
ビット3: Cポート上位4ビット設定 1で入力、0で出力
ビット2: 0
ビット1: Bポート設定 1で入力、0で出力
ビット0: Cポート下位4ビット設定 1で入力、0で出力
入出力はデータポートに対して実行します。
Z80SIO (シリアル通信入出力デバイス)
ザイログの資料をここに見つけましたので根気のある方は読んでみてください。
Z80SIOは、RS-232CやRS-422のようなシリアル信号の送受信を実行します。
AKI-80のTMPZ84C015のSIOには次のI/Oアドレスが割付けられています。
SIOAD: 0x18 チャンネルAデータポート
SIOAC: 0x19 チャンネルAコントロールポート
SIOBD: 0x1a チャンネルBデータポート
SIOBC: 0x1b チャンネルBコントロールポート
SIOの制御は、SIO内の複数の書き込み用WRレジスタに必用な設定データを書き込むことで行います。どのレジスタに書き込むかは、レジスタWR0で指定します。
RRレジスタという読み出し用レジスタもあって、送信完了などはRRレジスタをinp()することで看視することができます。
WR0
SIOのWR0は、このWR0の次に送られるデータをどのWRレジスタに書き込むかを決めるレジスタです。D2~D0でSIOの書き込みWRレジスタを指定します。例えば、SIOに対して1を書くと、次のデータはWR1に書きこむデータになります。
ただし、D2~D0を 000 にするとこの1バイトだけで実行する命令になります。例えばチャンネルリセット 00011000 (0x18) がこれです。
WR1
割り込みの設定をします。
受信割り込みだけをする場合は 0x10
送受信とも割込みする場合は下記(参考1)
ChBの Status Affects Vector のビットが1の場合、割り込みアクノリッジから返されるベクタは、以下の割り込み条件に従って変化します。
WR2
割り込みベクトルを書き込みます(チャンネルBだけです)
WR3
受信の設定です。8ビット,受信可にする場合は 0xc1 です。
WR4
受信の クロック分周速度、ストップビット数、パリティ有無 の指定です。
WR5
送信設定 DTR on,8ビット、送信可,RTS on なら 0xea です。
WR6,WR7 はSLDC用なので使いません。
RR0~RR2は読み出すためのレジスタで、 inp(SIOのアドレス)で読み出すことができます。
RR0
読み出しレジスタRR0は、ビット2で送信バッファの空、ビット0で受信データ有効を判断できます。
RR1
ビット6~4で通信エラー、ビット0は送信完了です。
RR2
ベクトルレジスタの読み出しです。チャンネルB だけです。
(参考1) SIO CH-Aを送受信とも割込みにする場合の制御語の例
(注:WR4はシステムクロック周波数およびCTC3の設定条件によって変わります。)
;CH-A
DB SIAC,00011000B ;CH-A リセット
DB SIAC,4 ;次は受信設定
DB SIAC,01000100B ; *16 STP=1 PARITY NONE 9600PBS
DB SIAC,1 ;次は割込み設定
DB SIAC,00010110B ; 受信割込有、送信割込有
DB SIAC,3 ;次は受信設定
DB SIAC,11100001B ; 8BIT
DB SIAC,5 ;次は送信設定
DB SIAC,11101010B ; 8BIT
;CH-B
DB SIBC,00011000B ;CH-B リセット
DB SIBC,2 ;次は割込ベクトル
DB SIBC,20H ; ベクトル値
DB SIBC,4 ;次は受信設定
DB SIBC,01000100B ; *16 STP=1 PARTY NONE 9600BPS
DB SIBC,1 ;次は割込み設定
DB SIBC,00000100B ; 割込みベクトル有効
DB SIBC,3 ;次は受信設定
DB SIBC,11100001B ; 8BIT
DB SIBC,5 ;次は送信設定
DB SIBC,11101010B ; 8BIT
送信割込み手順: 送信データの最初の1バイトをSIOのデータポートに書き込む。
SIOAの送信バッファが空になった時に送信割込み(iisia())が発生するが、次のデータが存在しない場合は、WR0 の Reset TxINT
Pending (保留中の送信割込みのリセット)を実行。
(参考2) Super AKI-80ではCTC3の出力端子 ZC/TO3 がSIOのクロック入力端子 TXCAとRXCA に接続されているため(下図参照)、CTC3のタイマー動作でSIOのクロック信号を生成することができます。Super AKI-80以外のボードの場合はボード外部で接続してください。
Z80の割り込み
プログラミングの検討に入る前に、割り込み処理について考えてみます。割り込み処理は、メインのプログラムが何処を実行していようが、割り込みが禁止されていない時に、割り込みが発生すると、予め定めておいた特定アドレスにジャンプして、そこに書かれたプログラムを実行し、割り込みからの復帰命令によって、中断していたメインプログラムに復帰するという仕組みです。
電源ダウンを検出し、重要データを退避させるノンマスカブルインタラプト、
センサーの周期監視、ステップモーター駆動、PWM制御のタイマー割り込み、
シリアルデータの受信/受信割込み、
装置の動きを検出するエンコーダー信号割込み
などが代表的な割込みです。
PICは、どんな割り込みが発生しても4番地にジャンプして、その要因は割込みフラグを調べて必用な処理をします。AVRは、 Int0の割り込みは1番地、Timer0
がオーバーフローしたら6番地、とうように固定したアドレスが割り振られています。このアドレスが並べられたテーブルはベクトルテーブル(ベクターテーブル)と呼ばれます。
Z80はもっとフレキシブルで、IM2と呼ばれるモードでは、ベクトルテーブルのアドレスを指定することができます。ベクトルテ―ブルのアドレスの上位8ビットは、CPUのIレジスタに書き込んだ値が適用され、下位8ビットは割り込みを発生するデバイスから送られてくる割込みベクトルが使われます。その各、デバイスのベクトルレジスタには、予めこのベクトルを書いておきます。ひとつのモジュールが複数の割込み機能を持っている場合は、先頭のベクトル値を書込みます。
そして、ベクトルテーブルには、割込処理プログラムの開始アドレスを書いておきます。このアドレスを CPU が読みとり、実際の割込処理プログラムにジャンプします。
通常、ベクトルテーブルは
0000番地 JP START ;コールドスタートプログラムへジャンプ
の後の、疑似命令
SECT CODE,ORG=010H
によって先頭アドレスが割り当てられて、続いて
DW 割込みベクトル
、、、
によってジャンプ先が指定されます。
下はCTCとSIOに割り当てられる下位の割込みベクトルの例です。
例えば、SIOAを受信割込みに設定し、
Iレジスタに 00H を書き、
SIOBには 2 に続く 20H によって、ベクトルレジスタにSIO割込みベクトル先頭値の20Hを書き込み、
割込み準備が済んだら EI (割込み許可)をします。
SIOのChAに受信割込み(Ch A Receive Charactor Available)が発生すると、
ChA 受信割り込み用アドレス 002CH のベクトルテーブルに書かれたアドレスにジャンプすることになります。
割込みが受付られると、割込み先の処理が終わって、EI に続く RETI 命令で、中断していたメインに復帰し、再度割込みが受付可能となります。ここでのEIは即有効になるのではなく、RETIの後に有効となります。
通常、この割込み処理部分は C言語ではなくアセンブラで記述されます。
vecadr: ;ベクトルテーブルで指定する割込み処理アドレス
push af
push bc
push de
push hl
call _cprog ;Cプログラム呼び出し
pop hl
pop de
pop bc
pop af
ei ;割込み許可
reti ;中断していたメインへ復帰
push で各レジスタペアが退避されて、cプログラムが呼ばれ、cプログラムから戻ったところで、逆順で各レジスタペアがpop されて、ei ,
reti で割込みプログラムからメインプログラムに復帰すると同時に、新たな割込みを受け付けます。
複数の割込み要求が同時に発生した場合、割込みの優先順は、IEI - IEO 信号のデイジーチェーン回路によって決定されます。
割込みに関係する注意:1
メインと割込みの双方で同じ変数、フラグ、関数などを利用していると、メインでこれらをアクセスしている最中に割込みが入ってしまい、メインに帰ってきた時、全く予期しなかったことが発生する危険性があります。これを避けるためには、
1)割込み先でアクセスする変数、フラグ、関数を、メイン側でアクセスする際は、必ず di() ei() で保護する。
2)メインと割込みに共通する関数の場合、関数の途中にei()が入ると再割込みされてしまうため、 di() ei() を入れたメイン用関数と、di() ei() を入れない割込み用関数の2種類用意する。
割込みに関係する注意:2
割込み時にアクセスする変数には
valatile 変数;
または
volatile static 変数;
のように、volatileを宣言して、安定したメモリを確保する必要があります。タイマー割込みなどは、static だけでは最適化によって非安定メモリー領域が割り当てられてしまう恐れがあるためです。
Super AKI-80 による
アセンブラプログラム
さて、ここからが秋月のCコンパイラによるプログラミングの説明です。
ほとんどの機能のプログラムはCで書けますが、最低限のプラットフォーム部分はアセンブラで記述することをお勧めします。例えば電源ONで実行されるスタート部分、ベクトルテーブル、割り込み処理の入り口と出口部分などです。
AVR studioやPICのMPLAB IDEのCプログラムは一見、Cだけで書かれているように見えますが、やはりこれらのプログラムはアセンブラで書かれたプラットフォームに乗っています。
ところで、このコンパイラには ei()、di() がマクロとして備わっていますが、入力関数inp() や出力関数 outp() が付いていないため、下記のサンプルプログラムには、アセンブラで組み込んでおきました。少なくとも入出力ができないと、画面とキーボードの無いPCと同じで、手も足もでませんから最低限必用という訳です。
以下はアセンブラソースのひな型 TST.xas です。
なお、以下のcプログラムは、TMPZ84Z015で動く Super AKI-80を使っていますが、Z80とZ80CTCとZ80SIOから構成されるシステムであれば基本的には動作可能のはずです。
ただし Super AKI-80以外のシステムを利用する場合はZC/TO3 をSIOのクロック入力端子 TXCAとRXCA に接続してください。
このアセンブラのプラットフォームの上でcプログラムが動くことが確認できれば、後はかなり高度なプログラムも、cだけで記述できる筈です。
;********************************
; TST.xas
; アセンブラ ソースファイル
;********************************
;別ファイルで定義する関数(このファイルで使うため)
EXTNAL _main
EXTNAL _iict0
EXTNAL _iisia
;関数の広域宣言(別ファイルで使えるために)
global _outp
global _inp
;ラベルの広域宣言(cファイルで使うため)
global ISIOB0
global ISIOB1
global ISIOB2
global ISIOB3
global ISIOA0
global ISIOA1
global ISIOA2
global ISIOA3
global ICT0
global ICT1
global ICT2
global ICT3
;定数
STK EQU 0FFFFH ;Stack address
;*******************************
INIT SECT CODE,ORG=0
JP START
;CTC 割込みベクトルテーブル
SECT CODE,ORG=010H
DW ICT0 ; 10H CTC0
DW ICT1 ; 12H CTC1
DW ICT2 ; 14H CTC2
DW ICT3 ; 16H CTC3
;SIO 割込みベクトルテーブル
SECT CODE,ORG=020H
DW ISIOB0 ; 20H SIOB TX BF EMPTY
DW ISIOB1 ; 22H EXT STATUS
DW ISIOB2 ; 24H RX AVAILABLE
DW ISIOB3 ; 26H SPECIAL RX
DW ISIOA0 ; 28H SIOA TX BF EMPTY
DW ISIOA1 ; 2AH EXT STATUS
DW ISIOA2 ; 2CH RX AVAILABLE
DW ISIOA3 ; 2EH SPECIAL RX
SECT CODE,ORG=038H
halt
;********* Power on Cold Start ***************
C_START SECT CODE
START:
LD SP,STK ; スタックの設定
XOR A
LD I,A ;
割込みテーブルの上位アドレスをIにセット
IM 2 ;
割込みモード2
CALL _main ;Cプログラムへ
HALT
;********* Cプログラム用アセンブラ **********
; ポート入力
; 変数 = inp(addr);
; cレジにポートaddrがセットされ,戻りドレスがpushされてcからcallされる
_inp:
ld hl,2 ;戻りアドレス分の2バイトをシフト
add hl,sp
ld c,(hl) ;c <--
ポートaddr
in a,(c) ;accに入力
ld c,a ;c
<-- 入力データ
ld b,0 ;b
<-- 0
ret
;ポート出力
; outp(addr,data); で呼ばれる
; dat,ポートaddr,戻りアドレス の順に各2バイトがpushされている
_outp:
ld hl,2 ;戻りアドレス分の2バイトをシフト
add hl,sp ;addr データをポイント
ld c,(hl) ;c <-- addr
inc hl
inc hl
ld b,(hl) ;data
out (c),b ;出力
ret
;******** 割込みのアセンブラ処理*********
;割込み発生でこのベクトルテーブルの下位バイトと
;Iにセットされた上位バイトのアドレスが実行される
ISIOB0: ; SIOB TX BF EMPTY
ei
reti
ISIOB1: ; EXT STATUS
ei
reti
ISIOB2: ; RX AVAILABLE
ei
reti
ISIOB3: ; SPECIAL RX
ei
reti
ISIOA0: ; SIOA TX BF EMPTY
ei
reti
ISIOA1: ; EXT STATUS
ei
reti
ISIOA2: ; RX AVAILABLE 受信割込み
push af
push bc
push de
push hl
call _iisia ;Cプログラム呼び出し
jr retint
ISIOA3: ;1E SPECIAL RX
EX AF,AF'
EXX
LD A,30H ;ERROR RESET
OUT (19H),A ;SIOAC
EXX
EX AF,AF'
ei
reti
ICT0: ;
CTC0 オーバーフロー割込み
push af
push bc
push de
push hl
call _iict0 ;Cプログラム呼び出し
jr retint
ICT1: ; CTC1
ei
reti
ICT2: ; CTC2
ei
reti
ICT3: ; CTC3
ei
reti
retint:
pop hl
pop de
pop bc
pop af
ei
reti
END
上のアセンブラプログラムは以下のような働きをします。
① 電源が投入された時に開始されるPower on Cold Start
スタックポインタ、Iレジスタ設定、割り込みモードを設定してからCのmainに飛んでいます。
② 割り込みのベクトルテーブルの配置と、このテーブルを参照して実行される割り込みルーチンの入り口と、cで記述される割り込み処理が終了した時に実行される割り込み復帰命令の reti 命令。
(割り込みプログラム中で ei をしない限り割り込みは再割り込みしません。ei に続く reti で割り込みが可能になります)
ベクトルテーブルでは、CTCの割込み下位アドレスは10H、SIOは20Hに設定しています。この例では、I レジスタで決める上位ベクトルは0Hにしています。後述のCTCとSIOの割り込みで使うのがこれらのアドレスですから、頭の隅へ入れておいてください。
③ ポート入力 inp() とポート出力 outp() 関数用のアセンブラプログラム。
cプログラム化した時、どうしても避けて通れないのが di, ei そしてこのポートへの入出力でしょう。cプログラム中にインラインアセンブラやマクロでこういった機能を記述する方法もありますが、このcコンパイラはどうもdi,eiのインラインしかなかったので、アセンブラで入出力ルーチンを記述し、これをcの中から呼ぶ方式を採っています。この入出力ルーチンは御覧のように使っているレジスタをpush,popで保護していません。もし弊害があったら追加して、その分sp(スタックポインタ)をシフトしてください。
秋月のZ80cコンパイラが持つプリプロセッサ機能の詳細は不明ですが、試したところ、以下のような簡単なマクロとインラインアセンブラの機能を持っているようです。
マクロ定義
#define in_PIA inp(PIOAD)
#define out_PIA(a) outp(PIOAD,(a))
#define in_PIB inp(PIOBD)
#define out_PIB(a) outp(PIOBD,(a))
これにより、
out_PIA(in_PIB);
のような簡潔な表現ができるようになります。
インラインアセンブラ
__asm(" ld c,(hl) ");
__asm(" inc hl");
のようにcソースファイル中にアセンブラ命令を入れることができます。
最適化
ビルド→設定→コンパイル → 設定カテゴリ 「最適化」から 「サイズ優先」か「実行スピード優先」か指定し適用します。
サンプルプログラムについて
このサンプルプログラムは、CTCのチャンネル0がタイマー割り込みで動作し、SIOチャンネルAが受信割り込みで動作するプログラムになっています。
RS-232Cのクロス接続は下図のような接続ですが、送信したデータを自身で受信して確認する場合は、2-3、4-6、7-8 をループバック接続ます。
なお、私もこのCコンパイラとの付き合いは日が浅いのですが、数値表現が10進と16進だけで、2進表現は受け付けてくれないなど、残念な面もありますが、二次元配列も扱える等、そこそこのレベルを持っているのではないかと思われます。コンパイル後のサイズや実行速度は決して優れているとは言えないようですが、簡易的とは言え統合開発環境の下のc言語である秋月のcコンパイラ、なかなかの安定性を示してくれています。改めてZ80を日の当たる場所に引き摺り出してくれることを期待したいものです。
LCD表示とEEPROM
-Super AKI80-
Z80を実用化するためには、書き換えたデータを保持できるEEPROMと、LCD表示が欠かせません。
EEPROMは2線式の24C16を使いましたが、I2Cインターフェースを持つデバイスなら、これより大きな容量のEEPROMでも勿論構いません。
LCDは秋月の16桁×2行(SC1602)です。
Super AKI80のポートとの接続
LCD - CPU基板
14 D7-- PIOB7
13 D6-- PIOB6
12 D5-- PIOB5
11 D4-- PIOB4
10
9
8
7
6 E -- PIOB3
5 R/W-- GND
4 RS -- PIOB2
3 Vo ----4.7k----GND
2 Vss -- GND
1 Vdd -- 5V
24C16 - CPU基板
8 Vcc -- 5V
7 Wp -- GND
6 SCL -- PIOA6 ---10k---Vcc
5 SDA -- PIOA7 ----10k---Vcc
4 GND -- GND
3 A2 -- GND
2 A1 -- GND
1 A0 -- GND
プログラムリスト
Z80_TRY.zip
訂正: Z80 TRY.zip における I/O map の PPI 設定の記述に誤りがありました。記載記事の範囲内では問題となりませんが、PPIを使うよう変更した場合、エラーとなりますので、I/O
map設定を上記 Z80 TRY.zip に差し替え願います。2023/5
解凍して、そのまま秋月の統合開発環境を使います。
写真はW-ROMを使ってEEPROMの書き込みと読み出しの実行
PICやAVRなどの場合はコントローラーの型番を開発環境へ入力するとメモリ領域も自動的に決定されますが、Z80の場合はRAMもROMもジャンパー線で設定するようになっていて、開発環境とは切り離されています。このため誤った設定にすると誤動作してしまう危険性が出てきます。少なくともオプションパラメーターにおけるRAM、ROMの領域設定と、基板上のRAM、ROMのサイズ設定と実際に差し込むROMのサイズが一致している必用があります。狭い領域しかアクセスできない場合はもちろんプログラムはまともに走りませんが、逆の場合はフロートしたアドレスがアクセスされることになるため、再現性のないトラブルに見舞われることになるので要注意です。
秋月のZ80ボード使う際の注意
秋月電子から発売されているZ80ボードは Super AKI-80 と AKI 80ゴールドボードがあります。
これらのボードのポートを入力ポートとして使う場合は必ず外付けの4.7k~10kΩでプルアップする必要があります。
なお、当管理人が設計製造に関わったZ80ボードでは、ポートだけでなく、データバス(D7~D0)もアドレスバス(A15~A0)も10kΩでプルアップ処理しています。これはZ80に限らず、3ステート回路はライン全体が浮いた状態(ハイインピーダンス)となるため、周辺回路からの電磁誘電や静電誘導の影響を受け易く、接続されているMOSゲートに思わぬ誤動作を引き起こしたり、時には素子の破壊を招くため、回路中の1点でプルアップ(またはプルダウン)するという原則に基づく対処です。残念ながら、Super
AKI80の上位アドレスは出ていないため処置できませんが、
Super AKI-80のコネクタマップとIOマップ (秋月電子 Z80 資料より)
AKI-80 ゴールドボードのコネクタマップとIOマップ