| 
 | 
[ここに書いてる内容は、FM TOWNSの技術情報を残すことを目的に書いてるので、どんどん転載しちゃってください。]
  Bit0: ?
Bit1: ?
Bit2: Boot Drive Number 
LSB (0=A drive)
Bit3: Boot Drive Number 
Bit4: Boot Drive Number 
Bit5: 
Boot Drive Number 
Bit6: Boot Drive Number MSB
Bit7: ?
Bit2 to Bit6 is the boot drive. By writing a different drive number to this I/O, FM TOWNS will believe the system started from the number in here.
Bit0, Bit1, and Bit7 seem to have a meaning. Therefore, when modifying, the program must make sure it first read the byte, and the only update bit2 to bit6.
If 'R' is written to 3A34H and 'A' is written to 3A36H, SYSINIT.EXE shows progress and debugging information. It is unknown if other processes are referring to these I/O addresses.
Input:
AH=0FDH         
Command Code.
AL=0BxH         Device 
Id.  x is SCSI ID.
CX=0000H        
LUN.  Must be zero.
DS:[DI-]        
Data Return Buffer Pointer and SCSI Command Information.
DS:[DI]         
Data Return Buffer Address
DS:[DI+2]       Data 
Return Buffer Segment
DS:[DI+4...15]  SCSI Command Up to 12 bytes.
Return:
CH!=0           
Could not communicate with the SCSI device.
CH=0            
Successfully communicated with the SCSI device.  AH=STATUS,  
AL=MESSAGE    
CDSD.SYSの解析で、FM-R/TOWNSがSCSI CD-ROMドライブにアクセスするには、I/Oを直接攻撃する以外にはこの隠し機能を使うしかないらしい。AL=0BxHのxはSCSI ID。
SCSI Commandは最長12バイトらしい。何バイトのコマンドなのか、上位3ビットで決まるらしい。(https://www.staff.uni-mainz.de/tacke/scsi/SCSI2-07.html) 上位3ビットが000の場合6バイト、001または010の場合10バイトコマンド、101の場合12バイトコマンドになる、とある。
そのコマンドを発行した結果デバイスから返ってくるデータはアドレスがWORD PTR DS:[DI]、セグメントがWORD PTR DS:[DI+2]からに格納される。
この機能は実行結果をAH, CL, CHに格納して返すことを突き止めた。TOWNS OS V2.1 L31の解析の結果、
CH=0, AH=DS:[051AH], AL=DS:[051BH], CH=0
または、
CH=1または2, AH=不定, AL=不定
のいずれかが返る。
戻り値を設定している箇所は、FM TOWNS、TOWNS OS V2.1 L31のBIOS逆アセンブリから、(アドレスはいずれも物理アドレス)
Successfully sent an started a SCSI comman?
    557f:	8a 26 1a 05          	mov    0x51a,%ah
    5583:	a0 1b 05             	mov    0x51b,%al
    5586:	b5 00                	mov    $0x0,%ch
Probably the SCSI device does not become READY within timeout period:
    In Sub-routine at 561b called from Sub-routine at 54E7
    564b: b5 01 mov $0x1,%ch
Probably the SCSI device does not become BUSY within timeout period:  (Called from 5553->)
    In Sub-routine at 5663 called from Sub-routine at 5553 called from Sub-routine at 54E7
    5701: b5 02 mov $0x2,%ch
どうも、CH=2というのはそもそもSCSIデバイスにコマンドを送ったけど何も応答がなかった、CH=1というのはそもそもコマンドを受け取らなかった、という意味のように見える。
コマンドを実際送信している箇所、DS:[051AH], DS:[051BH]に値を格納している箇所も見つけた。(アドレスはいずれも物理アドレス)
CS=0421H, IP=146BH
    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
    5686:	8e 1e 14 05          	mov    0x514,%ds
    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  
    (*) Red Book for FM TOWNS users means "FM TOWNS Technical Guidebook"  
CS=0421H, IP=1483H
    5693:	8b 14                	mov    (%si),%dx   DS:[SI]=0C30H, SCSI I/F Data Register
    5695:	ec                   	in     (%dx),%al
    5696:	a2 1a 05             	mov    %al,0x51a
    5699:	c3                   	ret    
CS=0421H, IP=148AH
    569a:	8b 14                	mov    (%si),%dx   DS:[SI]=0C30H, SCSI I/F Data Register
    569c:	ec                   	in     (%dx),%al
    569d:	a2 1b 05             	mov    %al,0x51b
    56a0:	c3                   	ret    
これらのプロシージャを呼んでいるのは、
Jump Table
    571d:   1491  <- Vector for NOP                           0 0 0 -> Data Out Phase: Data
    571f:   146b  <- Vector for CMD write                     0 0 1 -> Command Phase: Command
    5721:   1491  <- Vector for NOP                           0 1 0 -> Reserved
    5723:   1491  <- Vector for NOP                           0 1 1 -> Message Out Phase: Message
    5725:   1491  <- Vector for NOP                           1 0 0 -> Data In Phase: Data
    5727:   1483  <- Vector for Read and store in [0x51a]     1 0 1 -> Status Phase: Status
    5729:   1491  <- Vector for NOP                           1 1 0 -> Reserved
    572b:   148a  <- Vector for Read and store in [0x51b]     1 1 1 -> Message-In Phase: Message
CS=0x421 -> IP=151D
Vector to this address is found at Physcai address 0000d990 1D 15 21 04 (DS:[0x520])
    572d:	b8 47 0d                  mov    $0xd47,%ax
    572f:	8e d8                     mov    %ax,%ds
    5732:	be 39 05             	mov    $0x539,%si
    5735:	8b 54 02             	mov    0x2(%si),%dx     DX=0x0C32  SCSI Status Register
    5738:	ec                   	in     (%dx),%al
    5739:	a8 80                	test   $0x80,%al        Transfer Request? REQ (Active High)
    573b:	74 0d                	je     0x574a           Jump if no request.
    573d:	24 70                	and    $0x70,%al
    573f:	c0 e8 03             	shr    $0x3,%al         After shift AL Bit2=(0:Output 1:Input), Bit1=(0:Data 1:MSG), Bit0=(0:Data 1:Control)
    5742:	98                   	cbtw   
    5743:	8b d8                	mov    %ax,%bx
    5745:	2e ff 97 0d 15       	call   *%cs:0x150d(%bx)    CS:[150DH]=4210H+150DH=571DH(Jump Table)
    574a:	cb                   	lret   <- Returninb by lret, implies that it is called from FM-R BIOS
どこかで割り込み登録されている模様。割り込みベクターは物理アドレスのD990Hに書いてあった。割り込み登録箇所はおそらく、
     fbe4:	bf 1e 05             	mov    $0x51e,%di
    fbe7:	b2 08                	mov    $0x8,%dl
    fbe9:	b4 00                	mov    $0x0,%ah
    fbeb:	cd ae                	int    $0xae
仮にDS=0D47とするとDS:[051EH]は物理アドレスのD98EHに対応する。割り込み登録INT 0AEHはDS:[DI+2]が呼び出しアドレスだから部t理アドレスD990Hに完全に一致。
これによって、戻り値のAH=DS:[051AH]はSCSI STATUS, AL=DS:[051BH]はSCSI MESSAGEと特定できた。 なお、STATUSはhttps://www.staff.uni-mainz.de/tacke/scsi/SCSI2-07.htmlによると、次の通りらしい。
(STATUS&0x3E)==0:  Good
(STATUS&0x3E)==2:  Check Condition
(STATUS&0x3E)==4:  Condition Met
(STATUS&0x3E)==8:  Busy 
(STATUS&0x3E)==16: Intermediate 
(STATUS&0x3E)==20: Intermediate Condition Met
(STATUS&0x3E)==24: Reservation 
Conflict
(STATUS&0x3E)==34: Command Terminated
(STATUS&0x3E)==40: Queue 
Full
FM TOWNS CD-ROM BIOSの未公開機能AH=0EHは、基本的にTest Unit Ready (ドライブにディスクが入って使用可能かチェック)と同じ。ただし、違うのは、ドライブが使用可能状態でかつ内部フラグDS:[564H]が1のときは、内部フラグをクリアした上で、Media Changed Errorを返す。
なぜこの機能が必要か。SCSI CD-ROMドライブ自体に使用可能かどうか問い合わせるコマンド Test Unit Ready がある。これを使うことえ、ドライブが使用可能状態かどうかを調べることができる。CD-ROMドライブは、直前になんらかのCDアクセスがあってからTest Unit Readyコマンドが発行されるまでの間にCDメディアの入れ替えがあった場合、Media Changed Errorを返す。これを利用して、コンピュータはCDが交換されたかどうかを知ることができる。
しかし、ここにキャッシュが関わるとややこしくなる。CD-ROMドライブはどうしてもハードディスクなどと比べて遅い。とくにヘッドを特定セクタに移動するのが遅い。CD-ROMディスクのディレクトリは変化しないから、ファイルを読むたびにヘッドを内側に移動してディレクトリを読み直すよりは、一度ディレクトリ情報をキャッシュして次からは読み込まないようにした方がいい。
ところが、たとえばCDプレイヤーアプリケーションを起動したとする。その後CDを入れ替え再生する。すると、FM TOWNSのCD-ROM BIOSは再生する前にCDの入れ替えがあったことを通知するが、その後はMedia Changed Errorは返さない。CDプレイヤーを終了して、ふたたびディレクトリを参照しようとしたとき、すでに一度Media Changed Errorはコンピュータ側に通知されてしまった後なので、Test Unit ReadyコマンドはMedia Changedエラーを返さない。その結果、CDは入れ替わっているにも関わらず、前に入っていたCDのディレクトリが表示されてしまう。
これを防止するために、FM TOWNSのTOWNS_CDドライバは未公開機能AH=0EHを使う。FM TOWNSのCD-ROM BIOSのどの機能でも、Media Changed Errorを検出すると、DS:[0564H]に1を書き込む。TOWNS_CDドライバはファイルアクセスの前に必ずAH=0EHを呼ぶ。仮にCDドライブがReadyと言ったとしても、もしもDS:[564H]が0以外の場合は、DS:[564H]を0にクリアした上でMedia Changed Errorを返す。もしもCDドライブがReadyではなかった場合、単にDS:[564H]をクリアしてCDドライブが返したエラーをそのまま返す。
この方法で、AH=0EHは、最後にファイルまたはディレクトリにアクセスして以降のCD交換を検出する。TOWNS_CDの管轄外でCDメディアの交換があったとしても正しくCDの交換に対応できる。
Input: CL=5, 1, 2, 4, 8, or 16
この未公開機能AH=0FHは、CD-ROM BIOSの内部フラグに直接アクセスするための機能らしい。ただしCL=5以外で使われている形跡は無かった。デバッグ用に追加した機能をそのまま残したのかもしれない。CD-ROM BIOSにはなんらかのキャッシュと思われるフラグが5か所見つかった。
DS:[564H]  Media Changed Error Cache (See 
AH=0EH)
DS:[565H]  Set to 1 upon error, reset, or media change, but 
nothing is referring to it?
DS:[566H]  Checked and cleared at the 
beginning of CS:[0C16H](Physical 6906H)
DS:[567H]  Set to 1 upon error, 
reset, or media change, but nothing is referring to it?
DS:[568H]  PAUSE 
flag (1:Paused  2:Unpaused)
このうち意味がわかったのはDS:[564H]とDS:[568H]のみ。残りはDS:[564H]と似た働きをしているようだが、まだ解明できていない。未公開機能 AH=0FH はこれらのフラグに直接アクセスするためのものらしい。C++風に書くとこんな感じ。
int CDROM_BIOS_INT93H_0FH(unsigned char CL,unsigned char &DL)
{
    switch(CL)
    {
    case 5:
        DL=flag_0567H;
        flag_0567H=0;
        return NO_ERROR;
    case 0:
        DL=flag_0564H;  // Media_Changed_Cache
        return NO_ERROR;
    case 1:
        flag_0564H=DL;  // Media_Changed_Cache
        flag_0566H|=DL;
        return NO_ERROR;
    case 2:
        DL=flag_0565H;
        flag_0565H=0;
        return NO_ERROR;
    case 4:
        flag_0566H|=DL;
        return NO_ERROR;
    case 8:
        DL=flag_0568H; // Pause flag
        return NO_ERROR;
    case 16:
        flag_0568H=DL; // Pause flag
        return NO_ERROR;
    default:
        return PARAMETER_ERROR;
    }
}
CL==1の場合を見るとどうも0564Hと0566Hはかかわりがありそうな感じがする。もう少し使われ方を詰めればわかると思うんだけど。
この機能はコマンドダンプで実際使われている場面をまだ見たことが無い。CH!=0 || DL!=1の場合PARAMETER ERRORを返す。CH==0 && DL==1の場合、8バイトのパラメータバッファをクリアするもののコマンドは発行しない。そのままABNORMAL TERMINATION ERRORを返す。事実上何もしない。
     5a2d:	b4 80                	mov    $0x80,%ah
    5a2f:	b9 02 00             	mov    $0x2,%cx
    5a32:	8a 46 07             	mov    0x7(%bp),%al  AL=Incoming_CH
    5a35:	3c 00                	cmp    $0x0,%al
    5a37:	75 16                	jne    0x5a4f
    5a39:	8a 46 08             	mov    0x8(%bp),%al  AL=Incoming_DL
    5a3c:	3c 01                	cmp    $0x1,%al
    5a3e:	77 0f                	ja     0x5a4f
    5a40:	e8 8e 0c             	call   0x66d1        Clear 8 bytes from 57f (parameter buffer) Registers Preserved
    5a43:	3c 01                	cmp    $0x1,%al      AL is already checked.  AL==1
    5a45:	75 06                	jne    0x5a4d        Therefore never jumps.
    5a47:	b4 80                	mov    $0x80,%ah
    5a49:	b9 08 00             	mov    $0x8,%cx      Abnormal Termination
    5a4c:	c3                   	ret    
    5a4d:	b4 00                	mov    $0x0,%ah
    5a4f:	c3                   	ret    
電源切断時、リセット時にAH=11Hが呼ばれるのだが、これは何もしていなかった。
CD-ROM BIOS INT 93H AL=C0H, AH=11H Unpublished
5a50: b4 00 mov $0x0,%ah
5a52: c3 ret 
Input: DS:[DI]   Electric Volume 
Buffer
    DS:[DI]    0
    
DS:[DI+1]  Left Channel Electric Volume 0 to 255
    
DS:[DI+2]  1
    DS:[DI+3]  Right Channel Electric 
Volume 0 to 255
    DS:[DI+4]  2
    
DS:[DI+5]  Microphone Electric Volume (Probably)
    
DS:[DI+6]  3
    DS:[DI+7]  Modem Electric Volume 
(Probably)
CD-ROMの電子ボリュームを設定する。電子ボリュームはDS:[DI]からの8バイトのバッファに書いてあるはずだが、この機能はDS:[DI+1]およびDS:[DI+3]以外はアクセスしない。
Output: DS:[DI]   Electric Volume 
Buffer
    DS:[DI]    0
    
DS:[DI+1]  Left Channel Electric Volume 0 to 255
    
DS:[DI+2]  1
    DS:[DI+3]  Right Channel Electric 
Volume 0 to 255
    DS:[DI+4]  2
    
DS:[DI+5]  Microphone Electric Volume (Probably)
    
DS:[DI+6]  3
    DS:[DI+7]  Modem Electric Volume 
(Probably)
電子ボリュームを返す。CD-ROM以外にもマイクとモデムのボリュームも結果的に返ってしまう模様。
Input:
  DL=0,1,2,3
  When DL=0:
    
Towns OS V1.1   CL:Third parameter to the command 3FH
    
Towns OS V2.1   BL:Third parameter to the command 3FH
このコマンドは実際TOWNS_CDドライバから呼ばれているが、効果は不明。C++風に書くとこうなる。
int CDROM_BIOS_INT93H_61H(unsigned char DL,unsigned char &BL)
{
    if(DL==0)
    {
        DS:[0x740]=BL;
        return IssueCommand(0x3f,{0x02,0x00,0x0d,BL,0,0,0,0})
    }
    else if(DL==1)
    {
        DS:[0x741]=BL;
        return NO_ERROR;
    }
    else if(DL==0x10)
    {
        BL=DS:[0x740];
        return NO_ERROR;
    }
    else if(DL==0x11)
    {
        BL=DS:[0x741];
        return NO_ERROR;
    }
    return PARAMETER_ERROR;
}
Linux for FM TOWNSのソース (towns_cd.h) を見るとかなりのCD-ROMコマンドがわかるのだが、3FH (Return State Request Flag + 1FH) は不明と書いてある (CDxxx)。YSSCSICD.SYSではこの機能は常にNO ERROR扱いにしている。
Towns OSにはメジャーバージョンV1.1とV2.1がある。V2.1の方がV1.1よりもはるかに洗練されたユーザーインターフェースになっていて、V2.1L31以降はCooperative Multi Taskingを実現している。内部的にもいくつもの違いがあって、これまでに解析してわかったことを以下にまとめる。
Towns OS V1.1ではDOSはすべて下位640KBに収まっているらしく、UMB (640KB~1MB)は空き空間とされているらしい。これに対して、Towns OS V2.1では一部の機能をUMBに置いてDOSアプリケーションが使えるRAMを増やしているらしい。Galaxy Force IIがなぜV2.1から起動できないのかを調べていて、Towns OS V2.1はDOSが物理メモリ空間FC000~FFFFFを使用しているらしいということがわかった。この領域を破壊するとシステムがクラッシュしてしまう。Towns OS V1.1ではこの領域を破壊しても何も問題が起こらない。
Towns OS V2.1付属のDOS Extender (RUN386.EXE) はmalloc時UMB領域でDOSが使用する範囲を認識して回避する。しかし、Towns OS V1.1付属のDOS ExtenderはUMBの使用状態を認識しない。このため、Towns OS V2.1上でTowns OS V1.1のRUN386.EXEを使うと、DOSが使用するUMB領域を破壊してしまう危険がある。
Towns OS V1.1では基本的に起動ドライブが常にカレントドライブとなっている。DOSのデフォルトドライブって言うからきっと起動ドライブはカレントドライブと別におぼえているもんだと思ったら、同じものだった。
Towns OS V2.1では未公開I/O 3C32Hに起動ドライブが記録されている。多分これは起動時にブートローダーが書き込むものだと思うんだけど、起動後に変更も可能でYSSCSICD.SYSはそれを利用することでTowns OS V2.1にCDから起動したと思わせることに成功した。
多分実機が現役だったころは知ってたことなんだろうけど最近再度発見したこと。Towns OS V1.1のTBIOSは486DX以降の高速機に対応していないらしくマウスカーソルが飛びまくってしまう。この問題は、Towns OS V2.1 L20のTBIOS.SYSとTBIOS.BINをV1.1の起動ドライブにコピーすることで解決できて、とくに副作用も無いらしい。
| Comments are welcome.  
		Send E-Mail to:  |