==== Linear Memory Mapping PC-1600K(1) by kako(1992) ===== 〜 PC−1600Kのメモリマッピングの謎 〜  工学社発行の『PC-1600Kデータブック』には、p.94〜95にSLOT1MAP/ SLOT2MAPというIOCSが解説されています。これはメモリスロットS1と S2のメモリのマッピングを変更するためのIOCSです。しかし、これを 実際に何かに応用したという例は、未だに存在しないようです。  このSLOT1MAPとSLOT2MAPの利用方法の1つとして、全メモリ空間を リニアに64KB全部RAMにしてしまうというのが考えられます。 これにより、他のZ80システムのプログラムを利用することができ るのではないかと思われます。 ■ マップ変更のためのIOCSについて  例えば、スロット1に16KB,スロット2に32KBのRAMを 装着し、IOCSのSLOT2MAPでA=02Hを指定すると0000h〜7FFFhの空間の バンク1がRAMになります。そして、バンク1にマップしたメモリ を何かに使うために、IOCSのBANKSETを使ってバンク1を選択してや らなければなりません。  ・・・・・ さて、ここで問題が出てきます。  1つはIOCSです。ページ0のバンクを変更すると、もはや元に戻す ためのIOCSをはじめ、全てのIOCSを呼び出すことができなくなります。  もう1つは割り込みです。割り込みルーチンがバンク0のページ0 にありますので、ページ0のバンクを変更すると割り込みが暴走して しまいます。  これを解決するために、どちらの問題点についてもまず必要になる のがIOCSを使わないで直接バンクとメモリマップの変更をする方法で す。  これができればIOCSを使うときだけメモリマップを戻すことも可能 になりますし、割り込み発生時だけメモリマップを戻すことも可能で す。 ■ リニア64KのためのI/Oポート操作  次の3つのIOCSを解析すると、直接I/Oポートを操作する方法が 見つかりました。 名前 アドレス -------------------- BANKSET 0193h SLOT1MAP 0196h SLOT2MAP 0199h  まず、バンクの切り換えですが、これはデータブックのp.181にも 出ていますが、I/Oポート(31H)でバンクを切り換えます。  メモリマップの切り換えですが、これはI/Oポート(3CH)で 切り換えます。(ただし、3CHは読み出しができませんので、マッ プを調べる時にはF08Dhのワークを読み出します。) SLOT1MAPでA=00H/01Hとすると、bit2がセットされます。 SLOT2MAPでA=00H/01H/02Hとすると、bit4,5がセットされます。 (※その他のbitについては不明です。) すると下記のA,B,C,DのRAMのマップ(0000h-7FFFh)が変化します。 BANK#0 BANK#1 BANK#2 BANK#3 ... 8000h +------+ +------+ +------+ +------+ | | | | | | | | | A | | B | | C | | C | ... | | | | | | | | BFFFh +------+ +------+ +------+ +------+ bit2 | 0 0 0 1 1 1 bit4 | 0 0 1 0 0 1 bit5 | 0 1 0 0 1 0 --------------------|-------------------------- #1,0000h-3FFFh | - C D - C D #1,4000h-7FFFh | - - C B B B ここで64KBのメモリ空間すべてをRAMにする場合、どのような メモリマップにするのが都合がよいかを考えます。 コモンエリアの標準実装16KBに加え、  32KBモジュール×1個、16KBモジュール×1個の場合、 S1:に32KB、S2:に16KBで、bit(2,4,5)=(1,0,1)。 S1:に16KB、S2:に32KBで、bit(2,4,5)=(0,1,0)。  32KBモジュール×2個の場合、 S1:、S2:ともに32KBで、 bit(2,4,5)=(1,0,1),(1,1,0)あるいは(0,1,0)。 以上のように5通りが考えられます。 (16KBより小さいモジュールや、64KB以上のモジュールは この場合無視することにします。) これらのうちで最も都合がいいのは、bit(2,4,5)=(0,1,0)の場合です。 理由としては、 ・S2の32KBのマップだけを変化させ、S1は動かさなくてもよい。 ・S1についてかなり自由がきく。特に小さいソフトをロードする場合、  S1の中身はRAM/ROMであろうと、はたまた搭載されてなくても  影響がない。 というものがあげられます。 このような構成でリニア64Kに移行するには、 LD A,(0F08DH) AND 0CBH OR 10H OUT (3CH),A ;bit(2,4,5)=(0,1,0) LD A,03H OUT (31H),A ;BANK(#1,#1,#0,#0) という機械語を実行すればよいわけです。 (実際に使用する場合には、現在の状態を保存するコードも書かなければ なりません。それは次で紹介します。) ■ IOCSの実行方法  IOCSを使用時だけメモリマップを元に戻す方法について説明をします。  この場合、LINEARとNORMALという2つのサブルーチンを使用します。  そして、IOCSを実行するときには、 CALL NORMAL ;通常のメモリマップに戻す CALL xxxx ;なんらかのIOCS CALL LINEAR ;再度リニアマップに移行する  とします。 (※ただし、割り込みについて解決しないうちはEIで死にます。)  この切り替えは0000h〜7FFFhのエリアでは使えません。また、スタック  がこのエリアにある場合もだめです。  このような制限がありますが、システムコールの処理は上位のメモリで  処理するシステムが多いですし、実際には問題にはならないでしょう。 ;******************** ;******************** ;リニアに64Kにする ;ノーマルな状態に戻す ;******************** ;******************** LINEAR: NORMAL: DI DI PUSH AF PUSH AF IN A,(35H) IN A,(35H) PUSH AF PUSH AF XOR A XOR A OUT (35H),A OUT (35H),A LD A,(0F08DH) LD A,(SAVMAP) LD (SAVMAP),A LD (0F08DH),A AND 0CBH OUT (3CH),A OR 10H LD A,(SAVBNK) LD (0F08DH),A OUT (31H),A OUT (3CH),A POP AF IN A,(31H) OUT (35H),A LD (SAVBNK),A POP AF LD A,03H EI OUT (31H),A RET POP AF OUT (35H),A ;マップ状態保存ワーク POP AF SAVMAP: DB 0 EI SAVBNK: DB 0 RET ■ 割り込みに関する問題点  PC-1600Kの割り込みはZ80の「モード2割り込み」で処理されています。  これは、IレジスタとVレジスタが指ししめす割り込みベクタのアドレ  スを呼び出します。 割り込みベクタは0321hにあり、その値は082Chと  なっています。ここの割り込みエントリルーチンは、現在のバンク状態  を保存しページ1,バンク3,4021Hの割り込みサービスルーチンを呼び  出します。  IOCSによるキー入力や通信ポートでの入出力は、この割り込み処理でサ  ポートされています。  メモリマップを変更した場合、このエントリルーチンは使えませんので  新たに自分で代わりのルーチンを用意しなければなりません。しかも、  その代替ルーチンは、メモリマップ状態とメモリバンク状態の両方を保  存しなければなりません。  この代替ルーチンに処理を移すために、IレジスタとVレジスタを書き  換えてベクタのアドレスを変更しなければなりません。Vレジスタは、  I/Oポート(39H)で書き込みます。 (※RS-232Cの受信を取りこぼさないようにするために、PC-1600Kの割り込 みは、その他の割り込みを実行中にもRS-232Cに関して再エントリします。 ゆえに上記のLINEAR/NORMALは使えませんので、スタック上にマップ状態を 保存します。) SETINT: DI IN A,(35H) PUSH AF XOR A OUT (35H),A LD HL,VECTOR ;割り込みベクタ LD A,H ;をセットする LD I,A LD A,L OUT (39H),A POP AF OUT (35H),A EI RET VECTOR: DW INTRPT INTRPT: PUSH AF PUSH BC LD A,(0F08DH) PUSH AF LD A,(SAVMAP) LD (0F08DH),A OUT (3CH),A IN A,(31H) LD B,A LD A,(0F07DH) LD C,A LD A,04H LD (0F07DH),A OUT (3DH),A LD A,66H OUT (31H),A CALL 4021H ;割り込みサービス LD A,C ; ルーチンを呼び出す LD (0F07DH),A OUT (3DH),A LD A,B OUT (31H),A POP AF LD 0F08DH),A OUT (3CH),A POP BC POP AF EI RETI ■リニア64Kの応用例  CP/Mで0100Hからプログラムをロードして実行します。まだ作っている最中なので、 今回は簡単に紹介するだけにしておきます。というのはまだディスクにアクセスでき ないのです。それ以外のシステムコールは全部できています。実際、RS-232CからHEX 形式のCP/Mプログラムを0100hからメモリにロードし実行ができています。ただし、 ディスク関係のシステムコールが呼ばれるとエラーになりますけど。