JavaScriptを有効にすると、ここにメニューを表示します。
FM TOWNS内蔵CDROMドライブ解析プロジェクト

ysflight.com

2019/12/05

ああ、objdumpが逆アセンブルしてくれるのはありがたいけどGAS表記だからめちゃくちゃ読みにくい。もう少しいい逆アセンブラ欲しい。

Towns OS V1.1 L30の起動フロッピーディスク作成にも成功した。Towns OS V1.1のCONTROL.EXえはI/O 3C32Hは使っていないらしく、DOSのDefault Driveを参照してRUN386.EXEやTMENU.EXPの位置を特定していた。その箇所は下。

     26c:	b4 19                	mov    $0x19,%ah        Get Current Default Drive
     26e:	cd 21                	int    $0x21
     270:	a2 cb 00             	mov    %al,0xcb         Remember default drive in 0xCb, DS base is offset 0x0A50 -> 0x0A50+0xC4=0xB1B
     273:	a2 c4 00             	mov    %al,0xc4         Remember default drive in 0xC4, DS base is offset 0x0A50 -> 0x0A50+0xC4=0xB14 
     276:	04 41                	add    $0x41,%al        AL=AL+'A'
     278:	a2 31 00             	mov    %al,0x31         DS base is offset 0x0A50  0x0A50+0x31=0x0A81.  Drive letter for TMENU.EXP
     27b:	a2 16 00             	mov    %al,0x16         DS base is offset 0x0A50  0x0A50+0x16=0x0A66.  Drive letter for RUN386.EXE
     27e:	a2 3e 00             	mov    %al,0x3e         DS base is offset 0x0A50  0x0A50+0x3E=0x0A8E.  Drive letter for T_OAK2.EXE
     281:	3c 51                	cmp    $0x51,%al        'Q' drive?
     283:	75 0a                	jne    0x28f            Jump if not Q drive.
     285:	c6 06 c4 00 11       	movb   $0x11,0xc4       0x0A50+0xC4=0xB14  (0x11 is 'Q'-'A')
     28a:	c6 06 16 00 52       	movb   $0x52,0x16       Use R drive for RUN386.EXE

だから、I/Oの3C32Hの書き換えではなく、DOSのINT 21H AH=0EHを使ってTownsOSのドライブを設定する必要があった。が、これをYSSCSICD.SYSの中からやってしまうと、AUTOEXEC.BATに届く前にデフォルトドライブが変わってしまってDOSがQドライブのAUTOEXEC.BATを読みに行くが、MSCDEX.EXEがまだインストールされてないからQドライブが読めないという状況に陥るかもしれない。

そこで、SYSDRV.EXEにINT 21H AH=0EHを呼ぶ機能を追加して、AUTOEXEC.BATの先頭で呼ぶことでTownsOS V1.1 L30も起動できるようになった。おそらくこれでWing Commanderその他Towns OS V1.1ベースのゲームは起動できるようになると思うんだけど。

なお、II MXだとFASTモードになってるとマウスが飛びまくって現実問題として操作できない模様。

2019/12/04

ページ分割。

リダイレクタYSSCSICD.SYSとシステムドライブ変更プログラムSYSDRV.EXE

FM TOWNSの未公開BIOS機能とI/O Ports

昨日の段階で、フロッピーディスクから起動してSCSI CD-ROMドライブにあるTowns System Software V2.1 L20をスタートする起動ディスクを作成することに成功していたが、動作が完全ではなかった。

例えば、コマンドモードに降りて、TownsMENUに戻ろうとすると、TownsOSのディスクが入っていないと言われた。また、AUTOEXEC.BATの先頭付近でMSCDEX.EXEでQドライブを使用可能にして、以後はCD-ROM上のファイルで起動を続行したいのだが、MSCDEX.EXEをSYSINIT.EXE以降に置かないと、「TownsOSのためのメモリが足りません」というメッセージが出て、V2.1 L20だと起動を続行してくれるものの音声メッセージが使えないと言われ、V2.1 L31だと起動に失敗して再起動してしまった。

原因はほぼ見当がついていた。FM TOWNSは起動すると、起動ドライブをどこかに記憶している。なにかにつけてファイルを起動ドライブに探しに行く。その情報をどこに記憶しているのか解明して、例えばフロッピーディスクから起動してもQドライブから起動したことにしてしまえば、おそらくこの問題は解決するはずと思われた。

問題は、どこに起動ドライブを記憶してあるのかわからない。FM TOWNSを現役で使っていた当時、さんざん探したのだが見つけることができなかった。ただ、今回は、前よりツールが揃っていた。当時は良い8086逆アセンブラが無くて困ったのだが、今はLinuxにバイナリを持って行ってobjdumpコマンドで逆アセンブルが取れる。もうひとつ最近発見したのは、386|DOS Extender SDK付属の386DEBUG.EXEはFM TOWNSで実行できないが、DOSBOX上でデバッグ開始まではできる。これを利用して、エントリアドレスを特定できる。

黙っているとCONTROL.EXEが起動ドライブにあるTMENU.EXPを実行するわけだから、CONTROL.EXEの中のどこかで起動ドライブを検出しているはず。objdumpでCONTROL.EXEの逆アセンブルを取ってみた。

開始アドレスから逆アセンブルを読んでいって、気になったのがオフセット0B00H。ALをDS:[1016H]から読み込んで、12AB:0000にFAR CALLして、戻ってきたALをDS:[1016H]に戻している。さらに気になったのが、その後ALに41H (Aのキャラクターコード)を加えて複数個所にストアしていた点。もしも、DS:[1016H]が起動ドライブだとするといろいろ説明がつく。

では、このDS:[1016H]の値がどこから来ているかというと、オフセット AFA: IN AL,DX。果たして、起動ドライブはI/Oポートに隠れていた。直前を見ればI/Oポートの3C32Hに書いてあるとわかった。

      aee:	07                   	pop    %es
     aef:	1f                   	pop    %ds
     af0:	fc                   	cld    
     af1:	6a 01                	push   $0x1
     af3:	e8 ac 0e             	call   0x19a2   (17A2 in debugger)
     af6:	5a                   	pop    %dx
     af7:	ba 32 3c             	mov    $0x3c32,%dx          			I/O Unpublished
     afa:	ec                   	in     (%dx),%al
     afb:	c0 e8 02             	shr    $0x2,%al
     afe:	24 1f                	and    $0x1f,%al
     b00:	a2 16 10             	mov    %al,0x1016           			DS:[0x1016] Base Drive, Probably.
     b03:	9a 00 00 80 01       	lcall  $0x180,$0x0          12AB:0000 runtime
     b08:	a0 16 10             	mov    0x1016,%al           
     b0b:	a2 0f 10             	mov    %al,0x100f
     b0e:	04 41                	add    $0x41,%al            AL=AL+'A'  ! Drive Letter!
     b10:	a2 fe 0d             	mov    %al,0xdfe            Drive Letter for "TMENU.EXP"  (File offset 0xFFE)
     b13:	a2 95 0e             	mov    %al,0xe95            Drive Letter for "\HCOPY\DELDRV.EXP" (File offset 0x1095)
     b16:	a2 b4 0e             	mov    %al,0xeb4
     b19:	a2 c8 0e             	mov    %al,0xec8
     b1c:	a2 e0 0e             	mov    %al,0xee0
     b1f:	a2 fa 0e             	mov    %al,0xefa
     b22:	a2 0e 0f             	mov    %al,0xf0e
     b25:	a2 17 0d             	mov    %al,0xd17            Drive Letter for "RUN386.EXE"
     b28:	a2 27 0d             	mov    %al,0xd27            Drive Letter for "RUN386.EXE"
     b2b:	a2 b7 0d             	mov    %al,0xdb7
     b2e:	a2 ce 0d             	mov    %al,0xdce
     b31:	a2 e4 0d             	mov    %al,0xde4

その後、12AB:0000がオフセットのどこに対応するのか386DEBUGを使って特定。

12AB:0000
    1A00:   e8 0d 00                CALL   0x1A10   Console Clear Screen
    1A03:   e8 0f 00                CALL   0x1A15
    1A06:   e8 1e 00                CALL   0x1A27
    1A09:   e8 1f 01                CALL   0x1B2B   Command Parameters
    1A0C:   e8 e5 00                CALL   0x1AF4   Calling CD-ROM BIOS Set Idle Auto-Stop Time
    1a0f:	cb                   	lret   

コマンドパラメータを認識している関数が1B2Bと特定した。そして、CONTROL.EXEの/Dオプションを使うと、I/Oの3C32Hを上書きできることが判明。

'D' option
    1ba0:	e8 4b 00             	call   0x1bee
    1ba3:	74 46                	je     0x1beb
    1ba5:	3c 41                	cmp    $0x41,%al
    1ba7:	7c 92                	jl     0x1b3b		If AL<'A' ignore.
    1ba9:	3c 5a                	cmp    $0x5a,%al
    1bab:	7f 8e                	jg     0x1b3b		IF AL>'Z' ignore.
    1bad:	2c 41                	sub    $0x41,%al
    1baf:	26 a2 16 10          	mov    %al,%es:0x1016
    1bb3:	26 a2 0f 10                mov    %al,%es:0x100f
    1bb7:	ba 32 3c                   	mov    $0x3c32,%dx
    1bba:	8a e0                	      mov    %al,%ah
    1bbc:	c0 e4 02             	shl    $0x2,%ah
    1bbf:	ec                   	in     (%dx),%al       Read from I/O 0x3c32
    1bc0:	80 e4 7c             	and    $0x7c,%ah       Leave Bit2 to Bit6
    1bc3:	24 83                	and    $0x83,%al       Leave Bit7, Bit1, and Bit0
    1bc5:	0a c4                	or     %ah,%al
    1bc7:	ee                   	out    %al,(%dx)       Write to I/O [0x3c32]
    1bc8:	e9 70 ff             	jmp    0x1b3b

CONTROL.EXEに/D:Qオプションを追加することで、フロッピーディスクから起動して、SCSI CD-ROMドライブのTowns System Softwareを起動することに成功したのが昨日。

ところが、MSCDEX.EXEをAUTOEXEC.BATの先頭付近に置いて、その先の初期化をCD-ROMドライブのファイルで続けようとすると、「TownsOSのためのメモリが足りません」と言われる。このメッセージを出していたのはSYSINIT.EXE。僕はメッセージを真に受けて、MSCDEX.EXEがあらぬ場所のメモリを確保してしまって、下位1MBの空間に連続したメモリ領域を確保できなくなっているのかと思った。

ところが、それはぜんぜん違った。同じ方法を使って、SYSINIT.EXEの逆アセンブルを読んだのだが、メモリの確保に失敗してそうな場所がわからない。いや、わからないのはハイメモリアクセスの部分がはっきりしなかったからで、どうやらUnreal Modeというのを使ってるようだった。

仕方がないので絨毯爆撃。INT 21Hを発生させている箇所を一通り探した。その結果、どうやらデバッグメッセージを表示していると思われる箇所を特定。

PUTC
     a12:	52                   	push   %dx
     a13:	50                   	push   %ax
     a14:	8a e2                	mov    %dl,%ah
     a16:	ba 34 3a             	mov    $0x3a34,%dx   IO[3A34]?
     a19:	ec                   	in     (%dx),%al
     a1a:	3c 52                	cmp    $0x52,%al    'R'
     a1c:	75 0e                	jne    0xa2c
     a1e:	83 c2 02             	add    $0x2,%dx      IO[3A36]?
     a21:	ec                   	in     (%dx),%al
     a22:	3c 41                	cmp    $0x41,%al    'A'
     a24:	75 06                	jne    0xa2c
     a26:	8a d4                	mov    %ah,%dl
     a28:	b4 02                	mov    $0x2,%ah      Display Output
     a2a:	cd 21                	int    $0x21
     a2c:	58                   	pop    %ax
     a2d:	5a                   	pop    %dx
     a2e:	c3                   	ret    

PRINT DEBUG STRING from DX
     a2f:	56                   	push   %si
     a30:	8b f2                	mov    %dx,%si
     a32:	b4 02                	mov    $0x2,%ah
     a34:	ac                   	lods   %ds:(%si),%al
     a35:	84 c0                	test   %al,%al
     a37:	74 07                	je     0xa40
     a39:	8a d0                	mov    %al,%dl
     a3b:	e8 d4 ff             	call   0xa12
     a3e:	eb f4                	jmp    0xa34
     a40:	5e                   	pop    %si
     a41:	c3                   	ret    

だが、SYSINIT.EXEは何も表示しない。どうやら、I/Oの[3A34H][3A36H]が'R' 'A'だった場合のみメッセージを表示するらしい。このメッセージを表示させてみたい。そのためにSYSINIT.EXEに細工をした。オフセット A1D, A25にゼロを書き込んだバージョンを作って、起動してみた。

すると、なんとカレントドライブをQにして\SYSINIT\SYSINIT.EXEを呼んでも、データファイルをAドライブに探しに行っている。

SYSINIT.EXEが実行されるのはCONTROL.EXEよりも手前だから、CONTROL.EXEが起動ドライブを更新したのでは遅すぎる。なお、その後[3A34H]と[3A36H]はR/Wということがわかったので、SYSINIT.EXEに細工しなくてもデバッグ情報を表示させるSYSINIW.EXEを作った。AUTOEXEC.BATの先頭で実行しておくとSYSINIT.EXEがデバッグ情報を表示してくれる。

ということは、SYSINIT.EXEの前に起動ドライブをQドライブだったことにしてしまえばいい。それは、I/O 3C32Hを書き換えてしまえばいい。というわけで、SYSDRV.EXEを作った。どっちもGitHubからダウンロードできる。

そして、AUTOEXEC.BATの先頭でSYSDRV.EXEを実行したところ、フロッピーディスクから起動してSCSI CD-ROMドライブにあるTowns System V2.1 L20を完全に動作する状態で開始することに成功した。起動ディスク作成手順はここ

2019/11/30

FM TOWNS内蔵CD-ROM→SCSI CD-ROM BIOSリダイレクタ Ver. 0.5

いろいろ書かなきゃならないことが多いけど、とりあえず、公開だけ先にした。

https://github.com/captainys/FM

コンパイルしたYSSCSICD.SYSもアップロードしちゃった。20日でここまで来れるとは夢にも思わなかった。ものすごい分量の逆アセンブルを読んだ気がする。

簡単に説明すると、このドライバを使うことで、内蔵CD-ROMドライブが死んでしまったFM TOWNSを外付けSCSI CD-ROMドライブを使ってある程度救済できる(はず)。それはすでにCDSD.SYSとCDISC2.SYSで結構できていたが、起動ディスクイメージを公開しようと思ったときCDSD.SYSはバイナリの再配布禁止になってるし、許可をお願いしたくても作者に連絡つかないしという煮え切らない状態になっていた。使い方は、CDSD.SYSとCDISC2.SYSを、こんな感じでロードしていたところを:

DEVICE=CDSD.SYS ....
DEVICE=CDISC2.SYS ....

簡単に、

DEVICE=YSSCSICD.SYS

に置き換えるだけでOK。SCSI IDは勝手にスキャンするから指定の必要もなし。これで、リダイレクタがFM TOWNSのCD-ROM BIOSコールをSCSI BIOSコールに変換するから、ブートフロッピーとか使ってCD-ROMのゲームなどを起動できるようになる。結構いけるんじゃないかな。Afterburner IIとSplatter Houseだけ確認したけど。

CDSD.SYS + CDISC2.SYSだとCD入れ替えるたびに再起動しなきゃならんかったけど、YSSCSICD.SYSだとCDを入れ替えたときもきちんと判定できるようになっている。それと、数日前に発見したCDISC2.SYSの未対応機能もYSSCSICD.SYSでは少なくともエラーを返さないようにすることでSplatter Houseは起動できるようにした。

CDISC2.SYSは非常に複雑なことをやっている。ひとつはMSCDEX.EXEからのコマンドをCDSD.SYSにリダイレクトすること。もうひとつは、TOWNSのCD-ROM BIOSの呼び出しをMSCDEX.EXEの形式に変換してCDSD.SYSに送り、それを再度CD-ROM BIOSの形式に変換して戻す。だから間に二段階挟まっていた。今回作ったYSSCSICD.SYSはもっとシンプルにした。MSCDEXがドライバTOWNS_CDにコマンドを送ると、TOWNS_CDはCD-ROM BIOSにコマンドを発行する。YSSCSICD.SYSはそのコマンドを迎撃してSCSI BIOSを呼び出し、結果を返す。

副産物で、FM TOWNSを現役で使ってた時長いこと疑問に思ってた、起動ドライブはどこに書いてあるのか問題も判明。これはCONTROL.EXEの逆アセンブルを解析して見つけたんだけど、起動ドライブは、I/Oのアドレス0x3c32に書いてあって、Read/Write可。起動ドライブはそのアドレスのビット2~6に書いてあるようだ。ビット7、ビット1、ビット0にも意味があるようで、CONTROL.EXEで/Dオプションで変更すると、ビット2~6だけ更新していることもわかった。

うまくやれば多分起動フロッピーディスク+TownsOSで普通にTownsOSを起動できると思う。エミュレータ上だとメニューまで出るけどアイコンが表示されなくてクラッシュしちゃうんだけど、実機だと動くかどうか、明日以降試してみよう。Wing CommanderがTowns MENUから起動する形式だからできればこの手を使えるようにしたいところ。

CDSD.SYSの作者さんとCDISC2.SYSの作者さんにはソースコードを公開していただいて本当に助かった。

2019/11/29

CDSD.SYS, CDISC2.SYS を代替するドライバ、とりあえずDIRができて、コマンドからCDDA再生、ポーズ、ポーズ解除ができるようになった。未公開機能のAH=61H, 0FHでひっかかるのではないか、と、心配だったうえに、最初ばっちり0FH後にクラッシュしていたのでやっぱりダメかと思ったら、実はクラッシュの原因はその直前のAH=53HのPlay Stateの取得でひっかかっていた。

AH=53Hでは、CD再生中の場合AL=1で、DS:DIからの10バイトのバッファに再生情報を返す。が、再生中で無い場合、AL=0で、10バイトのバッファの内容は変更しないのが正しい。が、自分のドライバは再生中では無い場合10バイトのバッファの中身を破壊してしまっていた。このため、クラッシュしていたようだ。この部分を修正したら普通にDIRでファイル名を見ることができ、とりあえず RUN386 CD_PLAY.EXP でTowns OS標準CD Playerの起動にまで成功した。

ただし、ステートが正しく取れないのと、CDDA再生中止ができない。SCSI2のコマンド Read Sub Channel (42H)を使って再生状態を取得すると一時停止中はPlay State=12Hが返るはずだが、再生中を表す11Hが返ってきているようだ。CDISC2.SYSのソースを見ると、CD PAUSEは内部で状態をキャッシュしているようだ。ひょっとすると本質的にPAUSE状態は知ることができないのかもしれない。

また、SCSIコマンドのSTOP PLAY/SCAN (4EH)は、どうやらSCSI3のコマンドのようで、SCSI2のCDドライブでは対応していないようだ。強制的にSeekコマンドを発行して止めることはできるが、止めるたびにトラック0にヘッドを戻したくない。例えば、ある曲の再生を中止して、数トラック先にある曲を再生したいとき、ヘッドをいったん戻してから新しい曲のトラックまでヘッドを移動させるのは遠回りだ。だから、できればSeekやReadで止めるのは避けたい。

とりあえず一通りができたらここでソースとバイナリを公開したいんだけど。

2019/11/26

ということで、CDISC2.SYSを参考に、INT 93H, AL=C0Hの呼び出しを監視するプログラムをMASMで書いてみた。ドライバはTOWNS_CDをそのまま使うことにして。呼び出しがあるたびにレジスタの値をコンソールに出すようにしてみたところ、隠し機能 AH=61Hをばっちり使ってる。多分タイミング的にリセットとかそんな感じだと思うんだけどな。ただ、成功だったらAH=0, CX=0で返っていくようなので、必ず成功したことにしたらどうだろう?と、思って、試しにそのようにしたところ何事もなかったかのように動いているので、多分これはそれで良さそう。

あとは、ここで使ってる機能を一通りSCSI BIOS (INT 93H, AH=0FDH)にリダイレクトすれば、なんとかなりそうだな。

2019/11/25

とりあえず、実機で INT 93H, AH=0FDH をいろいろいじくってみて、とりあえず INQURY と READ_TOC で意味のある結果を得ることができた。

当初、CDISC2.SYSに簡単な修正を加えることで、CDSD.SYSをバイパスできるのではないか、と思ったのだが謎が発生。CDISC2.SYSは、どうやらふたつのリダイレクションをやってる。

なんでMSCDEX.EXEからの呼び出しに対応する必要があるのかよくわからん。単に故障した内蔵CDドライブの代わりに外付けSCSIドライブを使いたいだけだったら、INT 93H, AL=0C0Hのリダイレクトだけでいいはずだ。TOWNS_CDドライバがMSCDEX.EXEの呼び出しを受けて INT 93H, AL=0C0H を発行するはずだから。

結構高い可能性としてCDSD.SYSが内部でかなりいろいろキャッシュしてる影響で、CDISC2.SYSは機能単体の呼び出しができなかったのではないか?だとすれば、もっと小さなドライバでリダイレクトできるようになりそうな気がする。反面CDISC2.SYS、CDSD.SYSは参考にするとしてゼロからドライバ書かなきゃなんないな。

2019/11/24

FM-R/TOWNSのSCSI BIOSの未公開機能、INT 93H, AH=0FDHを探る

CDISC2.SYSを修正してSplatter House、飛翔鮫の外付けSCSIドライブからの起動の成功は結構自分としては希望が出る成果だった。本当はここにじゃんじゃん起動用フロッピーディスクイメージをアップロードしたいのだが、CDSD.SYSがバイナリ再配布禁止というのがそれを阻んでいる。作者に連絡を取る手段もわからない。SNSでも使えば見つかるのかね。僕はFaceBookアカウントはあるけど見てないし、Twitterはアカウントすら持ってないし。

そうではなく、CDISC2.SYSを改造してCDSD.SYSに依存せずにSCSIドライブにアクセスできるようにできないかを検討している。CDSD.SYSはソースは公開されているので、それと同じ機能を実現すればいい。調べたところ、FM-R/TOWNSではSCSI BIOS、INT 93Hの隠し機能 AH=0FDH を使っている。なぜか手元に、

インターブログ編, 富士通FMRシリーズ徹底解析マニュアル 増補改訂版, BNN, 1989

が奇跡的に残っているのだが、その中のINT 93Hの説明にはAH=0FDHは載っていない。FM TOWNSテクニカルガイドブックにも載っていない。CDSD.SYSのソースのコメントには "Direct Command Function" とある。さらにソースから推測できたのは、

INT 93H, 0FDH  
AH コマンドコード  0FDH
DS:DI 構造体へのポインタ
CH LUN (Unit number) SCSI IDとも違うらしい。ただ、CDISC2.SYSからは必ずゼロになってるような。
CL 00H
AL 下位4ビット: SCSI ID
上位4ビット: 1011 (SCSI device)

DS:DIの構造体  
Word Ptr [DS:DI] 読み込みデータ格納先アドレス
Word Ptr [DS:DI+2] 読み込みデータ格納先セグメント
[DS:DI+4~] SCSIコマンド (最大12バイト)
   

Return  
CH エラーコード  0:正常終了  2:パラメータエラー(?)  4:不明エラー
AX 値は返ってくるけど意味は不明

CDSD.SYSのソースでは、INT 93Hに続いて、

     int 93h
    xchg al,ah
    or ah,ah
    jz ExPhase2
    stc
ExPhase2:

このようになっているので、INT 93H復帰後のALをエラーコードとしているが、実際使ってみたところCHがエラーコードである可能性が高い。どうやらここもFM-R/TOWNS版CDSD.SYSのバグ。

試しにエミュレータ上でハードディスクに対して INT 93H, AH=0FDHを実行したところ、未接続のSCSI IDに対してはCH=02、ハードディスクイメージが接続してあるSCSI IDに対してはCH=0が返ってきた。どちらの場合もAX=0。

また、どうやらINT 93H, AH=0FDHは読み込んだバイト数がわからないらしい。最初AXがそれではないかと思ったが、INQUIRYに対してAX=0で戻ってくるからそうではないようだ。読み込みデータ格納先アドレスの先頭にバイト数が書いてあったりしないか、とも思ったがハードディスクに対してINQUIRYの結果が最初2倍と0だったからそれも違った。 

一応、UNZ.EXEのダンプからINT 93H, AH=0FDHに対応するBIOSの逆アセンブルを読んだところ、この機能はDMAを使ってSCSIデバイスからデータを読み込んでいるらしいことがわかった。DMA使ってるのに終わるまで待つ。また、SCSIコマンドを発行しているらしい箇所も特定できたのだが、どこからもその場所を呼んでいるように見えない。それが、これなんだけど:

     567b:	8b 1e 1c 05          	mov    0x51c,%bx   0x051c=Counter.
    567f:	8b 14                	mov    (%si),%dx   -> AH=0FDH, SCSI Disk -> DX=0x0C30  IO[0x0C30]=SCSI Data Register  RedBook pp. 262
    5681:	1e                   	push   %ds
    5682:	8b 3e 12 05          	mov    0x512,%di   Pointer to SCSI command array
    5686:	8e 1e 14 05          	mov    0x514,%ds   Pointer to SCSI command array
    568a:	8a 01                	mov    (%bx,%di),%al
    568c:	ee                   	out    %al,(%dx)
    568d:	1f                   	pop    %ds
    568e:	ff 06 1c 05          	incw   0x51c
    5692:	c3                   	ret    

SCSIデバイスからのData Requestに対するIRQハンドラとして呼ばれているのかと思ったけど、だとするとどこでそれを設定しているのかまで見つけられなかった。SCSIコマンドはコマンドによってバイト数が違うらしいから、どこで何バイト書き込むか決めてるのか特定したかったんだけど、まだそこまではできてない。

また、処理終了後、AX, CHになんらかの値を返すことがわかったのは逆アセンブルを読んだからなのだが、CHがエラーコードであることは間違いないが、AXの意味が今のところ不明。ただ、CDSD.SYSはAXを使ってないというか間違ってALを使ってるだけだからCDISC2.SYSから直接SCSI CDROMにコンタクトできるようにする目的には関係なさそう。

ちなみに、このSCSI BIOSの中で、タイマーBIOS (INT 97H) の未公開機能 AH=10H, AH=11Hを使ってるんだよね。インターバルタイマー機能っぽいんだけど。これもまだ未解明。

2019/11/21

CDISC2.SYS修正版!

とりあえず、修正版のダウンロードはこのリンク!

内蔵CDドライブが死んだFM TOWNSが残っていたら、捨てるの待った!

起動用フロッピーディスクかハードディスク(エミュレータでも可)が必要だけど、ここにCDSD.SYSとCDISC2.SYSを使って外付けSCSI CDドライブを内蔵ドライブの代わりに使う方法を書いた。が、それでは動かないタイトルが続出だった。どうやら、その原因はCDISC2がCD自動停止時間の指定をエミュレートしていなかったかららしい。

AH=052H, CH=0FFHの場合で、エラーを返すもんだからSplatter Houseは以下の部分で無限ループに陥っていた。ちなみにDOSエミュレータを使えば元祖の386DEBUGである程度までTowns用.EXPをトレースできることが判明。グラフィックス使い始めたらもう終わりだけど。

15334B			MOV		AX,052C0H
			MOV		CX,0FF00H
			INT		93H
			CMP		AH,00
			JNE		15334B

これに対するCDISC2.SYSの修正は簡単で、

CDStop		proc	near
; YS  This function (CH==0FFH) does not exist in SCSI-2 command
; YS  But, at least it shouldn't return an error.
; AH=52H, CH=0FFH means set sleep timer.
		cmp		ch,0ffh
		jne		@f
		mov		ah,	0
		ret

@@:

この修正で、Splatterhouseと飛翔鮫が起動してゲーム開始まで可能なことを確認した。時間の都合でこのふたつしか試してないけど、この修正で他にも動作するタイトルが増えたのではないだろうか。なお、飛翔鮫は専用の起動フロッピーまたは起動パーティションが必要。うーん、起動フロッピーの作り方ってどこかに書いたっけ?早い話が、

  1. Towns OS (V2.1 L10またはV2.1 L20がいいと思う)のフォーマットでシステムを組み込んだ起動ディスクを作る。本格的にCDドライブが死んでてまったく起動できない場合は、起動可能なディスクをなんとかゲットする。
  2. 起動したいゲームのCD-ROMからデバイスドライバをフロッピーディスクにコピーする。
  3. 起動フロッピーのCONFIG.SYSでは起動したいゲームのCONFIG.SYSと同じようにデバイスドライバを組み込み、それに加えて CDSD.SYSとCDISC2.SYSを組み込む。(CDSD.SYSを先に書く)
  4. 起動フロッピーのAUTOEXEC.BATは先頭行でMSCDEX.EXEを組み込んでQドライブを使えるようにして、Qドライブにカレントドライブを移動。以降はゲームのCD-ROMのAUTOEXEC.BATと基本的に同じ内容を書く。

というようなものを作ればいいんだけど。ハードディスクにブートパーティションを作って、それぞれのゲーム用のBIOSやデバイスドライバをディレクトリにわけてコピーしておいてCONFIG.SYSとAUTOEXEC.BATだけ書き換えてそのドライブにREIPLするという方法も使えるというか僕はそうやってる。

各ゲームの起動用ディスクイメージを作って公開したいんだけど、CDSD.SYSのライセンスの都合でできないんだが、作者さんに連絡を取って許可を得たいものの、連絡先がREADMEに書いてないからわからない。というかそもそも当時の連絡先がわかっても今はメールアドレスが変わってたりってことがほとんどだし。困ったな。

自分でTOWNSでSCSIいじくる方法を調べてCDISC2.SYSがCDSD.SYSに依存しないようにしてしまうって手もあるんだな。ちょっと考えてみよう。 

早速成果が出たのでもう少しCDISC2.SYSで動作するタイトルを増やす作戦を続けてみよう。なんでかWing CommanderでBGMが鳴らないんだけど、I/O直接制御してないと思うんだけどな。

2019/11/19

残念なことに、Splatter Houseと飛翔鮫は実機+CDSD.SYS+CDISC2.SYSでは起動しないが、それはCD-ROM BIOSの隠しコマンドを使っているからではないらしいことがわかった。隠しコマンドを使うと無限ループになるトラップを仕掛けたCDISC2.SYSを使ってエミュレータ上で起動してみたが、普通に起動できた。

ということはコピープロテクトのような目的でCD-ROM I/Oを直接使っているか、CDISC2.SYSのエミュレーションが不完全なため起動できていないかのどちらかということになる。

くっ、FM TOWNS用386DEBUGさえあれば。ヤフオクで僕に競り勝ったの誰かしらんけど、本当に使ってるんだろうなあ。ただのコレクションにしてるんだったら恨んでやる。

希望としてはCDISC2.SYSのエミュレーションの問題ならばエミュレーションを改善すればいい。せめてどういうコマンドがCD-ROM BIOSに送られているか調べることができれば。CDISC2.SYSのソースコードがあるんだから、CD-ROM BIOSコールのコマンド、パラメータなど普通にキャプチャできるが、問題はそれをどうやって外部に送り出すか。

はっ、RS232Cがあるじゃない。と、思ったが、CD-ROM BIOS内でさらにRS232C BIOSを呼び出していいもんだろうか?I/Oを直接制御した方が良さそうな気がする。FM TOWNSのRS232CのI/Oはどうなっているのか。。。。。

ただのIntel 8251じゃん。FM-7用RS232Cユーティリティ作るときさんざんいじくったよ。これならわかる。というわけで、MASMでRS232Cポートにデータを送信するプログラムを書いてみた。8251はわかったが、8251用クロックを生成するタイマーの使い方がわからなかったので、結局RS232C BIOSを解析してしまったが、Tera Termに19200bpsでデータを送信するコードをMASMで書いてみた。なんか最近アセンブリプログラミングのカンがどんどん戻ってきてる気がする。が、まったく本職に役に立たない。技術の持ち腐れだ。

[comtest.asm (ソースのみ)]

FM TOWNS上で実行するとRS232Cポートに19200bps, 1 stop bit, No parity, 8-bit data, で "YS"と送信することに成功した。

次は、CD-ROM BIOSコールが入ってくるたびに内容をRS232Cポートに出力するように仕込んだCDISC2.SYSを作って実機上でSplatter Houseとか実行してどこで止まってるか調べればいいんだな。 

2019/11/14

FM TOWNS 2FのROMも抜き出してCD-ROM BIOSのコードを逆アセンブルしてみたら、なんとMXと同じだ、と、思ったらCD-ROM BIOSはTowns OSのIO.SYS側にあったのか!起動に必要だからCD-ROM BIOSはROMからメモリに展開されてそれからブートするもんだと思ってた。それだとTowns OSによってCD-ROM BIOSが違う可能性があるんだな。

これだとロジックアナライザの解析を始める前にブートROMを解析しておいた方がよさそうだな。最初のやりとりはデータだけとわかってるし、IO.SYSの先頭部分が読み込まれるはずだから、どういうバイトデータが飛び交うか取れそうな気がする。

この先どういう流れで進めようかな。とりあえずさしあたりはCDISC2.SYSとCDSD.SYSで起動できるタイトルを増やすというのが直近の目標だから、そのためには、動かないタイトルを各個撃破するかな。Demosplashで展開したとき現状で動くタイトルを調べてきたんだけど、

問題なく動作(ただし起動フロッピーが必要な場合もあり)

起動するけどBGMが鳴らない

起動しない

去年起動してたのに今年起動しなかった(なんで!?)

そういえば現役でFM TOWNS使ってた頃、Afterburner III買わなかった。あれ、普通にG-LOCって言って売ってくれてれば買ったと思うんだが、またAfterburnerのネームバリューを使ってソフトを売ろうなんて、そんなけしからんソフト買うか、と、思って買わなかった。後になってあれって実はG-LOCって聞いて買えば良かったと思ったんだけど。ヤフオクで安く売ってたから買ったけど。

あとWing Commanderも起動したけどBGMが鳴らない現象だった気がする。

他にも試すつもりが案外時間なかったな。I/Oを直接攻撃しているタイトルの場合はどうせ改造が必要だけどそうでない場合はCDISC2のエミュレーションのレベルを上げれば対応できると思うんだよな。とくに、コマンドの16Hを使ってCDDA鳴らそうとしてたりするのがあったら鳴らない。しかも、CD演奏が始まったことをCDが存在することの確認に使っていたりするなら、演奏開始に失敗した場合そのまま起動しない可能性は十分ある。

2019/11/10

Demosplash 2019明けで重いFM TOWNS 2F, II MX、FM-7、FM77AV, AV40を会場まで運んで展開して撤収して収納してかなりの疲労状態。

FM TOWNS II MXのCD-ROM BIOSを解析していろいろおもしろいことがわかってきた。仕様として公表されているBIOSコマンドは、

と、これだけなのだが、CD-ROM BIOSの逆アセンブルを見たところ、コマンドFBH~16Hまでがデータ関連コマンド、4FH~62HまでがCDDA関係コマンドとして扱っているようだ。そして、各コマンドに対応するジャンプテーブルが、次の通り。

00005700 02 B5 02 80 FD FF 74 E1 C3 80 3E 29 05 80 75 0C ......t...>)..u.
00005710 C6 06 29 05 82 A0 28 05 B4 11 CD 97 C3 91 14 6B ..)...(........k
00005720 14 91 14 91 14 91 14 83 14 91 14 8A 14 B8 47 0D ..............G.
00005730 8E D8 BE 39 05 8B 54 02 EC A8 80 74 0D 24 70 C0 ...9..T....t.$p.
00005740 E8 03 98 8B D8 2E FF 97 0D 15 CB B8 47 0D 8E D8 ............G...
00005750 80 3E 29 05 80 75 05 C6 06 29 05 81 CB 00 00 00 .>)..u...)......
00005760 4E 1C 0E 16 0E 16 0E 16 11 16 45 16 8C 16 F4 16 N.........E.....
00005770 03 17 3F 17 0E 16 0E 16 0E 16 0E 16 0E 16 0E 16 ..?.............
00005780 71 17 0E 16 82 17 B8 17 1D 18 40 18 0E 16 0E 16 q.........@.....
00005790 FB 16 43 18 70 18 DE 18 1B 19 6E 19 F0 19 D1 1A ..C.p.....n.....
000057a0 0F 1B 46 1B A3 1B 0E 16 0E 16 0E 16 0E 16 0E 16 ..F.............
000057b0 0E 16 0E 16 C9 1B F9 1B 00 00 00 00 00 68 47 0D .............hG.
000057c0 1F 8A 46 03 BF 58 15 3C 16 7F 04 3C FB 7D 0F 2C ..F..X.<..<.}.,
000057d0 50 BF 84 15 3C 12 7F 04 3C FF 7D 02 33 FF B4 01 P...<..<.}.3...
000057e0 0B FF 74 14 98 8B D8 8A 46 02 24 0F B4 80 B9 04 ..t.....F.$.....
000057f0 00 3C 01 73 03 E8 19 00 80 FC 80 75 03 89 4E 06 .<.s.......u..N.
-------------------------------------

ライトブルーのバイトとそれに続く黄色のバイト青のバイトがコマンド00H~16Hに対応している。ピンクのバイトはFBH~FFH。青のバイトグリーンのバイトが50H~62H。なお、黄色のバイトは4FHにも対応している。このうち、0E 16は機能が割り当てられていなくて単にエラーコードを返す。それ以外はなんらかの機能が割り当てられている。昨日コードFBHで呼び出すと00 00 (0000H)にジャンプすると無限ループになる。多分スタックオーバーフローでクラッシュする。FCHに対応するジャンプ先 4E 1C  (1C4EH)は、機能コード00Hと同じ機能だが、ただしALの値をチェックしない。また、黄色のバイト青のバイトにオーバーラップがあるため、機能コード16Hが50Hと同じ動作をするように見える。また、機能コード4FHが15Hと同じ動作をするようだ。また、57H, 58H, 60H, 61Hにも機能が割り当てられているようだ。

CDISC2.SYSのソースを見ると、公開されているコマンド以外はリダイレクトしていなかった。CDISC2.SYSで外付けディスクで動作しないタイトルは、内蔵CD-ROMのI/Oを直接操作しているか、あるいは、未公開機能を使っているだけかもしれない。未公開機能は実はコピープロテクションなどに関連する機能の可能性がある。あるいは、機能コード16Hまたは4FHを使っているとしてもおそらく動作しない。ひょっとするとCDISC2.SYSでこれら未公開機能に対応してやるだけで動作するタイトルが増えるかもしれない。

機械工学科でまったく権力が無くて広い机など割り当ててもらうことは到底できない僕は実機によるテストができる時間が限られてしまう。しかし、エミュレータのステートファイルに手を加えて、プログラムが未公開機能を使ったことを検出するぐらいはできそうだ。引き続き調査を続行する。

2019/11/04

大体FM-7とFM77AVでやりたいことができるようになって、当面の動態保存の目途がついてきたので、フォーカスをFM TOWNSに移そうと思った。手元に一台のFM TOWNS II MXがある。が、その内蔵CDROMドライブは、半端に動作する状態。プレスしたCDからだとかろうじて起動するが、CD-Rはまったく読めない。レーザーが弱くなってるかフォーカスできなくなっているようだ。調べたところ、同様の問題は多発しているようでFM TOWNSの動態保存の障害になっているようだ。

実際、内蔵CDROMドライブを解析しようというプロジェクトも起ったようだが成功してはいないらしい。なぜかそれが海外で発生していて日本では見ないというのが、ゼロ戦を飛行状態に復元して飛ばしているのはなぜかアメリカという現状と重なって見えて、やや寂しい気がする。

手元には実家から回収してきた赤本がある。I/Oはわかる。実験のためにFM TOWNSエミュレータうんづ、MAMEがある程度活用できる。High-Cを使ってCDにコマンドを送るプログラムを書くことも可能だ。また、うんづは内部でコマンドをSCSIコマンドに変換することで内蔵CDROMドライブを再現しているらしい。だとすれば、同じことをハードウェアで実現すれば、実機の内蔵CDROMドライブコネクタに挟んでSCSI CDROMドライブを接続するコンバータを製作することが可能のはずだ。FPGAを使えば実現できるだろう。Arduinoでもなんとかなるかも。

問題は、I/Oポートの先。FM TOWNSの内蔵CDROMドライブは標準規格ができる前に作られたらしく、特殊な仕様となっている。しかも、コントロール用のワンチップマイコンがCPUとCDROMドライブの間に入っている。CPUからI/Oに書き込まれた内容はワンチップマイコンが適当に翻訳してCDROMドライブにコマンドを送り、データを受け取ってI/Oに出す。このワンチップマイコンが何をしているのか、そのコードはわからない。従ってI/Oに読み書きしているBIOSのコードを解析するだけではSCSIコネクタに出てくる信号にどう翻訳されるのかわからない。また、CDROMドライブのピン割り当てもわからない。それは調べなくてはならない。

GNDピンはマザーボードにテスタを当てて調べることができる。+5V, +12Vも多分テスタでわかる。また、制御しているワンチップマイコンを特定できれば、そのピンにつながっているピンがデータピンと見ることができる。

長期目標:

中期目標

短い期目標:

Survey Links:

 

Comments are welcome.  Send E-Mail to: 

Back to http://www.ysflight.com