このところ、実務が異常なほど忙しくて、全くレトロを触れていない…。
このままではいかん!胃に穴が空いてしまう!(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で何か動かすと楽しい!」という実験という事で!(^^)