PC-6001 エミュレータ開発日記 1999年版

■ [99/12/05] - ライトプロテクト

d88形式のファイルを直接扱えるように書き換えてみた。 PC-6001Mk2のみのサポートなので相変わらず1Dのみ。

ついでに書きこみできるようにしたいところだけど、 ディスクプロテクト(書きこみ禁止)の方法がわからない。 マニュアル類をひっくり返してもその辺の記述がほとんどないのだけれど、 どうやって書き込みの可・不可を判断すればいいのだろう?

タイミング的には、ドライブが書き込みコマンドを受け付けた段階で 制御ビットをエラー状態に持ちこめばよさそうなんだけど、どの信号線か わからないし、他のエラーとの判別もわからない。

BASICのエラー一覧にはFW Errorというのがあり、 FAT破損かライトプロテクト時に発生するらしいけど、どうやって判断してるんだろう?


Mk2のROMセットでディスクサポート状態に設定してPC-6601付属の コロニーオデッセイが動くかどうか?

軽くトレースしてみた感じだと動かないような気がする。 というのも、Mk2ではサポートされていないはずのI/O Port B1H(6601以降での ディスク制御信号)を使用しているし、音声ROM上に存在する PC-6601内臓ディスクアクセスルーチンをコールしているので、PC-6001Mk2では 存在しないコードを呼び出して暴走してしまう模様。

■ [99/11/20] - SUB CPU修正

新しいバージョンでもAX-1のゲームが動くようになった。DoorDoorMk2は 相変わらずダメ。


itasundrious

爆弾男を含む、ハドソン系のゲームが遊べるようになった。チェックポイントは 8255のPORT-C Bit5(PC5)。~RDの変化に合わせてPC5を1にするだけではだめで、 SUB CPUの状態に合わせてPC5を0にも変化させる必要があるらしい。 今のところ、条件付けとしては、

としてみた。(と、メモを残す)

一週間前、マイコンベーシックマガジン宛に「過去、ベーマガに掲載 されたプログラムをホームページ上で公開してもらえないでしょうか?」と 書き綴ったE-Mailを送付しました。いや、実際はかなり長い文章で、 紙面からディスク(テープ)イメージやテキストデータに変換するような 実作業はこちらで行いますとか、PC-6001に限らずエミュレータが存在する機種でも...等など、 書きました。つまりエミュレータ上で使用することも明記しまして。

昨年の10月13日に同様の質問をしてはいるのですが(過去の開発日記に 書いてある)、今回はいくつかの提案込みという形にしてみました。

今日現在、返答はありません。

■ [99/11/16] - JoyStick割り込み修正

キーリピートがおかしかったのは簡単に解決、 PC-6001のカーソルキー・シフトキー・スペースキーは他のキーとは扱いが違うので、 エミュレータでも処理を分けた方がいいみたい。 6つのキー状態をチェックするだけなら、GetAsyncKeyState()を使ってもいいかな? 簡単そうだからサクッと書いてみればいいのか...こうして夜がふけてゆく。

GetAsyncKeyState()を使ったみたら反応がよいのでこっちを採用。 でもエミュレータ起動時・ソフトリセット時の最初のCTRL+?, SHIFT+?が反応しなくなったとか、 TinyXeviousのロードが完了すると勝手にゲームが始まってしまう(最初だけ勝手にスペースか シフトが押されてしまう?)とか。

それでも、クロック数調整と合わせるとTinyXeviousが遊べる状態になったかも...って スミマセン、音もゲームの一部ですね、まだです。

■ [99/11/12] - クロック数修正

今まで、いくら速度調整をしても、TinyXEVIOUSが速すぎる問題が解決できなかった のだけれども、どうやらZ80エミュレーション部のクロック数計算が正しくない ということが判明してトホホホ。 なんでも、iP6の元になっているソースの方は修正済みとのことで、 組み込んでみたところバッチリ。


DoorDoorMk2が起動しなくなったのは、タイマ割り込みの発生タイミングが 微妙で、一度でも割り込みを拾い損ねてはいけないらしい。 実は、タイマ割り込みが発生した時に割り込み禁止状態だった場合の処理方法が よくわかってなかったりする。ペンディングになるのか、キャンセルされるのか、 キャンセルされるのはカウント値なのか割り込み信号なのか、それとも両方?

前のバージョンではよくまぁ動いていたものだなぁ。


キーボード割り込み制御部がうまく動かず、キーリピートが解除されない。 実機のリピート速度に合わせたのだけれど、なぜかキーが押しっぱなし 状態になったまま。8255のポートが書きかえられていないから?
ちゃっくんぽっぷのBGMが小さくなっていく問題点が解決できず。ナゼ?
画面描画ではみ出しが発生したりと問題が続出。

■ [99/11/7] - SUB CPU書きなおし

Z80エミュレート部をスレッドで実装、あぁMacintoshに移植する夢が 遠のいていく...。


爆弾男対応のために、 SUB CPU制御部分とそれに関連するI/Oポートと割り込みを書きなおしてみた。 基本的な部分だけしか組み込んでいないので、特殊なことをしている ソフトは起動しなくなった模様。実際、AX-1のブロック崩しはキーを受け付けず、 DoorDoorMk2はマシン語部のロードができなくなった(こりゃイタイ)。


How Many Files ?で-(マイナス)を入力するとリセットがかかるのは、 実機も一緒???


明日からまた本業が重くなるので今日までに出来なかったことのメモ。

■ [99/11/5] - タイマ割り込みから

新しいルーチンを使用した場合の、 一秒あたりに発生するタイマー割り込みの発生回数をチェック(実際に割り込みが発生した 回数ではない)。 Windowsの都合上、厳密にカウントすることができないので、 大まかな値を出してみたら535/sec.前後。 計算の上では512/sec.あたりが適正値なのでちょっと多いけど前よりはマシになった。

次に実際にタイマ割り込みが発生している回数をカウントしてみたら、390/sec.と かなり少なく、なるほどカーソル点滅回数が少ない原因はここにあるらしい。はて、 なにが原因なんだろうか、と考えるよりも割り込みまわりは作り直したほうが早いかも。

極力割込み源を減らしてから、 Interrupt()関数が0xffffを返す回数(つまり無駄?)をカウントしてみたら40/sec.ぐらい。 割り込みは発生しているけど、割込み源が不明な状態に該当する。 おそらくタイマ割り込みとゲーム用キー割り込みが同時に発生した時に 起こるのだと思うけど。


PC-TECHKNOW 6001Vol.1のP163にこんなプログラムがある。

		20 T1=TIME
		30 FOR I=0 TO 5000
		40 S=S+1
		50 NEXT
		60 PRINT TIME-T1
		

S=S+1を5001回実行した時に何回タイマ割り込みが発生するのかを 調べるプログラム。同書によると44226、手元の実機で二回試してみたら 44176とちょっと速かった。

当然iP6forWinでも試してみるべしと実行してみたら84000とかなり変。 割り込み回数はもっと多くてよかったみたい(すでに過去形)。

10行目がないのは意味があって、同じページに

		10 OUT &H93,2
		20 T1=TIME
		30 FOR I=0 TO 5000
		40 S=S+1
		50 NEXT
		60 PRINT TIME-T1
		70 OUT &H93,3
		
というプログラムがあり、それぞれの実行結果の違いを確認することができる。

■ [99/11/3] - 再開

ポチポチとプログラムを書き換え始めたけど、 タイマ割り込みは発生していてtimeの値と変化は実機と同じくらいで動いているのに カーソルの点滅と音の変化が遅くなってしまう現象が起きてナゾ。

開発マシンを変更した際にキーボードをPFUのHHKにしたのだけど、 101キーボード設定なのにiP6では106キーのように振舞う...。

■ [99/7/11] - 爆弾男解析

SUB CPUの動作をカンペキにするため、いまだに動かないソフトNo.1 PC-MAGAZINE版 爆弾男の キー入力チェックルーチンを再度読んでみた。

CODE 16Hの意味が分からずに読み飛ばしていた部分を重点的に調べ上げてみると、 かなり最適化されていて、なんとも整然とした効率のいいコーディングだということが理解できる。 前に読んだときには憎たらしくって嫌らしいプログラムだと思ったのはナイショ。 でも、CODE 16Hどころか、CODE02H(キーボード割り込みのベクトル)まで使っているとはなぁ。

いろいろ細工してゲーム画面が出るようになったけど、操作できないぞ、と。

BomberMan Img2

■ [99/7/10] - パラレル接続

先日、AT互換機とPC-6001をプリンタポート経由で接続実験。 ハードを破壊する危険があるから、AC/DC特性をきっちり測定してから試さないといけないのだろうけど(いや、 ソフトも基礎設計は大切です)いきなり信号の種別を調べてから結線して接続してみた。

Windows95でプリンタポートのデータと制御信号を監視しつつ、PC-6001から OUT命令を実行してみると、よしよし、ちゃんとデータが取れるじゃないか。

なぜかデータが論理反転しているのがよくわからないけど、セントロニクスなプリンタってそういうものなのか? もしかして電流が不足して...とか考えたけど、ハードウェアにはそれほど詳しくないし、8255のデータシートは実家だし、 AT互換機のパラレルポートはどういうシカケなのかさっぱりわからないので気にしないことにする。

なんとなく、すみっこに転がっているPC-286VJの背面をみたら、PC-6001と同じ形状のプリンタコネクタが...という ことは、もしかしてPC-9801やPC-8801とAT互換機をパラレル接続してROMやDISKを吸い出すことも できるのかな。

■ [99/6/29] - 訂正

昨日の「“押されていない”ことを通知するために割り込みを発生させている..」という部分、 そんなわけないっすね。ちゃんとSUB CPUにコマンド06を送らないと。

■ [99/6/28] - 16Hのヒミツ

昨日から、割り込み処理を一個所にまとめるために割込み源と割り込みベクタを書き出して、 ソースを書き換え始める。ここのところ仕事ではR3000を使っていて、 Z80はアタマからスッポリ抜けていたのでハンドブックを読みながら、 Z80の割り込み信号(INT)がイネーブルされた時に割り込みベクトルを生成する方法を調べていたら...なるほどっ! いままでオレ的に最大のナゾだったCODE 16Hって、SUB CPU 8049が割り込みを発生した時、8049(8255)が生成した割り込みベクトル値そのものだったのかぁ。

割り込みを発生させられない状態...たとえばRAM ONLYでプログラムを動かしていてROMを参照できない場合は割り込みを禁止にしないといけないんだけども、 そうすると本来割り込みを使用して通知する仕様になっている キーボード/カーソル入力を判別できなくなってしまうから、 SUB CPUが割り込みのつもりでデータバス(正確には8255のポート)に乗っけた 割り込みベクトル値16Hを監視していればMAIN CPU側でキーが押されたことをチェックできるわけか。

ただ、爆弾男のプログラムを見ているとキー(カーソルとスペース)が押されていない時でも “押されていない”ことを通知するために割り込みを発生させているように読めるから、一定時間毎に 割り込みを発生させて、ベクトル値16Hをポートに乗っけるようにすればいいのかな。 ここでの一定期間ってのは実機に合わせるべきなんだろうけど、はて、どれくらいなんだろ? (シンクロスコープかロジアナ欲しいなぁ)

■ [99/6/26] - Version0.6.3Rel3 / 次

Version0.6.3Release3を公開したんだけども、スレッドを使用しないバージョンはここまでにしようと決めた。


NT4.0と"SB PCI128 Playback"の環境で音が出ない原因はいまだに不明で色々試している最中。

■ [99/6/21] - バグ取りと機能追加

Jさんのおかげで、Ver063rel2でウィンドウが表示されないバグの原因をつきとめる事ができました。 (ウィンドウクラスの登録時、MENUがなくってもlpszMenuNameは正しく設定しよう)


仕事中、ちょっとした空き時間ができてしまったので内職。以前、MODE1-SCREEN4の疑似TVモードで 色を自由に変更できるようにしたくって機能だけは組み込んだのだけども、インタフェースを作るのが ひどく面倒(ダイアログ上に指定サイズで描画するのはねぇ)だったので保留状態になっていたのだが、 Aさんの要望でエンジンに火が入ったのでコーディング開始...完了。正しく動いているのか自信ないけど。

本当はエミュレータのウィンドウ画面をみながら変更できるようにしたかったんだけども、 基本的な部分から手を入れないとできなさそうなので、それは描画ルーチンを書き換える時に。


さらに空き時間ができてしまったので、Hさんの“フルスクリーンから通常のウィンドウに戻した時に 他のアプリケーションのウィンドウが左上によってしまうのですが”に対処すべく、テスト用のプログラムを 書き始めて...あっさり完了(まだ組み込んでないけど)。ありゃ、MLで「大変だから後回し」と答えてしまったよ。(^^;)

実際にはディスクトップ上に存在するすべてのウィンドウを列挙してその位置とサイズを記録、 フルスクリーンから復帰した際には記録してあるデータを元にして再設定するだけかな?と思って、 実際にやってみたら簡単だった。方法として、これでいいのかわからないし、 SetWindowPlacement()、MoveWindow()、SetWindowPos()のどれが適切かよくわからないけど、 結果オーラィがWindowsプログラミングの極意。

不特定数のウィンドウ情報を記録するのにリスト構造を使いたかったんだけども、自宅にしかリスト構造処理の ソースがなかったし、その場で作るのはまた別のバグに悩まされそうだったから、MFCのコレクションクラスとC++で記述。 でも、スタティックライブラリを使ったら100Kbytesもサイズが増えたのは痛い。(>_<;)

最初、本当にすべてのウィンドウを列挙してしまって、目に見えない裏方のウィンドウまで表示してしまい大慌て、 アラームってなに?とか。知ってる人はそんなの、と思うだろうけども、Windowsって見えないところに かなりのウィンドウが潜んでいて、たまに“デタラメもほどほどに”と思うようなデザイン & タイトルが 付けられているウィンドウがあったりするんだよねぇ。


mk2用のFDDルーチンを組み込んで、インタフェースを付けたのでテストが楽になった。イジェクトができなかったり、 SRでもメニュが表示されてしまったり、常にディスクの電源が入った状態なので毎回“How many files?”が表示されたりして わずらわしいんだけども、このあたりのインターフェースは付けなくっても困らない程度のことだし。

6601/SRのディスク解析は止まったままだなぁ。


あとはJoyStickの2Pをサポートした、とか。基本機能は変わらないけど、なんだかゴテゴテしてきたような。 そろそろサウンドルーチンとメインループの見直しを始めたいなぁ。

■ [99/6/20] - かっこいい音を出したい

音がヘロヘロな理由は調べていないけど、おそらく原因は二つある。

一つは、出力タイミングの基準になるタイマ割り込みが安定していない事だと考えられる。これは 安定した割り込みが発生するようにしてあげればいんだけども、今の作り方ではプロセスがアイドル状態の 時だけZ80エミュレーションが実行されるので、他のアプリや、自分自身の描画処理によってタイミングが 大きくずれてしまう。これについては解決案があるのだけれども、ソースを大幅に変更しなければ ならないので躊躇していたり。

もう一つは、音データの生成方法だと思う。これはホントにそうなのかわからないので推測。 Windows版(X版もかな?)では、一定時間分の音データを動的に作成して、 それをサウンドポートから出力しているのだけれども、その時点でのサウンドチップのレジスタ内容に 従ってその時間分だけをまとめて作成して出力しているものだから、“一定時間分”という時間よりも 短い間隔でサウンドチップのレジスタを書き換えている場合には音として現れないのだと思う。 “思う”だから、ホントにそうなのかわからないけど、これを修正するのは大変かも、 でも、プログラムとしては面白そう。


フルスクリーンにすると、他のアプリケーションのウィンドウが左上に集まってしまい、ついでに ウィンドウサイズが変わってしまう。 ChangeDisplaySettings()を実行するとそうなってしまうし、ChangeDisplaySettings()の使い方について、 色々な資料をあたってみたのだが、どれも同じなので結果も同じはずだ。

『きっと市販のゲームもそうでしょ』と思って手持ちのゲームを起動してみたのだが、うーむ、なぜか ウィンドウの位置はもとのまま。...ということは、それなりの処理をしているはずで、 フルスクリーン時にはディスクトップ上のウィンドウ位置とサイズをすべて記録しておいて、復元する最に 利用しているのだろうなぁ。Spy++でウィンドウメッセージをみているとそれっぽいメッセージが 飛び込んでくるし。

EnumWindow()とGetWindowRect()、SetWindowPos()の組み合わせれば実装できる、はずだけども、 ちょっと面倒かな。

■ [99/6/19] - DOS/V版 PC-6001エミュレータ

DOS/V版のPC-6001エミュレータが公開されましたが、 すごいです。キーのクリック音がとっても気持ちいいです。

■ [99/6/18] - 下がったり上がったり

今日の出来事。

いやはや。

エミュレータは起動しているのにウィンドウが表示されないというのは、描画がどうこうと言うよりも ウィンドウの作成に失敗しているか、表示開始指示が正しく伝わっていないかだと思われる。 ウィンドウ作成の失敗に関してはエラー通知をしてアプリケーションを終了するようになっているので 表示開始指示ShowWindow() APIの使い方がおかしいという事だろうか?

この関数の第二引数には、WinMain()のnCmdShowをそのまま渡しているので、これに変な値が入っているのかもしれない。 でも、今までは動いていたんだし...はて?


ビデオカードによって挙動が違うというのは、Win32 APIの使用方法を間違えている可能性が高い。 フルスクリーン時の動作が重くなるのはStretchBlt() APIの部分だということ だけはわかっているので、シンプルなプログラムでテストしてみようと思う。 Revolution3Dの挙動はよくわからないけど、無効なウィンドウハンドルに対して描画しているのかもしれないので CreateWindow()/DestroyWindow()周りをみなおしてみる。

ただ、今回は小さな修正で済むようにフルスクリーンをサポートしようとしたんだけども、そういう考え方自体が消極的で よくないと思い始めているので、清く正しく最初から書き直してしまおうと決意(これが仕事だったらそうはいかないけど)。 どちらにしても今のままじゃ遅すぎるし。


WinNT4.0環境で音が出ない現象は始めて。少なくとも自宅のマシンと会社のオレマシンでは音が出ているし...ということで、 さっそく動作レポートを送っていただいた。

自宅マシン

1 Sound device.
manufacturer ID: 2
Product ID: 68
DriverVersion: 450
Product name: AWE64G Wave Out
Support Formats: 00000fff
Support Channels: 2
Support: 0000002c

送っていただいたレポート

1 Sound device.
manufacturer ID: 7d
Product ID: 41
DriverVersion: 100
Product name: SB PCI128 Playback
Support Formats: 00000fff
Support Channels: 2
Support: 0000000c

この内容は、waveOutGetDevCaps() というAPIによって得られるオーディオデバイスの機能一覧なのだが、 サウンドカードカード種別を除けばSupport変数だけが違う結果で、この値は

/* flags for dwSupport field of WAVEOUTCAPS */
#define WAVECAPS_PITCH 0x0001
#define WAVECAPS_PLAYBACKRATE 0x0002
#define WAVECAPS_VOLUME 0x0004
#define WAVECAPS_LRVOLUME 0x0008
#define WAVECAPS_SYNC 0x0010
#define WAVECAPS_SAMPLEACCURATE 0x0020
#define WAVECAPS_DIRECTSOUND 0x0040
のOR組み合わせになるのだから、WAVECAPS_SAMPLEACCURATEをサポートしている/していないだけの違いでしかない。 じゃ、この機能はなにかというと、“同期動作をサポートしていて、バッファの再生中はブロックする”というものらしいが、 これが音のでない原因?...とは思えないなぁ。

あ、音関連APIの戻り値チェックとエラー表示はさぼっているから(音の出力は別スレッドなのでやたらとエラーメッセージを 表示できない)もしかしたら別の箇所でエラーになっているのかもしれないので、もうちょっとトラップを しかけて次のバージョンで詳しい原因を探ってみる事にしようと思う。(せっかくだから 同じボードを買ってしまおうか、うちのサウンドボードはNT4.0と相性が悪いし)

■ [99/6/17] - 細かいところで機能追加

初代機モードでRAMを16k/32kから選択できるようにした。

ROMカートリッジを使えるようにした。(インタフェースがないからファイル名が固定だけど)

NT4.0でフルスクリーン表示にした時にメニューが表示されないようにした。


フルスクリーンになるといっても、以前遊びで公開したDirectX版に比べてかなりパフォーマンス が落ちるのはしょうがないか。

DirectX版ではスクリーンサイズそのものを320x200Pixelにしていたので、エミュレータのウィンドウから タイトルバーとかメニュー、枠線を取ってしまえばよいだけだった。今回のフルスクリーン化では、 スクリーンサイズは640x480で、ウィンドウサイズもそれに合わせて640x480にしているので、面積にして 4倍の計算量になってしまう。

なぜ、320x200のフルスクリーンにしないのかというと、DirectXの力を借りないとそのモードにすることが できないからだ。少なくとも我が家のマシンでWindows95を使っている限りは、できない。


MLに流れていた通り、リザードのセーブ・ロード時にBreak in ...が表示されてゲームが終了してしまう件は解決。 その方法は、セーブ用のテープイメージのサイズをあらかじめ大き目に用意しておくだけ。つまり、セーブ時に 新規にテープイメージを作成してしまうとうまく動かない。

■ [99/6/16] - 最も遊べるマシン?

PC-6001のグリーンっぽい背景色を再現して欲しいとのメールをいただいたので『よし、作り込んでみるかぁ! (夜中の2時)』と思い立ち、初代機をビデオ出力にてテレビにつないで、color命令を何度か実行してみたのだが。 う、Mk2以降とは色処理がぜんぜん違うではないですか。

初代機のVDGにはRGB出力なんてものはなく、そもそもVDGのデータシートからしてRFモジュレータにつなぐ方法が 書かれているものだから、テレビ画面でみた結果がすべてということになる。それにしても、 screen1でのcolor1とcolor3で表示される白色が違うというのはどういうことですかね。 手元のRGBモニタにつながっているMk2SRではscreen1で赤系の色は出ないけれども、初代機だと きっちり赤色(マニュアルでは橙で記述)が表示されるし。

なんだか初代機だけは別ルーチンで作った方がいいんじゃないかと思うくらい、 mk2と見た目の動作が違うので...ちょっと仕切り直し。うわさのDOS用PC-6001エミュレータに期待しよう、とか。


初代機の取扱説明書を引っ張り出してきたのだが、4章5節、

・PC-6001が専用モニターまたはカラーテレビに写し出す色は、専用モニターまたはカラーテレビの調整の状態により大きく変わります。時にはどの色調が正しいのか判断が困難になる場合も生じます。(中略)PC-6001では、 電源ONの最初の状態またはリセットの状態で、画面の背景色が緑色になるように色調をあわせます。
・正確に色調をあわせるには、PC-6001に添付のデモテープに書かれているカラーバーをロードして画面に写し出します。(以下略)

うーん、アナログ感覚。ちなみにデモテープは持ってません。


初代機の取扱説明書に掲載されているモニターの写真は、チャンネルつまみがガチャガチャと回すやつだったり、5章の“故障と間違え易い現象”には、

“カートリッジで動作しない → カートリッジの挿入端子がアメ、チューインガムなどが 原因で汚れていないか確認します”
という、お子様向けの記述があったりする割には、6章に“函数”なんていう表記があったり。

■ [99/6/14] - NTでのフルスクリーン

フルスクリーンもどきが完成したので、自宅だけでなく、会社のマシンでもテストしたんだけども、 やっぱりNT4.0での挙動が怪しい。ChangeDisplaySettings()した直後にウィンドウを操作すると、タイトルバーが 消えたり、枠線が残ったり、ウィンドウサイズが変更されなかったり、メニューの位置がずれたりと、もう散々でトホホ。

■ [99/6/12] - 2倍表示とフルスクリーン

拡大表示はStretchBlt() API、640x480モードはChangeDisplaySettings() APIを使って ウィンドウを最前面に持ってくれば、あっというまにフルスクリーン...ぐ、パフォーマンスが落ちてるし... フルスクリーンから元のウィンドウモードに変更し直しても落ちたまま...。

どうやら、ディスプレイのモードを動的に変化させると (たとえ色数が同じであっても)デバイス コンテキストが変わってしまうらしく、再度 CreateCompatibleDC()で仮想画面を再構築しないとBlt()系の命令で変換処理が入ってしまうようだ。 現状では動的にDCやBITMAPを作り直せるようなプログラムにはなってないので、ちょっと作り込まないとなぁ。

不具合は、NT4.0でメニューハンドルを削除してもウィンドウからメニューが消えない&操作できてしまうとか。 Windows95だとあっさり消えてくれたことだし、メニューにチェックマークが付かないからリソースとしては 開放されているようにも見えるんだけど。

よくわからないから、そのままにして...そっか、この場合はウィンドウスタイルを変えるんじゃなくって、 一度ウィンドウを破棄してから、再度ウィンドウを構築すればいいのか...って、それはあまりにも大袈裟で 手間がかかり過ぎるけど、Windowsプログラミングなんてこんなもんだろて。

■ [99/6/11] - ご家庭のTV

インタレース

さすがにこれはやりすぎか...ってすみません、まじめに処理したわけではなく、PhotoShopで加工しました。 640x400の元画像を、インタレスラインとホワイトノイズを20%の透明度で重ねてからコントラスト調整して縮小したものです。 丁寧なことにゴーストまで発生してます。(暗めのモニターでみるとわからないかも)

G3 Macintoshでさえ、このフィルタ加工に3秒近くかかるから、リアルタイムで演算するとなると...あらかじめインタレスラインとノイズをテーブルで用意したとしても、それだけでデモとして通用してしまうんじゃなかろうか というくらい重い、まるでベンチマークソフトのようなものになっちゃいそうです。

■ [99/6/8] - リザード調査中/Mr.PC

リザードの不具合はストップキー周りが怪しいのかと考えていたんだけども、思い違いかなぁ。


とある方に6601SRを譲っていただいたのでさっそく電源ON!む、電池を入れないとキーボードは動かないですか。 さっそく電池を買ってきて、ポチッとな...って動かない。

ダメモトでキーボードをバラしたら、電源部分のケーブルが切れていたので半田ごてを取り出して修復。 む〜、いくつかのキーが反応しないように見えて、SHIFTキーを押しながらだと文字が出たりする。 ま、いいか、小文字が出ないくらい。

■ [99/6/6] - リザード調査中

リザードでできない件を重点的に意地になって調べてたり。ただ、本業の方で次から次へと 仕事が舞い込んできてなかなかまとまった時間が取れないのがくやしい。 今のところ“原因はSUB CPU周りの実装にある”と読んでいるけど。


友人宅でX1emuを見せてもらった。うーむ、個人的な意見(それも世間的な評価に反する)だけども、 インタレス表示はあまり好きじゃないなぁと感じた。ここでのインタレスっていうのは、 エミュレータ界(?)での1行おきに表示しないようにする、という処理のことね。
確かに実機ではそういう風に表示されているんだけど、なにも表示しないのではなくって、 ドットピッチが荒いモニタのように、上下の表示されているラインの色がぼやけているように ラインを表現したいところだねぇ、とか。(できるのか、そんなん)

あと、エミュレータは全画面表示の方がいい、と思った。PC-6001エミュレータの場合は、 小窓で動いているところに良さがあるかなぁと思っていたんだけど、実際に遊ぶとか過去の思い出を再体験する 場合には全画面でなければだめだなと。

そして、もっとも感動かつ衝撃的だったのは、HuBASICを起動してからキーボードを押すと、 “キークリック音が出る”ってところだったり。

やっぱりOSや他のアプリなんぞにジャマされないDOSモードっていいかも。

■ [99/6/4] - Version0.6.3公開

バグがたくさんありそうだけども公開する事にしちゃいました、Version0.6.3Rel.1。

■ [99/6/3] - Windows版 Version0.6.3/CMT割り込みで悩む

うーむ、一ヶ月も経つとすっかり忘れちゃうな。

X版Version0.6の移植を再開したのだが、今回から画面の色数や拡大処理、インタレス表示等が混ざっているので、 いままでのように手作業で描画処理を移植するのは危険な香りがしたので、0.5.4をベースにWindows版0.6を作成。

拡大表示はStretchBlt() APIを使えば非整数倍のウィンドウサイズにであっても表示できるけど、 問題はインタレス表示か。1ライン毎に間引いて転送してくれるBitBlt()があればいいんだけども、 そんな都合のいいものがあるわけないから、内部画像データを構築する時に間引いておくしかないだろうなぁ。

一部の描画処理を完全に移植できないまま最新版のVerion0.6.2を拾いにいったら 最新版Version0.6.3が公開されていたので、差分を取りつつWindows版に取り込む部分を見極めて移植。 キーボードエミュレーションが大きく変わっているみたいだけども、原理を理解していないので保留。

Windows版のVersion0.6.3は、見た目も動作もVersion0.5.4と変わらないので公開は先延ばし。

Version0.6.3から必要になったSRのNewROMを吸い出してKANJI命令の動作確認。 これで倉庫番が動くようになるのかな。


MLにも報告があった通り、DoorDoor Mk2がロードできなくて焦る。 アナログな非同期型デバイス(CPUよりも回りっぱなしのCMTが主導権を持っているようなものだ)を エミュレートするのは厄介、というよりもDoorDoorMk2のプログラムが絶妙すぎるのよ。

これって99/3/13でも悩んでいる部分じゃん、と気がついたんだけども、自分で書いた 日記の内容が理解できず。“読み込みサイズに 間に合わなくなる”ってかなり謎な日本語だなぁ。(--;)

■ [99/5/5] - 6601のディスクを解析

どうやらPC-6601のROMにもブロック単位のディスク読み書きルーチンが用意されているようなので そのあたりを調べてみる事にする。少なくともBASIC命令(FILESとか)を解析するよりは簡単だろうし。

とある資料によると...

■ 4274H ディスクとのセクタ単位の入出力

入力:
	A = 入出力するセクタ数
	B = トラック番号
	C = セクタ番号
	DE = データ格納メモリの先頭アドレス
	IX + 0 = ドライブ番号-1
	IX + 27 = エラーカウント
		*IXはBASICのモードやページ数によって変化する
	CY = 出力の時は1に設定する。入力の時は0にして、Zも0にするが、Zが1の時はチェック処理となる。
出力:
	DE = 次のアドレス(DE + A*256になる)
	CY = エラーが発生した場合は1
		
らしい。IXがイヤなところだけども、たいした使われ方をしていないようなのであまり深く考えないことにする。 それから、この手の資料にはミスが多いので、実際にROMを解析して間違いがないことが確認できるまでは うのみにしない事も重要。

さて、いきなり該当ルーチンを見てみると...

	PUSH    AF        ;4274
	LD      A,061H    ;4275
	; VOICE ROM選択
	CALL    042C8H    ;4277
	POP     AF        ;427A

	JP      07800H    ;427B
		
これだけしかないのは、JPする7800Hで実際にFDDを操作しているからだろう、ということで続けて VOICE-ROM内の7800Hを見てみると...
	JP      7824H
		
さらにジャンプしているのは、このあたりにジャンプテーブルが置かれているためだ。ROMなんだから テーブル化する必要があるのかどうか疑問だけども、もしかしたらBASICルーチンとFDD制御ルーチンの担当者が 別だったとか、将来(SRシリーズのことか?)ディスク制御チップが変更された時にBASIC-ROMを 変更せずに済ませるためかな、ということで7824Hからが本番処理になる。かなり長いルーチンなので引用はなし。

最初にFE75Hの値を取り出してドライブ接続数をチェックしている。FE75Hがドライブ数情報だということは この前の調査でわかったんだけども、本当かどうかはよくわかってない。もし、ドライブが接続されていない ようであれば、FE73Hに(IX+0D)の内容を書き込んで7C02HへJPする。7C02Hからは解析していないけど、 どうやら外付けディスクでの入出力制御部っぽい。

次に(IX+0D)の値を色々調べているけど、よくわからない。0か2未満だと処理が先に進むみたいだけども、 これもドライブ数?それとも処理対象となるドライブ番号か?とにかくその値をFE73Hに書き込んでいる。 一応、逆アセンブルリストから(IX+0D)を検索してみたけど、あまりこれといった手がかりはなかった。 まぁ実機でIX+0Dの値を表示してみればなにかわかるかもしれない。

IX+32Dに引数Areg.を書き込んでいる、これは“入出力するセクタ数”だ。

続けてCYによって処理を振り分けているので、入力ルーチン(ディスクからのREAD)側を読み進めることにする。

READルーチンでは、Ereg.に“トラック番号”をコピー、Breg.に“入出力するセクタ数”をコピー、 FE73Hの値をDにコピーして、F3HをI/OポートB1Hに出力(OUT)している。

次に00HをFE72Hに書き込んでから、Breg.の値が04H未満であればBreg.から04Hを引いてその値を FE71Hに書き込み、Breg.には04Hを代入し、FE72HにFFHを書き込む。なんだろ...例えば、ディスクアクセスルーチンは 1024byte単位で読み込むんだけども、このルーチンでは256byte単位だから、4分割しているとか? 一応、この先でBreg.がどんなことに使われているのかを調べてみると、NOT(CPL)してから10Hを足して I/OportのDAHに書き込み(OUT)しているみたいだ。

このすぐ後がFDDのリードルーチンの呼び出しで、引数は Creg. = 論理セクタ番号、Dreg. = UNIT 番号、 Ereg. = シリンダ番号でBreg.がさっきのよく分からない値(入出力するセクタ数をいじったもの)だ。 ふむふむ、以前調べたFDCへの送信コマンドでは理解できる理由が分からなかった、“読み込みセクタ長は常に1” なのは1024byte単位で読み込み処理を行なうように決めうちしているからなのだろうか?でも、PC-6601の マニュアルには“1セクタは256バイト”と記述されているんだよなぁ...。

とりあえず保留してその次をみると、別のルーチン(7AF2H)をCALLしているのだが、どうやらこれが FDDからのデータ読み込み部分らしく、ここはまだ未解析。

あとはエラーチェックとか、入出力セクタ数によるループとかを行なってBASIC-ROMへ戻っている。


ひと区切りつけて、データの読み込み部(7AF2H)を調べてみる。わかっているのはDEreg.からの 番地にデータが書き込まれるということくらいか。

処理はたったの17行。

いきなりEreg.に(FE78H)の値を書き込んで引数のEreg.を壊してるんですが...ん、そういえばずっと前の方で EX命令を使ってHLとDEを交換していたから、このルーチンの引数はDEではなくHLになるのか、覚えててよかった。 で、そのFE78Hを初期化しているのはFDCへREADコマンドを送信ところらしい。そこでは読み込みセクタ数(Breg.)を 書き込んでいるから、ここでEreg.には読み込みセクタ数が書き込まれることになる。

その後にHLreg.を書き換えて(よくわからん)いる。

それからレジスタの値を色々と定義してINDRとIND命令が並んでいる。これなんの命令...?ふむINDRは、 Creg.で示されるI/Oポート(ここではD0H)のデータをHLのアドレスに書き込んでHLから1を引いて、 Breg.から1をそれぞれ引き、Breg.が0になるまで繰り返すのか。ふむ、Breg.にはFFhが設定されているな。 先にHLを色々書き換えていたのはINDRがHLのデクリメント処理だからあらかじめポインタを先に進めて おいたんだね、たぶん。(だったらINIRを使えばいいんじゃ...?)

最後にINDを実行しているはBreg.にFFhが入っているからこれだと255回で1byte足りないから一度だけ INDを実行する必要がある、という事か。(だったらBreg.に00hを入れとけばいいんじゃ...?) あとはEreg.の回数(セクタ数)だけこのループを繰り返して終了。

うーむ、データの読み込みポートはD0hなのかな...。てっきりDDhから読み込むものだと思っていたのに。 これはちょっと予想しなかった。だって、外付けのディスク(パラレルポート互換みたいなやつ)が つながっていたらぶつかるんじゃないのかね?


とりあえず、おおざっぱなPC-6601のFDD調査はこれでオシマイ。あとは実装しながら調べた方がいいと思う。 漠然としているのが読み込みセクタ数が4未満の時の処理。それから読み込みセクタ数を I/Oポートに出力している理由が推測すらできないのは気持ちわるい。

あ、ディスクへの書き込みルーチンを調べていないや...。


ホンモノには程遠い疑似FDDエミュレートは比較的簡単で、少なくともBASICからのFILES/LOADくらいは あっさりできるんじゃないかと思う。 ただ、もう少し効率の良いディスクアクセス処理を独自に作成しているようなソフト(ようするにROM内ルーチンを 使ってない)があったら、正しくハードエミュレートしないとだめだと思うんだけど、でも、手元にあるFDD専用 ソフトって“コロニーオデッセィ”だけなんだよね。

“コロニーオデッセィ”ほどの大作を解析する根性はちょっとないかもしれないし、かといって他に FDD専用ソフトは持ってないし。

“コロニーオデッセィ”を解析できるくらいの根性があれば、 Windows版リバイバル“コロニーオデッセィ”を作れちゃうんじゃなかろうか。(ん?それは楽しそうかも)

■ [99/4/25]

ん?昨日の解析だと、DISK READコマンドを送った後にデータを読み取っている部分が見当たらないし、 DISK WRITEコマンド発行後にデータを送信している部分もない。 とゆーことは、DMAを使っているor割り込みで制御ということになるんだろうか?

やっぱりBASICインタプリタの解析をしないと駄目なのか、やだなぁ。

■ [99/4/24]

本業が煮詰まったから息抜きにPC-6601のフロッピィ制御部分を調べてみた。解析は記憶力と経験、それから 推理によるところが大きくって、あれこれと推測やら仮定を立ててからそれが正しいと確認できた時の 面白さはなんとも言えなかったりする。んで、まずはわかった部分の結果から。

	■ FDC周りのI/O port

	B1h	謎	(OUT... おそらくSRの資料と同じだろうけども、DMAはないと思う)
	B2h	謎	(IN... bit0を調べている、それも一回だけ) SR同様のFDC割り込みフラグ?
	B3h	謎	(OUT ... FEhのみ、それも一回だけ)

	-- たぶん外付けドライブ --
	D2h	謎	(IN)
	D3h	謎	(OUT)
	----------------------------

	D4h	謎	(IN) 一個所だけ
	D6h	謎	(OUT ... FFh等)

	D8h	謎	(OUT ... 00h, 01hのいずれか)

	DCh	FDC status(IN)
	DDh	FDC Data(IN, OUT)

	DAh	謎	(OUT)
	DEh	謎	(OUT)
		

ほとんど謎だけど、エミュレートする上ではDChとDDhだけを正しく動作するようにして、 IN命令で使用しているポートの戻り値を適当にでっち上げれば動くと思う。思うけど、実装し始めると結構時間が かかりそうな感じはするなぁ。FDCはおなじみの765Aで5個ほどのコマンドをサポートするだけでBASIC上でディスクを 使う事はできそうだ。ただ、ソフトによっては(コロニー...とか)より多くのコマンドを使用しているかもしれない。

一応参考までにサブルーチンは...

	7803h: DISK Init
	7809h: DISK Read
	780Ch: DISK Write
	780Fh: 全トラックに対してWRITE IDする(フォーマット?)
		
サブルーチンのジャンプテーブルをみるともう一つあるんだけど、用途が謎だった(ソフトリセット?)。 各ルーチンの詳しい引数がわかっていないけど、これはBASICでディスクのREAD/WRITEを行なう命令を調べれば正しくわかると思う。 でも、BASICインタプリタの解析って面倒だから気が向かなかったり。
PC-6601って外付けフロッピィドライブを接続することはできないんだけども、ROM内のルーチンではわざわざ調べているみたいだ。 もしかして、拡張カートリッジにドライブを接続する場合を想定しているんだろうか?

■ [99/4/18]

MLの方で協力していただき、リザードのイメージがロードできない原因が判明した。 リザードのローダープログラムでは後に続くマシン語プログラムを二回ロードしているのだが、その読み込み サブルーチンでは

  1. CMT 初期化(モーターON)
  2. ちょっとお休み(ただのWAIT)
  3. テープからの読み込み&データチェック
  4. ちょっとお休み(ただのWAIT)
  5. CMT の停止(モーターOFF)
このように、モーターOFFの前に少しだけWAIT処理を入れている。このWAITにどんな意味があるのか わからないけれども、エミュレータでは一つ目のマシン語部読み込み時に、このWAITで空回りしている間に テープイメージの読み込み位置が進んでしまい、二つ目のマシン語読み込み開始時には二つ目のマシン語部の 途中から読み込みされてしまう。これがTR Error発生の原因。

じゃ、実機ではどーなってるの?というと、このWAIT処理に相当する時間分だけ“ピー”というデータとしては 無意味な音が流れるようになっている。

暫定的(というかこれしかないと思うけど)な解決方法は...一つ目のBASICプログラムのイメージファイルを バイナリエディタで開いて、CD E0 80というデータの並びを探し出して(二個所ある)00 00 00 に書き換えると ゲームが始まるようになるはず。

ただ、MLでの報告によるとセーブできないとか...。

■ [99/4/6]

FAQのひとつに“T&E Softのゲームが起動しない”というのがある。これはエミュレータを使用されているユーザの方からの情報を元にしているんだけども、どうして00を7個追加しなければならないのか、その理由はわかっていなかったし特に調べる必要もなかったのだが、別件でT&E Softのテープイメージを調べることになり、 その時には自分のページのFAQのことをすっかり忘れていて、結果的に00を追加しなければならない理由を知る事になってしまった。

マシン語で記述されているローダー部分の処理は以下の通り。

  1. INPUT #-1命令のルーチン(259Ah)をコールしてテープを読み込みモードとして動作開始する。
  2. INPUT #-1命令ではヘッダ文字9Chを6個検出するまでテープを読み流す。
  3. AFhが5個出てくるまでテープを読み流す。
  4. マシン語部分の保存アドレスを2バイト読み込む
  5. マシン語部分のデータ長を2バイト読み込む
  6. ファイル名情報を2バイト読み込む
  7. CMT SAVE CLOSEルーチンをコールする(1B06h)。
  8. マシン語データ読み込みの準備とファイル名の表示。
  9. INPUT #-1命令のルーチン(259Ah)をコールしてテープを読み込みモードとして動作開始する。
  10. INPUT #-1命令ではヘッダ文字9Chを6個検出するまでテープを読み流す。
  11. マシン語データ部の読み込み
大体こんな感じなのだが、なぜかINPUT #-1でCMT LOAD OPENを実行しているのに 終了処理はCMT SAVE CLOSEルーチンを呼び出している。以前調べた雑誌掲載版の 爆弾男でもINPUT #-1を利用していたが、終了処理はCMT LOAD CLOSEを呼び出していたのだから、どうにも怪しい。

現在のエミュレータの実装では、CMT LOAD OPENしてからCMT SAVE CLOSEを実行しても テープの読み出しエミュレートは終了しないので、ファイル名を表示する部分の処理時間が 長すぎるとデータを読み捨てることになってしまい、その次の(9.)INPUT #-1で9Chを検出できずに テープの最後まで読み切ってしまうらしい。だから、00hを7個追加する事によって その00hを読み捨てるだけの時間的なゆとりができるのでヘッダ部分(9Ch x 6)を検出できるようになるようだ。

試しに、00hを7個追加する方法ではなく、CMT SAVE CLOSE呼び出しをCMT LOAD CLOSEに 書き換えてみたら正しくロードされるようになったのでこの考え方に間違いないと思う。 また、CMT SAVE CLOSE呼び出しが二個所あるので、テープイメージ作成時に 偶然CMT LOAD CLOSE呼び出しがCMT SAVE CLOSE呼び出しに化けた、ということは考えられないかな。

・・・これってT&E Soft側のバグでは、と思うのだが、実機ではこれで正しく動いている のだから、このバグもエミュレータで再現しないといけない?

■ [99/4/3]

軽い気持ちでX版のVer.0.6のソースを取り込もうと思って挫折したり。

■ [99/3/17]

ガビーン、今日のこの時まで普段使っているモニター(SHARPのCZ-600DE)...アナログ15PIN、VHF/UHF、 ビデオ入力、そしてディジタル入力を備えている(X1 TURBO-ZIIIでも使われていたから?)...に 6001をつないでいたんだけど、このモニターってColor1〜Color7のディジタル中間色(オレ命名)が でないことを今日知った。

PC-60m43が手元にはあるからテストには困らないんだけど、普段は箱の中だ。

どれだけ実機が使われずにエミュレータが作られているのかがよく分かるなぁと反省したり。

リザードのテストで実機を起動したんだけども、実機には独特の雰囲気がある。ただ、具体的にどこがPC-6001らしいのか を自分でもよく理解していないのが非常にもどかしい。キーのクリック感とクリック音、安いモノラルスピーカー、他にも気がついていない事がたくさんあるような気がする。

■ [99/3/16]

DirectX版が動いているのを見ているとドキドキしてしまうなぁ。こんなにいいものだったら さっさと作っておくべきだったか? でも、ユーザインタフェースとかが面倒でビデオカードとの相性も大変だ。自宅では 動作したのに、会社の環境では他のアプリケーションのウィンドウがすべて320x200になってしまい、 マウスの稼動範囲がおかしく、右ボタンメニューの位置がおかしいかったし。

でも、やる。

いつになるかわからないけど。


リザードでセーブ・ロードがおかしくなる問題を調べてみたんだけども、原因は単純で吸い出しミスっぽい。

結論...正しくテープイメージを作ってしまえばリザードは完動すると思います。


MLでもちょっと話題になったけど、ドアドアmk2はイメージの作成が大変です。 詳しく説明すると長くなるので端折りますが、マシン語部分の先頭は 60 00 5A...です。

■ [99/3/15]

仕事プログラムがタイクツだったから息抜きにちょっとDXで遊んでみることにした。

とは言っても正しく実装するのは大変だから、DXオブジェクトを生成して協調レベルとモードを 設定するだけで、メニューとステータスバーを削除してから、あとは通常どおりにウィンドウに対して描画させる。

ニヤリ、というよりも感動したカモ。

結構遊べると判断したので、コマンドラインからファイル名を引き渡せるようにして、ん〜 ウェイト解除したいからマウスの右ボタンに割り当ててみようかな。そうだ、ホントにテープを読み込みしているか 不安だから強引に表示してしまえ。

というわけで、お遊びで作ったDX対応版(期間限定?)。 マウスの右ボタンでメニューが出ますが選択してもチェックマークはつきません。 マウスの左ボタンで左上の情報が消えます。ダブルクリックして起動するよりも、MS-DOSプロンプトから 引数としてイメージファイル名を引き渡してあげるとちょっと幸せになれます。 非DX版と同じディレクトリに置いておくとINIファイルを読み込んでくれます。

OSやビデオカードによっては動作しませんし、場合によってはシステムに致命的な問題を作ってしまいますから 覚悟が必要です。(終了時にリフレッシュレートが変わってしまうなぁ...)


テープイメージからの読み込みが遅くなってしまったなぁ。

■ [99/3/14]

isioさんのP6 diary [99.03.12]を読んでいて、『ROMとRAMでは読み書きの速度に差がある(WAITが入る?)のかもなぁ』と思ったり したけど、tinyXEVIOUSだけその差が顕著に現れるっていうのも変かな。tinyXEVIOUSに限らず、他のゲームでも スピード調整はいまいちなんだけども。

ところで、どんなものであっても解析結果には非常に興味あるです。あと、ハイドライドのローダー部...[99.02.10] の途中経過話も気になるです(^^)。


日記が一日ずれていた〜。

■ [99/3/13]

0.5.4Rel.5を置いたけど、かなり不安。いくつかのゲームでテストしてはみたけれども、 こういうのって他の人から「動きましたよ」報告をもらわないと落ち着かない。 基本的にはエミュレータソフトに対する責任や保証はないけれど、なんだか仕事で 完成させた(市販品)ソフトをテスト部門に渡して“ステータス:チェック中”な気分。


Ver0.5.4 Rel.4を出したら、描画ウェイト値を上げてあるとテープの読み込みデータが化けるという バグ報告をいただいたのでさっそく調べてみた。

不思議なのは、化ける箇所がベーシックプログラムの一行目あたりだけということで、イメージ先頭部分に ある識別用のコードやファイル名には影響がないということだ。

とりあえずわかったのは、描画ウェイトを増やすとテープ読み込みの割り込みがテープの読み込みサイズに 間に合わなくなるらしいということで、タイマー割り込みの処理にテープ割り込み処理が負けてしまうみたい。

どうしてベーシックプログラムの一行目あたりだけが化けるのかというと、テープからファイル名を 読み込み終わった時にファイル名を画面に表示する処理に時間がかかっているのが原因っぽい。

あと、描画ウェイトをデフォルト値の192を超えた設定にするとドアドアmk2の読み込みに失敗しやすくなる。 これはドアドアmk2のテープ読み込み処理が“プログラムの読み込み”・“音楽再生”・“ロード画面の表示”と 処理が重く、ちょっとでもWAITを増やすとデータがこぼれてしまうのだ。

困ったな〜&みなさんすみません。

■ [99/3/11]

リザードのテープセーブ中に画面が化ける問題だけど、どうやらキーでの操作はできるみたい。 つまり、V-RAMへのアクセスがおかしくなっているみたいだからメモリバンク切り替えに失敗しているようにも思える。


CMTとタイマーの割り込みが同時に発生する可能性があった。でも、同時に発生した場合は タイマ割り込みがキャンセルされるだけなので致命的ではないと思う。


キー割り込みに問題がある。いや、あることは以前からわかっていたんだけど。

まず、キーが押されると“押されましたフラグ&押されたキーが格納されている変数”が書き換えられる。 その変数をみてキー割り込みを発生させるかどうか判断してから割り込みベクトルを発生させ、 割り込みルーチンでキーを読み取ると同時に先の変数をクリアする。

さて、ここで割り込みが禁止されていたりして変数がクリアされない場合はどうなるか? うん、常にキー割り込みが発生した状態になってしまう。 ほとんどの場合、あまり問題にはならないはずだし、実際に今のままでいくつかのソフトは動作していることも わかっている・・・なのに、絶妙なタイミングで割り込み判断に失敗するゲームがコイツ(↓)。

doordoormk2 game

実機でも動作しないタイミングことがあるんじゃないか?というような原因だから、どうにも納得がいかないけど、 もうちょっと深く考えてみないと正しい理由(原因)ははっきりしない。さて、コイツ(↑)の解析を始めたのが2/1だから、 ここまで到達するのに40日(毎日調べていたわけじゃないけど)。芋ずる式に別のバグもいくつか 見つかったし、かなりいいサンプルでした・・・って、ここでまとめてどーするですかね。

でも問題の対処は・・・むずかし〜な〜。手はあると思うけど、isioさんに相談、かな。(ここに書いても ^^;)

■ [99/3/10]

本業が忙しくって、PC-6001関連はさっぱり・・・なんだけど。

昨日の夜、ふとんに入って夢の世界に旅立つ直前になって、謎コード16H対応案が思い付いた。 なんでいままで気がつかなかったのか不思議なくらい簡単な実装方法なんだけど、『いつかSUB CPUエミュレートを 完全な形で書き上げる』っていう考えがあったから、あまり真剣に現状での対応案を考えていなかったのかも しれないなぁとか思いつつ、寝る前に思い付いた事って、翌日に起きるときれいさっぱり忘れているだろうから、と、 実装方法を簡単にメモして寝る。

翌朝には、やっぱりすっかり忘れていたり。

仕事を始めてからふと、机の横をみると過去の自分からのメッセージ “コマンド06hの連続発行回数をチェック” が届いることに気がつき、仕事を一時お休みして一週間ぶりにソースを書き換え始めた。

実装し始めて気がついたんだけど、寝る前に思い付いた方法だからか、どこかマヌケな抜けがあったりして結局うまく行かず、 結局ずいぶん前に思い付いた割り込み時・非割り込み時で処理を振り分ける方法を採用して、ドキドキしながらDoorDoorMk2を起動。ををっ、 ちゃんとデモが始まったぞ、勝利じゃ!と喜び勇んでスペースキーを押したら暴走した。

敗北

どうやらデータ領域のコードを実行し続けているみたいで、00H(NOP)を延々と繰り返しているようだ。 原因としてはメモリバンク切り替えの失敗か、割り込みベクトルの書き換え失敗でPCが変な値になってしまったとか いろいろ考えられるけど、これを調べるのはかなり大変。

割り込みベクトルの発行に失敗しているのかなぁとボーッと考えながらタイマ割り込み処理を眺めていると、 場合によっては通常よりも速く連続して割り込みがしてしまうルートがあることに気がつく。

ピキーンとひらめいた。

割り込み禁止時には割り込み発生カウンタが蓄積され続けて、割り込み禁止解除と同時に連続して割り込みが 発生するような仕掛けになっていたけども、これだとテープのデータを読み書き速度よりも速く割り込みが発生するので 読み込みミスが発生するのではなかろうか?

さっそくその箇所を書き換えてアスピックを起動してsaveしてみると・・・勝利だ! テープにセーブしたデータのチェックで失敗する事がなくなったぞっ!

喜んでリザードでもテストしたら・・・暴走した。敗北。リザードの方はディスクに 無理矢理保存したものだからかもしれないけど、画面をボコボコ書き壊しているにも関わらず、スペースキーを押すと テープが回る(カウンタが増えてく)という恐ろしい状態になる。


長くなったけど、ようするにDoorDoorMk2がタイトルデモまで見れるようになって、アスピックがセーブ(おそらくロードも) できるようになった(ん?ということはアスピック対応完了 ^^)ということ。


そういえば、爆弾男(PC-MAGAZINE掲載版)もCODE 16Hが原因で動かなかったのを思い出したのでテストしてみた。

結果的にはまったくだめで、こちらはI/O port92hの各bit状態を細かくチェックしているし、新・謎のCODE 02Hとの 比較処理していたり、CODE 16Hはスペースやカーソルだけではなく、通常のキーボード状態のチェックでも発行されることが 判明したり、AXシリーズでハマった割り込みを使用しないキーの状態獲得方法を使っていたりもする。

問題箇所やロジックはわかっているのに対応できないソフトNo.1だな、こいつは。

■ [99/3/3]

aspic encount lizard fight

動くようになりました。でも、まだセーブ・ロード部分がおかしいみたい。

■ [99/2/25]

ディスクイメージのマウントに成功。いくつかのゲームがサルベージされたんだけども、 なにがうれしいかって、テープイメージからの変換を意識せずに動作確認ができるから。

実際にいくつかのゲームの動作確認ができたけど、その中からの一品をご紹介。 でもまぁ、ここに書くネタって基本的に動かないものを取り上げているわけだから 本人としては(おそらく使う人にとっても)嬉しくなかったりするんだけど。

lizard title lizard bug

タイトル画面から塔に入って移動するところまでは完全に動作するんだけど、 敵にエンカウントするとバグる。


PC-Magazineに掲載された爆弾男のリストを入力したものが動かないというので調査。

BASICのローダーを解析してからマシン語部分のロードサイズを調べる。最初に引っかかった点は、 CMTオープンにinput#命令を使っているのでプログラムとは関係のない識別用のコードをイメージに 書き込んでおく必要があったこと。ちなみにイメージのサイズが不足していたり(コンバートミスや イメージをバイナリエディタで編集する必要がある時)、識別用のコードが正しく認識できなくて テープイメージの最後まで読み取ってしまった場合にはBreakや、Syntax Errorが出ることになる。

正しいテープイメージが作成できたところで実行してみると、画面が真っ暗になったまま停止状態。 どうやらループから抜け出せない状態なので、マシン語部分のロードが完了した段階でRAMの内容を 保存して逆アセンブル。うーむ、テープイメージから読み込んだ内容をLDIRで一括転送しているので、 アドレスがずれてしまうから、転送後の内容を再度逆アセンブル。

この状態でエミュレータを実行してループしていると思われるアドレスの前後を 拾い出して(ちょっとカッコワルイ)逆アセンブルリストと照らし合わせてみると・・・。

I/O portF2hの内容を取り出してbitチェックしている部分でループにはまり込んでいるらしい。 しょうがないので、とりあえずチェック部分をつぶしてみると、またもやループにはまる。

そして・・・Code 16Hの悲劇再び。

割込み禁止状態でJoyStickの状態を調べる時にはSUB-CPUにCOMMAND06を送ってから ポートの状態をチェックするのではなく、最初に16hがポートにのったのを確認してから、 直後にポートの内容を再度拾い出す必要がある・・・らしい。 DoorDoorMk2と同様、Code 16Hをエミュレータに組み込まないといけない、ということかぁ。

というわけで、16hとの比較部分をNOPに置きかえるとタイトル画面までは出る。

bomber man

でも、キーチェック部分をNOPに置き変えてしまった影響か、ゲームは始まらず。


ディスクイメージからも、いくつかのハドソン系ゲームを実行したけど、やはり動かなかった。


今日の日記は長い。

念願のOLIONをディスクから取り出すことができた。小学生の頃に遊び、一度手放し、 もう一度あの画面を見たいと思い続けて7年、長かった。 正直、昨年ぐらいまでは再びOLIONを見る事ができたらエミュレータとかPC-6001はもういいかなって思っていた。 でも、実際にこうして見て(んでもって音楽を聴いていると)いると、『通過点のひとつをクリアしただけなんだなぁ』 と思っていたりする。目的意識が変化したのかな。

Windows版は移植からのスタートなんだけども、いわゆる世間で言われているような“エミュレーター”を 作っているような意識はなくって、実機をモデルにしたもの、またはミニチュアを作ってるんだなぁということにも気がついたり。 あえて表現するなら(重い)ディスクトップアクセサリみたいなものかなぁ。

ところで、ゲームが起動するかどうかの確認はするけど、ゲームで遊ぶことはほとんどない。 どうしてかっていったら、遊んでる時に『突然動かなくなったらどうしよう』って 思うとドキドキしてゲームに集中できないんだよね。画面が小さくって遊ぶ気にならないとかもあるけど。(だからDirectX...早くね...)

■ [99/2/24]

23日の深夜。なんだか日記が一日分ずれちゃってるな。

disk test1

とりあえず勝利の雄叫びを。

問題点は、PC-6001mk2SR/6601/6601SRのROMでは動作しないという事か。

ディスクイメージは相変わらず正しく吸い出せなかったりする。


24日の夕方。

mk2SRのディスクチェック部分を読み始めた。ここまでハイペースで進んできた分、本業に影響が出るから ペースダウンしたいところなんだけども、BASIC-ROMがプログラムとして非常に読みやすいので止められなかったりする。

資料によると、disk初期化ルーチンは40b9hからと書かれていて、実際mk2ではその部分で接続チェックと ドライブ数をかぞえる処理が記述されていた。この資料はmk2SR/66SR用なので、当然mk2SRのN66-BASIC-ROMでも 通用するかと思ったら、SRをN66-BASICとして起動した場合にはアドレスが異なるらしい。

まず、40b9hをcallしている部分を探してみたら見当たらない。callする手段には普通のcall命令を使う以外にも pushしてretするような方法もあるけど、これまでの解析からBASIC-ROMを作った人の性格として そういう解析封じ的なことをしているとは思えない。実際、エミュレータでワナを仕掛けて 40b9hが実行されるのを監視していてもワナにかからずBASICが起動してしまう。

そこで、すでに解析済みのmk2-ROMで40b9をコールしている部分のアドレスを探し出して、SR-ROMで同じアドレスを 見てみると、呼び出し部分の処理はほぼ同一だということがわかる。mk2-ROMとSR-ROMの違いは、disk初期化アドレス そのもので、mk2だと先の40b9hだけどもSRのN66-BASICは4292hからがディスクの初期化らしい。

それで4292hからを追ってみると、ナゾのI/Oポートに読み書きをしてから(共通ルーチンっぽい)6c91hへジャンプする。

その6c91hからがよく分からなかったけど、isioさんから『6000h〜7000hはVOICEROMに含まれる』というタイムリーな メールを頂いたのでさっそく展開してみると謎ワークエリア1の内容をAccや別のワークエリアにコピーしてから、 接続されているドライブ数を数えて、続いて謎の処理をしていることがわかる。そして、6c91hからの戻り値はずばり接続ドライブ数ということが判明。

謎ワークエリア1がよく分からないところだけど、ドライブ数を数える時に使用している ことから推測するに、ずばり接続ドライブ数が保存されているということだ。ただ、この初期化ルーチン以外では そのワークエリアに対して書き込みをしている部分が見当たらない(簡単なチェックしかしていないから、レジスタ相対かもしれないけど) ということは、N66-BASICが起動する前のSR起動時に別のシステム(SRのメニュー起動部)がワークエリアに 書き込みをしているということになるのだろうか。

この周辺の処理は、まじめに追ってみると色々なことがわかるけど、あっと時間が吸い取られていくなぁ。


Aさんから資料をお借りしたのでさっそく読んでみたんだけども、インテリジェントタイプのディスクに送信する 各コマンドってPC-8801の内部DISK制御コマンドとまったく一緒なのにはびっくり。

これでPD765Cの制御方法も一緒だったら解析が楽になりそうなんだけど、PC-8801(mk2以降?)はディスク制御部だけで Z80を一つ使っていて、PC-6601/mk2SR/66SRの場合は(たぶん)DMAだから、どちらかというとPC-98シリーズに近いのかもしれない。 ん?88もドライブ側でDMA使っていたかな?


isioさんからいただいた資料を読んでいると、どうやらSRのディスク制御を調べる前に6601をチェックしたほうが よさそうに思えてきたので、SR解析は一時中断。

■ [99/2/23]

22日の深夜。風呂に入ったら頭すっきりで色々ひらめいたりする。

いくつか気になる点をメモ。


ディスク周りを実機で再チェック。PC-6001mk2SR + PC-6031の組み合わせだと、 dski()のトラック数には34までしか渡せないみたい。ということは、1Dしかサポートしていない? または、このドライブ自体が1Dモードでしか動かない?ということかな? hokutenさんのところのカタログをみると やっぱり3?トラック(字が小さくって読めなかった)までみたいだし。

さらにもう一点、実機とエミュレータでdskiの結果を比較してみると 最初のトラックのデータ(track00)は一致しているみたいだけども、track01以降は違っているみたいだ。 そっか、両面じゃなくって片面だからトラックの半分は読み捨てないといけないのか・・・ん? d88形式のファイルサイズが半分しかない???

とにかく正しいイメージが作成できていない、というところで22日はおしまい。

■ [99/2/22]

バグ報告。描画WAITを大きくしているとテープロード時にデータ化けが発生するそうです。(原因確認済み) タイマー割り込み同様に、時間基準でCMT割り込みを発生させているんだけども、完全な実装ミスでした。


ディスク対応の続き。日曜日のお昼から今日の深夜12:00まで、頭の中にはディスク制御だけに支配されてたなぁ。 資料がほとんどない状態だけども経験と推測でここまで進んだ。

PC-286で吸い上げた2Dディスクイメージを加工したものをdski関数で読み込んでみたんだけども、

How Many Files? dskfi function

うん、おっけ〜おっけ〜っすよ。ここまで来たんだから、思い切ってfilesを実行!したらAT Errorが出た。 なんで〜?と思ってdski関数でFATを直接読もうと思い、FATが書き込まれているTRACK37を見ようとしたら TS Errorが出る。またもやなんで〜?と心の中で叫びつつ、いろいろ値を変えてみるとTRACK34までしか 読み込みできない・・・それって1Dドライブとして判断してるってことじゃ〜ん。

ということろでガックリきたついでに頭のスイッチが切れたから一時打ち切り。

1DDと1Dの判別をどこでしているのかよく分からないし、mk2あたりの機種は1Dしかサポート していないのかもしれないし(それはないか?)、1Dの場合はFAT領域がどこにあるのかわからないし、 じゃ、フォーマットプログラムを実行してまっさらなディスクイメージを作成して、と思ったけど ディスクへの書き込み部分はまだ作ってないんだったっけ・・・とか色々あるなぁ。

dski$関数の引数チェック部分を調べれば、どこの領域に1D/1DDの種別が書き込まれているのかが わかると思うんだけども、dski関数の処理アドレスがわからないし、アドレスを調べるのがさらに面倒だったり。

ディスク制御部分のソースが綺麗じゃないのがなによりも気に入らないとかもある。


2/22の日記に書いた、DoorDoorMk2タイトルイメージがおかしいのは勘違いだったみたい。

■ [99/2/21]

SUB-CPUがDISK BIOSっていうのは勘違いか。インテリジェントタイプFDCと PC本体内にあるディスク用8255がつながっているみたい。

となると、8255の初期化データは91hだから、モード0で設定されて、 送受信データの中身を見ていると、こんな感じなのかな。

■ [99/2/20]

I/Oポートに流れてくるデータを眺めていると、サポートしていないコードが結構あるらしい。 SUB-CPUをCPUらしく実装してみたいけど、大掛かりな変更になりそうだから少し躊躇気味。

それはともかく、PC-6031をお借りする事が出来た。Iさんありがとうございます。


そんなわけでいきなり、やる事・出来る事・やりたい事が増えた。

手始めに、BASIC-ROM内の


を解析。 Z80からはSUB-CPUにコマンドを送っているだけで、細かい制御はしていないのだと思うけど、 要するにSUB-CPUがDISK BIOSみたいなものかな? ディスクドライブ内にFDCが載っていて、SUB-CPUがFDCを制御しているんでしょう、きっと。

肝心のコマンドはよくわからないので、とりあえず放置。明日はPC6001のブートシーケンスをチェック。


先日upしたDoorDoorMk2のロード中画面、よく見ると絵的にミスマッチな横線が見える。 これはイメージが化けている可能性かもしれづ。

■ [99/2/16]

15日の深夜。

風呂に入っている時、突然タイマ割り込みの実装部分でひらめいたので寝る前にプログラムを修正。 うん、無事に解決。・・・といっても、以前のバージョンで動いていたソフトが再び動き出すようになっただけ だからそれほどうれしくはないや。

ただ、I/OポートF3hに書き出している値を別のウィンドウに表示してずっと眺めている時に、 『すべてのI/Oポートに書き出されるデータをみていたらなにか別のことがわかるかもしれない、もしかしたら 未サポートのI/Oポートにアクセスしていたり、不都合がでる値を使用しているかもしれないし』と思いついた。 大した思いつきじゃないけども、以外と面白そうな結果が得られるかもしれないし(得られないかもしれないけど) プログラムとして実装するのは楽しそうだからちょっと組み込んでみようかな。 GUIが面倒だけども、コンソールに書き出してもいいだろうし、幸い、PC-6001シリーズが使用している I/Oポートの数はかなり少ないことだし。

きれい。

DoorDoorMkII_title

■ [99/2/15]

実機を引っぱり出してきて、IN A,(90H)実行とAccの内容を表示をループにしてみた。 表示処理はprint文呼び出しだから遅いけど(ROMコールでAccの表示ってないのかな〜)結果を見ている限りは 非常に単純で、8255のPORT Aはラッチ出力だから常に同じキーコード・・・ようするに 最後にSUB-CPUが出力した値が得られることになる。通常はキーボードが押されたら SUB-CPUはそれをZ80に割り込みとして通知するんだけども、割り込み禁止にしていたら、無条件に キーコードがラッチされる・・・と考えていいのかな?でも、SUB-CPU側でZ80が割込み禁止中かどうかを 判断できるとは思えないけど。

でも、これを下手に実装すると他のところに影響が出そうだ。


ついでだから、先日のDoorDoorMk2ナゾの16Hルーチンを実行してみたのだが・・・実機でも延々と ループし続けるんですけど。どう解釈したらいいのやら。


昨日解析したゲームはAX-1に入っているゲームで、次のバージョンではキーボードで遊べるようになると思う。

それとは別に今回のバージョン(054rel2)から動かなくなってしまったゲームがあることが判明。原因は I/OポートF3hのタイマ割り込み許可・不許可をサポートした事によるもの。でも、これもまた謎で、そのソフトは C0hとDFhを交互にあるタイミングでI/O F3hに出力しているんだけども、最終的にはタイマ割り込み不許可のまま 次の処理へ進み、タイマ割り込みが発生するのを待ち続けている。どつぼ。

どうしようかなぁ、F3hをサポートしたところで、今のところはDoorDoorMk2のロード中画面が表示される メリットしかないみたいだし・・・。

■ [99/2/14]

あるゲームソフトを解析。現象としては、キーボードの入力を受け付けないので ゲームが先に進まない状態になる、まずはキーボード入力を処理していそうなところを探して追っていく・・・のは 途中で面倒になったからIN命令を実行しているところを検索して IN A,(090H)をいくつか発見。

通常、キーボードからのキー入力は割り込みを利用していて、割り込みルーチン内で SUB-CPUと通信して押されたキーの状態を取得するか、割り込みを使用せずに直接SUB-CPUと通信して 押されているキーを取得する。もちろん通信っていうくらいだから、 バスの状態を監視して通信可能かどうか、有効なデータが得られるかどうかを確認する手順を踏んでいるんだけども。

このゲームの場合は、いきなりIN命令を実行してキーの状態を取得しているらしい。そりゃ、SUB-CPUだって ビックリさ。一応、I/O 90Hに対してIN命令をいきなり実行した場合に停止するよう エミュレータにワナを仕掛けてみたら見事に引っかかったので間違いなし。

こういう場合、ゲーム自体は実機で動いているんだからそれに合わせてエミュレータで実装すべきだし、 そうすれば解決なんだけども、なんだか偶然動いてしまっているような気がしないでもない。


エミュレータを使っていらっしゃる方からスペースハリアーのスナップショットを頂いたので ここに掲載。左側が実機で動作している画面で、右側がエミュレータ。

SpaceHarrier_o1 SpaceHarrier_e1

SpaceHarrier_o2 SpaceHarrier_e2

SpaceHarrier_o3 SpaceHarrier_e3

“スペースハリアーで赤と緑の入れ替えは、タイトル画面でSTOPキーを押す”とのこと。

■ [99/2/13]

キーボード割り当てを追加。

CPUクロックと描画ウェイト変更を追加。

ALTキーの割り当てを変更。

SCREEN MODE4で疑似カラフルモードにするとSCREEN MODE3の色がおかしくなるのを修正。

パレットを動的に変化させるように・・・できない。
まったくWindowsのパレット制御は実装から挙動まで、すべてにおいて変だ。 かつてDirectXが出るまでは、世界中のWindowsゲームプログラマーがMicrosoftにいるであろう、 Windowsパレット開発担当者を探しだそうとしていた(探してどうするのかはBlack調で想像してね)というのも、 あながちウソではないなぁ、と改めて思ったよ。

そんなわけで、0.5.4 Rel2公開。赤と緑の入れ替えはそれほど効果はないと思うんだけども、 やっぱりユーザが自由に色を設定できたりした方がいいんだろうなぁと思うので、次の課題かな。

■ [99/2/9]

F7とF8キーが利かなくなったとか(思い当たる部分はある)、今まで動いていたソフトが 動かなくなったとか(ICE BLOCKのは次の版で修正します)の報告が増えてきた。

疑似カラフルモードは赤と緑の入れ替えができるようになりませんか?という意見もちらほら。 ビデオカードにビデオ出力端子がついていたら、そこからRFコンバータ経由で 家庭用テレビに接続してツマミをいじるとか・・・逆転の発想で・・・だめ?だめだよね。
実は、あのあたりの処理ってX11版からそのまま持ってきているから、どのような原理で 再現しているのか把握していなかったり。

それから、スピードの調整も細かくできた方がいいみたい。 4MHzで動いているZ80を8MHzとかで動くように(1MHz単位?)設定できたりするといいかな? それと合わせて画面表示のウェイトを可変にするとか。

というわけでDoorDoorMk2やASPICは、なにかひらめくまで置いておくとして、 当面はスピード調整とかを先に手がけようかな、と思う。

■ [99/2/8]

かなり手強いDoorDoorMk2。無限ループ部分はここだっ。(誰でも書くような汎用ルーチンだからOKだとおもう)

		ORG	09B73H
	
	Z0001:	CALL	Z0000		;9B73	CD 81 9B 	...
		CP	016H		;9B76	FE 16 		..
		JR	NZ,Z0001	;9B78	20 F9 		 .
		CALL	Z0000		;9B7A	CD 81 9B 	...
		LD	(05F3EH),A	;9B7D	32 3E 5F 	2>_
		RET			;9B80	C9		.
	
		; -- まず、8049にデータ送信
		; PortC bit4(8049のWR)を0にする
	Z0000:	LD	A,08H		;9B81	3E 08 		>.
		OUT	(093H),A	;9B83	D3 93 		..
	
	Z0002:	IN	A,(092H)	;9B85	DB 92 		..
		AND	08H		;9B87	E6 08 		..
		JR	Z,Z0002		;9B89	28 FA 		(.
	
		IN	A,(092H)	;9B8B	DB 92 		..
		AND	080H		;9B8D	E6 80 		..
		JR	Z,Z0002		;9B8F	28 F4 		(.
	
		; PortC bit4(8049のWR)を1にする
		LD	A,09H		;9B91	3E 09 		>.
		OUT	(093H),A	;9B93	D3 93 		..
	
		; 送信するデータ本体(1byte)
		LD	A,06H		;9B95	3E 06 		>.
		OUT	(090H),A	;9B97	D3 90 		..
	
	        ; -- 8049と通信して8049からAにデータを取り込む
		; PortC bit6(8049のRD)を0にする
		LD	A,0CH		;9B99	3E 0C 		>.
		OUT	(093H),A	;9B9B	D3 93 		..
	
	Z0003:	IN	A,(092H)	;9B9D	DB 92 		..
		AND	08H		;9B9F	E6 08 		..
		JR	Z,Z0003		;9BA1	28 FA 		(.
	
		IN	A,(092H)	;9BA3	DB 92 		..
		AND	020H		;9BA5	E6 20 		. 
		JR	Z,Z0003		;9BA7	28 F4 		(.
	
		; PortC bit6(8049のRD)を1にする
		LD	A,0DH		;9BA9	3E 0D 		>.
		OUT	(093H),A	;9BAB	D3 93 		..
	
		; 戻り値
		IN	A,(090H)	;9BAD	DB 90 		..
		RET			;9BAF	C9		.

まず、サブルーチンである、Z000:からはSUB-CPUと通信してコマンド6を送り出し、その結果をAccに入れてリターン。 これって、Accに06hを入れてからBASIC-ROMの0E8Fh、0E78hを順にコールするのと一緒。

そのサブルーチンを呼び出しているZ0001:からは、Z000:を呼び出して、 返り値のAccが16hになるまでループしているんだけども、どうやらエミュレータではここで引っかかっている様子。 ちなみにコマンド6は矢印・スペース・ストップ・シフトキーの状態をSUB-CPUから取得するものなんだけど、 状態として16hになるのは、右・上・ストップを一緒に押した時だ。
それはとっても変な組み合わせに見えるから、きっとこの値に状態としての価値はないんだと思うし、 その次に再度Z000:を呼び出して結果を05F3Ehに保存しているから、二度目の呼び出しが状態としての 値だと思う。

BASIC-ROM内のルーチンでは、上のようにしてキーの状態を取得するのではなく、 SUB-CPUにコマンドを送信したら、SUB-CPUからの割り込みを待ち、データが確定するまで空ループしていたと思う。 上のルーチンでは、ここにジャンプしている段階では割り込み禁止になっているからその方法が使えないのか、 割り込まれたくないから禁止にしているのかはわからないけど、コマンド6を送信してからキーの状態が 確定するまでのタイムラグがあって、その対応をしているのだろうか?

でも、どうして16Hなのか、16Hになるまで何度もコマンドを発行し続けるのか、その理由がわからないや。 それに一度16Hを受け取らないと有効なキーの状態を取得できないというのも謎。
深く考えないで、そういうものだと割り切ってなんとか実装してしまえばいいのかな・・・。

実機では上のルーチンで動いているんだから、試しに同じルーチンを実機で実行して 挙動を確認すれば納得できる(かもしれない)けど、エミュレータに実装するのは 一苦労(ってできるんだろうか、こんなの)だろうなぁ。

じゃあ、試しに16Hと比較した後のJR NZ,Z0001をつぶしちゃったらどーなるの? ということで、NOP(00H)に書き換えると、99/2/6の日記のようにやっとキャラクタ紹介の画面が表示される。 でもって、スペースキーでゲームを始めようとすると、暴走。・・・ん〜いきづまったっぽい。 この先は根気の要る作業になりそうだなぁ。

実はテープイメージの作成失敗で、16Hは化けたコードだとかだったら泣いちゃうな。


動作中のRAM(64K)の状態をファイルに書き出すようにした。

■ [99/2/6]

動作中のSCREEN4での疑似カラフルモード変更は、まだバグがあるみたい。


がんばってここまで到達。

doordoor2_1 doordoor2_2

キー入力を受け付けないのでゲームが始まらない。どうやら、SUB-CPUの未実装部分で引っかかっている みたい。

■ [99/2/5]

昨日気が付いたバグはオリジナルから手を入れた部分。いつかはこういうミスをすると 思っていたけど、とうとうやってしまいましたね、という感じ。ま、いいか、仕事じゃないし。


それでもDoorDoorMk2は動かない。でも、1バイト、1クロックをクロックを 削るかのような気の利いたコードを読む(解析する)のはとても楽しい。 なんだか削るためのコーディングではなくって、 プログラムの美しさを求めて書かれているような感じさえする・・・なぁんて考えてたら 自己書き換えしている部分を発見して辛くなってきたり。

どうやらサポートしていない(と思われる)ポートに対して読み書きしているようだ。

■ [99/2/4]

遠方での打ち合わせと慣れない会議で体力的にダウン寸前だけどもコーヒー飲んで頭だけ活性化。 体は寝てても意識はしっかりしてるから、かえって集中できたりする・・・っていうか、普段からして 体力が余り過ぎなんだよなぁ・・・とか考えながらCのソースやらアセンブルリストを4つほど 開いてボ〜っと眺める。

1分経過。

Interrupt()内での処理では、なんらかの割り込みが発生すると割り込みジャンプアドレスを返す。 例えばそれは、2msecタイマ割り込みが発生した場合にはFA06Hという値のように。
じゃあ、LD A,0FFHしてからLD I,Aとした場合は・・・。

DoorDoorMk2では割り込みベクトルを変更しているから、“なぜタイマ割り込みを停止させると ロード処理が継続されるのか”の理由が分かったような気がする。でもタイマと同様に 割り込みを利用しているTAPEからのREADだっておかしくなるはずなのに。 ・・・と思ったけども、DoorDoorMk2ではTAPEからの1byte取得処理(SUB CPUとの通信)はBASIC ROM内のルーチン (つまり割り込みベクトル変更前のジャンプ先)とまったく同じ記述なのだから偶然動いているのか。

冴えてるぞフフフ。(眠くてちょっと壊れ気味?)さてと、メールチェックしてページグルグルして寝るかぁ〜 ・・・うきゃ〜?!X版の0.5.4が〜。

■ [99/2/3]

DoorDoorMk2の続き。ふむふむ、テープから読み取ったデータはリングバッファに貯えているみたいだ。 今ではちょっとコードをみただけで『これはリングバッファだ』って分かるけども、昔だったら 『なんだこの処理???』って悩み続けたんだろうなぁ。

割り込みベクタを書き換えている部分がある。タイマー割り込みのジャンプ先処理は 割り込み解除してC9・・・じゃなかった、RETしているだけだ。ということは、エミュレータで タイマ割り込みを止めると動き出すっていうのは割り込み処理のマスクか、割り込みベクトルの変更が うまくいってないってことだな。そろそろエミュレータ本体のソースを見直してもいいんだけど、 DoorDoorのプログラムが面白いからもうちょっと解析を続けようっと。

■ [99/2/2]

new version公開。

プログラムに没頭したい日だったのでDoorDoorMk2の解析を続ける。
結構読み進んだとは思うんだけども、音楽を鳴らしつつ、画像を読み込みながら表示し、プログラム本体を読み込んだ上に 面データの半分を読み捨てるという、PC-6001としては異常なまでのテープロードルーチンなのでなかなかに手強い。

isio氏に便利なデバッグルーチンを頂いたのでそれを使ってコードを追いかけると楽そうなんだけど、 テープイメージが正しいかどうか保証されていない現段階では問題点を絞り込めなくなるのがちょっとイヤかも。

■ [99/2/1]

とある方のご協力があり、DoorDoorMk2のローダー部分を解析し始めたのだが。

誰よ、このプログラムを書いた人は〜?!やっぱり中村氏自らかな〜?とにかく不規則に ジャンプするわ、プログラム自体をLDIRで転送してからそのアドレスにジャンプするわで なかなか読み応えがあるっていうか、平日の仕事後だったら挫けていただろうなぁ。 でもって、とにかく一回逆アセンブルしたくらいじゃソースを追うことができないので 後日、気合を入れなおして再度挑戦。

ちなみに、DoorDoorMk2をSRで動かす場合はSR専用品が必要らしい。 当然、SRから取り出したBASIC-ROMでエミュレータを起動してからDoorDoorMk2テープイメージを 読み込んでも動作しない訳なんだけど、本来は正しく動作するはずのMk2のBASIC-ROMでも SR同様、動作しないようだ。

ただし、TimerIntをOFFにするとマシン語部分の読み込みを開始する。 同様にSRのBASIC-ROMでもTimerIntをOFFにすると読み込みを開始してくれる。

・・・ん?ということは、もしかして割り込みマスクのエミュレートがうまくいってないのかな???

■ [99/1/31]

昨日、ビデオカードの設定を変更したせいだとは思うんだけどもNT4.0の描画 速度がとてつもなく遅くなってしまった。かなりイタイな、この速度は。

アスピックが動作しないのはエミュレータの方の問題かなぁ。

aspic-title aspic-bug

タイトルが出た後、かなりヘロヘロな音楽が流れてから途中から始めるかどうかの確認(左側画面)。 ここでシナリオをテープに作成するんだけど、これがうまくいかない。セーブが終わった後に チェックを選択するとなぜかエラーになってしまう。

しょうがないからゲームを始めると右側の画面の通り、画面を壊し続けるだけで明らかに暴走してる。

うーん、どこから手をつけたらいいのかさっぱりわからない。推測としてはメモリの切り替えに 失敗していてプログラム領域ではない部分のコードを実行しているような・・・。なんにしても、 暴走した状態でのメモリ状態とレジスタを見る手段を作らないとだめか。 その前に、PC-6001mk2のメモリマップ&I/Oがよくわからなかったり。

■ [99/1/30]

X版Ver.0.5.3を取り込んだ。大きな修正はSCREEN4での疑似カラフルモードと色の調整かな? 拡張ROMは・・・GUIを作るのが面倒だからとりあえず保留ということで。

とある方から、SRの資料をお借りする事ができたので軽く読み流してみる。う、モードによって 画面の書き換えタイミングが微妙に違うみたいだ。それに“画面表示中にV-RAMを書き換えると 画面が乱れます”と書いてあるってことは、SRとかだと、描画中でもメモリアクセスが出来るのかな? そろそろ機種別に処理を変えないとだめか。

DirectDrawを使わないフルスクリーンモードは魅力があるなぁと思い、ディスプレイの解像度変更 に挑戦。手持ちのビデオカードはWindowsNTで320x200 8bitColorを サポートしているみたいだから強制的に変更してみた。 メニューが表示されたり、タスクバーがジャマだったりするけどもなかなか味わい深い画面だ。 でもWin95で実行するとOSを再起動する必要があると思うし、 (実際にやってみたら、320x200をサポートしてなかった) モード変更後にディスクトップ上のアイコンがすべて左上に移動してしまうから 実用度は低いので、エミュレータでは不採用だな。

■ [99/1/27]

何人かの方々から資料を提供していただいていますが、本当にありがたいことです。 もともとが移植で始まったものだけれども、いろんな人の協力の結果として 出来たもの(まだまだ完成品ではないですが)というのはいいなぁと思います。 資料は常に募集していますので、ご協力よろしくお願いします。


ちょっと前にキーボードのクリック音がしないという指摘のメールを頂きました。うーむ。


資料読みと、5.0.3の組み込み、rel.4で発覚した問題点の解決、動作しないソフトの解析と やりたい事がたくさんあり過ぎ。

■ [99/1/20]

会社から借用してきたSONYのVAIO 505で動作テストをしてみる。 ガ〜ン、play"cde"を実行するとplay"ccddee"のような演奏になってしまう。 play"c1"とするとplay"c8"のように音が分断されるなぁ。 tinyXEVIOUSを実行してみると…これは聞くに耐えられん。

動作レポートでサウンドカードの性能をチェックしてみると… サウンドカードが三枚ある。一枚はVOICEモデムでもう一枚は謎、残りの 一枚をエミュレータでは使用している。 カードの性能としては44.1KHzをサポートしていないくらいかぁ。 どんな長さの音でも途中で分断されるってことは、生成している音パケットの サイズが小さいとか…わからん。まいったなぁ、これは。


スピードの調整をしたのはいいんだけども、CPUパワーが足りない場合は 前のバージョンとほとんど変わってないことになるなぁ。 他のメリットとしてはタイマ割り込みがほぼ2ms間隔で発生するとか。

ドキュメントには書いていないけど、INIファイルのUPERIODの値を書きかえると フレーム飛ばしになる。でもテストしてないからどんな弊害がでることやら。

■ [99/1/19]

Rel.4を会社の高速なマシンで動かしてみたところ、60fpsできっちり動作しているのだが、 無駄な空ループ処理のせいでOS全体の動作がぎこちなくなっている事に気がつく。 タスクマネージャでみると、iP6forWinのCPU占有率が100%近いのだから当然か。 対処方法はいろいろあるけれども、とりあえず目をつむることにしようかな。

なんにせよ、今週はこれ以上手を入れられないのでRel.4公開。

■ [99/1/18]

キーバインドの変更をしようかな、と思う。101キーボードとPC-9801(21)とノートパソコンに 共通して存在するキーに対して割り当てを行ない、ALTキーがGRAPHになっているのはやっぱり不便で Windowsライクじゃないのは気持ちが悪い。

GRAPHがファンクションキーだったりすると遠くて不便かもしれないけど そんな頻繁にGRAPHキーを使う人はいないでしょう、きっと。


音の長さがおかしいのは、タイマ割り込みの排他制御をサボっていたからみたい。 Iregなんていままで気にも留めないでいたし。 そんなわけでスピード調整はほぼ完了したつもりなんだけど、やっぱり音が舌たらずな感じ。

■ [99/1/17]

ウェイト調整のプログラムを書く。タイマーとCMT割り込みのバランスを取って、 CRTCがBUSREQを発行している状態でのウェイトも考えて、と。 なんとなくよさげな感じに仕上がった。

試しにplay"cdef"を実行して音の出る時間を計る。 ・・・音の出る長さがおかしい。なんだか通常の2倍の長さで音が出ているような気がする。 ということは、まだタイマー割り込みの間隔が変だってことかぁ。

そんな感じでコンパイルと実行を繰り返しているうちに、SB64と相性の悪いうちのNTマシンが ハングしたついでにソースがlostしたりもしたので (もちろんバックアップはとってあるけど)今日はおしまい。 今週後半はしばらくマシンに触れないので、いつRel.4を公開できるのやら。


キーボード割り込みの間隔がよくわからないので、実機を前にして 大体の間隔を測定してみる。でもBASICで試したから、実際の割り込み間隔は ちゃんとしたアセンブラプログラムを書くか、 シンクロスコープかデジアナで測定しないとわからないけど。

大体、1キーあたり、55〜60msecってところかな?エミュレータだと2倍くらい速いから、 これも割り込み処理としてちゃんと処理しないとなぁ。


この日記を更新すると、WWWCでチェックされている方々には申し訳ないのだが、 エミュレータ本体は更新してないのにpc-6001ページ(1個うえ)にある index.htmlの日付だけが更新されてしまうのであった。
ごめんなさい。

■ [99/1/15]

wav2bin.exeのテストを兼ねて久しぶりにテープからのコンバートをしたけれども、 TR Errorが出て変換できなかった。同じWavファイルをP6dataRecで変換したみたものを 実行してみたのがこれ。

galaxian digdug

どっちもそれなりに動いている感じ。スピード調整をサボってるから発音タイミングが いまいちだけど。


小峰さんという方から、 「PC6001mk2SRに1DDのFDDを増設して、そのメディアをPC-386Sで読み書き&PC6001形式の フォーマットできるプログラムを作ったことがある」というメールと、 合わせてそのプログラム(QuickBasicで書かれている)を頂いた。

FDDメディアの取り扱いはなんとかしたいところだけども、FDDが扱える実機や 周辺I/Oの資料がないからちょっとつらいところ。資料なしでSRのBASICを読むのは さすがに難しい。

■ [99/1/11]

とある方(Uedaさん)から、QueryPerformanceCounter()を使ったWAITルーチン プログラムを頂いたので組み込んでみた。実はこの方法、以前に試した時に 失敗に終わり、『QueryPerformanceCounter()は環境に依存するかな』と思って 深くは追求しないでいた。
結果としては成功で、それなりにCPUパワーがある環境だと 見た目は60fps 4.00MHzで動作するようになる。
ただし、TinyXEVIOUSは相変わらず瞬殺されてしまうし(なんでだろ?)、 画面更新頻度を下げるとタイマー割り込み間隔やテープリード割り込み間隔が 悪化してしまうので、まだまだ調整が必要かな。

OSのタイマーに依存してしまったので、LinuxやBSD、Macintoshで 同じ事をする場合は精度が低くなってしまうかも。


1998年までの日記

PC-6001のページに戻る