SHARP PC-1600KでCP/M80!その2

CP/M80のPC-1600Kへの移植!

その後も少しずつ進めていて、標準コマンドはだいたい動くようになったかな?というところまで来た。

f:id:PocketGriffon:20210429092508j:plain

DDT(デバッガ)が起動した時の画面↑

 

このブログでは、PC-1600K上でどのようにしてCP/M80を動かしているのかを、自分の備忘録も含めて書いていこうと思う。

 

先に正直な事を書いてしまうと、PC-1600K自体がCP/M80を起動するだけの能力を備えているので出来ているのであって、ソフトウェアで頑張って動かしました…という事で無かったりもする。当然、PC-1600Kを開発された方はCP/M80の移植も想定していたんだろうな…と思う(^^) 実際にやるかどうかは別として!!(^^;;

 

PC-1600K CP/M80のメモリサイズ

先日のブログで、大体のCP/M80イメージを固めた。

SHARP PC-1600KでCP/M80!その1 - レトロパソコンであそぼう!

この中で「IOCSを利用する」と決めた流れがあったが、これにはもう少し制限が加わる事になる。IOCSはメモリ中のF000h〜FFFFhをワークエリアとして利用する。この部分は詳しく調べられていないため、どこを壊して良いかなどの情報を持ち合わせていない。そのため、この領域は「触らない部分」として残す必要がある。

 

ところで…良くCP/M80の記述を見ていると「xxK CP/M」などの表記がある。「48K CP/M」「64K CP/M」とか、見た覚えがあると思う。このメモリサイズがどうやって決まるのかが気になっていた。

 

CP/M80の事について書かれた本は数あれど、私は移植する際にはこの本を活用している。

f:id:PocketGriffon:20210429095434j:plain

2014年にCP/M80が動くエミュレータを書いた際にもとても参考にした。

この本に、こんな記述がある。

f:id:PocketGriffon:20210429095548j:plain

CCPの先頭番地…というのが、実際にCP/Mシステムを置くアドレスを指しているのだが、このアドレスから始まるシステムであればCP/Mのサイズはこう名乗って良い…という感じだ。

なんとなく…このCP/Mで「使えるメモリサイズ」ではなく、このCP/Mが「動いているシステムのメモリサイズ」を表しているような気もする。

 

今回のPC-1600K CP/M80はCCPアドレスがC400hから始まっている。ということは56K CP/Mと名乗っても良いのかな…と思い、オープニングタイトルに56Kと書いた!

 

64KBオールRAMメモリマッピング

ここを詳しく書いていくと技術書並の情報量が必要になってしまうので、とても簡潔に済ませてしまおうかと思う(備忘録にはなる程度にw)。

 

PC-1600Kで64KB全体をRAMにするためには条件がある。

PC-1600Kをひっくり返して裏を見ると、拡張モジュールを取り付ける部分に「S1」「S2」と刻印がある。これがスロット1と2の事だ。

  スロット1に16KB以上のメモリモジュール

 スロット2に32KB以上のメモリモジュール

上記の拡張ハードウェアが必須。これが64KBオールRAMの最低条件。

PC-1600Kで良くある構成の、スロット1にCE-1600M、スロット2にCE-1650M(文節変換辞書)が取り付けられている人は、残念ながらアウトだ。

f:id:PocketGriffon:20210429101936j:plain

↑頑張って上記のどちらかを手に入れよう!

 ※たとえCE-1600Mを2つの構成にしたとしてもCP/M80は動かない(この辺りは後のブログで紹介)。

 

PC-1600Kはメモリマッピングがスロット1とスロット2で別々に設定出来る。ここの設定が非常にややこしい。

PC-1600Kデータブックに以下の記述がある。

f:id:PocketGriffon:20210429103019j:plain

これはスロット1の事を書かれた図なのだが、残念ながら誤植がある。

図2-63のA=1とA=0、これが左側のパラメータに書かれている言葉と図が逆になっている。これは書かれている文章の方が正しい。図のA=1とA=0を逆にして読む。

私が所有している本が初版だからかも知れないが、直ってる版を持っている人は当たりかもw

64KBマッピングではA=0(ややこしいが図の上、A=1と書かれている方)を利用する。

これでスロット1のαのメモリがバンク0の8000h〜BFFFhに見えるようになる。

 

スロット2の方はこちら。

f:id:PocketGriffon:20210429103441j:plain

これも…スロット1の図と同じα/βの記号が使われてしまっているため分かりづらい(ToT) 図だけを見た時に何を意味しているのかが理解出来ない。この図は「スロット2のメモリがメインメモリのどこに割り振られるのか」を示している。

 

こちらはA=02hを使用すると、条件的には上の図が採用される事となる。

これでバンク1の0000h〜7FFFhにスロット2のメモリが顔を出す。気をつけなければならないのは、メモリのβ側が0000h、α側が4000hから見える。なんとなく気持ち的には逆なのだが、そういうモノらしい(-_-;

 

上記の設定に加えて「メモリ空間にマッピングされるバンク設定」をする。

f:id:PocketGriffon:20210429105259j:plain

0000h〜3FFFhはバンク1(スロット2のβ)

4000h〜7FFFhはバンク1(スロット2のα)

8000h〜BFFFhはバンク0(スロット1のα)

C000h〜FFFFhはバンク0(標準搭載のメモリ)

ということで、I/Oポート31hには0_000_001_1b(つまり03h)を出力する。

 

これで64KB全てがRAMになる!

 

……と思ったら大間違いだった。

いや概念的には正しいのだが、これだけではダメだった。

IOCSのプログラムが置いてあるアドレス空間が切り替わってしまうため、メモリマッピングを変更した瞬間に暴走しちゃうのだ。そりゃそうだ!(ToT) 

これを回避するためには、IOCSのプログラムをメモリマッピングの影響のない領域、具体的にはC000h〜FFFFhに移動させる必要がある。これはもうIOCSのプログラムを解析して移植するしかない!(TOT)

ここまででようやく64KB全ての空間がRAMとなった。結構めんどい(T-T)

 

IOCS呼び出し

ちなみにこの状態ではCP/M80からIOCSを呼び出す事が出来ない。上にも書いた通り、IOCSのプログラム自体が見えなくなっているからだ。

IOCSを呼び出す際には、PC-1600Kが起動された時の状態にメモリマッピングを戻す必要がある。そのためにマッピングを切り替える前の状態を記録しておく必要がある。

実験した結果、I/Oポート31hは直接読めるようだが、スロット1、2のマッピングを切り替えるI/Oポートは読めないようだった。ワークエリアに保存されている値を見つける事が出来たため、それを利用することに。

 

Z80割り込み

さらに割り込みをONにすると不安定…というか、暴走するけれどもタイミングが一定ではない…という、割り込みにありがちな問題が出た。これも割り込み先のアドレスがなくなるために起きる問題だ。

 

PC-1600Kデータブックによると、割り込みはZ80のモード2を利用しているらしい。モード2の割り込みって珍しい気がする…。何度と無くZ80エミュレータを書いた事があるので、それぞれの割り込みについて動作も理解しているつもりだが、モード2って誰が使うんだろう…と思いつつ実装をしていた(^^;; まさかここで遭遇するとはw

 

モード2割り込みはちょっと理解が難しい。Z80のIレジスタに上位8ビットを設定、周辺機器(I/Oポート)に下位8ビットを設定する。割り込みが掛かるとPCレジスタに「Iレジスタ*256+周辺機器から送られてきた値」が代入される。もうこの時点でワケ分からん…となるだろう(^^;;

 

割り込みの処理もIOCSを解析し、似た処理を自前で書くこととなった。具体的には割り込みが掛かった時点でメモリマッピングを元に戻し→割り込み処理→64KB RAMへ戻す、という事をしている。割り込み処理自体が重くなってしまったのは心配だが、なんとか動いてる。

 

なんとなく文章ばかりになってきて読む側もつまらないと思うので、今回はここまで!

次回はCP/M80のブート、BIOSの書き方などをご紹介する予定!(^-^)

 

ではまた次回!(^-^)ノ