PC-9801のゲームをIBMPCで動かす!

ここのところお仕事が忙しくて、レトロ系に取り組めて無い。
やりたいことはてんこ盛りに増えていくのに、なにひとつ手が出せないというのは身体にも精神的にも悪いだろう!
ということで、合間合間をぬってちょこちょこ活動していた事をブログに残す!
自分の備忘録代わりにもなるし!(^^)
ここ最近で取り組んでいたのは、PC-9801のゲームをPocket386へ移植する事!
Pocket386とはなんぞや……については、本当にいろんなサイトで紹介されているので割愛するけれども、今どき珍しいMS-DOSが動作する小型のパソコンだ。
私自身、IBMPCマシンのMS-DOS上でゲームを遊んだ覚えがない。
いや、実はあったかな……と思い出そうとしてみたが、やっぱり覚えがない。
(追記:遊んでた!これ買って遊んだ!!
https://en.wikipedia.org/wiki/Comanche:_Maximum_Overkill)
初めてIBMPC(GATEWAY2000)を海外から購入した時は、最初から386BSDを動かす事しか頭になくて、DOSパーティションは3日も経たないうちに消してしまっていた(^^;;;
しかもバックアップも取らず!w(後に日本語版MS-DOSを購入した)
当時MS-DOSで遊べなかった事が心の片隅で後悔として残っていたので、今回は思う存分遊ぶことにしたのだ!
よーし、プログラム組むぞー! ← これが私の遊び(^^)b
移植するプログラムの条件
PC-9801のソフトであれば、何でもかんでも移植できるってわけじゃない。
やっぱりいくつか条件があるので書き出しておきたい。
GDCの機能を極力使わない
割と極めつけな条件かもしれないコレ。
GDCはGraphics Display Controllerの略で、グラフィックスに関するいろんな事を請け負ってくれる便利なコントローラだ。
ゲームでは画面全体のスクロールやライン描画、表示範囲の設定などに使われるケースが多いと思う。
私自身がIBMPCのグラフィックコントローラの詳細を全く知らないので、出来る限りGDCを利用しないプログラムを選びたい!(覚える気ゼロw)
テキスト画面の扱いについて注意が必要
PC-9801はテキストを表示する画面とグラフィックを表示する画面が分かれている。最終的には合成された見た目で画面には表示される。
IBMPCではグラフィックとテキストが切り替えとなっていて、それぞれを合成する事ができない(できないよね??) そのため、テキストとグラフィックを巧みに混在させたゲームの移植は難しい…と思う。
画面マスクもある意味同義。
BASIC ROMへの依存
PC-9801のBASIC…というか標準搭載されているROMは結構な多機能で、ROM内ルーチンを使ってるものを独自で書くのは簡単ではなさそうな感じがしてる。
そのため、出来る限りROMに依存しないプログラムを探したい。
基本方針
バイナリパッチのみ
以前からこのブログでも書いているが、著作物に対しては最大限の敬意を払いたい。
この手の移植では外部でプログラムコードを変更するのが一般的かと思うけど、ここではオリジナルバイナリには手を付けず、メモリへロード後、メモリ上でバイナリパッチを当てて動かすようにする。
バイナリパッチで手に負えなくなったら、そこで諦め。
著作物を軽視してまで遊ぶ事じゃない(^^)b
BASICプログラム
BASICのプログラムについてはオリジナルを参考にしつつ1から作成する。BASICインタプリタを似せるのは無理があるので、ここは無理せず自作で(^^)
ただしC言語を用いて楽はするよ!
C言語については、LSI C-86 Ver 3.30c 試食版を利用させていただいた。
ダンプリスト打ち込み
雑誌掲載のゲームのみを対象とし、ゲームのバイナリはダンプリストを打ち込むことで入手する。どんな長いバイナリがあっても自作ツールがあるから平気だ!(^-^)
自作の逆アセンブラを利用して解析を行う。
解析ツールとしてはこれしか無い!
あとは実行時にSYMDEB.EXEを活用したら、デバッグ環境としてはサイコーだ!(^-^)
ここで雑誌に掲載されているマシン語ルーチンのアドレスマップが大いに役立つ!

↑こういうアドレスマップを元に解析をしていた!
1、ベリコーサを移植!
まず手始めに取り組んでみたのは、工学社月刊I/O 1985年2月号に掲載されていた、PC-9801/E/F用のベリコーサ。

このゲームはゼビウス系のシューティングゲームで、当時の技術的な課題となっていた地上配置物と空中移動物の合成を、奇数偶数ライン別々に描画する事で解決をした作品。
力技とも言える方法だが、作者が「あえてGDCのスクロール機能を使わずに実現」と書いていたので、実験的かつ狙った方法であるのは間違いない(^^)
これを移植してみよう!
最初の移植で、移植方針もちゃんと定まってない状態で始めてしまったため、パッチ当て箇所は100箇所以上にも及んだ!
だけど……IBMPCのEGAの設定に慣れず、VRAMからVRAMへのコピーが思った通りできず、画面が化ける現象が出まくった!(TT)
解決法も考えてみたがバイナリパッチの域を超えてしまいそうなハデなモノになりそうだったため、途中で断念した!
【敗北】
— PocketGriffon (@GriffonPocket) 2024年9月22日
某雑誌のネタでしたが…w
PC-9801のゲーム、ベリコーサをIBMPCに移植してみた!
VRAM→VRAMのコピーがうまくいかず、もはやバイナリパッチの域を超えてしまうので移植断念です!(TT)
あと、テキストVRAMでのマスクもあって書き換えが見えちゃう(^^;;
ダメだこりゃ(ToT) pic.twitter.com/JxEpn6mMMG
2、魔獣島を移植
ベリコーサの敗因の一つはVRAM→VRAMのコピー。
そのコピーはなさそうだな…と思って次のターゲットとして選んだのは、デンジャーゾーン「魔獣島」(工学社 月刊I/O 1084年3月号掲載)。

実はベリコーサよりも前に発表されていたゲーム。
説明書きに「モニタの1ラインアセンブラで作った」と書かれていたので、あまり複雑なことはしていないんじゃないか…と思い移植(^-^)
このゲームもアドレスマップが書かれていて、移植するのは楽だろう…と思ったのだが…実際にはそれなりに苦戦した。
しかも……このゲームもキャラクタの表示にVRAMとのXORをしてるっぽい!(TT) そういえばXOR描画も当時の流行りだったかもしれない!(XORで表示、XORで消去) VRAMからの読み込み方法を克服しないと、この手のソフトは全滅してしまうかもしれないなぁ…orz
写真右に「冬になると雪が降る」と絵が載っているが、実はこの雪、テキスト画面に書かれるアスタリスク(*)だ!恐れていたテキスト画面との合成が必要だ!(TT)
結局、この段階ではテキストとグラフィックを上手に(効率よく)合成する方法が思いつかず、志し半ばで挫折…orz


PC-9801のゲームをIBMPCへ移植!
— PocketGriffon (@GriffonPocket) 2024年9月23日
表示系のバグを1つ修正できた!
本来の色に近づいたけど、やっぱりVRAMとの情報を合成してる辺りはうまく動いてない(^-^;;
ロープを降りてきたヘビの上に行き、ロープを切ってヘビを退治していけば良いらしい(^-^)
ここでキリつけます!
そこはかとない敗北感(TT) pic.twitter.com/E1D0LwPkGB
3、からくり忍者屋敷を移植
工学社 I/O別冊 ペーパーウェアPC-9801[2] に掲載されていたパズルゲーム。


このゲームからグラフィックVRAMの扱い方を変更した。
具体的には、メインメモリの空いた場所をグラフィックVRAMと見立てて操作出来るようにしたのだ!(具体的な手法はインセクトの復讐で詳しく説明)
さすがに……さすがにパズルゲームだったら画面とXOR取って表示したりはしないだろう…!
しかも、ゲーム画面を見る限りではテキストVRAMが使われていなさそう。
よーし、このゲームを移植して最後にするぜ!
……と思って取り組んだんですが…なんとグラフィック描画はBASIC ROMの機能を使ってた!
しかも!1キャラクタのサイズが横27ドット縦11ドットだ!
横が8の倍数になってない事がどれだけ大変なのか、アセンブラでキャラクタ表示ルーチンを書いたことがある方ならばご理解いただけるだろう…。
結局、BASIC ROMの機能を模倣することとなった。
横27ドットのキャラクタを、任意のドット単位の場所に表示する処理を書く……。


それっぽい処理をアセンブラで書いてみるが、やはり一発では動かなかった(^^;;
この移植ではSYMDEB.EXEのお世話にだいーぶなった。
この時代のデバッグ環境であっても、シンボル情報が扱えるのはとても便利だ!(^-^)
結局、この部分がネックとなり表示がちゃんとした頃には力尽きてしまった(TT)

4、インセクトの復讐を移植
今回の作業で最後に移植したのが、工学社I/O 1983年11月号に掲載されていたインセクトの復讐。ずーっと「逆襲」と勘違いして覚えていた…(^^;;

PC-9801が発表されて間もない頃に掲載されたゲーム。
見た目通りギャラクシアンな感じのシューティングゲーム(^^)
説明に「ハンドアセンブルで作った」と書かれているのだけど、逆アセンブルして解析をしてみると「まじ??」と思うほど整ったプログラムとなっていた。各ルーチンの後ろには4バイトほどの空きが用意されていて、コードが変更になった場合を考えられてはいるようだが…。
前2つの移植で失敗してるのは、VRAMからデータを読んで加工し、再びVRAMへ戻すといった処理で、VRAMからの読み込みが上手くいかない点だ。IBMPC(というかEGAとかVGAとか)にはPC-8801のALUのような複数プレーン同時書き込み等の機能が存在する。
このレジスタを正しくセットすればきっと期待通りの動きをするんだと思われるが、今現在は書籍を詳しく読み込んで理解しているような時間も惜しい(TT)

↑こんな分厚い本を読んで理解してる余裕なんてないのだよ…orz
仕方がないので別の方法を考える。
これまで移植してきたソフトは、主に初代PC-9801、つまり8086の5MHzで動くようになっている。それをPocket386(386SX 40MHz)で動かそうとすると、処理速度的な余裕がだいーぶある。感覚値で申し訳ないが、10倍以上の速度差を感じている。
となると、技術的困難なポイントへのアプローチもさまざまに考えられる。
その中で私が取った方法は「内部に仮想的なVRAMをもう1セット持つ」だ。
この1文だけを読んで「な……アホかお前!」と思った方は熟練者だろう(^^;;
つまりこういう事だ。

左側がPC-9801のメモリマップ。インセクトの復讐はこの構成で動く。
右側…というか真ん中がIBMPCのメモリマップ。
そして一番右側がインセクトの復讐で採用したメモリマップ。
ゲームのプログラムは4000:3000から置いた。8086においてプログラムのセグメントがずれる事は大きな問題ではない。が、プログラム内にデータセグメントを決め打ちされてる箇所が必ず存在するので、そこは修正が必要となる。
そしてテキストVRAMへのアクセスは8000セグメントへ、VRAMへのアクセスは8800セグメントへ移動するようにバイナリパッチを当てる。こうする事で、インセクトの復讐のプログラムは、 IBMPCの単なるRAMへ VRAMと思い込んで描画処理をする。
一連の処理が終了した時点で、仮想テキストVRAMの情報を基に、仮想グラフィックVRAMへ合成処理を行い、出来上がった画像データをA000セグメントからのVRAMへ一気に書き込んでいる(32KB * 3プレーン分)。
こんな膨大な処理をしてゲームが成り立つのか?と思われるかもしれないが、実際のところPocket386では速度が速すぎてゲームが成立しないほどとなっている(^^;;;

工学社I/O 1983年11月号に掲載されていたPC-9801用ゲーム「インセクトの復讐」をIBMPCに移植した!
— PocketGriffon (@GriffonPocket) 2024年11月24日
アルフォス、ベリコーサ、デンジャーゾーン、からくり忍者屋敷(未発表)と移植してきて、ようやくコツを掴んだ感じ!
仕事の合間に片手間で作業したけど、余裕の24時間以内!
よし!満足したww pic.twitter.com/jzcnHWfkET
その後、IBMPCにおけるリアルタイムキー入力の処理を教えていただけたので、キー入力対応、ついでにBEEP対応もしたところ、PC-9801版と遜色のない出来栄えとなった!(^^)
ちなみにパッチを当てた箇所は30箇所程度、PC-9801のフォント描画、画面更新処理など合わせても500行程度でできてしまった!
最後はシンプルかつ効果的な移植でキマったよ!(^-^)b
おわりに
なんとなく頭のリハビリ感覚で移植をしていたが、パズルっぽくて楽しかった!
面白そうだな、やってみたいな!と思った方は、ぜひチャレンジしてほしい!
当然だけど8086アセンブラは読めないといけないし、書く必要も出てくるだろう。
古のCPUに翻弄されるのもまた一興かな…と思う!(^-^)/
ではまた次回!(^^)/
Pocket386でアルフォスを動かした!

衝動的にPocket386というコンピュータを手に入れた!
CPUに386SXを積んだPC/AT互換機で、主OSがMS-DOSという「昭和の時代?!」と思うようなコンピュータだ!
以前から気になっていたんだけど、ここんところのストレスが半端なくて指が勝手にクリックしてしまった!(イイワケ

見よ!この勇姿!!(^o^)
そして起動と同時にコマンドプロンプトが出るユーザーの突き放し方!(^^;;
基本的な使い方はMS-DOSでアプリやゲームを動かすんだと思う。
そしてたまにWindows3.xを動かして優越感に浸る…(^^;

……それだけ?
……使い方としてはそんな感じ??
………それ、本当に今の時代に必要?(^^;;;
いかん!
ここで使い方を見失ってしまうと、手に入れた大義名分が無くなってしまう!(^^;
せっかくだから、最近流行ってるっぽいメキシカンハットでも表示させてみようかな!
最初からGW-BASICが入ってるから利用は簡単だけど…GW-BASICってグラフィック使えるんだっけ??
CP/MのMBASICではグラフィックが使えなかったので、当然のように使えないと思っていたのだが……。
GW-BASICのリファレンスを調べてみたら、驚いたことにPSETやLINE、PAINTといったグラフィックを扱う命令が用意されていた!

知らんかったー!
GW-BASICってグラフィック使えたんだ(^^;;
とりあえずPSET命令があればメキシカンハットは作れるけれど……
BASICで書いただけってのも味がないなー。

でも試しにやってみるけどね!(^^;;
せめてC言語で書いてみるのはどうだろうと思った時、はて、AT互換機でVRAMにアクセスするのはどうしたら良いんだろう?と疑問に…。
AT互換機でグラフィックを扱ったのは、Linuxがまだ1.0に達していなかった頃に使っていたX-Windowの、XFree86のVideo Driverを書いたのが最初で最後だ。この時はMach32というグラフィックチップのアクセラレーションを使うプログラムだった。
そんな事情で、MS-DOSでグラフィックを扱うプログラムは書いたことがないのだ!
CPUから直接VRAMにアクセスが出来るのか、はたまたやっぱりアクセラレーションを使わなければならないのか…すら知らない(^^;
そんなことを思いながら調べてみたのだが……興味深い事に気がついた。
EGAという規格で640x200ドット16色というモードが存在していた。
え?これって日本で良く使われるドット数じゃないのさ。
てっきりVGAに代表される640x480とか240とかだと思っていたのに!
もう少し調べてみたら、EGAってVGAが出てくる前の規格だったのね!
EGAが1984年、VGAが1987年に登場。
てっきりVGAのEnhancedな規格だからEGAだとか思い込んでたw(実際にEGA=Enhanced Graphics Adapterだし…)
そしてVRAM構成は、640x200のデータが4プレーンあるらしい。

うおお!それってPC-9801と同じ…というか、PC-8801とも同じじゃん。
PC-9801の場合はプレーンによってアドレス(というかセグメントというか…)がずれる。
EGAではアクセスするプレーンが違ってもアドレスは変化せず、I/Oポートにプレーンの情報を出力すれば良いらしい。
うむむ……見れば見るほどPC-9801のプログラムが移植できそうな気がしてならない…。
めちゃくちゃ興奮してきた気持ちを抑えつつ、もう少し詳しく調べてみると、やはり最初に想像したよりも簡単な話ではない事がわかってきた。
まずPC-9801はテキストVRAMとグラフィックが分離している。この両方を巧みに使っているプログラムはうまく動かせられない。スコア表示をテキストで…とか画面の一部をテキストでマスクして…みたいなタイプがソレだ。
さらにGDCの機能はPocket386には存在しないため、その機能を利用したモノもダメだ。
この時点でPC-9801用ゲームのギガンテスは候補から外れた(GDCの機能を利用して横512ドットに切り替えている)。
そんなことを考えていたら、まさに条件に合いそうなものが頭に浮かんだ!
そう…過去に開発した「PC-9801CV21の上で、PC-8801のアルフォスを動かした」プログラムだ!
これはPC-8801のプログラムをPC-9801で動かすために表示周りを細工している。
これを上手に変更することで、Pocket386でも動かせるのでは??
そんな妄想をしちゃったから、さー大変だ!!
本当に移植できるのか??
これをちゃんと説明するためには、PC-9801で動いてるアルフォスの内部構造を詳しく説明する必要がある。
正直、かなり面倒だ(^^;;
でもきっと読む側から見たら面白い情報かも知れないので、頑張って説明を書いてみようと思う。
まずPC-8801用のアルフォスをPC-9801で動かすためには、以下の要素が必要だ。
・Z80エミュレータ
・メモリウィンドウの実現
・640x200x8色の画面モード
・パレット機能
Z80エミュレータ
要であるZ80CPUのエミュレータは、V30用のアセンブラ言語で書かれている。
オールアセンブラで4000行以上もあるプログラムだが、残念ながらZ80の全命令が実装されているわけではない。N88-BASICとアルフォスを動かすためだけに作られているので、これらで使われていない(特に2バイト長の)命令は実装されていない!(^^;
エミュレータを作る上で最も面倒と思われるフラグ生成は、V30自体での計算結果で得られたフラグそのものを利用する構造となっている。
多分、V30で動くZ80エミュレータとしては最速に近いだろう(^^)
このプログラムはPC-9801には依存していないため、Pocket386でもそのまま動く。
メモリウィンドウの実現
PC-8801にはメモリウィンドウという厄介な機能が備わっている。
これはバンク切り替えなどで複雑なメモリ構成を持つPC-8801において、64KBのメモリ(RAM)空間を効率アクセスするための機構で、1KBの範囲で任意のRAMを覗き見する事ができる"すぐれモノ"だ。
N88-BASICのインタプリタはこの機能を巧みに活用して動いている。
私が所有しているアルフォスはテープ版であり、ローダーはBASICで書かれている。
そのため、BASICを動かすためにメモリウィンドウを実装する必要があった。
このメモリウィンドウをきちんと処理しようとすると、メモリアクセスのたびにアドレスチェックと変換が必要となり、10MHzのV30でまともな速度で動かなくなってしまう。
そこで64KBのメモリ空間を64つに分割して、それぞれの領域でのセグメントを設定するテーブルを持つ事にした。
一種のMMUもどきっぽい構造を入れたわけだ。

世にも恐ろしい手書きの概念図…
この構造のおかげで、本来であればバンク切り替えしなくては見ることの出来ないN88-BASICのROMなどでも、面倒なアドレス変換を意識する必要が無くなった。
その代わり……と言うには大きすぎる代償だが、メモリアクセスは全領域で一様に"遅く"なる事となった(TT)
640x200x8色の画面モード
PC-8801では640x200x8色の画面を、アドレスC000h以降の16KBをバンク切り替えする事で、RGBの各プレーン用VRAMメモリを用意している。
青、赤、緑の3プレーン分あり、必要に応じてバンクを切り替えながら絵を描画する。
バンクの切り替えはI/Oポートに値を出力する事で行われる。
PC-9801上のエミュレータではI/Oポートを監視していて、バンクを切り替える動作がくると上記のMMUのようなセグメントテーブルを書き換えて、別のアドレス(本来のPC-9801でのVRAM)を指すように工夫をした。
これで面倒なアドレス変換をせずとも高速にVRAMへアクセスする事ができる。
解像度については、そもそもPC-9801には640x200x8色を表示出来る機能が備わっている。おそらくPC-8801との(BASIC上の)互換性維持のためと思われるが、これはアルフォスを動かすことにおいて有利に働いた。
パレット機能
パレット機能についてはPC-8801とPC-9801でほぼ同じ機能があるが、パレットレジスタへ書き込むデータについてPC-8801との互換性がない。
ここは簡単なプログラムでこねくり回し、問題が出ないようにしていた。
Pocket386で動かすために…
まずは画面モードの設定が必要だ。
PC-9801ではハード的に640x200ドットモードに切り替えをしているが、この部分をEGAモードで初期化するプログラムに置き換える。
この辺りはBIOSの機能があるので、それを利用した。
ちなみにコンパイラはLSIC-86を使用している。

マジックナンバー が多いのはごめん(TT)
次にVRAMのバンク切り替えについて検討する。
PC-9801ではMMUっぽい構造を利用してアドレス変換をしていたが、Pocket386ではVRAMのアドレスは変えず、書き込みポートを操作するコードを追加した。
例えば青プレーンの選択はこんな感じ。

マジックナンバー が多いのは(以下略
パレットの切り替えについては思いっきりドハマリした。
先に結論を言ってしまえば、カラー番号がPC-9801とIBMPCとでは違うのだ(^^;;
日本人的な常識(?!)としては、COLOR1は青、COLOR2は赤、COLOR4が緑だろう。

だけどAT互換機の世界では、COLOR1が青、COLOR2が緑、そしてCOLOR4が赤なのだ!


早い話がVRAMのプレーン012が青赤緑なのか、青緑赤なのかの差だ。
この違いにしばらく気が付かず、なぜパレット変換に失敗するのだろう…と悩んだ(TT)
気がついてしまえば一瞬だけど、これは思い込みによる盲点としか言いようがない(^^;
移植してみる!
上記の情報に基づいて、PC-9801上で動いているPC-8801アルフォスを移植する。
DOSBoxで動かしたプログラムの実行結果と、Pocket386の動作結果が同じになることから、移植作業については、DOSBoxを積極的に活用する流れとした。
DOSBoxの結果
Pocket386実機の結果
まずはビデオモードを切り替えるコードを追加。


え!?
ビデオモードを切り替えただけで、画面にそれっぽい絵が表示された!
そうか、PC-9801とAT互換機ではVRAMのアドレスが重なってるところがあるのか!
これは画面見ながら動作確認が出来るのでラッキーだ!
ゲーム画面で化けたような文字が見えるのは、PC-8801のテキスト画面への出力が化けて見えているのが原因だ(そもそも表示してるのがダメ)。
次にVRAMの各プレーンに対しての書き込みを修正しつつ、テキストVRAMへの出力を廃止した。


よしよし、なんとなく見慣れた感じの色化けをした画面になった!(^^;;
ちゃんと各プレーンに対しての書き込みが出来るようになった証拠だ!
そして最後にパレット情報をAT互換機の機能と合わせてみる。

んー???なんとなく色が違うぞ??
そうか、16色表示出来るからカラー番号の0〜7はちょっと暗いのか。
そう思って色番号を+8してみたが、どうも色が合わない。
仕方ないので1色ずつパレット番号を合わせる仕組みを入れてみた。
変換するパレット番号を先頭から0,9,4,5,12,13,14,15にした。

そうそうそう!こんな感じの色よ!(^-^)/
DOSBoxでビルドしたEXEファイルを、Pocket386へコピーして動かしてみる。

おお!一発完動!(^-^)/
あれ?1時間もしないうちに移植作業が終わってしまった…(^^;;
PC-9801からのプログラム移植作業って、こんな簡単に済んでしまうのか……。
これはすごくない??
もっとPC-9801からのゲームが移植されてもいいのに…と思ったよ!(^-^)
おわりに
元々PC-9801で動かしていた時点でもゲームが出来る状態ではなく、基本はデモを見てるだけの機能しか無かった。つまり構造的にキー入力が入らないのだ(^^;;
せっかくPocket386で動かせたのだから実際に遊んでみたいな…と思ったけれど、エミュレータの構造を変更せねばならず簡単ではない事がわかった。
今回も見るだけアルフォスとなってしまったけど、自己満足度は高い!
みんなもPC-9801からのプログラム移植やってみよう!(^-^)
ではまた次回!(^^)ノ
ホバーアタックを動かしてみた!

多忙な状態が続く毎日!
そこにストレスフルな事件が起きちゃった日には、もうこれは仕事にならない!(TT)
またしても丸24時間をレトロにさわる時間と割り切っちゃう事にした!
いつも思うんだけど、チャレンジ開始時には脳みそがパチっと切り替わる。
この瞬間がたまらない!(^^)
今回は人生で1度も触ったことの無いマシン、SHARP X1にチャレンジ!
知ってる知識といえば…
・クリーンコンピュータ
・カセットが2700ボー
・VRAMがI/Oにある
・8色使えるPCGがある
くらいの情報のみ。
動いてるところを見たことがないマシンのエミュレータなんて、JR-300みたいなモノじゃないか!しかも今回は手元にX1の資料がいくつもある!

昔から「マシンは買えないけど本ならば…」と所有してないマシンの本を買ってました!
これだけあったら作れるかなぁ…と思ったけど、まだまだ懐疑的(TT)
だって起動した直後の画面すら想像できてないんだよ?(T-T)
まずはプログラムリスト!
資料があろうがなかろうか、手元にないと困るのがプログラムリスト!
何を動かしたいのかを決めて、限定的にエミュレータを作るのが勝利への道だ!
手抜きとも言う、いや言わない!言わないで!(TT)

まず動かすゲームソフトは、工学社のホバーアタックに決定!
これが出た時、8色出るPCGってステキ!!!と心底思った(^-^)
ただ、当時(作り始める今も!)の私では、ホバーアタックのどこがPCGで、どこがGVRAMなのか区別がついてなかった。
普通に考えたらスクロールするマップはPCGだよね…上に表示されてるテキストは??
そんな秘密も探りつつ、エミュレータを作っていくのが良いだろう!
ちなみにBASICプログラムのほぼ全てはPCGの定義命令だったため、このためだけにBASIC起動させるのは厳しいなぁ…と思い、別の形式で持つこととした!

このホバーアタック・エミュレータは、IPL-ROMもBASICも載っていない!

マシン語ダンプリストは1CA0h〜68FFhまでと少し長めだったが、お得意の自作ダンプエディタで楽しみながらOCRしまくったよ!(^^)
何も考えずに起動してみる!
メモリの中身をホバーアタックが起動出来る状態にして、おもむろにPCの値を1CA0hに設定してプログラムを起動してみる。
すると、どうやら何かのエントリを呼び出してるもよう。
これが…何なのかさっぱり分からない(^^;;
BASICインタプリタ自体が載っていないため、もしもBASIC内部のルーチンを呼び出していたらアウトだ(TT)
調べてみると、6つのエントリが呼び出されていた。
1文字表示
テキスト画面クリア
グラフィック画面クリア
ベルを鳴らす
サブCPUからのデータを受信
サブCPUにコマンドを送信
……サブCPUってなんだ?!(@_@;;;
え、CPU2つ載ってるんだっけ、X1って…?
いきなり知らない話が出てきて焦る焦る!!
とりあえず呼び出されたエントリを片っ端からC9(RET)に置き換えていく!
プログラムを1周回す(と私は表現してるが…)のが大事なので、解決したい気持ちはあるけれども後回しにする!
そうこうしているうちにプログラムが止まらなくなり、何かを実行し続ける状態になった。
この状態でI/Oのメモリダンプを見ると、なにやらグラフィック領域にデータが書き込まれていた!VRAMの内容を可視化してみたところ、見えたのがコレ。

うーん……何か幾何学的な???
HISCOREとかWAITはグラフィックで表示されてるんだ!?それにしても、この模様はなんだろう…うむむ、何か意味がありそうでなさそうで、これは悩む(^^;;
あと、テキストがWIDTH40の時は、グラフィックも320x200になるらしい!
テキストとグラフィックは分離しているのに影響を受けるのかー、これは面白い(^^)
あれ??テキストとグラフィックは、グラフィックの方が手前に表示されるんだ??
感覚的にテキストが前!っていうイメージがあったので、ちょっと驚いた(^^;
テキスト画面を表示!
グラフィックが化ける件は少し時間がかかりそうだったので、テキスト画面の表示を先にやっちゃおうと思った!

………なんか可愛いんですけど…(^-^;;;
色が変なのがあるけれども、PCGキャラクタをノーマルフォントで表示しちゃったら、こんな可愛い感じになってしまった!動画を撮っておけばよかったと後悔w

その後もPCG表示が化けてみたり……

色が緑一色になっちゃったりと紆余曲折ありましたが、ようやくなんとか…

ようやくそれっぽく表示された!!!
グラフィックのゴミは、どうやらパレットを反映させたら消えることとなった。
GVRAMをワークにでも使ってるんだろうか…??
これでよしよしと思いつつデモを見ていたら……

なんか画面が激しく壊れる…orz
BIOSなのかIOCSなのか、それともBASICのルーチンなのか不明なのだが、1文字表示処理を独自で実装してる。
しかし肝心の使い方が分からないため、座標はワークエリアから直接取ってきたり、座標更新の仕方など分からない事が多すぎる…。
何か別のエントリを呼び出しているのかなぁ…とか思いつつ、そういえばテキスト画面クリアの処理を入れてないままだった事に気がついた!
これで解決かと思ったが、画面は壊れたまま…なんじゃー(TT)
結局、突破口になったのは画面左上に表示されてるCLの文字。
これは多分キャラクタコードの12 が表示されてるんだな…と思った時、PC-8001の画面クリア(PRINT CHR$(12))を思い出した。
それと同時に1文字表示処理はコントロールコードが有効なのかと気がついた!
と…なると、画面クリアやカーソル移動などのコントロールコードも対応させる必要があるって事か…うん、きっとそうに違いない!
いくつかのコントロールコードを実装する事で、ようやくちゃんとした画面が出るようになった!
フォント問題
私はX1を所有しておらず、本体からフォントデータを抜き出す事ができない。
同様の理由でIPL ROMも使えないしBASICにいたってはカセットすら持っていない(TT)
フォントについては、実はPC-8001のものを流用させてもらっている。
大体は同じ配列なんだけど、肝心なところが違ってるケースもある。

7、4,1の枠がバケバケ(TT)
これはフォントを入れ替えないと対応ができない。
仕方ないので、フォントデータを読み込んだのちに、グラフ文字を入れ替える事にした。
フォントデータは著作物でもあるので、元データを変更するなどは極力さけたい(TT)

これでようやく表示がちゃんとできた!
おわりに
まだキー入力がまともに入らないのと、音が鳴らない。
音は24時間以内に対応が難しいので、ハナから入れる気はなかったが、キー入力はもう少し頑張りたいところだった!
24時間でダンプ入力からエミュレータの開発まで楽しんでみたけれど、今回は良く知らないマシンのエミュレータだったので、楽しさも倍増だった!
よーし、またこれでお仕事頑張れるよ!(^-^)
ではまた次回!(^-^)ノ
Cardputerでプログラミング!

前から少しだけ気になっていたCardputerを手に入れた!
少しだけ…という書き方がアレだけど、私の印象は「この小さな液晶と小さなキーボードで何かやる気が起きるんだろうか?」だったからだ。
でも、いざ買えるチャンスが訪れたら迷うこと無く手に入れてしまった(^^;;
SNSでの盛り上がりも後押ししたのかも知れないが、あとづけの理由としては某原稿の締切が近かったけどネタが無かったという事情もあるw
#本当は某原稿のためにギガンテスを動かしたはずなんだけど…orz
実際に手に入れてから、ようやくスペックを調べ始めた。
本体右上にM5StampS3がペタンと載っているのと、画面サイズが240x135ドット。
あれ?この解像度はM5StickC Plusと同じだ!うむむ、過去にM5Stickを触った時には、効果的な使い方が出来た覚えがない…。
過去のブログを参照してみたけれども、やはり画面の狭さに四苦八苦している様子がうかがえる。うーん、やっぱり今回も画面サイズで苦労しそうな予感…汗
開発環境の準備
まずは開発環境の整備だけど、これはM5Stackで使っているArduino IDEを利用すれば簡単に構築出来る事がわかった!特に悩むこともなくインストール出来た!
開発環境が一本化されてるのは本当に助かる(^^)
新規で環境を構築する場合でも、上のドキュメントに詳しく書かれているので、チャレンジしてもらいたい(^^)
動作確認
とりあえず、画面表示とキー入力、SDカードからの読み込み辺りをテストしてみよう。
表示系はM5Stackを扱ったことがある人ならば悩むことは無さそう。


setRotationで画面を回転させないと、左側が上になってしまい期待した感じの表示にならない。そのままでもテト◯ス作る分には良さそうな気がする(^^)
キーボードはサンプルをそのまま使っているが、特に困った点は見受けられない。


ANK文字は普通に取得できるけれど、okやoptなどは違う方法で得る。この辺りはサンプルとライブラリのソースを見てもらうのが確実かと思う(^^)
SDカードはサンプルが存在しなかったが、我らがNochiさん(@shikarunochi)がソースを開示してくれた。これをそのまま使えばSDカードへのアクセスが問題なく出来る。
きっとまもなく @lovyan03 さんが Lovyan Launcher for Cardputer を作ってくれると思いますが、その前に @TobozoTagada さんの M5Stack-SD-Updater 単体動作を試してみました。
— Nochi(ドウスル?▮) (@shikarunochi) 2023年10月22日
bin ファイル名直接指定で、プログラムを入れ替えてます。いい感じに動作します~。 pic.twitter.com/gqedkSMCc7
ファイルをフルパス指定にしないと書き込み時に失敗する現象が出た。単にフルパス指定をすれば済む話なので特に問題はないと思うけど、念のための注意喚起(^^)
他にもCardputerは多彩なハードウェアが載っているみたいだけど、私の用途ではあまり使わ無さそうな気がしていて調査をしていない…汗
マイクとかスピーカーとかBluetoothとかWiFiとかを使って、優れたソフトウェアを作れる人が羨ましい(^-^;;
念のため、ライブラリのソースは読んでおくと良さそうだ。
どのくらいのサイズまでmalloc出来るかを知りたかったのでメモリマップを探してみた。
https://dl.espressif.com/public/esp32s3-mm.pdf
コレを見て「あ、メモリがワリと素直」と思ってしまった(^^;;
命令キャッシュが32KB、データキャッシュが64KB、汎用的に使える領域が416KB…と解釈したら良いのかな…?
まぁでっかいメモリ領域をアロケーション出来そうな雰囲気があって、かなり安心した!(^^)
知れば知るほど、潤沢なCPUパワーと大きなメモリ、適度な表示サイズのバランスが良いのかも…と思うようになってきた!(^0^)
CP/M80の移植
てっとり早く何かを動かしてみようと思ったので、過去に作ったCP/M80を移植してみた。
ここのブログでは何度も何度も出てきているので詳細は省くけれど、何年か前に私自身がスクラッチから開発したプログラムだ。
開発当初はcursesライブラリを用いていたが、その後SDL2へ移行し、フレームバッファ直アクセス版やM5Stack版など、多岐に渡る改造がされている。ソースもちゃんとまとめていないので、全部書き散らかした感じだ(TT)
今回はM5Stack版を元にCardputerへ移植してみた。移植と言っても画面サイズの違いとキーボードからの読み込みの違い、そしてSDカードに関しては初期化さえきちんとすれば、あとのアクセスはライブラリが吸収してくれた。


「動かすぞ」と思ってから30分掛からずに動いてしまったCP/M80。むしろ画面解像度の狭さから、表示をどうしようか…と悩む方が時間かかったかも?
ちなみにフォントはPC-8001のモノを利用している。


悪ノリしてPC-6001のフォントに変更して、ついでに背景もそれっぽくした!
BASICの画面とあいまって、PC-6001が動いてるようで楽しい(^-^)
Arduino BASIC
同じく、過去に移植してあったArduino BASICをCardputerへ移植してみた。
「Arduino BASIC」→「SMART Response XE」→「RaspberryPi Pico」と何段階にも渡って移植されてきていて、特に私の代(Pico以降)はソースを適当に書いているため、とてもひどい(TT)
Picoからの移植はちょっと大変だった。
元々、PicoではLCDへのアクセスを独自で書いていたので、gpioやspiといったハードベタベタなソースコードになっていた部分が多かったが、これを全てM5ライブラリに置き換えた。
BASICの命令にグラフィック命令を拡張する改造もしてあった。
個人的な好みによりテキストとグラフィックを完全分離した。
内部でフレームバッファを3つ持っていて、それぞれテキスト用、グラフィック用、合成用としてある。
240x135x16bitの大きさを持つバッファを3つも確保したが、内部メモリの多さに助けられた。
BASICの駆動およびフレームバッファ生成はCore0で動かし、スクリーンを合成してLCDへ出力(push)するのはCore1で実行している。そのため、BASIC側の動作状況に関わらず、画面は定期的に更新される。
ただしSDカードがアクセスされた時は画面更新が止まる。


キーボードは本体付属の実キーがリアルタイムに読めるのに加え、Arduino IDEからのシリアル入力にも対応してみた。
実キーボードからの入力は、思ったよりも使い勝手は悪くなく、むしろ楽しんでプチプチ打ち込める感じだ!(^-^)
「FM-7グラフィックワークブック」という書籍に載っていたBASICプログラムを移植。
— PocketGriffon (@GriffonPocket) 2023年11月25日
SQR命令が無かったので、BASICでそれっぽいサブルーチンを作成。
それなりの計算量があるのにも関わらず、この速度!(^-^)
悪くないなぁ♪#Cardputer #BASIC pic.twitter.com/ONGaDYfF3b
さすがにESP32-S3ネイティブで動くBASICはめちゃくちゃ速い!
もう少しBASICの命令数が充実していたら、大きめのプログラムも作れそうな気がするんだけどなぁ…。これはもう独自で作るしか…(^^;
おわりに
せっかくのCardputerなのに、機能を活かしたアプリが作れていないのが残念だ(TT
こんな大きさで、キーボードと画面が付いた立派なコンピュータであることを考えると、妄想は果てしなく広がってしまう(^^)
きっと画面を縦方向に対応したテ◯リスあたりは、どなたかが作られるのではないかと思う(^^)
無事に原稿も書けたので、これにてCardputerは封印するけれども、ちょっと使っただけでも楽しいマシンだと思った!
また次に使う機会があれば…それまでにアイディアを温めておきたい(^^)
ではまた次回!(^-^)ノ
ギガンテスを動かしてみた!

このところ、実務が異常なほど忙しくて、全くレトロを触れていない…。
このままではいかん!胃に穴が空いてしまう!(ToT)
丸24時間をレトロさわる時間と割り切って、休息=プログラミングをする事にした!
……と言っても、24時間で作れるようなものなんてたかがしれてる。
でもせっかくやると決めたのならば、ある程度まとまったサイズのものを作りたい。
いろいろと思いを馳せてみたが、やはり私はエミュレータ作るのが楽しいなぁ……。
でもPCのエミュレータなんて24時間で作れるわけないじゃん…orz
唐突に話は変わるが…
PC-9801用の「ギガンテス」というゲームをご存知だろうか?

工学社I/Oの1985年5月号に掲載されていた、縦型のスクロールシューティングゲーム!
タイトルにもある通りタイニー版という事で、ダンプもたったの50KB!(泣

この見開きページで10.5KB。これの5倍くらいの量がある…。
当時であっても「これを打ち込む人いるんだろうか?」とマジで思った(^^;;
でもきっと打ち込んだ方いたよね!マジですごいです!(^o^)/
これを打ち込むとして……動かすとか?動かしちゃうとか?そんな事出来る?
そんな事が脳裏に浮かんでしまったから、さー大変だ!!(@_@;;
こんな強引な流れからエミュレータ開発へとなだれ込んで行くのでした…w
エミュレータ構想
ダンプリストを打ち込むのは根性があれば出来る気がするけど、問題はコレを動かすエミュレータだ!
残念ながらPC-9801のエミュレータは開発経験が無く、これを1から作るのなんて24時間で出来るワケがない!
ただ…ちょっと思うところがあって。
ギガンテスの掲載記事を見てみると、なーんとなくだけど…PC-9801というよりは、8086+GDCという構成であれば動くような気がしてる。
PC-9801のアーキテクチャには依存度が少ない雰囲気というか。
つまりPC-9801のBASIC ROMは極力使ってない感じがするのだ!
だとするとN88-BASIC(86)は起動する必要がなく、それならば開発するエミュレータの敷居はどどーんと下がる。
汎用エミュレータを作るのに比べたら労力は1/100以下だ!(適当なる当社比)
そう、目指すべき方向はPC-9801というハードをエミュレーションするのではなく、ギガンテスを動かす最低限のハードのエミュレータだ!(^-^)
まずはダンプ打ち込み!
何はともあれ、掲載されているダンプを打ち込まなければ話が始まらない!
ここで!我が家でのダンプ入力方法をご紹介してみたい!(^-^)
つい最近までの私は、ダンプリストを手入力する事をモットーにしていたが、ここ最近は独自で開発をしたダンプリスト入力ツール(OCR対応)を使って楽してる!(^^;
OCRするために、まずはダンプリストの写真が必要だ!

なんともシュールな……w
ダンプリストの上に透明のアクリル板を乗せて歪みを無くし、タンブラーの上に乗せたiPhoneでピントを合わせて写メを撮る!明るい方が良いと思ってライトも装備!
我が家にある何の変哲もない道具を使って写真撮ってるよw

撮った写真がこんな感じ。この写真を……

iPhone上の写真アプリで大雑把に枠を合わせ、色彩を「自動」「コントラスト最大」「明るさ最大」にすると、こんな感じのパキっとした写真になる。
この写真をダンプリスト入力ツールでOCRする。




あ、惜しい!ちょっとだけ読み取り間違いがあるようだ。

取り込んだ写真とバイナリエディタのウィンドウを並べたら比較も簡単!
どうやら13→18、00→09の読み取り誤認のようだ!
256バイトのうち3つが間違いということは、認識率98.8%!
ちなみにこれは認識率が悪い方で、全く誤認ナシというのが多かった!
全体での認識率は99.9%超えてると思う!すごい!(^-^)
こんな感じの工程で作業を進めていき、約5時間で50KBのダンプリストを入力出来た!
一番長いのは写真を加工している時間だ!(ToT)
これが自動化出来たら2時間以下になるんじゃない?
ダンプリストの入力革命まであと少しだ!(今の時代に?
エミュレータ作成開始
目的はシンプルに「ギガンテスが動けば良い」だ!(^-^)/
それ以外の機能は全て対応しない事を心に決めて作業を進める!
手抜き作業は得意中の得意だ!←自慢していーんだろうか?
解析用に念のため準備をしておいた方が良いだろう。
過去に文豪ミニ5を解析する際に新規開発をしていたV20用逆アセンブラをそのまま使うことにした。
ギガンテスのプログラムはいたってシンプルで、テーブルジャンプは2箇所のみだった。おかげでプログラムがとても追いやすくて助かった!(^^)
CPU
まずはCPUエミュレーションの準備。
これは過去に開発していたV20エミュレータをそのまま使う。
ギガンテスはPC-9801/E/Fが動作対象となっていて、この頃のPC-9801はCPUが8086だ。V20は8086との互換性があるので、そのまま流用が可能というわけ(^^)
ギガンテスのプログラムは、初期状態ではVRAM領域に配置される。プログラムが実行されると、内部で自分自身をメインメモリへコピーして動き出す。
雑誌掲載時の原稿に書いてあったが、ゲームのキャラクタは4ドット単位、弾は2ドット単位に描画される。これは実行時にリアルタイムにドットをずらしているのではなく、プログラムの初期化部分であらかじめドットをずらしたデータを用意するみたいだ。
そこの処理でシフトとローテイトがたくさん出てくる!
こういう部分でバグが出ると原因が分かるまでがとても長いので、慎重に確認作業を進めていく。
そしたら……案の定、動作が変になるバグが発生!
あれれ…ダンプリストの入力間違いか、それともV20エミュレータのバグ???
動作を追っていくと、どうやらV20エミュレータのバグが発覚(T-T)
うむむ…CP/M-86とかもちゃんと動いていたのに、まだバグは残ってるのねー(T^T)
そんな事を考えつつ修正をしていくと、今度は実装されていない命令に遭遇w
AAAとAAS!見た覚えあるけど動作を暗記してない(^^;;;
わーん!ぼろぼろじゃないかー!と泣きながら対応を進めるハメに(^-^;;
ソフトウェア割り込み
ギガンテスで呼び出されているソフトウェア割り込みはINT18のみで4種類ある。
1、CRTモードの設定
2、表示領域の設定
3、テキストVRAM初期化
4、ユーザー文字定義
1と2はそれっぽい動きをしてやれば良いだけ、3はメモリクリアすればOK!
問題は4の文字定義。
これは16x16ドットの文字を定義するものだけど、PC-9801って文字定義をどのメモリに格納してるの??(@_@;

よくわからんけど、テキストVRAMを描画する時に処理を横取りすればなんとかなりそう!
解析してて気がついたけど、ゲーム中には使われていないであろう「PLAYER 2」という文字の定義もあった。パッケージ版では2人(交代)プレイが出来たんだろうか(^^)
ハードウェア割り込み
ギガンテスで使われているハードウェア割り込みは2種類。
・タイマー割り込み
・キーボード割り込み
これらをそれっぽくエミュレーションしてやる必要がある。
ちなみにだけど、タイマー割り込みは何の対応もせずに動いてしまった。
プログラム中にCPUのクロックが5MHzなのか8MHzなのかをチェックしている箇所はあったが、タイマー割り込み自体がどこに使われていたのか謎(^^;;
素直に考えれば、画面切り替え時に参照しているはずなんだけど…汗
キーボード割り込みは、キースキャンを行い必要なデータをゲームの都合よくワークエリアに格納する構造になっていた。
本来であればPC-9801のキー入力をエミュレーションするべきなんだろうけど、それはちょーっと面倒くさい!
最低限の対応のみやろうという事で、SDL2のキーイベントをそのままゲーム中のワークエリアに入れ込む事にした!絶対アドレスに直接データを入れる暴挙!(^^;;

該当のキーが押されたらビットを立て、離されたら落とすだけの簡単処理! (^^)
GDC(Graphic Display Controller)
ギガンテスでGDCの対応が必要なのは、表示領域の設定とスクロール処理だ。
PC-9801の640x400ドットという画面構成に対し、ギガンテスではタイトル表示に512x400、ゲーム中は512x200ドットという構成になっている。
そしてゲーム中はVRAMを2つに分割し、2画面切り替えという方式も行っている。
初代PC-9801は画面が640x400の1画面しか無く、はてどうやって2画面切り替えをしてるんだろう…と思っていたが、画面を640x200ずつに分割をしてスクロールの値を操作する事で切り替えを行っていた。なるほど、確かにこれなら実現出来るね!(^^)
これらの機能をそれっぽくエミュレーションしてやれば、GDCモジュールを全部持ってくるなんて大掛かりな事をしなくても良い事に気がついた!(^^;
手を抜けるところはトコトン抜くよw
タイトル画面と自機がやられた時に表示される画面で、文字がラインごとにちょっとずつ表示される演出、実はこれもGDCの機能だ。「1行(=16ドット)のライン数を設定」というコマンドを使っている。
ゲーム中、ここでしか使われていない機能だけど、せっかくだったので対応してみた(^^)
開発は続くよ…
ギガンテスの内部説明をたくさん書いたけど、これだけ解析したら作るのは簡単!
……なんて思っちゃダメよ(T-T)


最初に表示された画面なんてこんなんよ?(^^;;;
これを見て「よーし画面が出た!お楽しみはこれからだ!」って前向きに思える人でないと、エミュレータを作るのは厳しいのかもしれない(^^;;

ようやくそれっぽい画面が出た頃。
横を512ドットにした時、VRAMの扱いをどうしたら良いのかが分からず試行錯誤してたw
メモリ的に640ドット分のサイズがあって次の行へ行くのか、それともメモリ自体も512ドット分になっているのか…。
実験してみた結果、どうやら横512ドット分のVRAM容量しか無いらしい事が判明。

↑ゲーム画面の縦が200ドットだと気づかずに実験してたあたり。
パレットをあわせる事で、なんとなくそれっぽいゲーム画面が出てきて嬉しい。

画面を512x200に合わせられたところ。まだスクロールを実装していないので画面の途中が描き換わって見える。
縦を引き伸ばして描画するのが面倒だったので、1ラインごと飛ばして描画してる。画面で見るとそれっぽいけど、写真に撮ると色が薄くなるね…汗

ゲーム開始時の文字の色もちゃんとした気がする。
雑誌掲載版のギガンテスはタイトルが表示されないらしいけど、これが正解??
画面下の水色文字部分は点滅するらしいけど、テキストVRAMのブリンク機能を上手に使って実現してるっぽい。
でもテキスト画面のブリンクを実装するのは面倒なので、ここは点滅せずで諦め(をぃ

GDCコマンドの表示範囲設定をちゃんとしていないので、本来見えてはいけない左側が丸見えな状態(^^;; 画面下17ドットが表示されない不可解なバグに悩むも突破口が見えない…。

テキストVRAMも反映されるようになり、スコア、残機、ダメージゲージが表示された!
テキストVRAMは、横を32文字と設定してもメモリ上は40文字分が確保されるみたい。それに気づかなくてしばらく悩んだ!(^^;;
完成したギガンテスエミュレータ
PC-9801のギガンテス
— PocketGriffon (@GriffonPocket) 2023年11月19日
それっぽく動きました!(^^)
後ほど開発記をブログに載せまーす!#PC9801 #ギガンテス #エミュレータ pic.twitter.com/iwLg2VnhcJ
こんな出来で「完成した」と書いて良いんだろうか…(^^;;
適当にも適当すぎる実装なのにw
でも作ろうと思ってから24時間経たずにして動いてしまった!
書いたソースコード量で言えば(V20エミュレータを除くと)1000行程度とコンパクト。コメント抜かしたら700行程度に収まっているのかも?
思った通りPC-9801に依存している部分は限定的で、これならば同じく8086+GDCという構成のMZ-5500などにも移植は難しくないだろうなーと思った(^-^)
ちなみにPC-9801のROMは一切使わずに動いてます!
M1 Mac+SDL2という環境で開発しているので、同じような構成(Windows+WSL、Linux)であればコード無変更で動くかも?(^^;
よし!納得の行くところまで作れて満足した!
仕事に戻りまーす!(^-^;;;
ではまた次回!(^-^)ノ
2023.11.19追記
ついでだったのでSHARPの電子辞書Brainでもギガンテスを動かしてみた!
SHARP の電子辞書 Brain で動くギガンテス!(^^)
— PocketGriffon (@GriffonPocket) 2023年11月19日
速度的なプログラム最適化は一切してないけど、それっぽい速度で動いてる?
やっぱり16ビットCPUのエミュレーションは遅くなっちゃいますね(^^;;;#Brainux #Linux #SHARP #Brain #電子辞書#PC9801 #ギガンテス pic.twitter.com/avNoB09h5O
しれっと動かしてみたけれども、実はけっこう大変だったw
SDL2→フレームバッファ直描きに修正するのは簡単だったんだけど、実はプログラム中にお作法の悪いメモリアクセスをしている箇所が多々あって、それの修正が大変だった!
これは「Brainで何か動かすと楽しい!」という実験という事で!(^^)
IBM ChipCard VW-200起動実験!
簡単にX(Twitter)で書けばいいや…と思ったけれど、書くことを想像していたら注意事項がたくさんあったので、ブログ化しといた方がいいか…となった(^^;;
念のため先に書いておきたい!(ToT)
ちゃんとした電気的な理論に基づいて実験してるわけではないので、ハード屋さんから見たら「ふざけんな!トンデモない事やってるぞ!」的な行為な可能性が高いです。
同じことをしてみたら大切なVW-200が壊れてしまった…となっても私は責任を負えない(T-T)
あくまでも自己責任で試してください!(T^T)

実験する前に…まずは(可能だったら)VW-200の電源が入るのかを確認してみて!
これにはPCMCIA Type2のスロットがあるPCが必要だ!
しかも、各種ドライバが正しく設定されていて、すでにPCカードが使える状態になっている必要がある…かも?
このPCのスロットにVW-200を差し込んでみると……

壊れていないVW-200であれば、この時点で画面が点灯する。
だけど…面倒なことに、起動させる事の出来るPCと起動させられないPCがあるっぽい。
どんな条件なのか私も分かってないが、手元で実験してみたところ、
・HP200LX 物理的にスロットに挿さらない
・ME-386 起動する
↑海外のIBM PC/AT互換のハンドヘルドマシン
というような感じで、起動するマシンの方が少ないのかも知れない。
おそらくだけどウルトラマンPC(PC-110)は確実に使えそうな気がする。
過去の実験
何年か前にVW-200の電極に直接乾電池を繋げる方法で、VW-200が起動するのを確認した事がある!(^^;;
確か単三電池の乾電池ケース3つの端子を、クリップで無理やりVW-200の裏面にある電源端子と繋げてみたのだw
そしたらVW-200の電源が入ることが分かった!
当時の写真があるはずなんだけど見つけられなかった…
相当カオスな状態での実験でした(^^;;;
でもこれで分かった事は、空気亜鉛電池でなくてもVW-200は起動する、という事だった!
電圧が同じであれば、おそらくVW-200は起動させられるんだろうという確証を得たのは大きかった(^^)
うまくいかない理由付け
ChipCard VW-200はPR2330という空気亜鉛電池というボタン電池を使用する。
そしてこのPR2330、すでに生産が終わっているみたいで入手がとても困難なのだ(T-T)
ダミー電池とか作ってみたらいいのかなぁ…とか、CR2032で代用出来る方法はないのかなぁ…とかいろいろと考えていた。
手軽に手に入るボタン電池が流量できないのは、電圧の違いによるものだ。
PR2330は1.5V、ボタン電池(例えばCR2032)は3Vなのだ(T-T)
3Vの電圧を、どうにかして1.5Vにできないか
そんな事を考えつつ、リチウムバッテリーの特性を見てみたら、電圧が下がり始めると一気に下がり切ってしまう特性がある事が分かった(T-T)
ちょうどよい1.5Vで安定してくれるはずないよね(T-T)
電池のサイズも違うからホルダに固定するのは簡単じゃない
という感じで、試す前に諦めてしまっていた。
それが……秋葉原の千石電商で初めてCR2330見て衝撃を受けた!!
この型番のボタン電池が存在する事を初めて知った!(^^;;;
同じサイズであれば電圧さえなんとかなれば行けるのかも??と頭をよぎってしまったw
準備するもの
起動するであろうVW-200本体
ボタン電池 CR2330
ソーラーモーター 03

勘の良い人であれば、このリストを見た時点で「お前、やりやがったな!」となるに違いない(^^;;
そう、結論から先に言えば、代替のボタン電池で起動させている!
多分ムチャなやり方
この先は、何の理論もへったくれもない方法を書いているので「へー、そんな事をやっちゃう人もいるんだね」くらいの感覚で眺めるだけがオススメだ!(^^;;
まず3VあるCR2330の電圧を下げる事をしてみる。
まずは失敗談を2つほど(^^;;
できる限り手元にあるもので済ませたいので、LEDライトの電源にボタン電池を3つ直列にして繋げてみた!(この時はまだCR2032を使ってた)

写真撮ってなかったけど、こんな感じのLEDライトがあるので、これの端子部分にボタン電池を繋げたよ!ボタン電池の容量は小さいから、あっという間に1.5Vまで下がって…と想像してたんだけど、何時間経ってもびくともしない(T-T)
丸2日くらい掛けて点灯し続けたら少し光が暗くなってきたので、よっしゃーとボタン電池の電圧を測ってみたら……3つのうち1つの電圧がどーんと下がっていて、残りの2つは新品同様だった…orz
てっきり平均的に電池が消耗していくと思ってたら、そうはいかないのね…(T-T)
失敗談その2!
3つのバッテリーを効率よく消費させたいので、それならばモーターでも動かせばいいのかな…と思い、手頃なモーターを入手した。

手に入れてから知ったのですが、ボタン電池ではモーターを動かせるほどの電流がないそうで、ピクリとも動かなかった…orz
3つも手に入れたのに、まるまる無駄になっちゃったよ(ToT)
そして成功したのがこちらの方法!

モーター作戦はダメなのかー……と思いながら千石電商のパーツを見ていたら、ソーラーパネルが置かれている横に「ソーラーパネルでも使える」モーターがあった!

説明を読んでみると、まさに今回のテストで使えそうな雰囲気!
先のモーター3つの失敗もあったので、コレ以上の出費はしないぞと思っていたけど、見つけちゃったからには試さないわけにはいかない(^-^)
同じく千石電商でCR2330を発見!

自宅にCR2325があり実験してみようと思っていたんだけど、ドンピシャサイズのボタン電池が存在する事を知らなかった!(^^;;
よーし、材料は揃った!!(^-^)
さっそく電圧を下げる実験をしてみよう!

はい!(^-^)
ボタン電池を固定して、モーターを回すだけ(^-^)b
ああ…この辺りで「ばかー!ばかー!」って聞こえてきそう(T-T)
このモーター、めちゃくちゃ静かなんですよ!
音がしないので動かしてる事をすっかり忘れてて、2時間ほどして見てみたらモーターが止まってた! しまった、バッテリーが0になっちゃったよ!……と思ったら、1.7Vくらい残ってたよ!
あれ、これはちょうど良い予感!(^^)
こうして約6時間を掛けて3つのボタン電池を1.7Vくらいまで落とす事に成功!
モーターが止まるまで待っていれば良いってのが楽ちんだった(^^;;
よーし、これで準備は整った!
本体に入れて電源を入れてみよう(^-^)

不思議な事に……この2つをハメた時点でVW-200がピッと音を出した!
へ?まだ2つしか入ってないよ?(@_@;;;
試しに蓋をしてリセットボタンを押してみる!

おお……おおおおおお、起動した!(^o^)/
正直なところ動くなんて思っていなかったけれど、きちんと動いてるよ!
でもなんで電池2つで動くの???(@_@;;

プログラマならば誰もが試すであろう256 x 256もちゃんと答えが出た!(^^)

使い方がさっぱりわからないけれど、カレンダーもキレイに表示された!
よーし!よーし!!(^o^)
おしまい
無理やり電圧を下げたボタン電池を使ってるので、リチウムの特性で一気に電池切れになる可能性が高い。連続動作時間は期待できないと思うので、早めに母艦となるPCと接続したいところだ…(^^;
それでもPCにも繋げずに単独で動いてるVW-200を見るのは格別!
これは感動するねー!(^-^)
動くと何か作りたくなっちゃうのはサガなのか……w
いや忙しいからやらないよやれないよやらないつもりだよ(弱
ご注意!
このブログを読んで「よしやってみよう!」と思った方、再度書くけど自己責任でお願いします(ToT) ヘタすると大切なVW-200を壊しちゃう可能性もあります。
読んでみて分かると思うけど、何か理論に基づいて動かしてるわけじゃないんだからねっ!
素人の実験に過ぎない事をご理解した上でお願いします(T-T)
ではまた次回!(^-^)ノ
CASIO FP-1100覚え書き!

FP-1100をげっとした!
最近、ブログを書いてる余裕すらないほど実務が忙しいんですけど、それでもやりたい事と、ちょっとやっちゃったけど忘れそうな事とかがいっぱいあるんですよね!(^^;
というわけで、今回はFP-1100の備忘録を書いてみる!

今回入手したFP-1100は、友人と共同で購入したもの。
今までは友人が使っていたが、もう思い残すことはない!?という事で私の手元に来た(^^;

そして私は、たまたまだけどFP-1100で使える拡張メモリパックを持っていた。
容量としては16Kバイトしかないメモリバックだけど、16KBって大きいよ!(^^)
これは秋葉原にある神田装備というお店のショーケースに展示されていたもの。
型番を見てすぐに「あ、これはFP-1100用だ!」と思ってげっとしていた!

脅威のバッテリーバックアップ機能付き!(^-^)
そういえばCASIOさんはFX-9000Pの頃からデータが消えないってのをウリにしてたね!
サイズ的にぴったりだったので、単5電池を2つ繋げて入れていた。
本当の電池は違うものを入れるんだろうなぁ……多分。
しかし電池ホルダのホールドが弱く、中で電池が外れてしまってバックアップが上手くできないという問題が発覚した。見栄えは悪いけれどテープでがっちり固定するよ!(^^;;

メモリパックへのアクセスはファイルディスクリプタPACK0:でアクセス出来る。
よし!これで安心してプログラム開発が行えるってモンですよ(^-^)
FP-1100の魅力
私自身、過去にFP-1100を使ったことはないけれど、いつかは使ってみたいと思っていたマシンの、かなり上位に君臨していた!

工学社のPIOという雑誌に書かれていた「サブCPUを制御して高速に画面描画を行っている」という情報を見て以来、いつかやってみたいと思っていたのだ!(^^)
こういう特殊な構造に魅力を感じる辺りがアレですが…(^^;;;
FP-1100付属のハードウェア解説書を見ると、C82-BASICは起動時にROMからRAMへコピーされ、それ以降はRAM上で動作しているらしい。ということはBASICの改造も比較的簡単にできそうな気がする!(^^)
メインCPUは言わずと知れたZ80で動作クロックは約4MHz。
VRAMが分離していることから、ノーウェイトで動いている気がする(勝手な予測)。
全体的にもっさり動く印象があるのは、おそらくBASIC内部でBCD演算をしているのと、表示が遅いせいなんだと思う。
そして表示系を司ってるサブCPUは、NECのμPD7801Gで動作クロックは約2MHz。
型番からZ80互換?と期待してしまったが、どうやら違うものらしい。
サブCPU側の事情については少しずつ書いていこうと思うけれど、噂ではかなり制限があるようで、こういった事情のあるマシンは大好きだ!(^-^)
なんとなくだけど、HC-80以上に苦労しそうな予感がバリバリにするw
メインのROMげっと大作戦!
何を解析するにも本体内部のROMをゲットしないことには始まらない!
まずは、FP-1100からROMを抜き出す方法を考えてみる。
てっとり早い方法はRS-232C経由でホストマシン(ここではMac)にコピーしちゃう事だけど、残念ながら我が家のFP-1100にはRS-232Cが付いていない(T-T)
じゃあ…というワケで、過去にJR-800で試してみた方法はどうだろうと検討。
この時はJR-800に表示させたダンプリストを、手作業で打ち込む方法を取った!
ROM容量は20KBだったけれど、かなーりの時間を要した覚えがある!
出張の移動時間にもJR-800とMacを広げ、ぷちぷちと打ち込んでいった(^^;;
今回、FP-1100のBASIC ROMは36KB分ある。
倍近い容量だよ!!無理でしょ…orz
この方法は努力と根性で出来そうな気もするが、失うもの(寿命とか)も多そうだ(T-T)
うーん、何か良い方法はないか…と考えていたところ、そうか画面に表示させたダンプリストを写真撮って、それをOCRしてみたらいいじゃん…!と思いついた!(^-^)
さっそく試してみるか!とやってみたところ……
画面に表示されたダンプリストを、OCRして入力出来そうかテストしてみた結果:厳しい!
— PocketGriffon (@GriffonPocket) 2023年9月2日
FP-1100にはソフトウェアPCGがあるから、HEX文字を定義し直してみようかな…果てしなくなりそうになる前に辞めます、はい…(-_-;; pic.twitter.com/sYtqc0HxAM
めちゃくちゃ認識率が悪い!!(ToT)
これはなぜなんだ??あれだけ雑誌の写真をOCRしまくってるというのに…。
もしかして……これはフォントの問題だろうか??
CASIOフォントではなくてNECフォントにしてみたら認識率が上がるかも?
よし、PC-8001のフォントを利用してダンプ表示をしてみよう(^^)
FP-1100のROMダンプ、PCGを定義してPC-8001のフォントを表示させるようにしたら、OCRの読み取りが劇的に改善された!!(^o^)
— PocketGriffon (@GriffonPocket) 2023年9月2日
とりあえずメインROMは吸い出せそうな予感!
…サブCPU側のデータはどーしたらいいんだ?(-_-;;
んー、簡単なプログラム作るしかないんだろうな…汗#FP1100 #CASIO pic.twitter.com/oAR7BpaiIq
FP-1100にはPCG定義命令があるので、これを利用して解決する(^^)
PCG定義が出来る文字は$E0〜$FFまでの32文字!
X1などのようにハードウェアで実現しているPCG機能ではなく、あくまでもソフトウェアで頑張るPCG機能のようだ!
試してみた結果、OCRの認識率が爆上がりすることが確認できた!(^^)
FP-1100のフォントとPC-8001のフォントの違いはこんな感じだ!
並べてみると結構違うんだなー(^^)


問題としては……1ブロック(256バイト)を表示するのに猛烈な時間がかかる。
256バイトを表示する速度!
— PocketGriffon (@GriffonPocket) 2023年9月2日
これを36KB分(144回)繰り返すのかーと思うとゲンナリ(><) pic.twitter.com/HC1BzGqsWj
動画で時間を確認してみたところ、256バイトを表示するのに約23秒!
写真撮って合計30秒。
36KB=144ブロックを写真撮るだけでも、休み無しで作業をしたとしても、最低で80分くらい掛かりそうな見込みだ(ToT)
これは……気が滅入りそうなので、時間があるときにちまちま進めるしか無いね(T-T)
でもこれでZ80側のROMはダンプできそうなメドがたった!(^-^)
これは一歩前進♪
サブCPU側のROMげっと大作戦!
次はサブCPU側のROMだ!
でも……サブCPU側のデータを読む方法なんてさっぱり分からぬ…orz
なんとなくだけど、サブCPU側にプログラムを送る必要がありそうな予感!


我が家にある唯一と言っても過言ではない技術資料を引っ張り出して読み漁る!
アセンブラも何もない環境で長いプログラムを作るわけにはいかないので、マシン語が極力小さくなるプログラムを考えてみた。
テストで以下にある写真のようなプログラムを作ってみた。

やってる事は、サブCPU側の任意のアドレスにある1バイトを表示する、だ。
70行80行がサブCPUに送るプログラムとなっている。
今回はハンドアセンブルしているが、プログラム的には以下のような感じ。
mov a,nnnn
mov $A000,a
ret
指定されたアドレスの1バイトを、サブCPUのメモリ空間の$A000に書き込んでいるだけのプログラムだ。$A000は緑VRAMの先頭を指していて、これで画面上に緑のドットが表示される!

120行目からのプログラムで画面上のドットを1つずつ調べ、1バイトのデータに再構成する。VRAMは世にも珍しい反転型というもので、例えば$00を書き込むと$FFが入るという奇抜なものだ!そのため、BASICのプログラムで反転している。
これでメインCPUでサブCPU側の特定のアドレスのデータが取得できる!
これを256回繰り返せば、任意の1ブロック分が表示できるという算段だ!(^^)
ちなみにNECの文豪ミニ5ZCという機種も反転型VRAMが使われている。
FP-1100だけではないということは、きっと何か反転型であるメリットがあるんだろうね…汗
おわりに
いまだかつて無いほど生活が忙しくなってしまい、なかなかレトロを触ってる時間が確保できなくなってしまった。
このFP-1100も取り組むまでに長い時間が掛かってしまいそうな予感がする。
気長に見ていってもらえれば…と思います!(^^)
ではまた次回!(^^)ノ