TRS-80 DOS - TRSDOS v2.3 for the Model I - BOOT/SYS Disassembled
Page Customization
Page Index
BOOT/SYS
Other Navigation
Introduction/Summary
TRSDOS v2.3 BOOT/SYS Disassembly - The Boot Sector (Model I)
BOOT/SYS is the file that holds track 0, sectors 0-4 of a TRSDOS 2.3 diskette. Only its first sector matters: when the computer is started or reset, the ROM reads track 0, sector 0 of drive 0 into 4200H-42FFH and jumps to 4200H. That sector clears the screen, finds the directory entry of SYS0/SYS, loads SYS0/SYS and jumps to its transfer address, which starts TRSDOS. When SYS0/SYS is not on the diskette it shows NO SYSTEM; when a sector cannot be read, DISK ERROR. Byte 2 of the sector is the diskette's directory track, which SYS0/SYS also reads (4B35H).
The file is 1,280 bytes, five sectors of 256, with no load records: it is the image of the sectors themselves. Sector 0 is shown at 4200H-42FFH, where it runs. Sectors 1-4 are not loaded or used by anything; their rows show the offset of each byte in the file (0100H-04FFH). Every byte of the file is on one row, checked against S:\1\BOOT.SYS and its listing.
Memory Map
| Address Range | Use |
|---|---|
| 37E1H 1 byte | The drive select latch: 01H selects drive 0 (420FH, 427CH). |
| 37ECH-37EFH 4 bytes | The floppy disk controller: command and status (37ECH), track (37EDH), sector (37EEH), data (37EFH). |
| 41FCH stack top | The Stack Pointer set at 4204H. |
| 4200H-4274H 117 bytes | The boot code: clear the screen, read the SYS0/SYS entry, load SYS0/SYS and jump to it. |
| 4275H-428FH 27 bytes | Fetch the next byte of SYS0/SYS, reading the next sector when the buffer is used up. |
| 4290H-4299H 10 bytes | Show DISK ERROR or NO SYSTEM, wait for ENTER and halt. |
| 429AH-42A9H 16 bytes | Display text up to 0DH or 03H. |
| 42AAH-42E1H 56 bytes | Read a sector: SEEK, READ SECTOR, two tries. |
| 42E2H-42FFH 30 bytes | The screen clear, NO SYSTEM, DISK ERROR, and two bytes not used. |
| 4D00H-4DFFH 256 bytes | The buffer: directory sector 4, then each sector of SYS0/SYS in turn. |
| File 0100H-04FFH 1,024 bytes | Sectors 1-4 of BOOT/SYS, never loaded. |
How the Boot Works
The code disables interrupts, sets the Stack Pointer to 41FCH and clears the screen (1CH cursor to the top left, 1FH erase to the end). It selects drive 0 and reads sector 4 of the directory track (byte 2 of this sector, 11H here) into 4D00H. Entry 0 of directory sector 4 is locator 02H, the entry of SYS0/SYS; when bit 4 of its first byte is clear the entry is not in use and NO SYSTEM is shown.
Otherwise bytes 16H-17H of the entry, the first extent, give the track (byte 16H) and the first granule on it (bits 5-7 of byte 17H); the first sector is the granule number times five. From there sectors are read one after the other into 4D00H, rolling over to sector 0 of the next track after sector 9; the other extents of the entry are not looked at. The bytes are taken as load records: type 01H stores its data at its load address (its length byte counts the two address bytes, so 02H gives no data, 00H gives 254 bytes and 01H gives 255), type 02H gives the transfer address, which the code jumps to with interrupts still disabled, and any other type is skipped by its length byte (00H = 256). Before each sector the drive select latch is written again.
The read routine seeks to the track (1BH), reads the sector (88H), checks the status with AND 5CH and tries a second time when that fails. A sector that cannot be read either time shows DISK ERROR. Both messages select 32 characters per line (17H) and give 40 spaces (E8H) before the text; the code then waits for a line through the ROM's line input (0040H) and executes HALT, so only RESET goes on.
Copies of the Boot Sector
- FORMAT/CMD carries its own copy at 5E00H, runs it at 4200H for its display and read routines, and writes it to track 0, sector 0 of the new diskette with the directory track it chose in byte 2. Its copy differs from this sector in byte 7DH as well: B6H there, so 427CH in that copy stores to 37B6H instead of the drive select latch. A diskette fresh from FORMAT/CMD has no SYS0/SYS entry, so its boot stops at NO SYSTEM before that store. Byte FFH is not in FORMAT's file.
- BACKUP/CMD copies track 0 of the source with the other tracks that hold data. On one drive it checks that a source diskette's boot sector starts with 00H; it writes 76H (HALT) there on the destination while the copy runs, and puts the real first byte back at the end.
- SYS0/SYS's 4B35H reads track 0, sector 0 of a drive when a directory sector reads back with the normal data mark, and takes byte 2 as that drive's directory track.
Notes from the Code
- 4201H is CP 11H: it compares and changes only the flags, so its operand, byte 2 of the sector, is free to hold the directory track.
- SYS0/SYS is loaded from its first extent only, the sectors taken one after the other; a SYS0/SYS whose sectors were not consecutive from its first granule would load wrongly.
- The loader takes a load record length of 02H as no data bytes, where SYS0/SYS's own loader (4C6AH-4C7DH) takes it as 256.
- After NO SYSTEM or DISK ERROR the ROM's line input reads into the message bytes themselves, up to Register B characters (4DH or 4EH, left by the read), before HALT.
- Bytes FEH-FFH (EBH, 5FH) are not used, nor are sectors 1-4.
Variables
Variables and Registers Kept
| Address Range | Purpose |
|---|---|
| 4202H 1 byte | The directory track, 11H in this file (the operand of CP nn at 4201H), read at 4212H and by SYS0/SYS at 4B4AH. |
| 4D00H-4DFFH 256 bytes | The sector buffer (4218H, 427FH); the SYS0/SYS entry is at 4D00H-4D1FH while directory sector 4 is in it. |
| 4D16H-4D17H 2 bytes | The first extent of the SYS0/SYS entry: track, granule byte (422BH). |
| BC' 2 bytes | Alternate Register Pair: the buffer pointer, 4DFFH to start (423AH), counted on by 4276H. |
| DE' 2 bytes | Alternate Register Pair: Register D' = the track, Register E' = the sector of the next read (422EH, 4239H, 4285H-428CH). |
Disassembly
4200H - Sector 0: the Boot Code
When the computer is started or reset with a diskette in drive 0, the ROM reads track 0, sector 0 into 4200H-42FFH and jumps to 4200H. These 256 bytes are sector 0 of BOOT/SYS. The code clears the screen, reads the directory entry of SYS0/SYS (directory sector 4, entry 0), and loads SYS0/SYS from the first sector of its first extent, record by record, then jumps to its transfer address. Two routines here, 429AH (display text) and 42AAH (read a sector), serve the boot code only; the copy of this sector that FORMAT/CMD carries uses them as well.
GOSUB to 4275H to fetch the next byte of SYS0/SYS into Register A: the type of the next load record. 4252H, 4267H loop back here.
DECrement Register B (the count) by 1, for the high address byte the first time and for each data byte after it. 4259H loops back here.
GOSUB to 4275H to fetch a byte of the record into Register A; it is not used. 4265H loops back here.
DECrement Register B (the bytes left to skip) and LOOP BACK to 4262H until the record is passed.
4275H - Fetch the Next Byte of SYS0/SYS
Returns the next byte of the file in Register A. The read position is kept in the alternate registers: Register Pair BC' = the buffer pointer, Register D' = the track, Register E' = the sector. When the buffer is used up the next sector is read into 4D00H, and the sector number runs on to the next track after sector 9.
4290H - Show an Error and Halt
4290H shows DISK ERROR; 4293H shows the message at Register Pair HL (NO SYSTEM from 4228H). Then waits for ENTER and halts.
429AH - Display Text
Register Pair HL = the text. Shows each character through the ROM up to and including 0DH, or up to 03H without showing it, and returns with Register Pair HL unchanged.
Fetch the next character from (HL) (Register Pair HL = the text pointer) into Register A. 42A6H loops back here.
If the NZ FLAG is set, LOOP BACK to 429BH for the next character.
42AAH - Read a Sector
Register D = track, Register E = sector, Register Pair BC = the buffer. Seeks to the track and reads the sector, trying twice. Returns the Z FLAG when read, or the NZ FLAG with Register A = the status AND 5CH.
Store Register Pair DE into 37EEH-37EFH: Register E (the sector) into the sector register at 37EEH, Register D (the track) into the data register at 37EFH, the track for the SEEK. 42ABH calls here.
| 1771 FDC Command: 1BH (00011011) | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | Command=Seek (bits 7-4 = 0001) h = 1: head load and settle delay V = 0: no verify r1 r0 = 11: 15 ms stepping rate | |
Fetch the controller's status from (HL) (Register Pair HL = 37ECH) into Register A. 42C1H loops back here.
| 1771 FDC Command: 88H (10001000) | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | Command=Read Sector (bits 7-5 = 100) m = 0: one sector b = 1: IBM sector length E = 0: no head load delay | |
Rotate Register A (the status) right, circularly: bit 0, BUSY, goes into the CARRY FLAG. 42D3H jumps here.
Fetch the controller's status from (HL) (Register Pair HL = 37ECH) into Register A. 42D8H jumps here.
| 1771 Status after Read Sector, AND 5CH | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | Bits kept by AND 5CH: 6: F9H or F8H data mark 4: record not found 3: CRC error 2: lost data Bit 5 (FAH or F8H mark) is not kept | |
| 1771 FDC Command: D0H (11010000) | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | Command=Force Interrupt (bits 7-4 = 1101) I3-I0 = 0000: end the command, no interrupt | |
42E2H - The Texts of the Boot Sector
The screen clear and the two messages, shown through 429AH.
Sector 1, File Bytes 0100H-01FFH
Sector 1 of BOOT/SYS on track 0. The directory entry of BOOT/SYS (written by FORMAT/CMD from 5780H) gives it granule 0, track 0 sectors 0-4, with the ending record number 5, so this sector is part of the file. The ROM loads only sector 0, the boot code never reads this sector, and SYS0/SYS reads sector 0 of track 0 for its byte 2 (4B35H) but not this one. The bytes have no use in TRSDOS 2.3; the rows show them with their offset in the file.
Sector 2, File Bytes 0200H-02FFH
Sector 2 of BOOT/SYS on track 0. The directory entry of BOOT/SYS (written by FORMAT/CMD from 5780H) gives it granule 0, track 0 sectors 0-4, with the ending record number 5, so this sector is part of the file. The ROM loads only sector 0, the boot code never reads this sector, and SYS0/SYS reads sector 0 of track 0 for its byte 2 (4B35H) but not this one. The bytes have no use in TRSDOS 2.3; the rows show them with their offset in the file.
Sector 3, File Bytes 0300H-03FFH
Sector 3 of BOOT/SYS on track 0. The directory entry of BOOT/SYS (written by FORMAT/CMD from 5780H) gives it granule 0, track 0 sectors 0-4, with the ending record number 5, so this sector is part of the file. The ROM loads only sector 0, the boot code never reads this sector, and SYS0/SYS reads sector 0 of track 0 for its byte 2 (4B35H) but not this one. The bytes have no use in TRSDOS 2.3; the rows show them with their offset in the file.
Sector 4, File Bytes 0400H-04FFH
Sector 4 of BOOT/SYS on track 0. The directory entry of BOOT/SYS (written by FORMAT/CMD from 5780H) gives it granule 0, track 0 sectors 0-4, with the ending record number 5, so this sector is part of the file. The ROM loads only sector 0, the boot code never reads this sector, and SYS0/SYS reads sector 0 of track 0 for its byte 2 (4B35H) but not this one. The bytes have no use in TRSDOS 2.3; the rows show them with their offset in the file.