平成26年4月 7日
昨日の説明は非常に言葉足らずでした。昨日分の文末に追記しましたので、続けて読んでいる方は先に昨日分の追記をお読みください。
割り込み処理への対応
z80の割り込みには、下記があります。
・NMI割り込みによる0x66番地からの実行
・INT割り込みモード0による各々0x00,0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38番地からの実行
・INT割り込みモード1による0x38番地からの実行
・INT割り込みモード2による割り込みベクタアドレスからの実行
これらのうちで問題になるのは、SuperAKI-80のROMアドレス領域からプログラムを実行するNMI割り込みとINT割り込みのモード0と1です。これらはROMアドレス領域なので後から変更は出来ません。従って仕様を決めて動作を固定するしかないのです(ちなみにINT割り込みのモード2では割り込みベクタをユーザープログラムでRAMアドレス内に設定します)。
ではどのように仕様を決めればいいか?
決まりきった方法としてはジャンプテーブルを使った方法があります。ROMアドレス領域内のプログラムからはRAM上の特定のアドレスにJMP命令によって移動します。このジャンプ先アドレスに実際に処理を行う関数へのジャンプ命令を書いておきます。
NMI割り込みを例に取ると次のようになります。
1.NMI割り込みによって0x66番地から実行開始される。
2.0x66番地には(RAM領域である)例えば0x8000番地へのジャンプ命令を配置しておきます。このアドレスは変更できません。
3.ユーザープログラムでは0x8000番地にジャンプ命令のコード0xc3に続けて実際の割り込み処理関数のアドレスを定義しておきます(どうやってやるかは後で説明します)。つまり、ここから再度、割り込み処理関数へジャンプします。
これでNMI割り込みが発生すると2回のジャンプ命令を介して実際に割り込み処理を行う関数にたどり着くことが出来ます。割り込み処理関数を指定しているアドレスはRAM上に配置されているので後からでもユーザープログラムで変更できます。
この方法の難点はRAM上の特定アドレスにジャンプテーブルが固定されてしまう点です。C言語では特定のアドレスに特定のコードを配置することは、それほど自由には出来ません。また、RAMのアドレス領域が変更になるとそれに伴ってモニタプログラムの一部を書き直す必要が出てきます(RAMの開始アドレスが変更になった場合など)。
これらの難点はあるもののジャンプテーブルによる方法は非常に単純です。また、あまり褒めた方法ではないですが、ROM内容のジャンプ先アドレスだけを後から人手で変更することも可能です。このような理由からか、比較的多くの場面で使用されています。今回もこの方法を採用します。
方針が決まったので、まず最初にモニタプログラムが占有するアドレス領域を先に決めてしまいます。ROMエリアは全てモニタプログラムが占有します。RAM領域(0x8000〜0xFFFF)にはモニタプログラム自身のワークとスタック領域が必要です。スタックサイズを0x100として、ワークに0x100の合計0x200をモニタプログラム用として確保します。アドレスはRAM領域であればどこでも良いのですが0xFE00〜0xFFFFを割り当てます。これでユーザーが使用できるRAM領域は0x8000〜0xFDFFとなります。このアドレス内にデバッグするプログラムのROM領域とRAM領域を割り当てます。
(平成26年4月9日追記)
以下の文書ではユーザーROM領域とユーザーRAM領域が逆に説明されていました。訂正します(追記ここまで)
都合によってユーザーRAM ユーザーROM領域を0x8000から取る様にします。これはユーザーが使用できる残り少ないメモリ空間を出来るだけ有効に活用するための配慮からきています。先のジャンプテーブルはRAM ユーザーROM領域の先頭0x8000番地から割り当てます。ジャンプテーブルは
・1番目はINT割り込みによる0番地からの実行へのジャンプ(実際には割り込みとしては使用できません)
・2番目はINT割り込みによる8番地
(省略.....)
・8番目はINT割り込みによる8(平成26年4月8日訂正)38(訂正ここまで)番地
・9番目はNMI割り込みによる66番地からのジャンプ
の合計9個必要です。
なお、実際の使用ではモニタプログラムを使ったデバッグでは、INT割り込みで0番地へのジャンプは使用禁止になります。実アドレスの0番地にはモニタROM のプログラムが書かれているので、この部分をジャンプ命令に置き換えることは出来ません。このジャンプを残しておく理由は、ユーザープログラムをリセットから実行する時の開始アドレスとして0番地の代わりに使用します。つまり、0x8000番地にジャンプするのはユーザープログラムを0番地から実行するのと同じ動作になります。
以上からメモリマップは下記のようになります。
0x0000〜0x7FFF モニタプログラム(ROM領域)
0x8000〜0x801A ジャンプテーブル(ユーザーRAM領域)
0x801b〜0xXXXX ユーザーRAM領域(0xXXXXは可変を意味しています)
0xXXXX〜0xFDFF ユーザーROM領域
0xFE00〜0xFFFF モニタプログラム(RAM領域)
0x8000〜0x801A ジャンプテーブル(ユーザーROM領域)
0x801b〜0xXXXX ユーザーROM領域(0xXXXXは可変を意味しています)
0xXXXX〜0xFDFF ユーザーRAM領域