RX-78エミュレータを作ろう日記。 へっぽこプログラマは日々こんなこと考えながらエミュ開発してます(笑) 2005/3/14-15 めがきらさんから実機をお借りしてから結構経つのですが、全然手をつけて いませんでした。 今日は体調崩して会社休んで、夜には体調が回復した結果、ちょっとした 空き時間ができましたので、軽く作業をしておこうかと思います。 まずはROMイメージの吸出しから。 BS-BASICのカートリッジにはデータレコーダ端子がついていますので、 例によってモニタからイメージを保存して、それをwavに録音して、 バイナリに変換、の手順でやります。 内蔵ROMが$0000-$1fff, カートリッジが$2000-$5fff。 フォーマットは、長波長が1、短波長が0。 1バイトは1????????、????????はMSB→LSBで。 この辺はまあ手馴れた作業ですので、3時間程度でさくさくと。 ただ波長が妙にふらふらするみたいなので、長波長か短波長かの判断は 多少マージンを大きめにしてやる必要がありました。 それ以外のソフトは、SHIFT+STOPを押したまま起動するとモニタから 立ち上がります。 で、カートリッジにデータレコーダ端子が付いているものであれば BS-BASICと同じ手段が使えるのですが、そうでないものが問題。 カードエッジもピッチが普通の2.54mmではないみたいですし、カセットは 借り物だから殻割して解析する訳にもいかないし。 最悪、モニタ上でダンプを表示して、それをビデオキャプチャして 連番bitmapを吐いて、OCRに掛けるしかないかなあ。 今回も技術資料が少なめなんですが、マニュアルにメモリマップと、一部の IPL内ルーチンの解説がありますので、少しはましですね。 まず吸い出したROMイメージを逆アセンブルして、使用しているI/Oを リストアップします。 後は、周辺のコードからI/Oの内容を想像したり、メモリ周りだけ実装して 実際にCPUを回してみてログをとってみたり。 I/O周りで重要そうなのは、 $f1 VRAMのアクセスの読込みバンク指定? $f2 VRAMのアクセスの書込みバンク指定? $f4 キーボードステータス取得、カラム指定 $ff サウンド関係? くらいのようです。 キー周り以外は入力もなし、出力ばかり。 後は、初期化の際に数回アクセスしてるだけ。 で、適当にVRAMから画面生成する処理を追加してやったら・・・ なんかあっさり起動画面っぽいものが表示されてしまいました。 解析開始して3時間程度なんだけど、ええのんか(苦笑) 2005/3/15 体調も回復したので、今日は普通に出社。 まず、起動画面が化け化けな件から。 vramは、1byte=8dot。 これは普通なのですが、画面左からLSB→MSBというのは珍しいかも。 文字は横6dotなので、複数のアドレスにまたがって(!)描画されます。 これでも画面がいまいち乱れるので、$f1, $f2周りを調査。 b0-b2でアクセスするバンクを指定しているのですが、複数bitを立てて 同時に複数バンクにアクセスすることができるようです。 (白を描画するときは7を指定、など) I/Oのログを見るとキーボードを延々読みにいっているようなので、先に実装。 カラムに$30を指定すると全カラムの内容のORが得られるようで、これが 非0の場合、個別のカラムをスキャンする、という処理内容。カラムは1-9。 これはエミュレータ上で実際に操作して調査してやります。 しかし、キーマップが実際のキー配列と関係ない、これまた珍しい。 これでBASICが操作できるようになったので、実際に命令を実行しながら I/Oの調査を行います。 $e2がプリンタのビジー(b0)、ストローブ(b7)。$e3でプリンタ出力。 背景色の指定は$fcのb6-b4。 hsync, vsyncのチェックはしていないのかな? サウンドは、3和音+1ノイズというのはSN76489っぽい? 保留。 ジョイスティックはキーボード扱いっぽい? 割り込みモードはIM1。 BASIC上のタイマはCTという変数で取得するのですが、これが0.133721secで 1カウント。つまり60frame/secとして8fram毎に1カウントしています。 多分こいつ用に、hsyncで割り込み掛けてるのではないかなあと。 実装してみた感じ、やっぱそうみたいですね。 後は適当にUIF周りを整理して、取り敢えず公開。 ROM吸出し込みで10時間程度というのは、私自身にとっても新記録です。 I/Oマップは抜けだらけだけど、こんなんでも動くんだなあ。 目下の問題は、文字の色が変えられないこと。 VRAMのバンクセレクトとまた別口なのかなあ。 マニュアルにある仕様の、6画面、27色というのも気になるところ。 実はパレットがどこかにあるのかもしれない。 2005/3/16 サウンド周りの解析。 $10bに約880HzでBEEPを鳴らすルーチンがありますので、処理を追いかけて みました・・・そのまんま、SN76489みたいです。 eb3 : wr ff, 90 1 001 0000 ch.1 減衰=0db eba : wr ff, 8f 1 000 1111 ch.1 N = 111 1111 = 7fh ec1 : wr ff, 7 0 000 0111 で880Hzの音を鳴らして、 f11 : wr ff, 9f 1 001 1111 ch.1 減衰=無音 f11 : wr ff, bf 1 011 1111 ch.2 減衰=無音 f11 : wr ff, df 1 101 1111 ch.3 減衰=無音 で全チャンネルを無音に。入力クロックを逆算してみると、 f = C / (32 * 7f) [Hz] より、C = 880 * 32 * 7fh = 3,576,320 Hz 正確なクロックを確認するため、Moliceさんから頂いた腑分け用マシンを ばらしてみます。 使用している水晶は28636.36KHzなので、これを8分周したものでしょう。 CPUクロックの方は、7分周した4090909Hzかな。 ついでに基板写真の撮影とか、使用しているチップの確認とか。 実装自体は、EmuPIAからひっぱってきてチップ数減らして、beepの 処理をオミットしてやるだけ。 データレコーダ周り。 適当にI/Oのログを取ってみた限りでは、入出力とも$f0のbit0。 ただ前後の処理を見る限り、タイミング調整はタイマを使用せずに、 ループ命令で待機してとっているようです。 まあタイマチップとか載っていないですしねえ。 エミュレータで閉じた処理ならいいのですが、実機とのやりとりを考えると 難しいです。メモリウェイトとかM1サイクルとか、どうしたものか。 で、ついでに仮想マシンのイベントコールバック処理の見直しを。 drive_vm(clock)で大きなクロックを与えた場合、イベントの発生タイミングの 誤差が大きかったので、この辺を修正しておきます。 これは同じスケルトンを使用している全エミュレータに反映させないと いけないのですが・・・まあ各々のアップデートをするときにでも。 フルスクリーン時は、画面を640x480にしてStretchBltで2倍に拡大表示 しているのですが、これがCPUパワー食いすぎということで、 画面を320x240に変更して、BitBltで等倍表示するようにしました。 2005/3/18 まずデータレコーダから。 基本処理はEmuPIA7から持ってきます。 但し、こちらはリモート端子がないので、録音/再生開始のトリガは $f0のアクセスを使用しています。終了時は手動です。 出力したwavを聴いてみると、実機と比較しても概ね同程度の周波数が 得られているようです。 ROM吸出しに使用した実機のwavをロードすることもできました。 増設RAMカートリッジ。 $6000-$afffの領域(20KB)にRAMがあれば、少なくともBS-BASICは勝手に 認識してくれるようです。 但し、上位アドレスから順に埋めていかないと、途切れたところ以下の アドレスのRAMは認識してくれません。 パレット操作周りのI/O周りの解析。 実機でBS-BASIC上から色々いじって試してみます。 詳細は解析資料参照ということですが、とにかくけったいな仕様です。 例えばパレットも、VRAM 3プレーンから0-7の色番号を得て、各々に色を 割り当てる、というのが普通なのですが。 このマシンだと、プレーンごとに色を割り当てて、それを合成して表示、 という仕様になってます。 その他にも色マスクとか、なんのためにある機能なのか不明なのも。 3DグラフィックスのROMを吸い出してみました。 一応動いているっぽいのですが、タイトル画面の表示などが欠けてしまって います。実機の仕様的にはもう1画面ある筈なので、そちらの合成が必要 なのでしょう。 こちらはもう少し解析が必要そうです。 2005/3/18-19 3Dグラフィックスの表示が欠けている件の調査を行いました。 まず判ったのが、$f0の読込みプレーン指定と$f1の書込みプレーン指定の 仕様が違っているということ。 $f1では複数プレーンへの同時書込みを想定して、各bitで各プレーンを 選択するか否かを指定しています。 これに対して、$f0では1-6の値を指定して、プレーン1-6のうち読込み対象と なるものを指定するようになっているようです。 また、プレーン1-3の1画面の他に、プレーン4-6でもう1画面存在している ことが判りました。 こちらの画面のパレットは、$f8-$faで指定するようです。 この辺りを実装したところ、正常に描画されるようになりました。 プレーン1-3とプレーン4-6の優先順位を指定するI/Oがどこかにある筈ですが、 こちらはまだ不明です。 現状では、プレーン1-3を常時優先として実装しています。 ただ謎なのが、VRAMの容量。 192x184/8で、1プレーン辺り4416bytesを使用します。 これが6プレーンで約26kbytes。 本体に実装されているRAMが最大で30KBなので??? もしかしたら、プレーン4-6は画面サイズが192x(n<184)なのかもしれません。 この辺は実機で要調査です。 先日フルスクリーン時の解像度を320x240に変更したのですが、 自前のInterlinkでこの解像度が使用できないことがわかりましたので、 320x240と640x480の解像度を選択できるようにしました。 640x480の場合はStretchBltで拡大表示しますので、320x240が使用できる のであれば、そちらの方が高速に描画されます。 この辺のフルスクリーンの処理は、5〜6年前にsystem3をwin32環境に 移植したときのコードを延々使い回しているんですが、いい加減に DirectXを使用したコードに置き換えたほうがいいのかもしれませんね。 データレコーダ端子の付いていないROMカートリッジの吸出しのアイデア。 モニタ上でダンプを表示して、それをキャプチャしてOCRに掛ける、 というのは些か安定性の観点で問題がありそう。 モニタ上から、バイナリでプログラムを入力して実行することはできますので、 メモリ上のbit列を文字を使用したパターンとして表示して、キャプチャして、 適当な処理をかましてデータを取得しようかな、と。 例えば$2a12:$94の場合は、画面上に__#_#_#____#__#_#__#_#__(#は豆腐、 _はスペース)と表示する、とか。 表示された文字をOCRで認識するよりは、6x8dotの領域が白か黒かと判定 する方が、エラーは発生しにくいでしょう。 1行24桁でアドレス16bit+データ8bitを表示して、それを例えば1度に16行だけ 表示すれば、1画面で16bytes分を表示できる。 毎秒4コマくらいとすれば、$4000だけ転送するのに約4分ちょい。 2005/3/19 名古屋でAZUCOさんオフに出席するため帰省中。 丁度姉夫妻が来ていて、義兄とP6,P8本をネタに盛り上がりました。 義兄はpc6001mk2だったそうです。 3Dグラフィックスのために、ジョイスティックを実装。 これはキーボード扱いと判っていましたので、キーマップを再調査して、 適当に実装してやります。 例えば左上なら通常左+上、という入力になるところが、左上という 独立したbitが与えられているというのは珍しいですね。 2005/3/19-20 オフより帰還。 エミュレータの実装技術について色々と盛り上がりました。 で、自分の現在のノウハウを纏めた文章を纏めてみたり。 2005/3/20-21 データレコーダ端子のついていないカートリッジの吸出しについて。 モニタ上から、ROMの内容をドットパターンとして表示するプログラムを 作成してみました。 文字表示ルーチンなど、IPL内のルーチンが色々公開されているので 有難いですね。 ORG 0B000H JR START 18 12 // 1byteのパターン表示 DISP: LD E,01H 1E 01 DISP0: LD A,01FH 3E 1F SLA D CB 22 JR C,DISP1 38 02 LD A,020H 3E 20 DISP1: CALL 0C3H CD C3 00 SLA E CB 23 JR NC,DISP0 30 F1 RET C9 START: LD HL,02000H 21 00 20 // 画面非表示 LOOP0: XOR A AF OUT (0FEH),A D3 FE // CLS LD A,06H 3E 06 CALLA 0C3H CD C3 00 // 1画面に22bytes分を表示する LD B,016H 06 16 // 1行分の表示 LOOP1: LD A, 02BH 3E 2B CALL 0C3H CD C3 00 CALL 0A5H CD A5 00 LD D,H 54 CALL DISP CD 02 B0 LD D,L 55 CALL DISP CD 02 B0 LD D,(HL) 56 CALL DISP CD 02 B0 LD A,02BH 3E 2B CALL 0C3H CD C3 00 INC HL 23 DEC B 05 JR NZ,LOOP1 20 E3 // 画面表示 LD A,07H 3E 07 OUT (0FEH),A D3 FE // キーボード待機 K0: CALL 09CH CD 9C 00 JR Z, K0 28 FB K1: CALL 09CH CD 9C 00 JR NZ, K1 20 FB JR LOOP0 18 C9 エミュレータ上で確認する限りでは、正常に動作しているようですね。 後は独身寮に帰還してからです。 2005/3/22 EmuZ-2500の時に作成したDLLをベースに、吸出しソフトを作成しました。 キャプチャデバイスにはLogitec LVC-TVを使用、早速実験してみます。 手持ちのソフトを全て吸い出して確認してみましたが、問題なく動作します。 どうやら正常に吸い出せているようですね。