ドキュメントを整理したとき、余った何かの寄せ集め+α。
エミュレーター津軽作者の山川さんからの要望に応えてVCPIなし環境に対応しました。TownsOSではXMSもエミュレートするので、ようやく素のTownsOS(MS-DOS 6.xなし)で動作するようになりました。
このため、CPUの16bitモード(リアルモード)と32bitモード切り替えを手書きしました。結構あっさり動作したのですが、うんづ(エミュレーター)とイマイチ相性がよくなかったり、PC/AT on VMwareで動かなかったりと散々。後者は実CPUでは動作しないという結構致命的な問題で、32bit→16bitは踏むべき手順が多くVMware(=実CPU)で動作させるまで苦労しました。
ついでに長年の懸案だったメモリ管理も修正。本当は線形リストで管理したほうが効率的だと思うのですが、線形リストをアセンブラで書きたくなくなかったので、ページ(4KB)ごとの空きメモリビットマップ構造にしました。とはいえ、それでも修正箇所が多くて大変でした。
こんな感じでいつもどおり少しだけ修正するつもりが、アレコレ修正しすぎて気づいたら十分な機能が整ったのでVersion 1.00としましたとさ(苦笑)
更に色々修正し、RUN386と高い互換性を持つようになったので、Ver0.90としました。TownsOSでは、RUN386をFree386で上書きして置き換えると、省メモリかつ少し速くなります。
前回書いた良いリンカがない問題は、FlatLinkというリンカを新たに作りました。
また、Open Watcomを使って「Ver2.16なNASM.EXP」を生成(添付)したので、開発が少しだけ楽になりました。FM TOWNS用として知られる(実際はDOS/EXP汎用)Ver0.98と比較すると、short/near jmpの自動切り替え(短縮)が効くとか(Ver0.98は条件分岐がshortで届かないときエラーを吐かれる)、es:[ebx] といった標準的なセレクタ書式が通るとか(Ver0.98は[es:ebx]と書かないとダメ)、些細な部分が多いのですがLinux版NASMとの違いを気にする必要がなくなりました。
元々、11月末に少しだけ修正するつもりだったのですが、気づいたら大型修正に。今回で分かってる問題点はあらかた修正し終えたので一段落となります(本当はメモリ管理が少しだけ手抜きなんですが……)。
バグとかあったら連絡ください。
たくさん修正したので、「Ver0.70」を飛ばして「Ver0.80」としました。
機能の追加はもちろん、細かいバグも様々修正し、ソースの汚い仕様を直し、新たに書き直したところは英語コメントにし、マニュアルも整備し、ファイル構成も整理しました。
例えば、Linuxでも、AT互換機でも、PC-98でも、Free386.com を簡単に make できるスクリプトを作りました。サンプルプログラムの make も……と思ったのですが、狭いDOS-Extender界でもPharLapさんはマイナーなほうでして、EXPを生成できる再配布可能な良いリンカがないんです。
またTOWNS版において、386SX機に対応し(Thanks to @RyuTakegami)、加えてCoCo/NSD常駐サービス関連の不安定だった部分に対応しました。Ver0.60でのCoCo対応はF-BASIC386製のプログラムが動かない不完全なものだったのですが、今回それを解消しました。
原因は、CoCoの特殊な機能。
TOWNSでは、EXPアプリ内でキー入力を行うと、DOSモードに切り替える割り込み処理が発生するのですが、CoCo/NSDドライバ(forrbios?)が特定のキー(BREAKなど)を押したときにDOSモードから、32bit側のルーチンをcall (far call) しています。おそらくタイマBIOSにも似たような機能があり、このための特殊機能がDOS-Extenderに備わっています。
この特殊機能のエントリ(呼び出し番地)をCoCoに取得させるため、なんと、DOS-Extender側がCoCoサービス(int 8eh, ax=C207h)を呼び出して教える必要があります(coco_nsd.txtに記載済)。DOS-Extenderの標準機能(int 21h, ax=250Dh)を使用するとか、プロテクトモード側で割り込みベクタ設定して機能提供するとか、他にいくらでもやりようがあったと思うので、愕然としました。CoCoまわりは本当にクソ実装だらけです……。
20数年越しで苦労しましたが、F-BASIC386製のとあるゲームデモ(どらひほ5というRPG)がようやくFree386上でヌルヌルきました。このゲームのマップ処理はアセンブラゴリゴリの超力技でできていまして、ゲームの作者ではありませんが、そのマップ処理を書いたのが自分ということもあり、「あのときのアセンブラコードがFree386で動いてるぅぅぅ!!!(脳汁)」みたいな謎の感動がありました(笑)
そういえば、この動作解析において、FM TOWNSエミュレーター「津軽」のデバッガが大変役に立ちました(感謝)。副産物としてf386def.incの設定に、コンソール出力をTsugaruのコンソールに出力する機能のフラグがあります(再アセンブルが必要)。
本当に一生懸命修正しましたが、こんな古いソフト、一体どこにニーズがあるのでしょうか……。とか言いつつ、Githubで一番スターもらってるリポジトリがコレなんですけどね(苦笑)
ふとしたこから、以前製作したDOS-Extenderの「Free386」をGitHubに公開しておこうと思いました。
どうせ公開するなら、NASM や alink も一緒に収録して(DOS環境があれば)誰でもアセンブルできるようにしようと思ったのが運の尽き。alinkにフラットモード.exe/.comファイル生成時のバグを発見してしまいました。色々狂い出したのがこの辺ですね(苦笑)
alink へのパッチ作業は Linux 上で行いました。そして alink.exp を生成するために TOWNS-gcc を使ったのですが、TOWNS-gcc の生成する MPヘッダ 形式の.EXPファイルが Free386 自身で実行できないバグを見つけました。これを修正しないと(普通はEXP実行環境など持っていないので)開発環境を含めての配布ができそうにありません。調べてみると、メモリの割り当て方にバグがあり、メモリ容量が8MBあたりを超え始めると、後ろの方に存在しないメモリ領域を割り当てていました。
実は、当時の Free386 はちゃんと動かないファイルが多く、動作が不安定になることもあって悩んでいたのですが、なんてことはないメモリの割り当てミスだったという。ただこれを調べるために、メモリマップやページングをダンプするツールを作成したため(収録してます)、結構な手間になりました。
さてメモリの割り当てバグが修正されると、ほぼすべてのDOS汎用EXPファイルと、多くのTOWNSソフトが動作するようになりました。しかし、TOWNS-OS最大の謎システムとされる CoCo/NSD ドライバ周りでコケてしまい、F-BASIC386で書かれたソフトなどが起動しません。ここまで来たら動かしたくなるのが人情というもの(笑)
そうして CoCo/NSDドライバ の解析に着手するわけです。少し調べると次のことはすぐに分かりました。
- CoCo.EXE は DOSメモリ(リアルメモリ) に常駐する。
- NSDD は 拡張メモリ に常駐する。
つまり CoCo は NSDファイル を拡張メモリにロードして、その情報を管理していると推測されます。さて問題はその管理情報をどうやって取得するかということです。SYSINITのように常駐しているCoCoメモリの中に情報があるのかな?と思いました。
とりあえず、その辺を調べるため Free386 に、割り込みをフックしてintサービスの実行前と後のレジスタ状況をダンプ出力する機能を付けました。調べる対象としては、仕組み上「NSDドライバを探す必要があり構造がより単純そうなもの」として、指定のNSDドライバを削除する機能がある \hcopy\deldrv.exp を解析しました。
------------------------------------------------------------------
Int = 0000_008E CS:EIP = 000C:0000_1ADC SS:ESP = 0014:0001_0B88
DS = 0014 ES = 0060 FS = 0014 GS = 0014
EAX = 0000_C003 EBX = 0000_0001 ECX = 0000_0000 EDX = 0000_66EC
ESI = 0000_0246 EDI = 2074_6E00 EBP = 0001_0C48 FLG = 0000_0046
CR0 = 8000_0021 CR2 = 0000_0000 CR3 = 0002_9000 D0 S1 P1 C0
------------------------------------------------------------------
*Ret:*
DS = 0014 ES = 0014 FS = 0014 GS = 0014
EAX = 0000_0003 EBX = 0000_0010 ECX = 0000_0000 EDX = 0001_0C18
ESI = 0000_0246 EDI = 2074_6E00 EBP = 0001_0C48 FLG = 0000_0006
CR0 = 8000_0021 CR2 = 0000_0000 CR3 = 0002_9000 D0 S0 P1 C0
------------------------------------------------------------------
こんな感じの情報が、順番にたくさん出てきます。CoCoの常駐状況などを変化させ動作の変化を見ていると、int 8eh/AX=Cx0x が、CoCoのサービスだということが分かります。同時に、int 8eh のログを取る常駐.comファイル(付属してます)を作って RUN386.EXE の挙動も調べ、両方の共通点を探ったりしながら 「自分だったら仕組みをどう設計するだろうか?」 という視点で CoCoサービス を調べていきました。
すると int 8eh/AX=C103h というドライバ常駐情報を提供するサービスまで辿り付きました。この情報を使って、拡張メモリに存在するNSDドライバを正しくメモリ上に貼り付け、セレクタ上に実装することができました。確認のために、Free386を使って deldrv.exp を実行してみたところ、NSDドライバを正しくアンインストールできました。
すばらしい。終わり。
……という風に解決したらよかったんですけどね。
TOWNS-OSというのは不思議な構造のOSでして、グラフィック処理などに32bit NativeモードのBIOS(TBIOS)があるにも関わらず、タイマなどの一部のサービスはFM-R互換の16bit動作のBIOSをそのまま使っています。16bitタイマBIOSなどに資源の管理をさせながら、32bitプログラム側からそれを使用するという意味不明な構造をしています。
酷いケースでは、タイマやキーボードなどリアルモード資源を扱うためCPUをリアルモードに切り替えて、もしそれらのリアルモードBIOS処理中に、FM音源やVSYNCなどの割り込みが発生するとBIOSの処理を中断して一旦プロテクトモードに戻ることもあるようです。
この意味不明な構造の仲介役をするのが、forRBIOS(for Real BIOS)というNSDドライバです。ちょうど、DOS-Extenderが32bitプログラムとMS-DOSの仲介役をするように、Real-mode BIOSと32bitプログラム仲介役をするわけです。
RUN386環境では forRBIOS.NSD が組み込まれていると、int 8eh などの割り込みベクタが書き換えられ、NSDドライバが割り込みを取得するようになります。この情報は一体どこにあるのか? ということが残された謎でした。しかし、RUN386 が .EXP を実行するまでのINTのログをいくらとってもそれらしいものがありません。常駐している CoCo のメモリを見てみてもそれらしい情報がありません。
もしや「常駐しているNSD自身に初期化させてるのでは?」と思い、常駐している forRBIOS のエントリーにパッチを充て、サービスルーチンが呼び出された時に無限ループに陥るという荒業を使ってみたところビンゴでした。
ようやく、F-BASIC386 などで生成した EXPファイル が実行できるようになりました。解析結果は doc 内に収録してあります。ちなみに、forRBIOSを必要としない(High-C等で書かれた)プログラムを実行するとき、forRBIOS を初期化すると初期化しない時に比べ全体の処理が遅くなります。本当にここは TOWNS-OS のクソ仕様だと思います。
そんなこんなで、2001年の開発停止から十数年ぶりに CoCo の謎が解決され、RUN386 と互換性の高い DOS-Extender が出来ました、ということで。
むかしむかし、mtaskというプロジェクトがありました。
FM TOWNS及びPC-98で動作するパソコン通信ホストプログラム実現のための、EXPファイルでネイティブマルチタスク環境(カーネル+シェル)を作成をしようとしていました。 開発は進み、簡単なサンプルプログラムを複数起動し、タスクスイッチする程度までは動いていました。
しかし、この mtask を開発する過程で、DOS-Extenderの壁にぶち当たります。TOWNS以外の機種ではEXE386を使用していたのですが、EXE386は作りにかなり問題があり、その上でマルチタスクカーネルを動かすのは不可能に近いことが分かりました。古きフリーソフト文化の精神。ないものは作る!
そんなわけで、mtaskから派生したのが、このFree386プロジェクトです。
幸いmtaskを開発する過程で、CPUの知識もDOS-Extenderの知識も、アセンブラルーチンも結構ありましたので、それらを活用することで開発を始めました。
そのうちに西暦2000年を過ぎてまして、パソコン通信はすでにオワコン。目的を見失ったFree386は、気づいたらFM TOWNS、PC-9801、PC/AT互換機で共通バイナリが動くDOS-Extender環境を目指していました。
そして、ある程度成果が見え、AT互換機やPC-98でEXPによるグラフィカルなデモ(長船さん作J7-System関連)が動き、独自APIの実装下地が整った頃、開発は下火となりました。
放置された要因は色々ありますが、技術的な問題としては「AT互換機のVESA BIOSがうまく動かなかったこと」と「TOWNS-OSのCoCoに対応できなかったこと」が大きかったと思います。
しかしまあ、20年以上の歳月を経て未だにバージョンアップするなんて、当時は夢にも思いませんでしたが(苦笑)
- int 29h (高速コンソール出力)が使えない。
- EXE386 自体が「286プロテクトモード」で動作している。
- このため 32MB までしか使えないし、起動が遅い。
- セレクタ操作などの function が微妙に非互換である。
- PACK されているかの判別が甘い。
- 割り込み処理ルーチンが奇数番地に align されていて謎すぎる。
- 仮想86モードで、INTを発行すると一般保護エラー(詳細は忘れた)
- 「cs=0ch / ds=14h」でないと int 21h を発行できない……。
- 発展途中で作成をやめてしまった感がある。