TRSDOS v2.3 FORMAT/CMD Disassembly
This is a disassembly of TRSDOS v2.3’s FORMAT/CMD File.
The FORMAT process is mostly about building a directory track, so an understanding of the TRSDOS v2.3 directory structure is important.
There are three files which MUST be in specific locations on a TRSDOS v2.3 disk: BOOT/SYS, SYS0/SYS, and DIR/SYS. BOOT/SYS must start at Track 0, Sector 0. SYS0/SYS must start at Track 0, Sector 5. DIR/SYS must start at Track 17 (11H) and go for 10 consecutive sectors.
The directory is 10 sectors. The first sector (sector 0) is the Granule Allocation Table, or GAT. The second sector (sector 1) is the Hash Code Index Table, or HIT. The remaining 8 sectors are for the actual files.
- The GAT sector contains all the information needed to let DOS allocate space for files. The sector covers assigned/unassigned granules, locked out granules, the master disk password, the disk name and date, and the AUTO command, if any.
- FF = the first and second granules are allocated (all 10 sectors)
- FE = the second granule is allocated (sectors 5-9)
- FD = the first granule is allocated (sectors 0-4)
- FC = no granules allocated (all sectors are free)
Bytes CE-CF are the master disk password hash.
Bytes D0-DF is the disk name and backup date
Bytes E0-FF are the AUTO command, with the note that if E0H contains an 0DH then the AUTO command will NOT execute. - The HIT sector contains the program name hash code and the corresponding location in the remaining 8 sectors for the relevant information about that file. The program filename’s hash will appear on columns 01-08 to signify where in the 8 remaining sectors the file’s information can be found. Columns 9-16 are not used.
- The rest of the sectors (2-9), called the FPDE (File Primary Directory Entry)/DXDE (File Extension Directory Entry) include the file type, entry status, space availability status, the End of File number, the logocal record length, the filename and extension, the passwords, the number of sectors assigned to the file, the file extents, the track and sector location of the start of the file, the number of continguous sectors in the extent, and the entry type. Each sector has 8 entries (00-1F, 20-3F, 40-5F, …, E0-FF).
- Byte 00 = Bit Record: Bits 0-2 = 3 Bit Protection Level, Bit 3 = Visible [0] or Invisible [1], Bit 4 = Assigned [1], Bit 5 = Not Used, Bit 6 = System File [1], Bit 7 = Primary [0] or Extended [1]
- Byte 01 = Not used if this is a FPDE (and will be 00H). If this is a FXDE then it is the DEC pointing back to the FPDE.
- Byte 02 = Not used
- Byte 03 = Relative position of the last byte of the program in the EOF sector (i.e., how many bytes in on the final sector)
- Byte 04 = Logical Record Length (0-255). TRSDOS v2.3 does not use this byte, so it is normally 00H.
- Bytes 05-0C = Filename. The “/” is not stored.
- Bytes 0D-0F = Extension
- Bytes 10-11 = Hash of UPDATE password
- Bytes 12-13 = Hash of ACCESS password
- Bytes 14-15 = EOF Relative Sector. If the EOF byte = 00H, then this is the ACTUAL relative sector count. If the EOF byte is NOT 00H, then this is the relative sector count + 1.
- Bytes 16-17 = Extent 1
- Bytes 18-19 = Extent 2
- Bytes 1A-1B = Extent 3
- Bytes 1C-1D = Extent 4
- Bytes 1E-1F = Extent 5
5200H – FORMAT/CMD Entry Point
- If Register A equals C7H/199, the Z FLAG is set.
- If A < C7H/199/, the CARRY FLAG will be set.
- if A >= C7H/199/, the NO CARRY FLAG will be set.
- If Bit 4 is set, then SYS6/SYS is loaded in RAM (and can be called by RST 28H).
- If Bit 5 is set, then CHAINING is in effect.
- If Bit 7 is set, then DEBUG was set to active.
NOTE: 4467H is a vector call to 44CFH which sends the message pointed to by HL to the video display. HL is preserved.
NOTE: 4030H will load and execute the SYS1/SYS overlay with a Request Code of 2, so as to get the next command.
521CH – Continuing the FORMAT Routine now that we know that it was not called from a BATCH file.
We now need to fetch a single drive number from the user.
NOTE: 0040H is the Model I ROM routine to wait for keyboard input of B characters and put store the character at (HL).
- If Register A equals 04H, the Z FLAG is set.
- If A < 04H, the CARRY FLAG will be set.
- if A >= 04H/4/, the NO CARRY FLAG will be set.
At this point we know we received either a “0”, “1”, “2”, or “3” as the drive number from the user; now we need to conver that into something we can use.
These 3 RLCAS turn a “0” into an 00H, “1” into an 08H, a “2” into a 10H, and a “3” into 0CH.
That OR C7H turns a “0” into C7H, a “1” into CFH, a “2” into D7H, and a “3” into DFH.
5278H – Get Diskette Name from User
The next instructions move the 8 spaces stored at 5778H to 5CD0H, which will be the buffer used to hold the DISK NAME the user enters.
5296H
529DH – Get Creation Date from User
Set up to the creastion date, of 8 characters, from the user and store it at 5D00H
NOTE: 0040H is the Model I ROM routine to wait for keyboard input of B characters and put store the character at (HL).
- If Register A equals 08H, the Z FLAG is set.
- If A < 08H, the CARRY FLAG will be set.
- if A >= 08H, the NO CARRY FLAG will be set.
We are now going to move the user entered date to 5CD8H.
52CCH – Get Master Password from User
NOTE: 0040H is the Model I ROM routine to wait for keyboard input of B characters and put store the character at (HL).
At this point, both A and B contain the number of characters the user entered for the MASTER PASSWORD, C contains 8 (which was the number of acceptable characters in a date), HL contains 5D00, and DE contains 401DH.
At this point 5200H points to 8 characters of a master password; padded with spaces if need be.
52F6H – This subroutine will hash the master password into HL and RETurn.
On the first pass, right now A=FF, B=08, C=08, D=20, E=FF, H=FF, and L=FF
The next 3 rotations take the lower 3 bits (which are the only ones which are still live, and moves them to the highest bits)
5322H – Continuation of the FORMAT command.
Jumped here from 52F4H At this point, the DATE and MASTER PASSWORD have been entered, validated, and hashed. The DATE is at 5CD8H, the MASTER PASSWORD at 5D00H, the DISK NAME at 5CD0H, the DATE at 5CD8H, and the MASTER PASSWORD hash is at 5CCEH.
5C00H-5CCAH are all FFH at this point. The next instructions will fill bytes 5C00-5C22H with FCH.
Once A hits 23H it will fall through here and fill with FFH’s A until it gets to CBH.
5338H – Not sequential. Jumped here from 536DH.
533EH – Continuation of the FORMAT command. Jumped here from 5330H, which just filled the RAM from 5C00H to 5CCAH with FC’s or FF’s.
NOTE: 0040H is the Model I ROM routine to wait for keyboard input of B characters and put store the character at (HL).
If we are here, the user said YES to DO YOU WANT TO LOCK OUT ANY TRACKS, so now we have to process that.
NOTE: 0040H is the Model I ROM routine to wait for keyboard input of B characters and put store the character at (HL).
If we are here, then we found a “-” so we need to parse the second set of numbers.
- If Register A equals 35, the Z FLAG is set.
- If A < 35, the CARRY FLAG will be set.
- if A >= 35, the NO CARRY FLAG will be set.
- If Register A equals 35, the Z FLAG is set.
- If A < 35, the CARRY FLAG will be set.
- if A >= 35, the NO CARRY FLAG will be set.
Start of a DJNZ loop to put FFH’s into the locations at 5CxxH which represent the tracks to be locked out.
At this point, a FFH has been placed in 5Css (starting track to lock out) to 5cee (ending track to lock out) .
If we are here, then we have finished processing the DO YOU WANT TO LOCK OUT TRACKS / WHICH TRACKS routines.
NOTE: 0040H is the Model I ROM routine to wait for keyboard input of B characters and put store the character at (HL).
539EH – Drive Ready and Disk Verification Checks
If we are here, then Floppy Disk Controller did not return any error response codes, so we can continue.
Set up for the next disk-in-drive-and-ready test. This will count down from 204 to 0 to test for a DISKETTE IN DRIVE.
53CAH
OR C
Set up for the next disk-in-drive-and-ready test. This will count down from 6557 to 0 to test for DOOR OPEN.
53DDH
OR C
Set up for the next disk-in-drive-and-ready test. This will count down from 186 to 0 to test for a DISKETTE IN DRIVE.
53F3H
OR C
Set up for the next disk-in-drive-and-ready test. This will count down from 5920 to 0 to test for DOOR OPEN.
5407H
OR C
5435H – Directory Track Selection Loop
Top of a loop of 35 tracks to look for the directory track.
5448H – Continuation of FORMAT routine. On entry, Register A is holding the offset into 5Cnn for the byte being worked on.
This is a jump point from 5446H when all 35 tracks have been checked for FC vs FF
5452H – Continuation of FORMAT routine. Jumped here from 5438H if a FCH byte is found when scanning 5Cnn. The Directory Track to be used is held in A
NOTE: 4202H is the where TRSDOS 2.3 stores the Directory Track Number.
5467H – Main Formatting Track Loop
- If Register A equals the value held in Register B, the Z FLAG is set.
- If A < B/23060/, the CARRY FLAG will be set.
- if A >= B/23060/, the NO CARRY FLAG will be set.
5499H – Set up Track Formatting Pattern in RAM
This next routine sets up the following fixed pattern in RAM:
5F00: FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00
5F10: 00 00 00 00 FE 00 00 00 01 F7 FF FF FF FF FF FF
5F20: FF FF FF FF FF FF 00 00 00 00 00 00 nn E5 E5 E5
5F30: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
...
6010: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
6020: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 F7 FF FF
6030: FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00
6040: FE 00 00 05 01 F7 FF FF FF FF FF FF FF FF FF FF
6050: FF FF 00 00 00 00 00 00 FB E5 E5 E5 E5 E5 E5 E5
6060: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
...
6140: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
6150: E5 E5 E5 E5 E5 E5 E5 E5 E5 F7 FF FF FF FF FF FF
6160: FF FF FF FF FF FF 00 00 00 00 00 00 FE 00 00 01
6170: 01 F7 FF FF FF FF FF FF FF FF FF FF FF FF 00 00
6180: 00 00 00 00 FB E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
6190: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
...
6270: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
6280: E5 E5 E5 E5 E5 F7 FF FF FF FF FF FF FF FF FF FF
6290: FF FF 00 00 00 00 00 00 FE 00 00 06 01 F7 FF FF
62A0: FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00
62B0: FB E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
...
63A0: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
63B0: E5 F7 FF FF FF FF FF FF FF FF FF FF FF FF 00 00
63C0: 00 00 00 00 FE 00 00 02 01 F7 FF FF FF FF FF FF
63D0: FF FF FF FF FF FF 00 00 00 00 00 00 FB E5 E5 E5
63E0: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
...
64C0: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
64D0: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 F7 FF FF
64E0: FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00
64F0: FE 00 00 07 01 F7 FF FF FF FF FF FF FF FF FF FF
6500: FF FF 00 00 00 00 00 00 FB E5 E5 E5 E5 E5 E5 E5
6500: FF FF 00 00 00 00 00 00 FB E5 E5 E5 E5 E5 E5 E5
6510: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
...
65F0: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
6600: E5 E5 E5 E5 E5 E5 E5 E5 E5 F7 FF FF FF FF FF FF
6600: E5 E5 E5 E5 E5 E5 E5 E5 E5 F7 FF FF FF FF FF FF
6610: FF FF FF FF FF FF 00 00 00 00 00 00 FE 00 00 03
6620: 01 F7 FF FF FF FF FF FF FF FF FF FF FF FF 00 00
6630: 00 00 00 00 FB E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
...
6720: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
6730: E5 E5 E5 E5 E5 F7 FF FF FF FF FF FF FF FF FF FF
6740: FF FF 00 00 00 00 00 00 FE 00 00 08 01 F7 FF FF
6750: FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00
6760: FB E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
6770: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
...
6850: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
6860: E5 F7 FF FF FF FF FF FF FF FF FF FF FF FF 00 00
6870: 00 00 00 00 FE 00 00 04 01 F7 FF FF FF FF FF FF
6880: FF FF FF FF FF FF 00 00 00 00 00 00 FB E5 E5 E5
6890: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5
...
5502H – Continue Formatting Next Track
5513H
5514H
5515H
POP AF
PUSH AF
POP AF
551FH – Selects the designated drive, triggers a write track with the code from the above routine, point DE at the address of the floppy drive controller status register, and JUMP to 553BH.
NOTE: 37ECH is the Floppy Disk Controller’s Command Status Register
NOTE: 37EFH is the Floppy Disk Controller’s Data Register (i.e., the byte to be written/read from disk).
5532H
5533H
5534H
POP BC
PUSH BC
POP BC
5538H – Check that the drive is ready, and write the byte pointed at by BC to the diskette.
5546H – Jumped here from 5539H if the INDEX/BUSY status isn’t quite right to either declare “TRANSFER RATE TOO FAST,” “MOTOR FAST,” “MOTOR SLOW,” and HALT in those cases, or to just REturn.
If the disk WAS at Track 0 despite the issues, then we need to figure out if it was too fast or too slow and if neither, then this routine RETurns. To do this, various numbers are added together to see if the CARRY FLAG trips or not.
Throughout all this math, A, B, and C never change. DE takes on its initial value at 5555H with an EX DE, HL and then stays the same the entire routine as well. Only HL and the flags change.
If we are here, then there is still something wrong with the INDEX/BUSY timing, but it wasn’t because the motor was too slow …
556BH – Last Routine of FORMAT. This routine verifies the format, writes out the directory, and finished up.
We are done formatting, so now we need to display a CARRIAGE RETURN to move off of the “FORMATTING TRACK nn” overwriting message.
The next routine verifies the tracks.
While this can be a pass through, it is also the jump point if the byte in the in-RAM GAT was FFH
At this point, we have verified all tracks, now lets make a duplicate copy of the GAT into 5C60H.
Next, set the BOOT GAT entry to “Sectors 0-4 Used” by turning on Bit 0 of the first entry in the GAT; thus changing the FCH (completely empty) to FDH (sectors 0-4 in use).
Next, set the DIRECTORY GAT entry to “all granules on track used” (FFH).
NOTE: 4200H is the storage location for the [TAKEN FROM PAGE] System Sector Buffer Area
The next instructions move the BOOT/SYS FPDE entry to 5D00H and then send it to disk.
Top of a loop to ZERO out 5D00H-5DFFH
Now that 5D00H-5DFFH has been ZEROed out, and HL is back to 5D00H, let’s start filling that buffer.
The next instructions move the BOOT/SYS FPDE entry to 5D00H and then send it to disk.
The next instructions move the DIR/SYS FPDE entry to 5D00H and then send it to disk.
The next instructions clear the 32 bytes from 5D00H, and writes out 4 (tracked in E) blank FPDE/FXDE entries..
56ADH – Can be a pass through OR Jumped here if the drive is not doing what was desired. Will display “HIT ENTER TO CONTINUE” and then HALT the system if ENTER is hit.
NOTE: 3840H is the value held at Keyboard Row 7 – which is ENTER, CLEAR, BREAK, UP, DOWN, LEFT, RIGHT, SPACE.
56BDH – Subroutine to Put A8 or A9 into the OPCODE LD (HL),nnH at 56F7H, Save BC, send DE to the FDC Sector Register, Send a SEEK and a WRITE FBH or F8H, and JUMP to 5706H to write out some data.
56CBH – Display “CAN’T INITIALIZE SYSTEM INFORMATION”, prompt for an ENTER, and then HALT the system.
56D1H – Display “CAN’T FORMAT, DIRECTORY TRACK FLAWED!”, prompt for an ENTER, and then HALT the system.
56D7H – Routine to put the contents of Register A into the OPCODE LD (HL),nnH at 56F7H, Save BC, send DE to the FDC Sector Register, Send a SEEK and a WRITE FBH or F8H, and JUMP to 5706H to write out some data.
This is the SUBROUTINE call from the prior routine, but is also a pass through. If this was a subroutine, the Z/NZ flag is important.
NOTE: 37ECH is the Floppy Disk Controller’s Command Status Register.
POP AF
PUSH AF
POP AF
POP BC
PUSH BC
POP BC
5703H – Routine to, on entry, test Bit 0 and if it is 0 JUMP to 5711 to isolate bits 2-6 at (HL), POP DE, and either exit the loop vis a RET then or write a bunch of stuff to the disk.
5711H – Continuation of the routine at 5703H by isolating bits 2-6 of (HL), POPping DE, and RETurning if those bits were all 0. If not, put a D0H at (HL) and RETurn.
5719H – Displays the message pointed to by Register Pair HL and then puts a FFH into the in-RAM GAT at 5Cnn (nn = the contents of Register D) before JUMPing to 55BDH.
5726H – SUBROUTINE to Set Registers C and B to the ASCII Number corresponding to Register A (Tens Digit in ASCII to C and Ones Digit in ASCII to B).
5733H – SUBroutine to parse a memory buffer pointed to by Register Pair HL and accumulate the number into Register E.
- If Register A equals 0, the Z FLAG is set.
- If A < 0, the CARRY FLAG will be set.
- if A >= 0, the NO CARRY FLAG will be set.
- If Register A equals :, the Z FLAG is set.
- If A < :, the CARRY FLAG will be set.
- if A >= :, the NO CARRY FLAG will be set.
If we are here, then A is an ASCII character from “0” through “9”.
5749H – Set C = FFH and then do ‘put the value held in Register C into (HL) and then BUMP HL by 1’ Register B times.
574BH – Do ‘put the value held in Register C into (HL) and then BUMP HL by 1’ Register B times.
5751H – Put C into (HL) and then BUMP HL by 1.
5754H – Subroutine to send a RESTORE/LOAD HEAD to the Floppy Drive and then keep checking the floppy drive controller status until the drive is not BUSY.
POP AF
PUSH AF
POP AF
5767H – Send a nnH to the disk drive select latch address and RETurn.
576DH – STORAGE LOCATION
5780H-579FH – Literal Code for the BOOT/SYS entry in the FPDE/FXDE area … Sector 1 Bytes 00-1F
57A0H-57BFH – Literal Code for the DIR/SYS entry in the FPDE/FXDE area … Sector 2 Bytes 00-1F
57C0H – MESSAGE STORAGE AREA
5B9CH – Display “DISKETTE CONTAINS DATA, FORMAT OR NOT?” message and get a “Y” or “N” from the user. Jump to 56B0H for a NO and RETurn for a YES.
NOTE: 0040H is the Model I ROM routine to wait for keyboard input of B characters and put store the character at (HL).