X68000エミュレータXM6 version 2.05改
X68000 EMULATOR XM6 version 2.05+

 XM6に新機能WindrvXMデバイスを実装しました。
 いわゆるテクノロジープレビュー版ってやつです。
 改良のアイディアやバグ報告などがあればぜひお知らせください。

ダウンロード

XM6改について

 XM6 v2.05に以下の改造を施しています。XP以降のOSとSSE2対応CPUが必要です。

 さらに、XM6 TypeG独自の追加機能および数々の改良点を、作者のGIMONS氏の全面協力のもと、ソースコードに組み込んでいただきました。
 XM6 TypeGの改良箇所は描画、入力、GUI、内部処理など多岐に渡ります。この改良によって、エミュレーションの精度がさらに高められています。
 改良部分のソース公開についてもご快諾をいただきました。
 この場を借りてあらためてお礼申し上げます。ありがとうございました。

 なお、XM6改で試作した追加機能はXM6 TypeGにも搭載される予定です。
 68030MPUエミュレーションにも対応した多機能・高性能なエミュレータとして併せてお勧めです。

使いかた

 基本的に原作のプラスα版なので、詳細は原作のドキュメントを参照してください。
 ちなみに原作の動作環境が既にある場合、実行ファイルをXM6p.exeなどの別名に適当にリネームしてコピーし、以前のXM6.iniをコピーしてXM6p.iniなどの別名にリネームすれば共存可能です。

 まず、エミュレータを起動し、右クリック→ツール→オプションで設定のWINDRVタブを開き、「WindrvXMを使う」のチェックボックスに印をつけます。

 次に、エミュレータ内のHuman68kに、デバイスドライバ(WindrvXM.SYS)を組み込みます。
 フロッピーディスクイメージを用意しておきましたので、まずこれをマウントしてデバイスドライバのファイルを他のディスクにコピーしてください。
 てっとり早く試してみたい場合は、Human68kのシステムディスクにコピーするのが簡単です。

 最後に、Human68kのCONFIG.SYSの末尾に以下の行を追加してドライバを組み込みます。

DEVICE = (インストールしたパス名)\WindrvXM.SYS

 これでホスト側のファイルシステムをエミュレータの内部から掌握できるようになります。以上。

ね?簡単でしょう(Very Easy)

ちくわ大明神

 ソースは最小限のファイル差分となっています。バージョン2.05のソースツリーにそのまま上書きしてください。

 オリジナル部分のソースコードの著作権については、これまでと変わらず原作者のPI.氏に帰属します(該当するものはすべてソース先頭部分に著作権表示があります)。ソースコードの扱いに関してはXM6原作のドキュメントを参照ください。

 また、描画系をはじめとしたXM6 TypeGの改良部分のソースコードの著作権については、作者のGIMONS氏に帰属します(該当するものはすべてソース先頭部分に著作権表示があります)。ソースコードの扱いに関してはXM6 TypeGのドキュメントを参照ください。

 そして、「無いものは作る」という素晴らしいX68000文化の普及に役立つことを願い、私が作成したWindrvXMに関するプログラム(ソースの差分箇所)およびドキュメント(これ)はすべてCC0 PUBLIC DOMAINとします。自由にご活用ください。無いものは作る。それだけだ。いいね?

 
 

 以下、WindrvXMに関する簡単な解説。

WINDRVとは

 WINDRVとは、SHARP X68000シリーズ(以下X68000)のエミュレータ上にて動作する、ホスト側ファイルをリモート操作するためのプログラムです。これはX68000エミュレータの先駆けであるEX68用に開発されたものでしたが、その後、同等機能がWinX68kにも実装され、事実上X68000エミュレータ用のリモートファイルシステムの標準規格となっています。
 (なお、WINDRVの機能は、エミュレータ内部のI/Oポートエミュレーションと、Human68k側のデバイスドライバを組み合わせることにより実現されています。本稿ではエミュレータ側とHuman68k側の機能の両者を同一名称で呼んでいますので、ご注意ください。)

WindrvXMとは

 WindrvXMは、従来のWINDRVの動作を参考に、X68000エミュレータXM6上に同等の機能を実装した仮想デバイスです。
 従来のWINDRVの実装では、XM6の仮想マシン(以下VM)の動作に一部支障をきたす可能性があったため、一から設計を見直し、VMとデバイスドライバ間の通信プロトコルを改良して解決を図っています。
 XM6におけるWindrvXMデバイスは従来のWINDRVの完全上位互換デバイスとして動作します。
 従来のデバイスとはポート番号が重ならないように設計してあるため、新開発のドライバを使ってパフォーマンスを改善することはもちろん、従来のデバイスドライバで作られた環境をそのまま動作させる事も可能となっています。

WINDRVとWindrvXMの違い

 WindrvXMは、従来のWINDRVからさらなる使い易さを追求するべく、以下の改良が加えられています。

 WindrvXMデバイスは従来のWINDRVデバイスの上位互換として動作するため、従来のデバイスドライバがそのまま使うことができます。

番外編: WINDRVとは

 こちらの知る限り、X68000の歴史上においてWINDRVと呼ばれるソフトウェアは2種類存在します。将来混乱が起きないよう、ここにメモを残しておきます。
 最初に作られたものは、X68000用ウィンドウシステムKo-Windowにおいて、bgdrvによるマルチタスク環境を実現するための仮想端末BG-termに付属のデバイスドライバ(windrv.sys)です。作者は小笠原博之(COR.)氏です。
 そしてもう一方は、X68000エミュレータEX68およびWinX68k用に作られた、エミュレータのホスト側のファイルシステムをリモートドライブとして扱うためのドライバです。作者はyamama氏です。その後立花@桑島技研氏によるバグフィクスが行なわれています。

使いかた

 WindrvXMの利用には、以下の3つの手順が必要です。

1. エミュレータ側の設定を変更し、WindrvXM機能を有効化する
2. エミュレータ上のHuman68kに、デバイスドライバ(WindrvXM.SYSもしくはWINDRV.SYS)をインストール
3. お好みでデバイスドライバの引数を設定して完了 (最新版は引数設定は不要です)

 順を追って解説します。

1. エミュレータ側の設定

 XM6をインストールした直後の状態では、WindrvXMデバイスが動作していないため、まずこれを有効化する必要があります。
 まず、XM6を一度実行→終了させて.INIファイルを編集します。[Windrv]セクションの中にEnable=0という記述がありますので、この行を編集して、Enable=1とします。

 この値は以下の意味を持ちます。

動作
Enable=0ポート0,1ともに存在するがデバイスは停止状態 (XM6のデフォルト動作)
Enable=1WINDRV互換ポート0およびWindrvXMポート1の両方を有効にする
Enable=2WINDRV互換ポート0のみを有効にする
Enable=3Enable=1と同じ (初期のWindrvXMとの互換性のため)
Enable=255予約 (実機と同様にバスエラー扱いとなる)

 最新のXM6系のエミュレータ(XM6 TypeG等)であれば、オプション画面で上記の0,1,2に相当する設定ができるのでとっても便利です。

 ほかにも、追加設定で.INIファイルのOptions=0の部分を書き換えることで、削除操作をごみ箱にすることができます。

動作
Option=0通常の削除を行ないます。削除したファイルは二度と復元できません。
Option=1ファイルおよびフォルダの削除にOSのごみ箱機能を利用します。復元はOS側で操作してください。

2. エミュレータ内のHuman68kにデバイスドライバをインストール

 エミュレータ内のHuman68kに、デバイスドライバ(WindrvXM.SYSもしくはWINDRV.SYS)を組み込みます。
 この際、何らかの手段でホストOS上にあるデバイスドライバのファイルを、エミュレータ内部へ送り込む必要があります。フロッピーディスクイメージを用意しておきましたので、まずこれをマウントしてハードディスクにコピーします。
 次に、Human68kのCONFIG.SYSに以下の行を追加します。

DEVICE = (インストールしたパス名)\WindrvXM.SYS

 組込む位置はどの場所でも構いませんが、以下の注意があります。

 詳細については、デバイスドライバ側のマニュアルを参照してください。

3. 引数の設定(省略可能)

ここは面倒なんで読む必要はありません。引数なんてなかった。現在の版では2の設定だけで便利に使えます。

 前項までの作業が済めば、WindrvXMが有効となり、ホスト側の全ドライブがHuman68k側にマウントされて自由に操作可能となります。

 そのままでも十分使えますが、さらに便利に使うために各種設定を行なうことが可能です。設定は、Human68k側のCONFIG.SYSの行に、以下のオプションを指定することで行ないます。

・削除処理のごみ箱利用 -d -D : 直接削除 / +d +D : ごみ箱利用
 このオプション指定は廃止されました。前述のXM6.iniのOptions=1設定を使ってください。
 ファイルを削除した場合、直接削除するか、一旦ホストOSのごみ箱に移動するかどうかを指定します。
 デフォルトは-Dで、直接削除を行ないます。
 ごみ箱を利用すると、間違ってファイル削除を行なってもホストOS側の操作で復活ができる反面、アプリケーションによっては著しい速度低下が起こる可能性があります。
※この設定がデバイスドライバからできるようになっているのは、エミュレータのGUI設定を作り込むまでの間の仮仕様です。将来はデバイスドライバ側ではなく、エミュレータのGUI設定で設定できるようになる予定です。

・カーネル・ドライバ監視 -k -K : なし / +k +K : あり (+Kだと±A/T/Cを自動設定)
 このオプション指定は最新版では不要となり廃止されました。最新版では、Human68kカーネル内のファイルシステムドライバ(TwentyOne)を自動認識して設定内容をWindrvXMの設定にも反映します。

・メディアバイト処理 -m -M : 固定 / +m +M : 変動
 このオプション指定は最新版では不要となりました。ファイルシステムドライバ(TwentyOne)の発見時に自動的に有効化されます。
 WindrvXMのドライブのメディアバイトの値を、ホスト側ドライブのメディア種類によって以下のように変更します。
 デフォルトは-Mで、何も変更しません(常に0xF3となる)。
 なお、リモートドライブ上においてメディアバイトの値を反映させるためには、(V)TwentyOne version 1.36c modified +14 patchlevel 6以降が必要です(TwentyOneを使わない場合はHuman68kのバグ?により、リモートドライブのメディアバイトの値はドライブ名に依存する値となります)。
0xF3: ハードディスク
0xF2: リムーバブルメディア(CD-ROM・メモリーカード)
0xF1: 手動イジェクトメディア(フロッピーディスク)

・ファイル名変換 -a -A : 18+3 / +a +A : 8+3 (-K時のみ有効)
 ホスト側のファイル名変換の文字数を指定します。
 デフォルトは-Aで、18+3文字のファイル名を生成します。

・ファイル名比較(未実装) -t -T : 8+3 / +t +T : 18+3 (-K時のみ有効)
 ホスト側のファイル名の比較の文字数を指定します。
 デフォルトは+Tで、18+3文字すべてを比較します。
(なお、-Tは未実装です。)

・大文字小文字区別 -c -C : なし / +c +C : あり (-K時のみ有効)
 ホスト側のファイル名の大文字小文字を区別するかどうを指定します。
 デフォルトは-Cで、大文字と小文字の違いは区別されません。

・ファイル名変換 先頭のピリオド -E : なし / +E : '_'
・ファイル名変換 中間のピリオド -P : なし / +P : '_'
・ファイル名変換 先頭のハイフン -N : なし / +N : '_'
・ファイル名変換 中間のハイフン -H : なし / +H : '_'
・ファイル名変換 無効な文字 -X : なし / +X : '_'
・ファイル名変換 スペース -S : なし / +S : '_'
 ホスト側のファイル名をHuman68kファイル名に変換する際、該当する文字を'_'(アンダースコア)に変換するかどうかを指定します。
 デフォルトでは、変換は行ないません。

・ファイル名短縮 先頭のピリオド -e : なし / +e : 短縮
・ファイル名短縮 中間のピリオド -p : なし / +p : 短縮
・ファイル名短縮 先頭のハイフン -n : なし / +n : 短縮
・ファイル名短縮 中間のハイフン -h : なし / +h : 短縮
・ファイル名短縮 無効な文字 -x : なし / +x : 短縮
・ファイル名短縮 スペース -s : なし / +s : 短縮
 ホスト側のファイル名をHuman68kファイル名に変換する際、該当する文字を削除して文字数を短縮するかどうかを指定します。
 デフォルトでは、短縮は行ないません。

例)
DEVICE = \SYS\WindrvXM.SYS +KT -DMAC -EPNHXS -epnhxs

 
 

このページを訪れた方へお願い
 もしXM6原作者のPI.氏と連絡が取れる方がおりましたら、氏のご迷惑にならない範囲で、以下の一言だけで構いませんのでお伝え願えないでしょうか。
 
「最高のものを作りました。お暇な時で構いませんのでぜひご覧頂きたいです。」
 
 長いこと連絡が取れず、途方に暮れております。どうかよろしくお願いします。
PI.さん、たいへんお久しぶりです。

 
 

履歴

2006.02.13 初版

まずはカタチから入る。

自家製ROMパッチの多い日も安心。

設定ファイルのやりとりでトラブったため。
最初の起動時に、変なファイル名がINIファイルに残ってしまうので、推測されたファイルが存在しなかった場合はSxSI初期値と同様にファイル名無しの状態になるよう変更。

設定ファイルのやりとりでトラブったため。
コンフィグファイルの読み書きの際、実行ファイルのパスと前方一致した場合は、その部分を省略するように変更。インストール先が違う人同士でも、INIファイルをそのまま利用可能。

config.h: window_resume window_x window_y 追加
ステートファイル互換性消失

config.h: menu_bar status_bar 追加
ステートファイル互換性消失
メニューバー回りは未実装

config.h: fd_resume fd_file[] mo_resume mo_file 追加
ステートファイル互換性消失
FD2/FD3の挿入・イジェクト関連GUIは未実装(INIファイルを直接編集すれば可)
MOは未実装

config.h: port_384 削除
config.h: port_force port_speed 追加
ステートファイル互換性消失
速度設定のGUIは未実装(INIファイルを直接編集すれば可)

WINDRV.SYSと聞くとKo-Window用のデバイスドライバが先に思い出される今日このごろ
FCB回りの処理はEX68と互換性がないが、それなりに動くはず。…動かなかった。…動くようになった。
TwentyOne系のインストール必須だったが、入ってなくてもそれなりに動くようにしてみた。
EX68同様、ホストOSのハンドルは一切保持せず、呼び出しのたびに確保/破棄しているため、動作速度が遅い(実機の動作速度に比べたら誤差みたいなものだが)。
ファイルの削除はごみ箱を使用。
エラー処理未実装(実装中)
コマンド$51〜$58未実装(EX68同様に何もせず終了)
リードオンリー判定処理未実装
ベースパス処理未実装
許可ドライブ/リードオンリー/ベースパス設定GUI/設定保存未実装

2006.02.14

コマンド$51(CtrlDrive)実装。ようやくmintからドライブが見えるようになった(まだ止まるけど)。
コマンド$52(GetDPB)実装。立花@桑島技研氏のwindrv_.sysのパラメータをそのまま流用。
残りのコマンドはEX68でも使われていないので放置…と思ったが、排他制御回りはきっちりやっておかないとSX-Windowとかまずいかも。

2006.02.15 ひとまず完成とする

FD状態復元のタイミングが間違っていたので修正(PI.さん、ありがとうございます)。

コマンド$4E(SEEK)が失敗するバグを修正。
コマンド$47(FILES)で扱えるファイルサイズの最大値を2GBから4GBに変更。
ファイルサイズが1〜2GBを超えたあたりから、正常に動かないアプリが出る恐れがあるので要注意。
コマンド$53 $54 $55(IOCTRL系)の動作を変更。今までは無条件成功としていたが、lzdsysが常駐していると、実行直後に付近のメモリをポインタとしてアクセスしてアドレスエラーが起きることがあったため、無条件失敗とするように修正。厳密にやるなら、入力パラメータを正しく解釈して該当するメモリを正しく設定して正常終了させるべき?
ファイルのオープン・クローズをHuman68kからの指示に厳密に従うように修正。

2006.02.16 マッスルドッキング

・アイコン変更
・ROMバージョンチェック削除
・INIファイルへ相対パスで保存するよう変更
・ウィンドウ位置保存
・ステータスバー表示設定の保存
・リムーバブルメディアの挿入状態の保存
・WINDRV実装
それ以外の修正(ResetSASI()とシリアルポート関係)は没。なかったことにする。

2006.02.18 WindrvXM対応

2006.02.21 バグとり

 といいつつエミュレーションしてみるテスト

2006.02.24 移行

WindrvXM(仮)実装。API発行を別スレッドで行なうことで、VM側への負担をなくすことができる。
しかし、かなり速度低下を起こしてアワワ
将来に向けて、ディレクトリエントリをエミュレーションでなんとかしてみることに。
ディレクトリエントリのエミュレーションを仮実装。DOS _FILES/_NFILES直後に、1つだけディレクトリエントリが存在する仮想的なセクタを生成する。FILBUF(非公開)を見てディレクトリエントリを直接アクセスするタイプのプログラムが動くようになるはず。

2006.02.26

ディレクトリエントリの生成を常に行なうのはアレなので、_DISKREDによるリクエストがあった時点で動的に生成するように修正。
ディレクトリエントリを見て、ファイル実体の先頭セクタを計算するタイプのプログラムに対応させた。
SCM.xがWindrv上にあるLZD圧縮されたファイルを正常に演奏できるようになったので満足。

SCM.xが正常に表示されるようになった。
が、スターウォーズが化け化けになったのでボツ。正攻法でやらないとダメらしい。

2006.03.11

ディレクトリエントリのキャッシュ処理を追加。
18+3文字のみのフォルダ・ファイル名で構成されたパスを自動生成するように修正。
PROGRA~1などという名前はHuman68k側からは観測・アクセスが一切できない世界を実現。う〜ん満足。

2006.03.13

ファイル名の中のスペースがTwentyOneがあってもうまく処理できない。Human68k内部で空白部分が消滅している?なぜだー
ファイル名重複時のパターンを1000通りほど用意。VeryLongFile$0.tar.gzってな感じになる(現在は$ではなく@を使っている)。
クラス構成を見直し。CSerializeを廃止し、CWindrvに統合。
リードオンリー処理追加(仮実装)
低速デバイス処理追加
めぼしいバグはつぶしたつもり。
ねる。

2006.03.14

クラス構成を見直し。CWindrvにすべてコマンドハンドラを移動。美しい。一時的にログが利用不可能となっている。そのうちなんとかする。
ベースパス実装開始。

2006.03.19

複数スレッドからの呼び出しでハンドル管理がうまくいかないバグを修正。パラメータを最適化し、VM側に必要なコード量を削減。

2006.03.20

DOS _FILESの戻り値を修正。パス名検索時(内部処理でファイル名へ到達する前)にエラーが発生した場合は-3を返すようにした(立花@桑島技研さん、ありがとうございます)。
リモートコール$49で、ファイル上書き確認処理を実装。DOS _NEWFILEがファイル上書き時に正しくエラーを返すように修正した(立花@桑島技研さん、そのほかさまざまなアドバイスをありがとうございます!)。

コマンドハンドラ実行完了時の、VMのロック/アンロック処理の無駄を省いて高速化。
利用不可能になっていたログ表示処理を追加。
メディアバイトを固定値にする試験開始。

2006.03.21

DOS _CREATE/_NEWFILEにて、ファイル属性値のビット8〜15にゴミが混ざることがある。混ざってもHuman→Hostの属性変換で消えるので問題はないが、下位8ビットのみしか扱わないように修正。
ファイル削除時にキャッシュと実ファイルの状態が不一致になるバグを修正。
DOS _RMDIRにて、ファイルが存在していても削除できてしまうバグを修正。
DOS _NFILESとファイル削除を同時に実行すると、正しく全てのファイルが取得できないバグを修正。
DOS _OPENにて、ファイルが存在しない時、間違ったエラーコードを返してしまうバグを修正。

2006.03.22

ルートディレクトリのファイル更新を検出できないバグを修正。
DOS _NFILESで、キャッシュに変化がない場合の検索処理を高速化。
DOS _SEEKで、0x80000000バイト以上の位置へ移動するとデバッグモード時にエラーログが出力されるバグを修正。
ファイル最大サイズを0xFFFFFF7Fバイトに変更。

2006.03.23

他のアプリケーションがフォルダを削除しまくっている最中に削除中のフォルダに対してアクセスを行なった場合、タイミングが悪いとメモリーリークが発生するバグを修正。
メディアバイトの値を0xF3に変更。
動作オプションをだいたい実装。
ファイル名重複時のパターン最大数を1000パターンから6千万パターンに増強。

2006.03.26

ライトプロテクト処理を実装。
リムーバブルメディアの状態取得処理を実装(Windows NT系専用)。
リムーバブルメディアのイジェクト処理を実装(Windows NT系専用)。
ドライブの状況は、DOS _DRVCTRLにリアルタイムで反映される。
DOS _GETDPBとDOS _DISKFREのクラスタ情報が一致するよう改良。コンセプトは「見た目は人間、中身は液体金属。」
セクタサイズが512バイト以外のメディアでも、セクタサイズが512バイトとして換算するように修正。
仮想セクタ処理を、クラスタサイズが512バイト以外でも正常に動作するよう修正。一度獲得したクラスタサイズはキャッシュし、lzdsysのための仮想セクタ処理を僅かながら高速化。
CD-ROMメディアにおいて、容量取得時にクラスタ数が16ビットの範囲を超えてしまい正確な値が伝わらなかったため、クラスタサイズを補正して正しい値を返すよう修正。
ボリュームラベルの取得処理と残り容量・クラスタ構成の取得処理を、CWindrv(コマンドハンドラ管理クラス)からCWinFileDrv(ドライブ管理クラス)に移動。
他のアプリケーションによるリムーバブルメディアの入れ換え検出方法が不明なため、キャッシュの不一致が起きた場合は、DOS _DRVCTRLでメディアをイジェクトさせること。

2006.03.30

コマンド$56(FLUSH)を実装。キャッシュを強制クリアする。
「ディスクが入っていません」の白帯エラーを仮実装。まだ有効にはしない。
SHChangeNotifyRegisterを使ってCD-ROMなどのリムーバブルメディアの状態を取得するよう改良。CD-ROMドライブをmintで監視し続けた場合でも、スムースに認識するようになった。
フロッピーディスクなどの手動イジェクトを行なうメディアで、無駄なアクセス音を極力発生させないように改良。
概要: 現在のIBM-PC/AT互換機では、FDD内のメディアの存在を、FDD内のデータに直接アクセスすることでしか観測できない。この観測行為には3つの問題が存在する。
1. 一般的なAT互換機では、FDDのモーターが停止している状態からのドライブへのアクセス完了まで、どんなAPIを利用しても1000ms以上かってしまう。X68000では、mint等の代表的なファイラーにおいて、ドライブ変更の度に全ドライブのメディア挿入状態を頻繁に確認しているため、毎回観測してしまうと、動作速度が極端に低下し、ユーザの使用感を著しく悪化させる。
2. FDDのモーターが回転していた場合でも、観測完了までは数10〜100ms程度の処理時間を要する。X68000では、通常のHuman68kの利用においても、メディア状態のチェックが頻繁に行なわれるため、VM側からの指示の度に観測すると動作速度が低下してしまう。
3. FDDにメディアが存在しない場合に観測が行なわれると、FDDから異音が発生してしまう。これはハードウェアの制約でありソフトウェア側からは解決できない。一方、X68000では、ポーリングによりメディア存在確認を行なうのが一般的である。VM側からの指示通りに観測行為を行なった場合、一定間隔でFDDが異音を奏でる最悪の事態が発生し、某国民機の悪夢が再来する。
そこで、手動イジェクト型のリムーバブルメディアについては、以下の条件でメディアの観測を行なう仕様とした。
1. 実際にホスト側OSによるアクセスが行なわれる直前に観測する。
2. 短期間に集中してメディア観測要求が発生した場合に観測する。
3. 上記2つだけではメディアが入れ換わったことを検出できない可能性があるため、ディレクトリエントリキャッシュの有効期間を数秒間に制限して対処する。
4. 連続して観測を行なわないよう、一度アクセスしたら数秒間のガード期間を設け、VM側へはキャッシュ情報を渡す。
上記仕様のため、手動イジェクト型のリムーバブルメディアについては、メディアが存在しない場合のアクセスは正常系とみなし、白帯エラーは出さないことにする。

2006.03.32

フロッピーディスク以外のリムーバブルメディアに対応。USB-Flash/PCMCIA-Flashで動作確認。フラッシュメモリの場合、イジェクトは「カードの取り外し」操作で代用する。メディアの挿入/イジェクトの際、Windowsに何も通知されない不届きなデバイスについては、後述する動作フラグ強制指定を使って手動イジェクトメディアとして動作させる。
コンフィグのファイルシステム動作フラグの指定は標準で0とし、ドライブ登録時にWindrv側で適正な動作フラグを判別するように修正。以前の指定方法は、判別がうまくいかないドライブ(独自規格のUSBストレージなど)に対して動作フラグを強制指定するために隠しオプションとして残しておく。これでUIをシンプルにできる。
リムーバブルメディアのキャッシュ有効時間を別スレッドで判定し、WindrvがホストOSのドライブを長時間ロックしないように修正。ロック中はUSBやPCカードのイジェクトが禁止されてしまう問題があったため。ホスト側を正規の手順でイジェクト禁止に指定することも考えたが、Windrvにはその権限を持たせるべきではないため却下。
ドライブ名を持たないネットワークパスもベースパスとして利用可能にした。
リムーバブルメディアでの「ディスクが入っていません」の白帯エラーを有効化(手動イジェクトメディアでは白帯は出さない)。
SX-Windowにてイジェクト判定に失敗することがあったため、イジェクト後にドライブ状態を正しくチェックするよう修正。ちなみにSX-Windowはメディア強制イジェクトには対応していないため、ホスト側でメディア強制イジェクトした場合は、SX-Window側のイジェクトボタンを押して状態を同じにしておくこと(内蔵FDDを強制イジェクトしても同様の問題が起きるので、SX-Windowの仕様らしい。SX-Windowはドライブ状態をポーリングでこまめに見ているので、ちょっと弄れば直りそうな予感)。
白帯が出たとき、リトライが正常に行なえなかったバグを修正。
ディスクの入っていないドライブに対してコマンド$53(セクタ読み込み)を行なおうとするとホスト側で0除算エラーが発生するバグを修正。
キャッシュ一括消去時に、末尾のキャッシュを消去漏れすることがあるバグを修正。
Win32スレッドの作成に失敗したときのエラー処理が間違っていたのを修正。

2006.04.03

ウィンドウの枠を描画するようにして、VC6の編集可能エリアやMS-DOSプロンプトのような見た目にした。ずっとこれがやりたかった!ステータスバーをVC6のようにウィンドウと一体化して描画するようにしたいが、やりかたがわからず断念…
メニューバーの表示を消せるように変更。表示状態はステータスバー同様コンフィグに保存するようにした([Window]内のMenuBarを0にする。デフォルト1)。
ウィンドウをリサイズできるようにした。しかし!ウィンドウのリサイズの最小サイズの制限をしていないため、窓が描画領域より狭くなった場合なにかと問題あり。制限方法は調査中。
ついでに最大化アイコンを追加。本当は最大化を押すとフルスクリーンになるようにしたい。
タイトルバーの%表示がチラチラするのがちょっと気になったので、コンフィグの隠しオプションで表示を消せるようにして没入感アップ([Window]内のTitleBarを0にする。デフォルト1)。
青色LEDの色の再現が難しい件について。青色LEDの写真をデジカメで撮影してみるとLEDの光の部分はほとんど白もしくは水色の色コードで構成されている。そして光っている部分からだいぶ離れた位置に青い色コードが出現する(いわゆるHDR)。つまりステータスバーの小さい領域だけであの光を再現するのは難しそう。ひとまず、青白(水色)の背景にしてもステータスバーの文字が潰れないように、白い文字に黒い影をつけて描画するようにしてみた。
X68030のROMを利用中にSCSIディスクイメージの指定ができるよう修正。

2006.04.11

コマンド$55(_IOCTRL)と$58(_LOCK)のエントリ追加。
設定オプションを一部変更。TwentyOneの動作で補える部分(ファイル名変更処理など)、TwentyOneの動作では補えない部分(ファイル大文字小文字比較、18+3/8+3判定など)、TwentyOneと関係ないWindrvXM内部処理(削除動作など)の3種類でビットの位置をまとめてみたつもり。
VM側からWINDRVのオプションを設定できるように変更。案は2つ。
1. WINDRVポートを使う方式
2. DOS _IOCTRLを使う方式
さらに、ユーザアプリからオプションを設定させる必要がある。案は3つ。
A. 直接ポートアクセスしてもらうか、DOS _IOCTRLを呼んでもらう
B. 新規DOSコールを追加
C. 新規IOCSコールを追加
まずは1-Aの方法で効果を確認。DOS _IOCTRLの利用方法は調査中。
ApplyCfg()後に、ディレクトリエントリの再構成が必要な設定変更があった場合、キャッシュクリアするよう修正。ファイル名生成規則に変化があったときなど、キャッシュ内容がそのままだと問題になるケースがあるため。

2006.04.12

WINDRV互換機能との共存をデフォルトでOFFに。旧WINDRVの機能との共存を行ないたい場合は、[Windrv]のEnableの値で設定可能とした。旧仕様との共存を強要するのも、互換性を一切なくすのも、どちらを選んでもなんとも収まりが悪い気がしていたのだが、全部の実装パターンを自由に選べるようにして、ようやく個人的に納得できる形となった気がする(0:ポートなし 1:WindrvXM専用 2:WINDRV専用 3:WindrvXM+WINDRV共存 255:ポートのみ実装)。

2006.04.14

Twentyone Option略してTwop.R試作。実行するとDOS _TWONを発行してTwentyOneの設定を読み込み、Windrvの動作オプションを自動設定する。将来的には、DOS _TWONを書き換える常駐モノにするか、twentyone.sys自体を改造する予定。

2006.04.17

ハードウェア直接アクセスによる設定は美しくないので没。
表示内容の一部をオプション設定の表記に活用予定。

2006.04.25

WINDRVポートを使ったオプション設定方式はバランスが悪いので削除。かわりに、DOS _IOCTRLを使用する予定(起動時のオプション設定とカーネル監視処理を実装したら、ユーザアプリからのオプション設定変更に必要性を感じなくなったのであとまわし。あと、DOS _TWONの乗っとりも面倒なので廃止)。(汗

WINDRV常駐時にコマンドラインオプションをチェックするよう変更。オプションは以下の通り。

-d -D / +d +D 削除処理のごみ箱利用 *直接 / ごみ箱
-k -K / +k +K カーネル・ドライバ監視 *なし / あり +Kだと±A/T/Cを自動設定
-m -M / +m +M メディアバイト処理 *固定 / 変動
-a -A / +a +A ファイル名変換 *18+3 / 8+3 -K時のみ有効
-t -T / +t +T ファイル名比較(未実装) 8+3 /*18+3 -K時のみ有効
-c -C / +c +C 大文字小文字区別 *なし / あり -K時のみ有効

-E / +E ファイル名変換 先頭のピリオド *なし / '_'
-P / +P ファイル名変換 中間のピリオド *なし / '_'
-N / +N ファイル名変換 先頭のハイフン *なし / '_'
-H / +H ファイル名変換 中間のハイフン *なし / '_'
-X / +X ファイル名変換 無効な文字 *なし / '_'
-S / +S ファイル名変換 スペース *なし / '_'

-e / +e ファイル名短縮 先頭のピリオド *なし / 短縮
-p / +p ファイル名短縮 中間のピリオド *なし / 短縮
-n / +n ファイル名短縮 先頭のハイフン *なし / 短縮
-h / +h ファイル名短縮 中間のハイフン *なし / 短縮
-x / +x ファイル名短縮 無効な文字 *なし / 短縮
-s / +s ファイル名短縮 スペース *なし / 短縮

デフォルトは、+T -DKMACEPNHXSepnhxsとなっている。オプション±A/T/CはTwentyOneとほぼ同じ意味をもつ。他の文字もTwentyOneのオプションとかぶらないようにしたつもり。
例) TwentyOneの常駐とファイル名の空白の変換処理を入れたい場合は、
DEVICE = WindrvXM.SYS +KS
と書く。オプションの記述は+KSでも+K +SでもOK。

オプション設定ができるようになったため、INIファイルのデフォルト値を1から0に変更([Windrv] Option=0)。オプション設定でINIファイルとほぼ同等の設定ができるため、INIファイル側に設定を残す必要はなくなった。しかし、CONFIG.SYSに1バイトたりとも無駄なデータを書きたくない場面もあるかもしれないので、INIファイルの設定は残しておく。
従来のXM6との互換性を持たせるため、インストール直後のWINDRVデバイスはデフォルトで無効([Windrv] Enable=0)とした。つまり、現状ではXM6を初めてインストール→実行→終了した後に、一度INIファイルを手動で書き換えないとWINDRV機能を使うことができないということを意味する。将来的にはGUIメニューで変更できるようになるので問題なくなるはず。
従来のXM6との互換性を持たせるため、WINDRVデバイスの動作モードを変更。Enable=0の場合は従来のXM6と同じ動作(ポートのみ実装)とし、Enableの値が0〜3以外の値のときはポートが存在しない(アクセスするとバスエラーとなる)ように変更。
リムーバブルの場合にメディアバイトの値を変動させる処理を追加。オプション+Mで有効となる。ハードディスク 0xF3 / リムーバブルメディア(CD-ROM・メモリーカード) 0xF2 / 手動イジェクトメディア(フロッピーディスク) 0xF1となる。
TwentyOneのオプション監視処理を追加。オプション+Kで有効となる。メディア挿入チェックのタイミングで常駐チェックを行なう(メディア挿入チェックは必ずコマンド実行に先立ってHuman68kから呼び出されるため、他のコマンドにチェック処理を追加する必要はない)。常駐チェックの結果、正常に検出された場合は次回から検索処理は不要となり、実行時間はほぼ0となる。しかしながら、TwentyOneが常駐していない環境では、チェックの度に100KB近い領域の検索を行なってしまうため、速度が低下する(ネイティブコードで検索するので爆速マシンだと誤差みたいなものだが)。そのため、検索に失敗した場合は、その後一定回数(10回)メディア挿入チェックが行なわれるまで何も検索しない仕様とした。
__fastcall呼び出し規約を使うとほとんどのパラメータがレジスタ渡しになると勘違いして組んでいた。実際には先頭2つのパラメータしかレジスタ渡しにならないことを知ってショック。高速化のために二重のデータ渡しを行なっていた部分を削除した。

2006.04.30

リムーバブルメディアの挿入チェック方式を変更。アクセス頻度に関係なく、コマンド$41→コマンド$57の順に呼び出された場合にメディア挿入チェックを行なうようにした。これにより、mint2.x系もそれなりに使えるようになった。とはいえmint2.x系はメディアバイトの対応や挿入/排出の自動認識が正常に動作しないため、3.x系の使用を推奨。この変更の弊害として、カレントディレクトリの変更時に無駄なディスクアクセスが発生する(mintでWindrvのフロッピーディスクドライブを表示しておき、そのドライブにカーソルを移動させた瞬間ディスクアクセスが発生してしまう)が、許容範囲内なので気にしないことにする。従来使っていたアクセス頻度による検出方法は、しばらく様子を見た上で将来コマンドラインオプションで有効化できるようにする予定。
コマンド$51のモード0時の動作を修正。メディア未挿入の場合はライトプロテクトビットを立てないようにして実機の動作に合わせた。
コマンド$51のモード8,9を実装。
コマンド$55を実装。DOS _IOCTRLからの制御に対応。susie.x互換のファンクションコールとオプション設定機能を実装した(立花@桑島技研さん、情報ありがとうございます)。
コマンド$57の動作を修正。メディアが存在していない場合はエラーを返すようにした。エラーを返すことで、Human68k内部でカレントディレクトリのリセットが行なわれるようになり、自然な動きになる。
オプション設定を行なった後、Windrv関連の設定が初期化されてしまうバグがあったので、INIファイルの設定は、デバイスドライバ組込み時の初期値として使用するように修正した。手動で書き換えない限り、常に0のままで使われることになる。

2006.05.07

従来のアクセス頻度によるメディア挿入チェックの動作を確認してみた。よくよく動作を見てみたら、こちらの方式でもmintでディスクアクセスが発生していることが判明。アクセス頻度によるメディア挿入チェック方式に変えても利点がないことがわかった。コマンドラインオプションによる検出方式の選択処理は没とする。
WinNT判定を独自処理を使わず::IsWinNT()で行なうように変更。
ShellNotify処理の引数を減らして全てレジスタ渡しになるように変更。

両方のシフトキーを押した状態で、片方のシフトキーを離すと、まだ残りのシフトキーを押したままであるにもかかわらずキーが離されたことになる問題を修正。

2006.05.12

2006.06.19

2006.07.01

2006.08.12

2006.08.18

ファイル名変換後に不正なファイル名ができてしまうバグを修正(立花@桑島技研さん、ありがとうございます)
(1)ディレクトリ名("."および"..")の場合は変換処理を行なわないように修正
(2)Human68kピリオドの位置を間違えるバグを修正
(3)ファイル名変換の結果、不正なファイル名(ファイル名消失/表現できない空白/ディレクトリ名と同一)になった場合の補正処理を追加
TwentyOne検索処理にて、見つかったNULデバイスのアドレスを保持するよう改良。TwentyOneが常駐していない状態での検索時間を大幅に短縮した。

2006.08.19

ファイル名変換処理を改良。ファイル名変換時の拡張子の位置情報を使ってディレクトリエントリの名前部分を生成するようにした。これにより、ファイル名短縮で本体が0文字になった場合でも、拡張子部分の形が維持されるようになった。
ファイル名が重複した際に、同一のディレクトリエントリが生成されるバグを修正。
ファイル名変換処理には、依然として根本的な問題が残っている。例えば、-nhオプション指定時は、"-"と"--"と"---"は同一の空の名称に変換され、内部で重複防止のための文字を追加して"@0" "@1" "@2"のエントリが生成されるのだが、この数字はあくまでファイルシステム上の発見順に付けられる番号であり、ファイル名と必ず一意に対応するものではない。(問題点1)ここで"rm @1"を実行した場合、どのファイルが消えるのかは、ファイルシステムの状態によって変わる。(問題点2)さらに削除の実行後、ディレクトリエントリの再構成が行なわれ、その結果"@0" "@1"の2つのエントリが生成される(このとき再構成を行なわないという選択もあるが、ホストOS側でも書き換えが随時行なわれる可能性がある上、一部のメディアではキャッシュの生存時間が極端に短かい場合もあるため万能ではない。なお、この部分は将来改良予定)。つまり、ユーザプログラムから見ると、@1を消したはずなのに、削除後も同じファイルが残っているように見えてしまう。これを防ぐには重複防止用の文字列に順番の数字を使わずに、元ファイルから一意に決まるハッシュ(例えばディスク上のセクタ番号とか、ファイル名のCRCとか)を使うべきなのだが、そうするとファイル名の可読性が低下してしまい本末転倒となってしまう。ファイル名変換機能の利用はこれらの特性をよく理解した上で、最小限の範囲に止めるのが望ましい。

2006.08.20

Human68kで扱えないファイル名を生成しないように改良。具体的には以下のようなパターンが防止される
(1)スペースで始まるもの 例: "(スペース1文字以上)a[拡張子]"
(2)ファイル名本体部分がスペースで終了するもの 例: "a(スペース1文字以上)[拡張子]" "a(スペース17文字以上)a[拡張子]"
(3)拡張子部分がスペースで終了するもの 例: "a.a(スペース1〜2文字)"
(1)と(3)はスペースを除去、(2)は末尾に補正文字を追加して対処する。なお、この処理よりもファイル名変換処理のほうが優先して行なわれる(ファイル名変換の結果、どうしても表現不可能な名前になる場合のみ補正が行なわれる)。
これにより、Human68k + TwentyOne(特殊文字の利用許可) + WindrvXM(ファイル名変換指定なし)の組み合わせでアクセスできないファイル名はなくなったものと思われる。これ以外でアクセスできないファイル名のパターンを見つけたらぜひ連絡を。
なお、ファイル名本体が8文字以上の場合、理論上は空白での終了が表現可能のはずなのだが、Human68kではなぜか正しく扱えない模様。
無駄なメモリアクセスの削減と拡張子の位置キャッシュにより、ディレクトリエントリの生成・検索処理を若干高速化。

2006.09.01

…すごく…デスマーチを感じます…

2006.09.26

ディレクトリエントリの再構成時に、前回の生成済みエントリ名を優先して利用する処理を追加(2006.08.19の問題点2の改善)。前回のエントリ名の保存処理の高速化。
サブディレクトリ名(ピリオド1つおよび2つのもの)の内部表現が間違っていたバグを修正(実害なし)。

2006.11.25

 C99処理系でエラーにならないように変数宣言を一部修正。

2006.12.24

 孤独を愛する獣使いにジョブチェンジ。

2007.03.31

 コジマ粒子を身に纏うが、操作困難により二階級特進。

2007.05.17

 "a-b .txt"などの、ファイル名本体が8文字以下でかつHuman68kでは(TwentyOneをもってしても)表現できないファイル名の場合に、ファイル名が補正されずそのまま出力されてしまい、結果的にそのファイルへはアクセスできなくなってしまうバグを修正(立花@桑島技研さん、ありがとうございます)。

2010

 冬コミ用に作ってたゲームは(検閲削除)
 とりあえず現在の最新環境(VC6SP6+PP)にてコンパイルが通るように修正。
 現在分かっている不安なポイント
CD/DVDドライブのメディアチェックで原因不明のエラーが毎回出ている。
ごみ箱を使った削除が猛烈に遅い
 今後の修正予定
試験的にWindrv系ソースのコメントをDoxygen対応させてみる
XM6本体をUnicode化せずにWindrvのみUnicode化
デバイスをDLLで外部に分離できるようにモジュール化
 誰かDoxygenのパーサ部分をカスタマイズできるFlexDoxygenとか作ってほすぃ(他力本願)
 mfc_hostのファイル処理をFileioへ一本化できないか検討してみた。しかしFileioはファイル名の受け渡しにFilepathを使っており、オーバヘッドが大きすぎて一本化せずにこのまま改造してみることにした。
 コンパイル関連操作の繰り返し時の速度を上げるため、star.asmをstar.exe生成時に作成するよう変更してみた。やべー!最近のパソコン、めっちゃ速いんですけど!

2011

 Doxygen対応

2012

 Windows Vistaで管理者権限なしで実行した場合に、ホスト側ドライブの状態を正しく取得できないバグを修正……したつもりが一部のドライブだけ認識されない強烈なエンバグが発生し使いものにならなくなってしまった。何が何だかわからない。己の無力を恥じつつ放置せざるを得ない。どうすればいいかわからない。

2012

 Windows 7のAeroではウィンドウの枠線が描かれると美しくないため消した。こんな低レベルなこと(1行コメントアウトするだけ)しかできなくて情けない…。
 2006.04.03の時とはまったく正反対の変更となってしまうわけだが、とにかくXM6のウィンドウ表示スタイルは清楚で美しくあるべきと勝手に思い込んでるわけで。基本はコマンドプロンプトの表示スタイルに近い状態にしておくべきだと思うのさ。むしろコマンドプロンプトのほうが、クライアントエッジを削って枠線をもっと細くするべき。

2013

 愛機X68040turbo compactが沈黙しました
 もう動かないや
 かなしい

2013

 コンパイラの動作デフォルトをFASTCALL側に倒してもコード生成できるようしてみた。当然のごとく既にほとんどがFASTCALL宣言済みのため、バイナリはほとんど変わらんかった。逆に何が変わるのか見れて面白い。他のものを作る時はいつもFASTCALL側にしているので、XM6も同じにできてボク、満足。
 VC2013でもプリコンパイルドヘッダ生成(os.cpp)とかやってVC6時代の速度に迫ってみるテスト。無意味にリビルドしまくって気を紛らわすのであった。

2013

 日本語入力システムの開発で得たノウハウをWindrvXMの性能向上に全力投入しようと決意した。
 つかWindrvXMはファイルシステム処理のくせにファイル名関連処理にリニアサーチを使ってたりして、マジ恥ずかしい作りだったりするのでちゃんと書き直したい。
 明日から本気出す。

2013

 冬コミの時間だオラァ!
 管理者権限の問題がついに解決。GetLastErrorすれば良いだけの人生だった。つかもうXM6 TypeGというもの凄い派生版があるみたいなんだよね……、既にWINDRV互換性特化で管理者権限の問題とかもきちんと解決してるみたいだし。もはやWindrvXMとかいらなくね?
 Enable=1の時でもWINDRV互換デバイスを有効化。本来のWindrvXMの設計は従来のデバイスの完全上位互換デバイスとして実装することが目的の1つだったのでこうした。XM6 TypeGなどのエミュレータではEnable=1で使うのがデファクト化してきているようなので、こうしておくのがベストなはず。
 WindrvXM.SYSのオプション指定を一掃したい……。
 自分用にいろいろ手直ししていた部分をまとめて公開するための準備を開始しようと決意した。
 明日から本気出す。

2014

 XM6のソースの話題があったので、自分もいつかソースを公開できるようにXM6 2.05ベースに戻して全システムを再構築しようと決意したはずだったのだがいつの間にか寝てしまった。
 明日から本気出す。

2014

 マルチスレッドによる並列動作が正しく機能しておらず、WindrvXMが本来の力をまったく発揮できていなかったバグを修正。当時、シングルコアのノートPCでパフォーマンスをうまく引き出せなくて、なんとかしようと必死で弄ってるうちに変なコードになってた。当時はこれがベストだと思い込んでた。マルチコア全盛の今、8年前に夢見たWindrvXMデバイスの真の姿をようやく取り戻せたかもしれない。
 並列動作の自動調整機能(をやろうとして激しくバグってた機能)をばっさり排除。動作ロジックの見直し。処理の単純化と余分な変数の削除。榛名は大丈夫です!で検索。
 大幅な速度低下の発生を防ぐためVMコアのロック処理を暫定的に無効化。THEガッツ方式によるホストとVMコア間の真のロックフリー化に向けて再設計中。
 Human68kカーネル内のデバイスドライバのリンクリストを環状化させてエミュレータ側の無限ループを誘発させる等の攻撃への対抗措置を追加。
 TwentyOneの常駐解除判定が行なわれていなかったバグを修正。
 TwentyOneの発見時はメディアバイト処理を自動的に有効化するよう改良。
 TwentyOneの自動判定を常に有効化し、WindrvXM.SYSのオプション指定なしでも実用的に使えるよう改良。これでオプションなしでドライバを常駐させても、Human上でtwonで-aと+aとか指定するだけでファイル名生成動作が追従するようになった。こういう簡単に使えるシンプルな設定がずっと欲しかったので麻呂は満足でおじゃる。

2014

 XM6 2.05ベースで全システムを再構築。
 WindrvXM.SYSのサイズを800バイトまでゆるふわ縮小。
 WindrvXM.SYSのサイズを768バイトまでガチふわ縮小。
 ステートセーブ・ロード系のバージョン番号の値を見て何か妙なふいんき(なぜか変換できない)を感じたので調べてみたら……バージョン番号関連はすべて内部処理BCDだったとかもうね……誰も教えてくれなかったお……。

2014

 リセット時にデバイスの動作モードを設定するようにして、動作中はデバイスのモードが切り替わらないよう改良。いわば動作中にデバイス引っこ抜きが簡単にできちゃうような実装のまま放置してた。すまんかった。
 CWindrvまわりのクラス構成見直し。
 クラス構成の見直し。不要な仮想関数テーブルの除去によるコードサイズ縮小。
 まずは3フェーズ方式でロックフリー化を実現。これは速い!
 Read/Write系もすべてロックフリー化した。
 ステートのロード・セーブ(レジューム)対応。バージョン2.06以下のバージョンのセーブデータと互換性を持たせつつ、動作停止せず続行可能となるよう改良。
 レジューム後にドライブ構成が大幅に変化した際の仕様(使いものにならないバグっぽい動作)を変更。
 まず、ホスト側のドライブ数が減った状態でレジュームすると無効なユニットエラーの白帯が出てしまうのは使いづらいため出ないようにした。そうするとこんどはDPBの取得に失敗したあたりでHuman68k内部でドライブが消滅してしまうので、消滅しないようダミー情報を掴ませてメディアなしのドライブとしてエミュレーションするよう改良。この状態のドライブは基本的には「ディスクを入れてください」の白帯とする設計とした。
 白帯が出た状態でいったん保存し、元のドライブ状態と同じ環境ロードして再開してリトライを選択すれば問題なく処理を続行できる。

 エラーチェックが厳しすぎるとmintでドライブ選択するだけで白帯になってしまい操作性が低下するため、一般的なドライブ選択操作程度であればエラーを出さずに操作を続行できるようエラー判定を調整した。
 ついに納得できるものが完成した。
 メールは届かなかった。
 少し泣く。

 知り合いの伝をあたってみたが連絡つかず……。どなたかPI.氏に連絡できる方がおりましたら、氏のご迷惑にならない範囲でお伝え願います。

2014

 デバイス初期化時の処理が無駄が多いんじゃないかって気がしてきた。よく考えてみたら、LASTDRIVEがZじゃない環境だってあるわけで、26-ドライブ数という計算に何の意味もないのではなかろうか?と疑問を感じて関連処理を全部消してみた。むしゃくしゃしてやった。問題なかった。つかレジュームの時最大26ドライブ生成とかやってるし愛さえあれば問題ないよね?

2014.09.09

 XM6 TypeG対応。さらにXM6iにも対応させるべくWindrvXMデバイス側のWin32 APIを分離した。これで移植が簡単に!Host側……うっ頭が……。
 明日から本気出す。

2014

 Hostコンポーネントを簡略化。
 マルチプラットフォーム化を見越してクラス名からWindowsっぽい名称を除去。さらにエラーハンドラをデバイス側に意識させない作りとした。_WIN32シンボルが定義されていない場合でもHost側のヘッダは通るようにしてみた。これからが本当の地獄だ。
 コード効率の悪い箇所を発見したので修正。バイナリで256バイト程度の無駄な命令を削減。
 デバイス名の生成がエンバグしていてメディアタイプの取得などが正常にできていなかったので修正。
 最近のSATA-HDDなどは非リムーバブルメディアであっても取り外すことができるため、ハードディスクの取り外し判定処理を復活。
 SATA-HDDのロックを解除するために、従来はHDDに対して$56 Flashコマンドを発行することで対応としていたが、これだと該当するコマンドを発行するのが普通の利用者には困難。なんとかする。
 つーかそもそも、長期間デバイスをロック状態にしている、というのが美しくない。そこで10分間アクセスがなければハードディスクもロックを自動解除するよう改良。
 VM側から簡単に誰でも手動解除できるよう、非リムーバブルメディア以外のドライブに対してもイジェクトコマンドの発行でロック解除できるようにした。
 ボリュームラベル検索要求がルートディレクトリ以外から発生した場合はエラーを返すよう改良。本当はルートディレクトリでファイル検索要求が発生したら厳密な仮想エントリを用意すべき。現在は2つ課題があり未実装となっている。課題1:ボリュームラベルを取得する既存アプリでは、DOS _NFILESが使われていない(仕様上はまったく問題ない)。そのため厳密に処理すると内部でハンドルが一つ開かれたままになってしまう。なお実は現在の実装ではあえて内部でハンドルを残しておくことにより、DOS _FILES後にバッファの内部の未公開情報を利用してセクタリードを実施するタイプのアプリに対応させていたりする。よって、こちらは事実上解決済みであるといえる。課題2:ルートディレクトリの検索要求は発行回数が多く、なるべく無駄な処理を挟みたくない。現代のプロセッサから見れば誤差レベルの話。未来の世界ではきっと解決しているはず。
 ボリュームラベル作成要求にエラーを返すよう改良。
 MS-DOSで属性0のファイルはHuman68k側からも属性0として観測できるように改良。
 アプリのメディアバイト対応状況を調べてみた。かなりバラバラ。
drive.xは0xF4以上なら認識。
VSは0xF6以上なら認識。
SX-WINDOWは0xF5以上なら認識。
Ko-Windowはどの値でも認識。最強。
 WindrvXMデバイスでメディアバイトを偽装することで回避するという手もあるのだが(実際上記のテストは偽装して調べた)、それだとディスク直接アクセス系のアプリに影響が出てしまうのでできればやりたくない。SXとVSはパッチを当てるのがよさそうだ。
 タイムスタンプの変更後、FCBを更新するよう改良。既存のアプリでこの領域を見ているものは皆無なので事実上意味のない更新ではあるが、自己満足こそが最強である。

2014

 Windows 2000以降必須のWin32 API、Shell Lightweight Utility Functionsを採用。素直にVC2007以降を使う場合は追加設定は不要でそのままコンパイルできる。
 VC6時代から見るとわりと新し目のライブラリなので、VC6標準のライブラリでは、コンパイル・リンクができないもしれない。SDK v5.0以上のヘッダとかWindows Server 2003 SP1 Platform SDKのshlwapi.libなどを使えば、まだVC6でもバイナリを生成できる。(ちなみに配布版は根性でVC6で構築している)

2014.09.18

 ファイル属性0の拡張。ホスト側のファイル属性が0の場合、Human68k側でも0として扱えるように改良。
 仮想FSのキャッシュ機構の見直し。内部処理を簡略化、高速化してパフォーマンスの改善。まだ改良の余地はありまくる。
 マイナーバグ修正。カレントディレクトリにしたフォルダを削除できないなどの問題が発生していた環境で改善が見込めるかもしれない。
 WIN32APIの完全分離。一応自作のPOSIXエミュレータもどきで動かして、ホスト側のドライブにインストールした市販ゲームを起動するくらいまでは動くようにしてみた。TCHAR系APIをマクロで置き換えればたぶんわりと楽に(初期のWindrvのコードに比べれば格段に楽に)動かせるようになるのではと期待。
 ファイル削除方式でごみ箱の設定をXM6.iniの[Windrv]のOption=1とすることで有効化できるよう変更。これまでずっとこの値は謎の0だったけど、これからはこの0と1がメインとなる予定。

2014

 リモートドライブのフォルダのタイムスタンプを変更できるよう改良。
 DPBの上限を2GB以上にすると一部のアプリ(Fu.x等)でディスク残量なし(マイナス)と誤判定されてしまうため、Human68kのDPBで表現できる符合つき整数の最大値である512×64×65535($7FFF8000)に制限した。
 一部のアプリではファイルサイズが負の数として扱われてしまい、2GBを越えるサイズのファイルの扱いに失敗するものが多い(特に、Cで書かれていたアプリは何も考えずに符合つきで処理をやらかしちゃってるものが多い気がする)。仕方ないので、DOS _FILES等で取得できるファイルサイズの上限を2GB……正確にはDPB上限値と同じサイズに制限した。
 Fu.xがリモートドライブ上でDOS _FATCHKを実行してしまい(当然リモートドライブにはFATなんぞねーわけで、ルートディレクトリ以外だとリモートデバイスに制御が渡らずHuman68k内部レベルでエラーになってしまい)エラーメッセージが出てしまう問題は、どうにもならないので、Fu.xにパッチを当てることで解決。
 Fu.xを解析してわかったことを書いておく。Fu.xは、ディレクトリ(フォルダ)を含むコピーにおいて以下の挙動を取る。
1. コピー先にフォルダと同名のエントリがないかどうかを確認
2. 問題がなければフォルダを作る
3. 突然、フォルダのタイムスタンプを変える (※問題1)
3-A. フォルダの属性にアーカイブ属性をなぜか加える
3-B. タイムスタンプを変える
3-C. フォルダの属性を元に戻す
4. ファイルをコピー
4-A. ファイルの書き込み先をオープンする
4-B. 突然、ディスクの残りサイズを調べるためクラスタサイズを計算する (※問題2)
4-C. ファイルの中身をコピーする
5. 再帰的に繰り返す
 印をつけた2箇所は現代のリモートドライブの仕様とは微妙に合致しない挙動である。
 まず、リモートドライブ先として最もよく使われるであろうNTFSでは、フォルダの中身が更新されるとそのフォルダ自体のタイムスタンプも更新される。フォルダの時刻が変化しないFATファイルシステムとは根本的に異なる。このため、4の操作によって、せっかく設定したタイムスタンプ情報は消えてしまう。
 もう一方もFATを想定した動作である。ファイルコピーのためにファイルをオープンした直後、普通ならそのままデータの書き込みを行ってドライバがディスク残量を確認すべき場面で、あろうことかディスクのDPB(FAT時代の遺物)の情報を見てディスク容量を勝手に計算してしまう。(ここで計算結果が2GBを超えていると負の値と判断されてしまいコピーに失敗する)
 確かに、リモート型デバイスは当時としてはCD-ROMドライバの一部くらいしか対応してなかったレアな存在ではあるが、FATありきで作り込まれてしまったアプリはドライバ側からはどうすることもできない場合もある。こういった事例を見るにつけ、mintがいかに詳細まで練って作り込まれていたかを知ることとなるのであった。

 ボリュームラベルが正しく取得できないエンバグが発生したので修正。
 手動イジェクトのメディアに対してイジェクトを実行しても白帯が出ないよう改良。
 ファイルのタイムスタンプの秒がコマンドプロンプトやエクスプローラで表示されるものから微妙にずれてしまうことがある問題を修正。
 Win32APIだからと信じて送り出した時刻変換処理がアヘ顔二秒ずれてるなんて……。
 原因はWin32 APIであるFileTimeToDosDateTimeの仕様にあった。なんかどこにも明文化されてないんだけど、このAPIによる変換では2秒単位での切り上げが行なわれておりたとえ100ナノ秒(最小単位)でも秒の境界からずれていれば2秒切り上げられてしまうのだ(なお、当然ながらコマンドプロンプトやエクスプローラでは一般に良く知られている通り、1秒単位での切り捨てであり、FATファイルシステムの時刻はこの時間をさらに2秒単位で切り捨てたものとなる)。

 以下、検証結果。
システムタイム値コマンドプロンプト等の時刻FileTimeToDosDateTime奴
$01A8E79FE1D580001980/01/01 00:00:00.00080-01-01 00:00:00
$01A8E79FE1D580011980/01/01 00:00:00.00080-01-01 00:00:02 <アッー

 要するに、一般の利用者が観測し信じている世界(コマンドプロンプトやエクスプローラと同じ時刻)と同じ値を得るためには、Win32APIによる変換を行う前にファイルシステム時間から19999999を減算しなければならない。これで解決ではあるのだが……こんな巨大な値の補正をすべてのアプリで使わせる(しかもサンプルも用意せず明文化していない)とか、狂気としか言いようがない。でもこんなこと、この楽園Mics○roftなら日常茶飯事だぜ。ジャスティス!

 異なるドライブ間のキャッシュを分離しキャッシュアクセスのロックフリー化。探索パラメータの削減による高速化。
 キャッシュデータを完全に消さず、ディレクトリエントリの変換規則データとして残すことで、複数の似たような長いファイル名についた別名が、長時間経過によって入れかわることがないよう改良。これは2006.08.19版の問題点2と3に対する回答である。実現まで長い道程だったが、これなら長時間の作業でもファイル名の一貫性を維持し続けることができるはずだ。

2014.09.23

 次世代WindrvXM先行試作版、ついに完成。
 キャッシュ更新判定をOSの監視処理に頼らずほぼ自力で動作するよう改良。OS側の監視動作を最小限に抑え、仮想ディレクトリエントリの再構築(読み直し)の回数を大幅に削減し高速化。mintを使った簡単なファイルコピー動作程度であれば、ホストOS側のネイティブアプリケーションのファイルコピーと遜色ない速度で動作するはず。
 そしてこの動作の前提となる、ディレクトリのタイムスタンプエミュレーション機能を搭載。Human68kアプリの動作によってホスト側のファイルシステム(NTFS等)が更新された際、ディレクトリのタイムスタンプを気合いで維持し続けることにより、Human68kアプリ側から見た時の動作をFAT操作時と同様となるようにした。
 要するにこれで、mintなどのファイラーを使ってディレクトリを丸ごとコピーした時、タイムスタンプもきっちりコピーされるようになるのだ。ローカルドライブのタイムスタンプ情報を完全に維持したままリモートドライブ側にコピーできる。ずっとこの機能が欲しかったけど過去の自分にはどうしても作れなかった。ついに……ついに俺はやったよ師匠!
 ちなみにNTFSではファイルの並び順序までは再現できないが、ここまで必要なら素直にディスクイメージを使うべき。このあたりがリモートドライブとディスクイメージの境界と割り切って使うべし。

2014.09.27

 長年のXM6にまつわるキー入力回りの問題を解決すべくDirectInputによるキー入力をいきなり廃止。かわりにOSのキーイベントを使い、キースキャンコード変更後のキーの並びで機能割り当てができるように改良した。実はXM6改ではDirectInput5を使っていたのでスキャンコードの入れ替え回りについては問題はなかったのだが、一部のキーが未定義キーに割り当てられるなどの古いDirectInput固有の問題が残っていたのだ。
 この変更については、過去にPI.氏がこのように変えたいと話をしていたので、その内容に極力沿うように直してみたつもり。
 なお、しぶとくDirectInputで頑張る場合の対策コードもソースレベルでは実装してあるので進化の方向は好みで選べるようになっている。
 ほかにも、XM6原作では半角/全角ひらがな(ローマ字)、英数(CapsLock)は操作がロックされるという理由でキーを割り当てて使うことができなかった(英数キーは一応割り当てはできたけど、押しかたによっては入力されっぱなしになるという潜在的な問題があった)のだが、これらのキーは押下の瞬間のみ反応するキーとしてX68000側のキーを割り当てられるようになっている。
 ソフトウェアキーのボタンをマウスで激しく連打してもダブルクリック判定されてしまい文字が高速に打てない、爽快感がないという問題を解決。シングルクリックのみ認識し、クリックしただけ文字が入る。
 ALTキーに機能割り当てしているにもかかわらず、起動してからメインウィンドウをマウスでクリックするなどしてフォーカスを変えるまで、ALTキーがシステムキーとして機能してしまうバグを修正。
 ほかにもキー名称の一部変更など。
 SKKFEPの開発で得たノウハウの一部をようやくXM6に投入できて、ボク、満足!
 と思ったらリリース版だとキーの反応が悪すぎることが判明。
DirectInput
「あの子のほうが」「検出性能いいから」「私と別れたの?」
「いいよ」「あたしは」「メッセージポンプ無視する」
 というわけでまともに動かないので結局DirectInputに戻すことになった。ショボーン(´・ω・`)
 とりあえずキー割り当て自体はDirectInputの補正処理が効いて同じように使えるので、今回の追加機能自体に影響はない。
 XM6gの作者さまに相談したところ、GetAsyncKeyStateは使えないか?とのこと。早速試してみたら……使えちゃった。メッセージポンプ意味ナッシングである。備えよう。

2014

 まだだ……まだ慌てる時間じゃない。というわけでPI.氏が以前言っていた(気がする)最終手段、RAWINPUTを試してみた。こっ……これは……アカン……!最初は軽い気持ちだった――
 OSのキースキャンコードの入れ替え前の生データ見れるし、左右のシフトを同時押ししてもきちんと離した時のイベントが取得できるし、システムキー回り(WM_SYSKEYDOWN系)のメッセージを完全にブロックできるし、おまけに複数のキーボードを接続してる時、どのキーボードから操作してるかまで分かるしで、さすがローレベル入力と謳うだけの性能だな!とか調子に乗って使っていたんだが……
 これ、その気になればフォーカスがなくても全キーボード操作を取り込める。あまりに予想外の動きで面白いからとりあえずソースには残しておく。これはDirectInputの源流に使われてる処理じゃね……?
 しかしその後、さんざん調査してみたけど、結局のところRAWINPUTを持ってしても、半角/全角のキーオンとキーオフのタイミングは取得できないことが判明してしまった。WM_INPUTを実行しないようにしてGetRawInputBufferを直接取得するようにしてストリームを直接読んだりしてみたけどダメだった。
 結局できることはWM_KEYDOWNと何ら変わらないので、複数のキーボードの判別やシフトキー両側に別々の機能を割り当てるなどの特殊事情でもない限りは無理して使う必要はないのではないか、という結論に落ち着いてしまった。
 結局、これよりもDirectXのほうが遅延が明らかに短いという理由により、メッセージ系はデフォルトの座を降りることとなった。MFCのメッセージポンプのスリープが長めだとキーイベント系(WM_KEYDOWNやRAWINPUT)の処理遅延が体感で分かってしまう。特にキーリピート速度を最高速にしてキーを離した時の応答時間を見るのが分かりやすい。
 もちろん、メッセージポンプのスリープ時間を極端に短くすることで、DirectInputと遜色ない動きは再現できるのだが、CPUコアの負荷が増えて消費電力が増えてしまうという明確なデメリットが出てしまう。メッセージポンプ最強伝説を実証したかったが、ここは素直にDirectInput+GetAsyncKeyStateを使うのが一番堅実ではないかという結論に至りつつある――
 Windowsキーだけでなくアプリケーションキーに機能割り当てした時、メニューが開かないよう防止処理を入れた。XM6原作の防止処理だと、ボタンを超連射すると一瞬メニューが出てしまう。これを完璧に防ぐためには低レベルキーフックが必要。いずれちゃんと実装する。
 不要な引数を整理し入力系の関数を同一化。リンカのCOMDAT圧縮率を上げておいた。
 原作ではソフトウェアキーボードとコンフィグ画面で右シフトキーの反応が微妙に遅れていたが、これはそもそも実在しない右シフトキーを単独キーとして別扱いとして、高レイヤ側で無理に補正処理をしていたことに原因があった。そこでシフトキーの描画を左右同時に行ない、補正処理は最小限に抑えることで根本的な解決を図った。これで右シフトの描画もビシバシ反応するようになった。スッキリでゴザル。

 ALTキーに何も割り当てていない状態で、何かキーを押したままALTキーを押したままにすると、最初に押していたキーを離してもキーリピート状態になってしまう現象を修正。
 ALTキーに何か割り当てた状態で(メニューバーをオフにして)ALTキーを押しながら何かキーを押すとそのキーが稀に2回入力されてしまう現象を修正。
 とりあえずシフトキーの押し離しのタイミングが1/60秒単位でクォンタイズされてしまうのとマウスの反応が悪いのが我慢ならなかったので、入力系のポーリング速度を1msに短縮。遅延はこれまでの1/17となる。これまでは最大1フレームの入力遅延が発生していたのだが、これがほぼ無視できるレベルになったはず。

 XM6原作のキー入力には2つの問題が存在したため、一部仕様を変更する。

問題1. キー入力処理の管理が複雑でバックグラウンド動作を必要とする点。

 キー入力情報はVM側で使うだけではなく、コンフィグや各種操作でも利用する。そのため、原作のInputKeyでは2種類のフラグを使い以下の3種類の動作を切り替えていた。

動作1: キー情報を取得する。VMに反映する。
動作2: キー情報を取得せず空の情報を使う。VMに反映する。
動作3: キー情報を取得する。VMに反映しない。(コンフィグ系専用動作)

 従来はこの3つの動作モードがVMと同じメインスレッド側で常に動作していた。このため、メインスレッドが入力フォーカスを持たない状態であってもキー入力を行う必要があり、DirectInputのバックグラウンド動作を使う必要があった。

 そこで、動作3を分離し、InputKeyの動作範囲を上記動作1〜2に限定する。キー入力処理を新設のGetKeyに移動し、動作3の箇所は入力フォーカスを持つウィンドウが自前でキー入力処理を呼ぶ。いずれDirectInputのバックグラウンド動作を不要とすることを狙いとする。

問題2. 入力デバイスのポーリング周期が長くCRTC設定に依存している点。

 XM6原作では1フレーム周期ごとに入力デバイスの状態を取得していた。VM上のアプリケーションは、実際にVMがデータを取得してからしばらく時間が経過した後でそのデータを利用する。アプリケーション(特にゲーム)の多くはCRTCの垂直帰線期間を基準として入力を読むため、アプリケーションの作りによっては最大1フレーム周期の入力遅延が発生してしまう可能性があった。

 1フレーム周期はCRTCの設定に依存する。一例として24kHzの横1024ドットモードではフレームレートが30〜40fpsまで低下する。当時はウィンドウシステム等の環境において、長残光モニタなどを併用し解像度を追求する用途が存在した。原作のXM6の実装では、こうした状況で入力の遅延が増大してしまう特性があった。

 本来、キーボードコントローラの動作はCRTCとは無関係であるため、エミュレーション精度向上のためにはポーリング周期の再考が必要である。標本化定理により、理想的な周期は原信号の最大周波数の二倍となる。キーボード操作信号の最大周波数(時間軸方向の分解能)は、理想的には1フレーム周期の数十倍程度と予想される。現時点ではこの周期を実現するのは困難だが、入力遅延を従来の数分の一程度まで抑えることで、より快適な操作性を得られるものと考える。

 XM6では最短1msで入力のポーリングが可能である。従来は標準的な1フレーム周期に合わせるため約17回に1回の割合で入力を行なっていたが、現在のPCの性能であれば1ms毎にキー入力を行なったとしても、描画系などと比べて大きな負荷にはならないと考える。よってCRTCに依存しない1msで入力を行なうよう変更する。

 低レベルキーボードフックを使ってALT/Windows/アプリケーションキーに機能割り当て中はOS側の操作を無効化するよう改良。原作では連打するとたまに取りこぼすことがあったが、これで完璧に阻止できる。当然、割り当てしない限りキーボードフックは一切使わないようにしておいた。デフォルト設定では割り当てがないのでフック部分は起動しない。よってデフォルト時の動作は完全に原作通りとなる。
 低レベルキーボードフックはMSDNでゲーム用などの用途で厳選して使えよ?絶対使えよ?みたいに書かれているくらい、本気で何でも乗っ取れちゃうのでちょっと感動。調子に乗ってVMware PlayerみたいにOSのショートカットキー操作を無効化できるようにしといた。
 低レベルキーボードフック側でほとんどの処理を済ませ、高レベル(ウィンドウメッセージ)側の処理をより簡略化。また、左右ALTキーの片方だけに割り当てた場合、割り当ててないほうのALTキーの動作は普通に反映されるようにした。
 ショートカットキーの無効設定値を見直し。利用頻度が高いと思われるALT+F4およびALT+ENTERを低ビット側に配置。さすがにALT+TABまで無効化したいという人はあまりいないと思われるので、ほとんどのケースではマスク値が0〜3の範囲に収まるはずだ。また、ALT+SPACECTRL+ESCなどのXM6側の操作を優先すべき操作については、ALT/Windows/アプリケーションキーに何か機能を割り当てた時点で(低レベルキーボードフックの処理中は常に)無効化される。

 最終的なXM6.iniのKeyMaskの値の設定は以下の通り。ALTキーに機能を割り当てた時の挙動を変更できる。
内容デフォルト
+1ALT+F4を無効化する無効
+2ALT+ENTERを無効化する有効
+4ALT+TABを無効化する有効

 キーボード設定のデフォルトボタンを押した時の確認ダイアログを追加。
 メッセージボックスのMB_YESNOタイプをすべて駆逐。MB_YESNOは×ボタンやESCALT+F4といった、誤操作から最速で復帰するための一般的なキャンセル操作を一切受けつけないという、ただその一点において、そびえ立つクソすら生ぬるいWindowsの汚点の真骨頂ともいえるUIである(わかってると思うけどMB_YESNOCANCELは問題ないんよ)。
 というわけで該当する全3箇所(CKbdPage::OnRClick, CKbdMapDlg::OnApp, CTKeyPage::OnRClick)をMB_OKCANCELに変更した。
 全画面モードから復帰した時ウィンドウ枠がつかないように変更。
 キーボードの名称テーブルのかな刻印部分を半角カナからひらがなに変更。後世の人間がソフトウェアキーボードの挙動を見た時、キーボードに半角カナが刻印されていたかのように勘違いされてしまうことを阻止するため。さらに、キーボードLEDが消灯状態でもどのキーにLEDがあるのか、前提知識なしでも判別がつくようLEDを持つキーの名称にはマークを追加した。最近のキーボードしか知らないと、INSキーにLEDがついているとか想像がつかないかもしれないので。他にも、ひらがなと全角のLEDは緑色だよ的な情報も残しておいたほうが良いかもしれないと思ったのでソースに記載しといた。

 TypeG作者さまとの協議の結果、XM6.iniのKeyMaskの場所は[Keyboard]セクションに置くことに決定。古い定義ファイルだと[Keyboard]セクション以外の場所にKeyMaskの設定が残ってしまうかも。手動で削除するか放置でおk。
 ごく稀なタイミングで、アプリ起動直後の瞬間にウィンドウフォーカスが変わると正しくフォーカスを取得できない(原作からある)問題を修正。
 このタイミングでもまだウィンドウ生成直後にフォーカスが変化した時にフォーカスが正しく認識できないタイミングがあることが判明したため、TypeG作者さま協力のもとTypeGと同じフォーカス修正処理を追加。おらっしゃぁぁぁ

2014.10.05

 久々にトイレで転んで便器に頭をぶつけた瞬間にコーディングの神が降臨キタ━(゚∀゚)━!原作の問題点の修正方法を閃いて一挙に2つ解決した。
 特にメッセージループが止まらずに最速でスムースに回るようになったのであらゆるキーボード・マウス操作が感動的なくらいスパスパ動くようになった。

その1 整合性レベル中以下DirectInputのキーがロックする問題を解決
 原作では管理者権限ではない状態で実行していてウィンドウフォーカスを移動させた時に、キーが押されたままロックしてしまう現象が存在した。

 DirectInput使用時、プロセスの整合性レベルが中以下だとウィンドウが入力フォーカスを失った時の状態で内部でキーが押されたままになってしまう環境がある(これは原作でも発生する現象である)。そこでフォーカス喪失時に内部状態をリセットして回避している。

その2 UIメッセージスレッドの不定期な遅延を解消
 原作ではマウス操作やウィンドウ移動などに不定期の遅延(操作の引っかかり)が存在した。
 原因は2つ。

 まずメッセージポンプは全部書き直した。根本的に解決するためには書き直すしかなかった。博士、お許しください。

 UIスレッドでVMコアをロックするとUIスレッドに不定期の遅延が発生し操作性を著しく低下させる要因となっていた。
 今回、通常動作におけるUIスレッド側からのVMコアのロックを除去し、無駄に消費していただけの待ち時間をなくした。これによりUI応答性能の大幅な改善とわずかながらMPUエミュレーション速度向上を達成した。

 VMコアのステータス取得には中継用のバッファを用い、UIスレッドをロックフリー化。
 この処理はUIスレッドのメッセージポンプがアイドル状態の時、定期的に呼ばれる。原作では、ここで毎回VMロックが行なわれていたため、UIスレッドの応答性能が極端に悪化する根本原因となっていた。
 そこで、VM情報をいったんメインスレッド側でバッファリングしUIスレッド側はそのバッファを読むことで、UIスレッド側からのVMコアのロックを完全に排除し、UI操作に遅延が一切発生しないよう改良した。
 バッファの排他制御には遅延ゼロのインターロック操作を用いる。
 VMコアへのアクセスは原作同様に最小限となるよう、UIスレッド側がバッファを読み出してから10ms以内に一度だけ動作する。UIスレッド側がアイドル状態ではなくなり、バッファを読み取る余裕がない時は、VMコアへのアクセスは一切発生しない。

 まず、その1のアイドル状態で動作するステータスバー更新時にVMロックが使われていたので、VMの状態取得と描画とを非同期で駆動できるよう改良した。

 あと、ウィンドウ移動中の操作の引っかかりを解消した。
 特にウィンドウ移動中に端が少しでも画面外にかぶるとUI操作が長時間止まる問題を根絶した。
 他にも、原作にはステータスバーが画面外に消えた状態からウィンドウを画面内に移動した際、ステータスバーが黒塗りになる(正確であるが故の)不自然な挙動があったのでこれも消えないよう変更した。

 UIスレッドでVMコアをロックするとメッセージポンプに不定期の遅延が発生し操作性が著しく低下する。今後はUIスレッドでのVMコアのロックの使用には細心の注意を払うこと。

 リリース版でもキーイベント系での操作のもたつきがまったく発生しなくなった。ついに、低レベルキーボードフックやキーイベント系を実用化する目処が立った。

2014.10.07

 GIMONS氏の提唱するジョイスティック入力遅延低減処理を先行試作。従来のジョイスティックのポーリング処理を廃止し、VMが8255のポートを読み出すタイミングを契機にホスト側でデータを取得するよう改良。これにより理論上はジョイスティック入力の遅延は完全にゼロとなった。G2のしゃがみ斬り斬りからの立ち斬りの失敗が減って出しやすくなったような気がする。(プラシーボ)
 デジタル方向入力としてジョイスティックのPOV情報も利用するよう改良。要するにPS4コントローラを買ってきてPCに標準HIDドライバで接続した状態で十字キーでもゲームを操作できるようになった。ダッシュの入力にレバー二回とかの操作が必要なG2は、アナログスティックだとマジ操作がつらいので速攻で対応させといた。
 TOWNSパッドのコンフィグにAB同時押し設定を暫定追加。要するにPS4コントローラの適当なボタンにA+Bを割り当てておくことでG2でベティ呼び出し操作をミスって痛恨のタイムロスで泣かなくて済むようになった。(当時3ボタンのジョイスティックを自作する時はダイオードを使って3ボタン目にAB同時押しを割り当てるのがわりと普通だった気がする。)
 というわけでみんなG2で遊ぶべし。半透明が見えなくてもフォースと根性で乗り切るんだ。
 ウィンドウフォーカスが外れた状態でもジョイスティックの操作を受け付ける設定を追加。Background=1で操作可能となる。デフォルトは0。

Backgroundの値内容
0バックグラウンド時にジョイスティック操作を受け付けない (デフォルト)
1バックグラウンド時にジョイスティック操作を受け付ける

 ジョイスティックの連射判定をCRTCの表示カウンタの変化に合わせるよう改良。
 オプション設定でALTキーの割り当てを追加・削除した後、再起動不要で低レベルキーボードフックの設定が正しく反映されるよう改良。

2014

 と、PS4コントローラで調子にのってG2で遊んでいたら
_人人人人人人人人人_
>  突然のスリープ  <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄
 どうやらジョイスティックの操作はシステムのアクティビティに含まれないようなので、ジョイスティック操作があったら10秒おきにOSにアクティビティを通知するようにした。これでジョイスティックでもゲーム祭りだぜ!
 調子に乗ってマウスの入力低減も実装した。X68000ではマウスの状態取得をソフトウェアでやっている所がエミュレーション実装のポイントとなる。キーボードは押せば必ず取得できるのでポーリングを細かくすればするほど再現度が上がるが、マウスはソフト側の実装によって取得速度を任意に変えられるのだ。原作のマウス入力処理では、VMへのデータ入力とマウスモード脱出判定のボタン取得を同時にやっていたので、取得の遅延ゼロ化で問題が発生する。例えば、既存のアプリでいうとHMOUSEのオートパワーマネジメントモードや割り込み停止モードがこれに該当する。
 そこでマウスについては、原作通りのCRTCの表示カウントに応じた取得(マウスモード脱出判定用)と、遅延ゼロ取得の二系統の処理を動かすことで、遅延ゼロ状態であっても正確に動くように改良した。

 原作のロジックでは、マウスモードON突入直後に1フレームだけボタンが離されるタイプのチャタリングを防止できない。念のため別のロジックを検討しておくべき。

 ジョイスティックのデータ取得に失敗した場合に直前のデータが残ったままになる仕様を変更し、エラー時は入力データをクリアするよう改良。
 マウスモードからの復帰時にマウスカーソルの座標を元の位置に戻すよう改良。これまでは、例えば30インチWQXGAとかの巨大なモニタの左上で作業していて画面中央(注視点から大きく離れた位置)にマウスカーソルが飛ぶと、どんなに身構えていても必ずといってよいほど位置を一瞬見失ってしまうし、元の位置に戻すためにマウスを長距離動かさないといけなかった。よってこの改良で、多少はマウスモードが使いやすくなったのではなかろうか。
 OSへのアクティビティ通知をVM側モジュール内部からではなくホスト側のモジュールから出すよう改良。

2014.10.13

TypeG友情出演!

 ここ最近TypeGにXM6改のコードをマージしてたりして作者さまと頻繁に情報交換してた。
 TypeGの音源まわりへのこだわりは話を聞けば聞くほど凄いの一言である。音源以外でも、VMコアの内部まで手が入りまくっている……というか、MPUエミュレーションコアごと換装されてしまっているあたり、もう一体何を食べたらこういうのが作れるようになるのかというレベルでいろいろ変更が入っている。凄い。
 で、いろいろ話をして意気投合したのでWindrvのGUIを使わせてもらえないかと聞いてみたところ、なんとあっさり快諾していただけた。GUIのみに留まらず、イベント処理回りのパフォーマンスアップやMFPのエッジ判定処理の改良などのノウハウも教えていただいた。キーマスクとジョイスティックのバックグラウンドのGUIも使っていいとのこと。ハラショー……。ありがとうございます。
 というわけで速攻取り込んだお!
 ねんがんの GUIを てにいれたぞ!な、なにをする(ry

2014

 この前の版まではVC6を使って根性でバイナリを生成してた。コードサイズが小さくてXPでも使えるので重宝してたんだけど、やっぱりもうちょっとパフォーマンスが欲しい。かといってVC2013にするとDLL配布が必要……。一体どうすればよかんべか……(と毛布に包まったまま寝てしまう)。
 「VC2013のCランタイムがなければ、VC6のランタイムにリンクすればいいじゃない」
 という試みを長いことやっていたのだけど、ようやく例外処理込みで実現できる見通しが立ったのでプロト版のバイナリを実戦投入。
 プロファイラを使った最適化が威力を発揮してくれるおかげで、VMコアのエミュレーション速度が原作の1割程度向上。(こちらの環境だとsiのシステムパフォーマンス計測値が18500台から20500台程度に上がった)なおMPUコア自体は元々アセンブラなので速度向上はほとんどないものと思われる。I/Oや割り込み系の処理効率アップで速度を稼いでいるイメージ。
 ステータスバーのメモリ消費量削減の改良を入れた際、バッファオーバーフローのエンバグが入ってたので修正。
 WindrvXMのGUIがついたことで、INIファイルの[Windrv]セクションのResumeは不要となった。というかそもそも[Resume]セクションと見分けがつかなくて非常に紛らわしい代物だったのでこの機会にデストローイすることにした。デストローイ

2014.10.15

 反復法を用いたキーマトリクスの電気回路シミュレータを搭載。これにより「下さい」が「下さいお」となる誤入力まで完全に再現する。他にも、キーの完全同時押しの際のデータ送信順序をDirectXの並びではなく実機のキーマトリクス順となるよう改良した。

 原作ではマトリクス順ではなくスキャンコード順にキーを走査しているが、これだとキーボードコントローラ内でスキャンコード順に送信内容をソートしてから送るという内部モデルとなり、1回のポーリングで複数のキーの状態が同時に変化した時、実機と異なる順序でキーデータが送信されてしまう可能性がある。
 キーマトリクスで衝突が起きた時の文字入力パターンから判断する限り、キーボードコントローラ(80C51)の内部では、『キーマトリクスの順』に送信バッファに格納しているものと推測される。そこで、キーデータ送信順序の判断はVM側に任せて、ホスト側は複数キーの同時変化の情報を正確にVM側に伝えることに専念する。

 当時、この回避方法はキーマトリクスに逆流防止ダイオードをすべて接続するというハードウェアベースのもの(Oh!Xにこの改造に関する広告が時々載ってた)とソフトウェア(KeyWitch.X)を使い入力を遅延させるという2つの手法が存在した※。特にハードウェアによるアプローチは最上級Sレア改造の一種とされ、なかなか手が出せなかった。

X68000 LIBRARYより KeyWitch.X

 XM6の開発方針に従い、デフォルト状態は原作と同じ挙動(ダイオードあり)とする。
 ここまで再現しているエミュレータは他機種のものでもなかなか存在しないのではなかろうか。これで名実ともに「他に類を見ない独自機能」の実現まで漕ぎ着けたと言ってよいだろう。
 つかWindrvの改良は超絶苦労した割に地味子ちゃん過ぎて、一体何が独自なのかまるで理解されないレベルだったので、わかりやすい独自機能が欲しかったのでようやく一段落である。

2014

 ダイオード追加改造をGUI設定に追加。
 リソースを見直したら2.01改の頃のメニューの変更がほとんど消えてたことに気付いた。2.05系に移行するとき差分を適用するのをすっかり忘れてた。サクっと戻した。
 キャプション・ステータスバー・メニューバーの変更が発生する際、常時ロックを行っていた部分を変化があった時限定でロックするよう改良。一時はロック自体も無効化していたのだが、ここはロックしないとVMの描画処理の時に問題が起きる可能性がありそうなので、きちんとロックするように戻した。
 コンフィグ関連ワークのゼロクリア処理を改良。

2014.10.20

 ダイオード追加改造のINIファイル定義を変更。[Keyboard]から[Alter ]セクションに移動し論理を反転。

Keymatrixの値内容
0キーボード通常状態 (同時押しで誤入力発生)
1逆流防止ダイオードの追加改造あり (デフォルト)

 あと後述のADPCMの倍速改造(テスト実装中)の設定も暫定追加。クロック選択回路は未実装なので有効化すると素直に倍速再生になる。SCM -2で使うべし。

ADPCMClock値内容
0ADPCM通常状態 (デフォルト)
1ADPCM倍速再生回路の追加改造あり (選択回路は未実装)

 英語メニュー選択機能を追加。せっかくの英語リソースがあるのだから日本語OSもメッセージをまるっと国際化するのデース。イングリッシュを話してるみたいでカッコイイのデース。紅茶が飲みたいネー
 この実装はTypeGの機能をリスペクトし新規に書き起こしたものです。TypeG作者のGIMONSさんに実装のアイディアを使わせていただくことをご快諾いただきました。この場を借りてあらためて感謝します。ありがとうございました。

 F10キーに割り当てがある場合、低レベルキーボードフックを使って処理を除外するよう改良。

 SCC/ADPCM/PPIの偶数アドレスのバイトアクセス時のバスエラーを実装。(PPIのはジョイスティックアクセス関連の改造の時に既に入れてた気がする)

 SCCの改造が7.5MHzだったのがどうしても納得いかないので正しい値である7.3728MHzに変えた。むしゃくしゃしてやった。正確に115.2Kbpsを再現するには当時からこうするしかなかった。今は(実機は)他界している。
 嫌じゃ。わらわは7.5MHzなんぞ使いとうない。こんな歪な周波数が広まってしまったのは、アレがメジャーになってしまったのが全ての元凶だというのはまるっとお見通しだ。もちろん当時この周波数の水晶発振器(通称原発)はヒジョーに高価だったし、私のような地方民にとって、猛烈に入手困難な状態だったなんてことは百も承知なわけよ。それでもだな、大都会秋葉原まで遠征して7.3728MHzを苦労して手に入れて、クロックアップで最初にくっつけた5MHzをはずして、載せかえてぶっ壊して顔面蒼白になるまでが形式美だったじゃん?じゃんじゃん?チーッス
 SCCの主要な処理を書き直した。チャネル処理を共通化。共通化の過程で、2箇所の問題を発見。
 最初のWR9の問題はTypeGをみたら既に修正済みだった(実装は異なるが同じ意図)。最後のやつはまだ直っていないようなのでフィードバックしといた。
 SCCのレジスタ読み込み回りでテーブルを不要化。
 データ送信処理の先頭の入力データの無意味な論理演算を廃止。マウス側で正しく8ビットの送信データを生成するよう改良。

 ADPCMの倍速再生選択回路の改造機能を実装。これも当時改造したかったけどついに叶わなかった最上級Sレア改造の一種。ま〜きゅり〜ゆにっとを持たないXM6改における高音質BGM再生への最後の希望である。(S44PLAYとかは別格な※)

※X68000にはS44PLAY.XというPCM8並に凄い音声再生ソフトが存在する。奥の手はまだまだあるのだ。

 実のところこちらでは対応ソフトはSCMしか持ってなかったりするのだけど、コナミSCCの波形メモリを使うタイプの曲(F1スピリットのBGM等)の一部で劇的に音質が良くなるものがある。逆にPCMデータを使っているタイプのものは15.6kHz再生用に調整されているせいか、音質が悪化してしまうものもあったりする。

お願い
 Oh!Xの改造記事にはクロック選択回路があるらしいのだけど、該当の号が見つからないので未実装。
 改造記事の詳細についてご存知の方がおりましたらぜひ内容をお知らせください。
→見つかりました。情報ありがとうございます

 誰かPCM8系……つかwbcwを倍速再生に対応させてくださいおながいします。おながいします。おーなーがーいーしーまー

 ADPCMのコマンドレジスタ書き込みの際、動作停止と録音・再生スタートの3ビットが同時に指定された場合は停止→再生の動作判定となっているが、これは本当に実機と同じかどうか確認する必要がありそう。

 ADPCMの波形計算処理を高速化。コンパイラへの最適化ヒントを追加し無駄な構造体書き込みアクセスを排除。テーブル内容を一部変更し計算回数を削減。複数処理をまとめ処理効率を向上させコードサイズを削減。
 ADPCMの再生スピード調整機能をさらに改良。FM音源の処理とADPCMの処理時間が僅差であれば、補正用のばね定数を弱めることで突発的な外乱(ホスト側の負荷変動によるVMコア実行率の瞬間的な変化)の発生時の振動型のジッタ(外乱に合わせて再生速度が揺れる現象)を抑制。
 ちなみにTypeGには、このばね定数を弱くする変更が入っているんだけど、単に弱めただけなので、外乱で大きく発音タイミングが乱れた時、テンポがずれた状態で長時間演奏が行なわれてしまうという改悪になってしまっていて、BGMを流しながら作業していると、聞くに耐えない演奏状態が何度も起きてしまい、とても……とてもつらかった。この改良によって、原作とTypeGの両方のいいとこ取りができるような形になったはず。(当然こういう重要なポイントはしっかりとTypeGにフィードバック済みなんで安心されたし)
 まだまだ行くよー。ADPCM初回データ検出判定で$08を見ない謎の仕様を変更。再生データのニブルに差分1以上の値が存在した時に正しく検出するよう変更した。判定の処理量も1/3に短縮。これを直したところで実質的には何の影響もないけど、こういうのは自己満足が大事。
 ADPCM初回演奏時のロジックを変更し、処理をシンプルにしてコードサイズを縮めた。イベント関連の同値チェックが1回減り動作クロックも減る。
 ADPCM波形計算処理を変更。二段階のテーブル参照を全て整数演算のみで代替。ホスト側のCPUクロックが高速になればなるほど、メモリ参照よりも効率が上がるはず。
 ぷちノイズ防止処理の反応を1ステップ高速化。
 音量計算とデコーダ一段目のボリューム計算精度の向上による音質改善。ボリューム計算後の値をバッファに展開する際の線形補完処理をDDAで高速化。
 ぷちノイズ防止処理を改良し、無音時のピー音防止処理を廃止。この処理が動いている限りは必ず0付近で波形が鈍るため、音質低下の原因となっていた。これによりさらなる高音質化を実現。
 以上により、原作とはもうADPCMの出力波形レベルでぜんぜん違ってきてしまったし、ソースもだいぶ原作からかけ離れた感じに変更してしまったが、音源を知り尽くしたPI.さんが見ればきっと、きっとすべての意図を一瞬で理解してくれるはず。
PI.さんドコー (;_;)

2014

 原作ではマウス速度設定で速度100%にした時、設定値が257(100.39%)になってしまうのだが、これはスライダーの内部の値が表示用の値と異なる範囲(0〜512)で動いているのが根本原因である。そこでスライダーは0〜200の整数値で扱い、正確にGUIの値が設定値に反映されるよう改良した。
 もしかして同様の問題が音量設定まわりにも大量に存在するかも……と思ったが音量は0〜100の値をそのまま使っており、この種の問題は一切発生しないことがわかった。しかし、音量が100段階しか選べないというのはちょっと解像度が足りないんじゃなかろうか?(実質使われるのはその中でも10%程度の範囲だけなので10段階程度ってことになる)……まいっか。

 ADPCM倍クロック改造の回路図キタ━(゚∀゚)━!
 というわけで早速実装。

 IOCTRLでドライブ状態を正しく返さないディスクをWindrvXM/WINDRVで認識できるよう改良。
 これは一体どういうことかというと、WindrvXMでは最近のSATAドライブのような、「ハードディスクだけどリムーバブルに扱える」というデバイスも正しく認識できるようにするため、起動直後に一回だけデバイスの状態を見るように(これにより起動の瞬間にオフラインになったデバイスでエラーが出てしまうのを防止)しているわけ。(8年前はこういうデバイスはまだ一般的じゃなかった)
 ところがGavotte Ramdiskのような作りの悪い(古い考えで作られている)ドライバでは、常にデバイスがオフラインと報告されてしまいどうやっても見ることができない。要するにSATAのデバイスドライバを信じるか、作りの悪いドライバを信じるかという問題となる。
 IOCTRLの値を見た瞬間、これは……さすがに……切り捨てていいカナ?カナ?と思ったんだけど、このドライバは無料でかつ容量制限もないという便利な代物らしい。何より以前は32Bit OSのオーバー4GB越えで有名だったため、潜在的な利用者はとても多いかもしれない。実際、TypeGのような利用者の多いエミュが公開された瞬間、問題が発覚したくらいだし。なによりも、今困ってる利用者がいるのだから何とかするのが技術屋ってもんである。よって対応する道を選んだ。情報提供と調査協力ありがとうございました。
 こういうトラブルがTypeGの公開によって即発覚するというあたり、TypeGはさすがの知名度という感じである。よくよく考えると、これって実はXM6改はだれもテストしてないということの証左とも言えるし、さらには長年の試作期間はまったく無意味だったとも言えちゃうかもしれないけど、ううん、よく知らないけどきっとそんなことはないはず。泣いてない。くっ……殺せ!
 2ちゃんねるで報告があったVM停止中のステータスバーの非同期更新処理を追加。これはUIスレッドのロックフリー化を行なった際、VM停止時の情報取得処理が足りていなかったのが原因。というわけでサクっと追加実装した。情報提供ありがとうございました。
 DirectInput5では認識できないF13以降のファンクションキーの入力に仮対応。これはX68000キーボードのUSBコンバータではF13〜F20までを使うという利用者からの情報提供によるもの。
 本来、XM6ではF15までのファンクションキーに対応しているはずだったのだが、調査の結果DirectInput5ではF13以降のファンクションキーやマルチメディアキーなどが認識できず未定義コードNUL($00)になることが判明した。そこで右シフトキーの時と同様にキー入力APIで補完することにした。
 ただ、全てのキーに関してAPIを毎回発行するのは高速化の美学に反するため、あらかじめF13に何かキーを割り当てておき、F13の割り当てがある場合のみAPIを使ってF14〜F20まで追加認識するという二段階方式とした。情報提供と調査協力ありがとうございました。
 SCCクロック改造時の内部処理の丸め誤差を最小化。5MHz時の値を原作と同一としつつ、7.3728MHz時の値がより正確な値で動作するようにした。ちなみに前回、7.3728MHz化改造ミスでアオイ火花綺麗アハハと失意のズンドコに陥った俺ちゃん氏であるが、その後は涙目で互換動作用に用意しておいた4.9152MHzを使って修理して幸せに暮らしましたとさ。めでたしめでたし。

 現在、ここまでのコードをXM6 TypeG公開版に適用済み。
 なおXM6 TypeGにはアイコンデータや68030モードでのアイコン色変更など、めっちゃフリーダムにネタを提供させてもらったり、トラブルシューティングの依頼や、XM6改のエンバグ修正依頼などいろいろと無理難題を押しつけてしまっていたりするのだが、いつも快く採用していただいて感謝感激である。ちなみにアイコンはジオグラフシールのエンディングを眺めていたら白と赤でX68000とX68030のロゴが出たのを見て、実機ロゴと同じ感じになるぞコレはとキュピーンと閃いたのがキッカケ。

2014

 ADPCMデコーダ(一次バッファ内)の線形補完を完全に排除する、通称「フルデジタル化」設定を追加。これはADPCM(MSM6258V)のDASO端子から生のデジタルデータを直接吸い出す改造(現代の技術を用いれば理論的には可能という最高難度のS級超レア魔改造)に相当する。原波形を一切の劣化なしのデジタルデータとして取得し、イコライザなどのデジタルフィルタ技術を駆使しまくって最終的にはアナログ回路部分の挙動を完全再現する謎の計画のために避けては通れない道である。
 なお、XM6原作で一次デコーダの出力に線形補完が入っているのは、ADPCMのアナログ出力に対する擬似的な電気回路シミュレーション(もしくは簡易LPFとしての効果を狙ったもの)であると推測される。
 現在の実装ではアナログ接続時(補完あり)のほうが、ボリューム計算の端数で切り捨てとなってしまう情報を拾って補完動作を行なっているため(以前の波形高品質化改良)、実質的にはデジタル接続時よりも波形に含まれる情報量自体は多くなっている。しかしアナログ時はこの補正がかかってしまうがために、エッジの鋭い波形の再現が苦手となってしまう。もちろんこの特性はXM6原作や実機でも同様である。ホントは内蔵の10bit DACを使ってる時は2ビット情報量を落とさないといかんのだろうけど……まいっか。
 補完を全て外すと奇数次倍音成分を含んだキレッキレの特徴的な音質になるので、耳の良い人なら一撃で違いを知覚できるはず。微妙な違いなんだけどこの積み重ねが大事。
 とにかく、よくわからない場合は、全てデフォルト設定にしておけばだいたい同じ音が出ると思っておけばよい。弄るなよ?絶対弄るなよ?……って、全然波形が違うじゃないですかヤダー!大丈夫だ、問題ない。ちょっとだけ!先っちょだけ!恐くない痛くない考えるな感じるんだXM6改は初めてか?力抜けよ

ADPCMAnalogの値内容
0デジタル12ビット出力端子を選択
1内蔵の10ビットDACのアナログ出力を選択 (デフォルト)

 現状でもこの設定は、ADPCMの倍速クロック改造と併せることで、厳密な矩形波成分の再生を必要とするアプリケーション(SCM等)で存分に威力を発揮してくれるはず。他にもPCMデータがリッチなもの、元がX68000由来ではないもの(RSDのアウトランとか)がいい感じで鳴ってくれるようになった気がする。ただし、X68000本来のサンプリングデータを使う場合は逆効果となってしまうこともあるので注意。さらに言うと、フィルタが一切かかっていない生のデータが出てしまうため、ホストからアナログ回路を経由せずに光デジタルで疑似サラウンドをかけて出力したりすると、倍音成分が増強されまくってスンゴいことになる場合がある。最終段までに何らかのアンチエイリアスをかける(LPFをかます)べきかもしれないし、むしろこのキンキン感がたまらんちな我々の業界ではご褒美レベルかもしれない。もっと……もっとだ!

 さてここまで何度か話題に出ているSCMだが、SCM v0.26からは改造に対応しているとドキュメントにあるものの、実際に動かしてみるとCT1端子が常に0になってしまっているため周波数がうまく切り替わらなかった。そこで切り替え処理を追加しておいた。第一線で今なお大活躍されている伝説級の御方のプログラムを改変するのは恐れ多いが……博士、お許しください!
SCM v0.26用の倍速クロック対応パッチ

 デコーダ補完なしの設定にするとSCMで15.6kHzと31.2kHzでの再生音がだいぶ似た感じになるのが面白い(またプラシーボ)。デジタルフィルタに入れる前段データとしての可能性を感じる(またまたプラシーボ)。

 補完設定をGUIでもできるようにしておいた。他にも英語のスペルミス(Interpolation)の修正など。
 ADPCMのバッファオーバラン判定の範囲記述ミスを修正。
 データロード時に2.05からの更新部分(セーブデータに含まれない情報)はデフォルト値ではなくINIファイルの設定状況に合わせるよう改良。

 ADPCMまわりでのTypeGで修正されている箇所の情報を共有。たいへん貴重な情報をありがとうございます。内容の詳細を公開してよいかは微妙と思われるのでここには書かないがとにかくTypeGはいろいろ凄いぜ!とだけ書くにとどめておく。この後実機調査なども交えてもっと凄くなっちまうんだぜ?フフ怖
 TypeG修正箇所の1つ、原作のバッファ後半部分の未使用問題を修正。バッファポインタがFM音源などの他のデバイスと同等の範囲を指すよう修正した。これによりADPCMデコード時にバッファを全て使いきるようになったの。もしかするとサウンドバッファのアンダーラン・オーバーランが以前よりは若干発生しにくくなり安定して再生できるようになったかもしれない。

 悪の秘密結社プチノイザーのコード(まだ封印状態)をデータシートに合わせて改良。

 ADPCMデコーダに波形劣化ゼロの次世代ぷちノイズフィルタを搭載。プチノイザー襲来に備えて守備を固めるのだ。
 一定時間音エネルギーが閾値以下の場合にハム音とぷちノイズを完全遮断する。これにより、原作では除去できなかったPCM8Aの無音中の耳障りな音や、SCM無音中の(非常にかすかな)高音ノイズ、演奏終了状態でプログラムを終了させた際のぷちノイズを除去できるようになった。
 最初は大量のバッファスキャンが必要な低速でどうしようもない処理だったが気合いで有限オートマトンを使ってバッファレス化して理論上最速で動作するよう改良した。

2014

 古いバージョンのセーブデータを読んだ時に、INIファイルが初期化されて毎回手動で直す羽目になる、互換性や再現性という意味では非常に厳密であるが、あまり利用者にとっては嬉しくない仕様を廃止。VM動作の互換性が保障できる最小限の設定のみを行い、他の設定については極力現状を維持するよう改良した。

 ジョイスティックのボタン設定が反映されなくなってしまったエンバグを修正。
 原作のジョイスティックボタンの反映は100ms秒(秒間10回)でもっさりしすぎていて連射力が反映されなくてつらいので10倍速にした。連射は一日一時間。
 英語キーボードをDirectInputで読んだ時、存在しないはずの漢字キーが誤入力され続ける環境があることが利用者の報告から判明。Windowsのキー入力回りは闇属性に満ちているけどこれは特にヤヴァい。
 というわけでカウンタで反応時間をチェックしてさっくり無視するようにしておいた。
 TypeGで、英語キーボードかどうか判定してから無視する改良が入ったので導入。

 この時、キーボード情報からファンクションキーの個数も調査できるようなので、USBアダプタのファンクションキー個数がAPIからはどう見えているか調査してもらったところ、残念ながら一般的な106キーボードそのものとして扱われているため、ファンクションキー個数12個固定となっていて正しく取得できないということが判明した。ご協力ありがとうございます。
 現状だとワンチップマイコンなどを用いた自作USB系はこのパターンが多いため、APIで数を取得するのは難しいということなのかもしれない。こうした理由により、これまではF13に割り当てがあったらF14以降が有効になる二段階方式を取らざるを得なかった。で、ついさっきトイレで転んで(中略)閃いた。コンフィグ時は常に全キーをチェックし、通常キー入力では必要最小限の範囲をスキャンすることで高速化と準備設定不要化の2つの改良を同時に入れることに成功。

 低レベルキーボードフックまわりに2種類のバグが発覚。修正した。
その1: キーフックをかける前にDirectInputが制御を握っているとフックが動作しないことがある。この二者は内部動作レベルでは似たような情報をつかんでいるので、内部動作で何か関連があるのかもしれない(MSDNには該当するドキュメントは見つからなかった)。ひとまずフック前にUnaquireするよう修正。
その2: キーフックはキー押下だけを無効化できれば十分なのに無理してキーを離した時にも無効化していたため、特定のキー操作パターンを行なった時、稀に一部のモディファイアキーが押されたままになる可能性があった。モディファイアキーを処理から除外し、かつキー押下時のみ除外処理を行なうよう修正。
 TypeGで、Unaquireのかわりにキーイベントの情報を使ってDirectInputのキーを補正する改良が入ったので導入。これは、CAPS漢字ひらがなキーを押した時、他の無関係なキーが同時に押されていると、そのキーも巻き添えをくらって状態がクリアされてしまうという従来の制限を、キー入力APIやDirectInputを使わずに解決する画期的な方式である。
 ここからさらにキーイベントの処理方式を発展させ、SHIFT+CAPSALT+漢字の押下中であれば、押し離しの情報を正確に取得できるように改良した。これまで散々見てきたDirectInputの内部動作を妄想で補完して、内部で複数キーが1つのバッファを同時に上書きしないようにすることで実現した。これでようやくDirectInputを超えたと言っても問題ないだろう。
 キーイベントとDirectInputの実装部分を同時に有効化すると、なぜかプロファイラ最適化後のパフォーマンス上限が0.5%ほど低下するようになったので対策。こういう時は命令・データキャッシュのどっかでミスヒットが起きてたりしてタイミングが微妙に変わったりしていることが多い。ひとまず殆んど参照しないテーブルの利用を廃止し、メモリ書き込み量を極力減らすようにして高速化。元のパフォーマンスに戻ったので一安心。
 GIMONS氏よりTypeGの改良取り込みの許可をいただいたので一部取り込み
その1: ADPCMの再生状態で再生コマンドを発行すると音量がリセットされてしまうという、原作の問題を修正。OVERTAKEのデモで音がおかしい問題が直るとのこと。
その2: ジョイスティックのデバイス選択で、同じデバイス名が複数並んでいる時に区別がつけられるよう、デバイス名の頭に数字をつけて区別しやすくする改良を追加。

 WindrvXMのソース一式をTypeGと共通化できるよう改良。
 DOS _WRITEで長さ0を指定した時、ファイル末尾を切り詰める機能を実装。
 サイズ0の時の挙動は、ブロックデバイスではHuman68k内部で処理されていたが、リモートデバイスではファイルシステムの制御権はリモート側にあるため、この処理はリモート側が責任を持たねばならないらしい。備えよう。

2014

 既に実機が壊れてしまって、実機調査が不可能となってから久しい。
 でもどうしてもADPCMまわりの実機調査をやりたいと頼んだところGIMONS氏が一晩でやってくれました。


 調査結果とデータシートから、ビット0〜6は固定値ではなくチップ(MSM6258V)の内部状態を起因とした不定値と考えておくのが妥当である。
 不定値の一例して、ゼロインピーダンスによるデータバス未接続状態の可能性がある。すなわち、直前のMPUのデータバスの状態やデータバス上のノイズ等が影響を及ぼしている可能性も考えられる。
 厳密なエミュレーションを目指す場合は、ビット7以外にはランダムな値を一定確率で混ぜるなどの手法が有効かもしれない。

 この調査結果はTypeGとXM6改の両者に既に反映済み。ありがとうございました。

2014

 キーイベントに問題発生。CAPSキーを押した時にひらがなが、ひらがなを押した時にCAPSキーが一瞬入る可能性があるエンバグを修正した。

 ジョイスティックのボタン数を最大12個から14個に拡張。これはPS4のコントローラであるDUALSHOCK4が14ボタンのため。これで全てのボタンを認識できるようになった。
 実はXM6のセーブデータにはボタン12個分の情報しか入っていないので残りの情報についてはINIファイルのもので補完するようにしている。また、新セーブデータを使う場合は4つ追加して最大16ボタンまで扱えるようにしておいた。(実際にはXM6改は2.05のセーブデータ方式で吐き出すので新セーブデータはソース上にしか存在しない非実在フォーマットである)
 DUALSHOCK3が13ボタン、DUALSHOCK4が14ボタンだったので、この調子ならPS6の頃は16ボタンとなるので、その後どうするかまた考えよう(白目)

 あと、「ATARI標準」という言い回しは強烈な違和感があるので、「ATARI仕様」に変えた。これだけは絶対に譲れない。正直、今となっては「ATARI規格」でも「ATARI互換(コンパチ)」でも「ATARI標準」でもきちんと通じるし何も問題ないとは思うが、当時はこの呼び名のほうが一般的だったはず。私がそう思うんならそうなんだろう、私 ん 中 で は な。
 ジョイスティック設定画面で座標を縦に詰めて整列。バックグラウンド設定の項目のシステムキー(G)を追加。
 ジョイスティック詳細設定画面のY座標が不揃いだったので整列。割り当ての文字を空白で区切ることで見易さを向上。
 あと、同様の理由でTOWNSパッドの名称を「ATARI標準+START/SELECT」から「ATARI仕様+RUN/SELECT」に変更した。TOWNSパッドのボタンをSTARTと書くのは違和感があるので正確に書いておくことにした。つーかN○Cとか富士○はなんでRUNなんていう別の名称でいちいち書くのであるか?実際、当時このボタンを会話中に「ラン」などと蝶ネクタイの小○生探偵みたいに呼んでいたゲーマーはいないと思うけど(普通は「スタート押して!スタート!スタート!!スタアアアアアアアアアトゥゥゥゥォォォォォ!!!(ドゴーン)GAME OVER」みたいに使う。魂を吐き出すような咄嗟の事態で「RUN」などというハイカラな単語を意思疎通に使うオトナの余裕はない)。しかしながら、ここは資料的意味において正確に記述しておくべきだ。もっと言うと、個人的にはSTART→SELECTではなくSELECT→STARTの順で左にSELECTを記述するほうが妥当だと思っているが、さすがにそこまで変える必要はないだろう。
 あと全然関係ないけど、Aボタンは内側に配置するのが正義だから。あんなの認めないから。え……X1純正ジョイパッド?イヤーッ!グワーッ!アーケードゲームは攻撃(確定系)は内。ジャンプ(キャンセル系)は外。つまり、ABボタンの交換機能とAB同時押しボタンを備えた自作3ボタンジョイスティックが最強。んぅぅ〜ジャスティス。
 ちなみにコンフィグに「TOWNS」という恐怖の水曜日な文字列を入れずに暗黙の名称にしているのは原作リスペクトである。つーかTOWNSパッドはATARI仕様そのものなわけで、設定をわざわざ別にする必要なんてないし設定を分けることになんの意味もないと思っている。当時3ボタン以上のジョイスティックを制作し市販品を楽々と超えていた自作集団に羨望の眼差しを向けて、己はただただ鼻水を垂らすしかできなかった身としては(こうした自作ジョイスティックには当然のように同時押し用のダイオードが多数搭載されていた)、正直、XM6のデフォルト設定であるATARI仕様側に同時押し系の操作をすべて統合するのが筋であり、TOWNSパッドなどという狭い分類なんて必要のない世界にしたい。でも原作との互換性の観点からあえて分けたままにしている。いつか消したる。わしがやったる。明日から本気出す。

 当時の自分のメモをもとに名称が異なる部分を微妙に修正。
×パックランド専用パッド (Left, Jump, Right)
○パックランド専用コントローラ (A, B, C)

×マジカルパッド
○魔法パッド

 基本的にXM6のボタン割り当てはすべて6ボタン(ABCXYZ/ABXYLR)+サポート用2ボタン(START/SELECT等)となっている。基本的にデジタルジョイスティックは全てこの配置に統一すべきだ。
 こうすることで、格ゲーで6ボタンパッドにセッティングした状態から、ジョイスティック種別を変えるだけでボタン再設定不要でATARI準拠に切り替えて即座に使うことができる。
 利用者(私)の利便性がしがらみを上回るのであれば、今、ここで、変えるべき。いいぜ。てめえが何でも思い通りに再現出来るってなら、まずはそのふざけた互換性をぶち殺す。
 というわけで変えた。むしゃむしゃしてやった。刑事さん……私はやりましたよ。また何度でもやるでしょう。今は反芻している。むしゃむしゃ。
TOWNSパッドのA+B/L+R/U+Dを変更。
メガドラ3ボタンパッドのSTARTを変更。
CPSF-SFCのABXYを変更。
魔法パッドのLRを変更。
 サイバースティックのロジックミスと思われる部分を修正。
 魔法パッドのロジックミスと思われる部分を修正。

 んーここまでやっちゃったらもういっか。ボク理性との戦いに疲れちゃった。統合しちゃえ。ATARI仕様にTOWNSパッドを統合。むしゃむしゃしてやった。

 リソースの各種コントロールの名称で、意味を持たない無駄な文字列を削除しサイズ縮小。
 システムクロックに24MHz(REDZONE)を追加。

 GUIにメモリマップの選択機能を追加。ROM V1.1〜1.3をGUIでも選択できるように改良した。
 メモリマップの選択自体は、8年前最初にXM6を見た頃から実装済みだった。
 要するにINIファイルの編集を行なえばかなり古い版のXM6でもこの機能は動作する。
 当時、改造しようとソースを見て、X68030のROMの利用をも想定した設計が行なわれていたことに驚愕した覚えがある。おそらく初期バージョンの段階から設計に含まれていたのだろう。
 これは何気に凄い機能だし、埋もれたままにしておくのはもったいないので、GUIに設定を追加しておくことにした。
 とはいえ、原作ではGUIが省かれていたのには何か理由があるはずである。高い再現率を至上としそこに集中すべきというXM6の設計思想があった故に、この機能はあえて表に出さず「知る人ぞ知る」機能に留めておいたのではなかろうか。
 というわけで今回の追加では、このあたりの背景をきちんと理解した上で、それでも設定を変えてみたいという上級者向けオプションという位置付けとした。ノークレームノーリターン/ノータリンノーライフでおながいします。

Mapの値最低限必要なROMメモリマップ種別
1〜3IPLROM.DATV1.0 従来通り (初代〜SUPER相当)
4IPLROMXV.DAT, SCSIINROM.DATV1.1 X68000 XVI相当
5IPLROMCO.DAT, SCSIINROM.DATV1.2 X68000 Compact相当
6IPLROM30.DAT, ROM30.DATV1.3 X68030/X68030 Comact相当
※設定変更後は速やかにプログラムを再起動すること。ROMが揃っていないと動かないので注意。

 V1.0以外のメモリマップ時は、設定画面のSASI/SxSIの設定タブを表示しないよう変更。
 設定画面のSCSIインタフェースの「装着しない」で、原作の有効化判定ロジックにミスがあったので修正。
 設定画面にSASIのページがなくても全ての設定ができるよう、SASI/SCSIのメモリスイッチ自動設定を分離してSCSIのページにも増設。

 PPIのポートAとポートBに対して1ミリ秒以内の連続読み込みを行なった場合はキャッシュを行うことでホスト側の負荷が上昇しすぎないよう改良。

 PPIの読み込みアクセスはウエイト発生以外の副作用がないため、FM音源のアクセス待ち等に利用されることもある。即ち、アプリケーションによってはジョイスティックと無関係なポートへのアクセスが大量に発生する可能性がある。そこで、1ms未満の間隔で連続アクセスした場合はデータを更新せずにキャッシュを利用する。結果、VM側のデータ取得要求は毎秒1000回が上限となり、ホスト側の負荷を抑えることができる。

 ホストの動作速度が極端に遅い場合は、この値を2〜8ms程度に調整するとよい。(入力遅延と動作速度のトレードオフ)

 なお、実用上は問題ないが、この処理だと35分47秒の整数倍の間隔を置いて意図的ポートにアクセスした場合にデータが読み出せない可能性がある。厳密にやるなら別系統のカウンタを用意しダブルチェックが必要。


 PPIアクセスでFM音源レジスタアクセス制限を解除する方式を検討する。
 当時は、X68030や68040以降のマシンであっても8255さえアクセスしておけばすぐ書き込めるという不文律があり、それに従って作られた音楽再生アプリケーションや修正パッチが存在する。(SCM等)

 FM音源レジスタのBUSYチェックのエミュレーションは綿密な調査と高度な技術によって実現されているが、開発当時には想定されていないような「桁外れ」のMPUの高速化(近代化改修)を行う場合、厳密すぎる動作エミュレーションは、過去のソフトウェア資産の互換性を削いでしまう恐れがある。
 本当のエミュレーションの「精度」とは何か、再定義する必要がある。
 例えば、当時の適切なコードであれば自動的に制限を緩和し、不適切なコードは実機と同様に高クロックでは書き込みに失敗する、といったさらなる動作改善の余地があるはず。

 ジョイスティックのボタン設定の表記を変えた。
 原作では、ホスト側の「ボタン1」とVM側「ボタン1」と、同じ名前で2つの意味があってわかりづらかったのでホスト側は「ボタン+数字」とし、VM側は「名前+ボタン」となるように変更した。

 ジョイスティック系のヘッダを弄るだけで、大量のソースの再コンパイルが走らないよう、コンフィグ系ヘッダにデバイス系のヘッダを含めないよう変更。

2014

 

TypeG友情出演再び!

 

 ある日、TypeGのソースを弄って遊んでいたらGIMONS氏より謎のソース一式が届いた。
 なんとTypeGのグラフィック処理系をまるごとXM6改にも入れてみたとのこと。
 あたかも朝飯前にサクっと載せちゃったZe!とでも言ってのけるかのごとく軽い調子でメッセージが届いているのだが、こ、これはとんでもない代物である。
 この処理は、TypeGのグラフィック処理系の中枢機能に相当するソースコードなのだ。
 これがまるっとすべて移植されているってことは、えーと……つまり……どういうことだってばよ?
 ……思わずソースを二度見した。三度見した。四度見……(中略)……十度見したがこれはやはり中枢機能で間違いなさそうである。つまり……どういうことだってばよ?(混乱)

 GIMONS氏曰く、もともとこの処理は2年前に既に完成しており、改造としては一区切りついているとのこと。
 そして、改造部分はすべてGIMONS氏の手によるものであり、XM6改とともにソースを公開してもよい、との心強い言葉をいただいた。

 XM6改ではWindrvXMの改造やUI系の改良(要するにホスト側機能の改良・拡張)がメインで、グラフィックまわりにはまったく手をつけていなかった。つまりこのグラフィック処理系のソース部分は独立しており、ほぼそのままXM6原作にも適用が可能である。
 TypeGのドキュメントには「いつか成果を反映できたら」と書かれているが、これはまさに、原作XM6に対するTypeGの純粋なソース差分の形で成果が実ったものである、といっても過言ではないだろう。

 さらに少しだけ補足すると、この処理というのは、TypeGのドキュメントにある機能強化部分の、グラフィック関係のほぼすべてに相当する。

CRTC
GVRAM
SPRITE
VC
RENDER
CZ-6XXDエミュレーション

 TypeGではこれに加えてDirectGraphicsを用いた高速かつスムースな描画やVSYNC同期、ストレッチ回りの処理の改良が行われている。
 XM6改ではXM6原作のグラフィック処理(GDIによる描画)をそのまま引き継いでいるため、GDIで動く範囲の動作に限定されている。(一部機能は枠組みとして残っているとのこと)

 というわけで早速全機能取り込みである。あまりにも内容が高度かつ複雑で、取捨選択しながらコピペできるほど中身が理解できてないため、もう、ただひたすらソースを上書きコピーするのであった。ありがたやありがたや。

 というわけで、TypeGのもつ、半透明や特殊プライオリティをはじめとした、X68000の描画処理をフルサポート
 原作の二倍近いアセンブラ記述をはじめとする怒涛の改良をGIMONS氏に組み込んで頂きました。

 

ありがとうございました!

 

2014


これまでのあらすじ
XM6改ゎ走った……
TypeGとXM6iの凄ぃ改良がまってる……

でも……
難しくて……ぜんぜん理解できない……

でも……
諦めるのょくなぃって……
がんばった…

でも……ゴメン……
またエンバグしちゃった……

でも……
XM6シリーズゎ……ズッ友だょ……!!

 
 TypeGのキー入力改良の取り込み(CapsLock、半角/全角、ひらがなキーのリリース制御を融合)
 このTypeGの改良は、何気にすごい画期的なのでここに概要を記しておく。
 これまで、DirectInputでは、WindowsNTのキーボードドライバの特性上、CAPS半角/全角ひらがなといったキーのリリースを検出できないという構造的な欠点が存在した。これ自体は回避できないのだけど、これを補完するためにキーイベントやキー入力APIなどを駆使していたのだけど、今回の改良ではDirectInputだけで処理する新たな手法を編み出している。具体的にはDirectInputのキーバッファリングデータを解析することにより、キーボードイベントと等価な情報を取得している。まさかDirectInputだけで処理できるなんて思っていなかったので、これには驚いた。
 今回のソースで、DirectInputのみ使用する設定にしてコンパイルすることで、この処理が有効になるようになっている。キー入力系のトラブルが発生した時、いろいろ条件を変えて動作解析できるようにしておくときっと役立つはずである。

 スキャンライン描画オプションを追加。
 スムーシング描画オプションのINI項目名を変更。
 INIファイルの設定は、TypeGに合わせて以下のようにしてある。

項目名内容
Filterスムーシング描画の有無 (1で有効。デフォルトは0)
ScanLineスキャンライン描画の有無 (1で有効。デフォルトは0)

 なお、GDIによる描画のため、スムーシング描画はなんかうまく動作しないというか、なんか遅くなってるような気がするというか、たまに化けるというか……。なんとも微妙な代物になっているが、これは仕様である。
 移植の際、GDIの実装上の問題があったため、今回GIMONS氏から頂いたTypeG移植コードでは、スムーシング描画機能の搭載は見送られたという経緯があった。
 本来、無効化されて然るべきはずの処理を、無理矢理有効にして動かしているというヘブン状態なわけで、すべてを受け入れられる上級者向けの設定ということにしておく。

2014.11.11

 横256ドット/512ドット時の描画幅を正確に計算するよう改良。(1ドット多めに処理されていたので修正)
 謎のNTSCアスペクト比表示モードを搭載。
 ホイールをゆっくり、確実に、1刻みづつ奥に回すべし。
 X68000とE500のドットが正方形などというのは甘え。その設定がGDIの判定を断ち切る。もっと描画する!

 当時、X68000ユーザでゲーム作りを志した人は、X68000の画面のドットが正方形でないことに絶望し、フレームレートが59.94006Hzでない(どうして約55Hzなどという超もっさり遅いのはなんでだぜ?)ことに絶望し、そして、それらをものともせず発表される信じられない完成度の市販ソフトや同人ソフトの数々にヘブン状態になっていつの間にか自分が何をやろうとしていたのか忘れてしまい、また最初から絶望しなおすという無限ループに陥っていた人も少なくはないはずである。主に私とか。

 そうして生まれては消えていった数々の黒歴史ドット絵たちを現代のX68000エミュレータの画面で見ると、どうなるのか。
 そう、正方形とか3:2のくっきりとしたドットになって見えるわけ。
 768×512モードならホストの1x1ドットに、512×512モードなら1.5×1ドットに、256×256モードなら3×2ドットに投影されるわけ。
 やめて!私を正方形にするつもりでしょう?某国民機みたいに!某国民機みたいに!

ぼくは きれいな ドットえ。
 

違う、そうじゃない。

X68000のドットが描かれる時はね
誰にも邪魔されず
自由で
なんというか
正方形のドットに対する
羨望とか畏怖とか執念とか怨念とか絶望とか情熱・思想・理念・頭脳・気品・優雅さ・勤勉さ……
そういうものが救われて滲み出ていないと
ダメなんだ
独りで静かで豊かで……

 ああ、新設したさ。当時の縮尺を正確に再現するモードをな。
 当時は長方形のドットがこの世界の全てだったんだ。
 ドットが歪んでる?知ったことか。きっとこの世界そのものが歪んでしまったんじゃね?
 768×512モードの1ドットが、CRTの縦幅調整ツマミが折れるほど回しまくって爪楊枝を突っ込んで弄りまくってもどうしようもないくらいに縦長で、悔しくて悲しくてビクンビクンしながら涙で枕を濡らした日々とか、あらゆるゲームを秒間60フレームにしようと徹底的に15kHzモード化するパッチを当てまくったら、こんどはフレームレートが61.5Hzなどという難易度うなぎ上りの超高速ハードモードになっちゃって、ぜんぜんクリアできなくなって悔しくてビクンビクン(中略)日々のこと、時々でいいから思い出してください。

 なお、表示モードは試験的にマウスホイールをゆっくり回すと切り替えられるようにしてみた。
 リリースモードのバイナリで、ホイールのイベントの反応が悪い問題を解析してみたところ、ここにもまた例のUIスレッドからのVMロック問題が発生していることが判明した。修正。ぬるぬる反応するようになった。ぬるぬる。
 マウスホイール処理関連のUIスレッドからVMコアをロックフリー化。

 ホイールだけで操作するにはやっぱり無理があった。というわけで操作系を変更。
 通常のホイール回転で拡大モードを3段階切り替え。
 SHIFT+ホイール回転で強制4:3モードの切り替えとした。

Stretchの値内容
0常にドットバイドットで表示する (従来通り)
1768×512ドット時以外はアスペクト比3:2に拡大する (従来通り、デフォルト)
2768×512ドット時以外はアスペクト比4:3に拡大する (新規追加)
3画面モードにかかわらずアスペクト比4:3に固定する (新規追加)

2014

宇宙暦6665年  ATARI仕様ジョイスティックの圧倒的な数の暴力の前に、存亡の危機に瀕した旧TOWNSパッドFMT-PD101。彼は「俺より強い奴に会いに行く」との言葉を最後に忽然と姿を消してしまう。これを期にATARI仕様ジョイスティックの設定は統合され、XM6改に単一の設定項目が誕生した。
宇宙暦6666年  惑星XM6改のネオ・スペースプラントからの通信が一斉に途絶える『サイレント・ナイトメア事件』発生。何者かによる侵略であることが判明。
宇宙暦6666年  侵略者は、復活したTOWNS6ボタンパッドFMT-PAD601であった―― (ここでボタン数マシマシ画像をカットイン)

 というわけで、きた!ヤツが帰ってきた!これで勝つる!
 旧TOWNSパッドFMT-PD101が、TOWNS6ボタンパッドFMT-PAD601に生まれ変わって再登場!XM6改を侵略!侵略ゥ!

 PPI関連を大胆にリファクタリング。処理を単純化し仮想関数の総数を大幅に削減
 PPIの未実装レジスタのアクセスログのレジスタ番号が、読み込みと書き込みとで同じレジスタでも値が異なってしまう原作のバグを修正。
 サイバースティック系は3軸と表記しているが、実際には内部で4軸分の情報を要求し、そのうち3番目の軸を使わない動作となっている。これは方向レバー2本目の上下情報をスロットルとして使うためにあえてこうしているものと推測される。特に動作を変えたり値を弄る必要はないと思うがヒジョーに紛らわしいのでコメントを追加しておくべきだろう。
 サイバースティックアナログ部分の無駄な演算を削除し処理効率を向上。他にも細かなロジックミスなどを可能な限り排除したつもり。

 あと、ジョイスティックの名称とかも弄った。こんな感じ。
 変換器ってのはチェルノブの付属アダプタで、CPA001はカプコン製でスト2ダッシュ付属や別売りだった。元のCPSファイターってのはこのアダプタとは無関係。可能な限り正確に表記している。

 強制4:3モードを右クリックメニューから変更できるように改良。
 メニューの「最新の情報に更新」を除外。この手の冗長な操作が一切必要ないようにすべきという意思。
 システムクロックの選択プルダウンメニューで全項目を一覧できるよう表示範囲を拡大。
 ジョイスティックタイプの選択プルダウンメニューで全項目を一覧できるよう表示範囲を拡大。
 ジョイスティックのデバイス名詳細表示のサイズを微調整。

 ドットバイドットモードの時に画面が1ドットずれる問題を修正。

 G2のタイトル画面が出ている時にバージョン表示が正しく表示できない、原作の問題を修正。Vista以降のOSでも正しく画面が縮小表示されるようになった。この二点はTypeGで改良済みの内容を取り込ませていただきました。

 バージョン情報のディスプレイ画面に黒い縁を描画し画面をみやすく改良。表示サイズを僅かに拡大。
 バージョン表示の本体LEDの青色改造時にブルーム効果を追加し「輝き」の表現を追加。また、原作は赤色LEDを併設しない簡易改造を想定していたが、そんな生半可な改造だけでは当時の改造野郎たちに釘バットでヒャッハーされるのがオチなのでちゃんと赤色LEDを併設して動作するよう改良しておいた。
 ――なお、SCCオシレータを破損して涙目で肩パッドにトゲトゲをチクチクと必死で縫い付けていた世紀末俺ちゃん氏であったが、彼は二色LEDのモールドを削って青LEDをくっつけて疑似3色LEDを作っていたらしい(今でこそ3色LEDなんてありふれてるけど、当時は高価すぎてどこにも売ってなかったのだよ……)。しかし、光軸がずれて正面から見るとちょっと暗い……というかほとんど光が見えなくて、微妙に斜めから見ると眩しすぎるというなんともアレな作りになってしまっていたらしいのだが……当人が満足なら、いいことだ。

 これらはXM6原作における最大級のこだわり部分だと思われるので、考え得る最高の表示結果を得られるようにしてみた。満足した!

2014

 バージョン表示のディスプレイのLEDも本体の電源状態に連動して光るようにしてみた。つか元絵が眩しすぎるので補正した。もっと凝るならTVCTRL制御を受けて状態を変化させるべき。どうすりゃいいんだ。

 寝る前にバグ報告を見つけた。詳細報告に感謝。Windowsキー左右とアプリケーションキーに機能を割り当てた時にOS側の動作を正しく抑制できないエンバグ(20141102版で発生)を修正。

 CRTCの垂直帰線期間開始タイミングで描画を行うことで描画の遅延を減らし、かつ原作にあった15kHzなどの画面モード時に描画フレームレートが低下する問題を解決する、TypeGの改良を取り込み。

 ウィンドウクローズ操作時のUIスレッドの反応速度を大幅に向上。操作に即反応してスパっと閉じるよう改良。これでUIスレッドからのVMコアのロックフリー化まわりはほぼ完了となる。長い戦いだった……。

 800×540ドット以上の画面モードで強制的にドットバイドットモードとして扱うよう改良(すまん、Twitterのアナウンス間違えてた。すべてにおいてソース記述こそが正しいってことで)。これにより、RCDやKo-WindowのCRTC設定ツールなど、31kHzで縦横のドット数を微妙に増やす系のアプリで、デフォルト設定のままでも画面がずれないように改良。
 解像度が高すぎる場合はウィンドウサイズを変えずにぎりぎりのサイズに縮小表示するよう改良。

 キーイベント回りの設計ミスが判明。XM6改では問題はないが、TypeG側で問題があった。若干修正。
 英語のSASIメニューのデフォルト値の記述がなかったので修正。(たぶん相当前に直したものと思われる)
 Trap #0命令メニューの英語部分の説明が間違っていたので修正。
 WindrvXMが内部で使用するウィンドウメッセージをWM_USER系からWM_APP系に変更。

 TypeG作者さま直々の要望により、PrintScreenキー割り当て時のOS側の動作の無効化とALT+PrintScreenショートカットキーの無効化設定を追加。INIファイルのKeyMaskのビット3を1にすると無効化される。無効化した状態では、XM6内ではPrintScreenキーを副作用のない普通のキーとして利用可能となる。
 機能追加と同時にGIMONS氏に速攻でGUIの対応をしていただいたので、こちらも処理を取り込み。GUIでも変更可能となった。(なんか体感3分ぐらいで速攻で対応していただいて焦った)(汗
 KeyMask回りのメッセージと画面レイアウトを若干調整。
 TypeGのCRTCエミュレーションの精度が上がったので取り込み。
 Comapact以降のROMで、Vキーを押したまま起動した24kHzの640x480ドットの画面モード時、デフォルト設定状態とドットバイドット設定状態とで画像が一致するよう改良。ちなみに、戻すのはNキー押したまま起動でござる。

 INIファイルにCRTCのブロックスキャン設定項目を追加。
 なおブロックスキャンが必要となるアプリを持っていないため、本機能はエラーチェック程度しか動作確認が取れていない状況。情報求む。
 現在のTypeG互換のINI設定は以下のようになっている。

項目名内容
Filterスムーシング描画の有無 (1で有効。デフォルトは0) 【GDIによる互換動作のため上級者向け】
ScanLineスキャンライン描画の有無 (1で有効。デフォルトは0)
BlockScanブロックスキャン処理の有無 (1で有効。デフォルトは0)

 XM6の2.06以前のセーブデータを読み込んだ時にCRTCのブロックスキャン設定等が消えないよう改良。また、セーブ時に互換性のあるデータを出力するよう改良。

2014.11.18

さらばDirectInput! (二回目)

 Windows XPで低レベルキーボードフックが動作しない問題を修正。DirectInputの内部で低レベルキーボードフックが使われているとの情報をTypeGの作者さまから聞いていたので、それを元に調査してみたら、なんかDirectInputが有効になっていると、Windows XPだとフック自体は成功するんだけど、自分自身のプロセスの時だけコールバックが戻らないというおかしな状態になってた。
 よしDirectInputでのキー入力はやめよう。やめやめ。やめちゃった。デュフフコポォ

 キーイベントだと、PrintSceenキーの押下を検出できないため補正処理を追加。

2014

 スケジューラの高速化の沼にはまって抜け出せぬ

2014.11.25

 TypeG作者さまより、ホスト側のシフトキーをVM側のシフト以外のキーに割り当てた場合の挙動がおかしいとの報告を受ける。そ……ッッ……そうきたかァ〜〜ッッッ!その発想はなかった……。柔軟な発想、すばらしいね!
 早速対応しといた。
 あと、キーボードイベントでも右シフトが見れるように改良。キーイベントこそシンプルで美しい最強の方式であり、イベントさえ通知されていれば何だってできる。そう考えていた時期が、私にもありました。

 Windowsでは通常のキーイベントの発生時に、同時に押されているモディファイアキーの左右を判定することが可能であり、キー入力APIを使用する例がMSDNで提示されている。しかし、シフトキーそのものの操作を左右別々にイベントから取得することは困難である。例えば、片方のシフトキーともう1つ、まったく他のキーを同時に押した状態で、残りの側のシフトキーの操作を行なった場合、どちらかのシフトキーが押されているともう一方の側のシフトキーを離した時にイベントが発生しない。
 そこで、イベントとは別のタイミングでキー入力APIを用いて左右シフトキーの状態を補正する。
 他にも、Windows全般でPrintScreenキーのキーダウンイベントが発生しない仕様となっているため、こちらもキー入力APIで補正する。

2014

 速度比較のため、スケジューラの処理を何通りか作成。あと不要な仮想関数を見つけたので潰した。使いもしないジャンプテーブルの保守のためにOPコードが1バイトづつモリモリ増えてるとか見ちゃうともうね……。くっ……殺せ!

スケジューラの動作を根本的に変えることで高速化を図る。
イベント処理用の優先度つきキューには通常は「残り時間」が入っているのだが、これを「処理時刻」に変更する。こうすることで、先頭のキューのみ時刻を更新するだけでよくなり、処理のたびに残り時間の減算を全オブジェクトに対して行なう必要がなくなる。これは劇的に速くなるはず……ッ!
……0.5%ほど高速になった。ショボーン
そうだ。これは夢なんだ。ぼくは今、夢を見ているんだ。ヒープを使った高速化が入ればさらに世界が変わるはずなんだ。
なお、この方式でビルドして、システム→スケジューラの表示を見てみると今まで見慣れたXM6の美しいスケジューラとはまったく異質の妖しい世界が見えるので面白いかもしれない。

優先度つきキューに登録されるイベントの数自体を減らすことで高速化を図る。
だいたい普通の用途であれば2/3から1/2程度にイベント数が減る。
あまり効果は得られなかった。ショボーン

キューに登録されたイベントの中で、動作中のものだけを収集して高速化を図る。
TypeGやXM6iで使われている方式がこれ。実績のある作りなだけに、これも劇的な効果が期待できるはず……ッ!
あまり効果は得られなかった。ショボーン

FASTQUEUEとそれ以外とで、最短時間を持つキューを探索する最内周の処理部分をアセンブラ化した。
もともとFASTQUEUE以外の部分は、既に__cdecl呼び出し規約で書かれたアセンブラコードが原作にあるのだが、今回、気合いを入れるべくすべてFASTCALL向けに書き直した。(実質、原作とほぼ同一のコードになってる)

 FASTQUEUE+REDUCE+ASMの組み合わせが今のところ最も効果が高い模様。スケジューラ側の改良なのにMPUのトップスピードも微妙に上がっている点は面白い(恐らくスケジューラの負荷が減った分でMPUが回っている)。しかし何をやってもホントに効果が出ぬ……解せぬ……。どうすんのコレ。
 ちなみに、プロファイラの予測分岐最適化がうまく作用すると、siのシステムパフォーマンスが10%ほど高速化する。XM6改の「原作より速い」という売り文句はここから来ている。これをアルゴリズムで凌駕するのは相当にきついかもしれない。
 現時点ではこんな感じ。

スケジューラの最内周ループを必死で書き換えて内部処理16パターンの組み合わせの中から一番速かったバイナリを厳選してもトップスピードが0.5%程度しか変化せず プロファイラの予測分岐最適化のほうが遥かに優秀すぎてワロ……た…… pic.twitter.com/neZz5tyEqG

— どうしてcoなった (@coexe) 2014, 11月 24

 なお、安定度の観点から、現時点ではREDUCEのみ採用している。この状態でも従来とはスケジューラの動作はまったく違ったものになっているのが、システム→スケジューラの表示を比べてみるとよく分かるはず。み、見るな……!くっ……コロリンコロリン

ほかにもスケジューラ回りでかなり弄ったので詳細はあとでまとめる。ねるぽ。

 調子に乗ってさらにもう1タイプを試作中。未完成。
Mark&Sweep方式によるガベージコレクタでイベントを削減し高速化を図る。
GC本体は未実装。明日から本気出す。
(現在の版だとREDUCEタイプより若干多くなってしまうが想定内。未完成につき、まだ一部のアプリが動作しないなど制約多め)

 XM6は、VMのコア部分に近ければ近いほどデバッグが困難なので(コアが適切な制御を受けていないとメッセージポンプがうまく回らなくなるようで、デバッガのキー操作の反応が極端に悪くなって操作の結果が30秒以上かかるとかの過酷な状況に耐える必要が出てくる)、ちょっと書き換えようと思ってもなかなか作業が進まない。むせる。

2014

 OnKickのメッセージポンプの中で止まっているとの報告を受けたので調査。メッセージポンプの書き方自体に問題はないと思われたが、開放済みのメモリ領域へのアクセスの兆候が見えたのでOnKickの動作を根本的に変更した。

原作のOnKickの動作の注意点
 デバッガ経由で動かしている場合、WM_DESTROYの直後に、CRTのデバッグ機構によってthisの内容は即座に破壊される。リリース版をデバッガ経由で動かした場合も同様に破壊される。
 OnKickの終了時、m_bExitの値はTRUE(0x00000001)ではなく不定値(0xFEEEFEEE)になっている。すなわち、OnKickでは開放済みの領域を参照している可能性がある。
http://www.nobugs.org/developer/win32/debug_crt_heap.html

 
 なお、現在の処理ではウィンドウ移動中であってもInfoの更新が継続して行われる仕様となっている。今どきのPCの処理能力であれば問題になることはないと判断し、アイドル状態の検出に負荷をかけるよりも通常状態での無駄をなくし、平均パフォーマンスを上げる方向にチューニングした。

 FrmWndのOnTimer内ではPeekMessageやGetQueueStatusによる取得を行うことができないので注意。現在のPCの負荷であれば、ウィンドウ移動中にInfo処理を継続しても特に問題ないレベルであり、特にフィルタは行わない。

 実はこの処理方式、以前一度やった覚えがあるんだけど、当時はUIスレッドにおけるVMコアのロックが速度低下に及ぼす影響などが十分に判明していない状態だったので、ウィンドウ移動操作がカックカクになってしまって使いものにならなかった。そのため即断で採用を見送ったという悲しい経緯があった。

 現在の作りであれば、自信を持ってこれで問題ないと言い切れる。実際スムーチ。

2014

 リソースの順序の微調整。
 ジョイスティックボタン割り当てメニューのプルダウンメニューのサイズ拡大。
 グラフィック(バッファ0)だと統一感がないのでグラフィックバッファ(ページ0)に変更。
 256色のページ1の表記の誤字を修正。
 PPIの遅延を数クロック削減。例によって人類にはわからないレベル。
 インプット情報ウィンドウに全ボタンの情報が出るよう改良。

 

日記はここで終わっている

目標

(MXDRVのSHIFT+OPT.2みたいなアレじゃよ!)

野望


co (Twitter)

inserted by FC2 system