|
[ I am writing this to preserve historic Japanese computer called FM TOWNS. Please feel free to copy this information to anywhere. ]
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 source code indicates that you need to use this unpublished function to access SCSI CD-ROM drive unless you want to directly beat I/O ports. Input parameter x of AL=0BxH is SCSI ID.
SCSI command can be as long as 12 bytes. Actually how many bytes is defined according to the high 3 bits of the command. (https://www.staff.uni-mainz.de/tacke/scsi/SCSI2-07.html) If high 3 bits are 000 the command takes 6 bytes, 001 10 bytes, 101 12 bytes.
The data reading from the command will be stored from address in WORD PTR DS:[DI], segment in WORD PTR DS:[DI+2].
The result of the command will be returned in CH, AH, and AL. There are two possibilites:
CH=0, AH=DS:[051AH], AL=DS:[051BH], CH=0
or,
CH=1 or 2, AH undefined, AL undefined.
The return values are set in the following places (addresses are physical addresses.)
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
It appears that CH=2 means the command was sent but no response, and CH=1 means failed to send the command.
I also found a location where commands are sent, and status bytes are received.
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
These procedures are called from:
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
The procedure must be registered as a interrupt handler somewhere. The interrupt vector was found at physical address D990H. The interrupt is registered at:
fbe4: bf 1e 05 mov $0x51e,%di fbe7: b2 08 mov $0x8,%dl fbe9: b4 00 mov $0x0,%ah fbeb: cd ae int $0xae
If DS=0D47H, DS:[051EH] is physical address D98EH. The interrupt vector registration takes interrupt handler at [DI+2], which makes it D990H. Perfect match!
Finally, I was able to conclude that the return value of INT 93H AH=0FDH AL=0BxH means AH=DS:[051AH]=SCSI STATUS, AL=DS:[051BH]=SCSI MESSAGE. The meaning of the STATUS is according to 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 INT 93H AH=0EH is basically Test Unit Ready, which checks if the media is in the CD-ROM drive and ready to read/write. But, if the drive is ready and if a flag DS:[564H] is non-zero, it clears the flag and returns Meida Changed Error.
Why is this function necessary? SCSI CD-ROM Drive has a command Test Unit Ready. If a CD media is changed after the last SCSI function before Test Unit Ready, it returns Media Changed error. The computer can tell if the CD media changed by looking at the return value.
But, the things gets complicated if something is cached. A CD-ROM is slower than a hard disk drive. Especially moving head to a specific location takes much longer. It is inefficient to move head to the inner-most position to read directory information every time accessing a file. Rather, it is faster to cache directory information and not-updating until the media is changed.
But, let's say you start a CD-Player application. Then you change a media. Then start playing. And then go back to the GUI or command shell. Since CD-Player application already sensed Media Changed Error, the computer won't get a Media Changed Error when it access a file or directory next time. As a result, even though the CD has changed, the computer does not think it has changed, and show directory of the previous disc.
To prevent this problem, TOWNS_CD driver uses an unpublished function 0EH. Any CD-ROM BIOS function, when it detects media change, sets a flag DS:[564H] to 1. TOWNS_CD driver always calls function 0EH before accessing a file or directory. If the CD drive is Ready and flag DS:[564H] is non-zero, function 0EH clears the flag and returns Media Changed Error. If the drive is not ready, it just clears DS:[564H] and returns whatever error received from the drive.
This way Function 0EH will tell media change since last file access.
Input: CL=5, 1, 2, 4, 8, or 16
Function 0FH is used for directly access internal flags of the CD-ROM BIOS. I have never observed this function request except CL=5. This function may be added for debugging purpose and left unchanged in the release version. I have found five flags in the CD-ROM BIOS:
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)
I have figured the meaning of 564H and 568H. Others seem to have a similar meaning as 564H, but cannot really find the functionality. Function 0FH is for directly accessing these flags. If I write it like 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 case suggests that 564H and 566H are similar. But, at this time I cannot really tell the exact meaning.
I have never seen this function actually used. Maybe not used after all. This function returns PARAMETER ERROR if CH!=0 || DL!=1. If CH==0 && DL==1, it clears the parameter buffer, but does not issue any command, and returns ABNORMAL TERMINATION ERROR. It does nothing useful.
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
This function (11H) is called before power off or reset. But, it is not doing anything.
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)
This function sets electric volume of CD-ROM. Electric Volume should be written in the 8-byte buffer starting at DS:[DI]. However, this function only reads DS:[DI+1] and DS:[DI+3] and other values are ignored.
This function may return Media Changed Error or Drive Not Ready Error.
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)
It returns the electric volume settings. Although this is a CD-ROM BIOS functions, it ends up returning also microphone and modem electric volume information.
Electric volume values are written in an 8-byte buffer from DS:[738H]. In CD-ROM BIOS of Towns OS V2.1, DS=0D47H. DS:[0738H] is physical address DBA8H.
This function may return Media Changed Error or Drive Not Ready Error.
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
This function (61H) is actually used from TOWNS_CD driver. But the meaning is unknown. Interestingly, the third parameter to the command is taken from CL in Towns OS V1.1, but from BL in Towns OS V2.1. If I rewrite in C++ style, it works like this:
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 source (towns_cd.h) gives some hints on internal CD-ROM commands. But, 3FH (Return State Request Flag + 1FH) is marked as unknown (CDxxx). In YSSCSICD.SYS, it pretends there is always no error for this command.
Towns OS has two major versions, V1.1 and V2.1. V2.1 has more sophisticated GUI than V1.1, and V2.1L31 added cooperative multi tasking. V2.1 also has many internal differences from V1.1. I summarize what I discovered so far.
Towns OS is based on MS-DOS, probably V3.1. Towns OS V1.1 keeps everything DOS-related below 640KB, and UMB (640KB to 1MB) area is unused. Towns OS V2.1 apparently uses some space in the UMB. I found it while reading disassembly of Galaxy Force II to understand why it didn't start from V2.1. Towns OS V2.1 crashes if the memory area FC000 to FFFFF is destroyed. Towns OS V1.1 is unaffected.
DOS Extender (RUN386.EXE) that comes with Towns OS V2.1 recognizes and avoids used UMB area. RUN386.EXE of Towns OS V1.1 is not aware of UMB usage. Therefore, if you start a program on Towns OS V2.1 using RUN386.EXE of V1.1, it might destroy critical UMB area, and the whole system may crash.
Towns OS V1.1 basically keeps the boot drive as the current drive all the time. I first thought "Default Drive" of the DOS is different from the current drive. But later I figured these are the same thing.
Towns OS V2.1 remembers the boot drive in unpublished I/O 3C32H. Probably the boot loader writes to this I/O. It can be written after the system starts. YSSCSICD.SYS modifies this value to let CD-ROM based Towns OS V2.1 think it is started from the CD-ROM drive.
TBIOS or Towns BIOS of Towns OS V1.1 is not aware of the newer versions of FM TOWNS hardware, namely faster models. Therefore, if you start Towns OS V1.1 on 486DX FM TOWNS in the FAST mode, mouse driver cannot scan mouse movement correctly, and the cursor will jump around.
The workaround for this is to copy TBIOS.SYS and TBIOS.BIN of Towns OS V2.1 L20 (Probably L10 works, too) to the Towns OS V1.1 boot drive. As far as I experimented with my Towns II MX (486DX), Towns OS V1.1 with V2.1L20 TBIOS runs with no problem and no jumping mouse cursors in the FAST mode.
Comments are welcome. Send E-Mail to: |