TRS-80 DOS - TRSDOS v2.3 for the Model I - BOOT/SYS Disassembled
Page Customization
Page Index
BOOT/SYS
Other Navigation
Introduction:
TRSDOS 2.3 BOOT/SYS Disassembly - Bootstrap Loader (Model I)
BOOT/SYS is the 256-byte boot sector of TRSDOS v2.3 for the TRS-80 Model I. It resides on Track 0, Sector 0 of the system disk and is loaded into memory at 4200H by the Level II ROM bootstrap routine (located at 06B6H-06CBH in the ROM). The ROM reads this single sector using the FDC at 37ECH, then jumps to 4203H (the entry point embedded in the CP instruction at 4201H) to transfer control to the boot code.
The sole purpose of BOOT/SYS is to locate SYS0/SYS on the disk, load it into memory, and transfer control to it. It accomplishes this in three stages:
1. It reads the directory track (Track 17) to find the directory entry for SYS0/SYS (which must be at directory entry position 4 on the directory track). If the directory entry's "active" flag (bit 4) is not set, the boot displays "NO SYSTEM" and halts.
2. If SYS0/SYS is found, it extracts the starting track/sector and granule count from the directory entry, then reads SYS0/SYS sector by sector into a buffer at 4D00H. The data is decompressed using a simple inline decompression scheme with three record types: type 01H (load address + data block), type 02H (repeat byte fill), and type 00H (end-of-file with execution address).
3. Once all data is loaded and decompressed, the boot code jumps to the execution address specified in the EOF record, transferring control to SYS0/SYS which then initializes the full DOS.
The boot sector also contains two error messages ("NO SYSTEM" and "DISK ERROR") and a low-level disk sector read routine that communicates directly with the WD1771 FDC chip at the hardware I/O addresses 37E1H-37EFH.
Memory Map
| Address Range | Purpose |
|---|---|
| 4200H-4200H (1 byte) | BOOT/SYS flag byte (NOP). Tested by BACKUP to identify boot sector |
| 4201H-4202H (2 bytes) | CP 11H instruction - also embeds directory track number (11H) at 4202H |
| 4203H-42E1H (223 bytes) | Executable boot code (entry point at 4203H) |
| 42E2H-42E4H (3 bytes) | Clear screen control sequence (1CH 1FH 03H) |
| 42E5H-42F0H (12 bytes) | "NO SYSTEM" error message |
| 42F1H-42FDH (13 bytes) | "DISK ERROR" error message |
| 42FEH-42FFH (2 bytes) | Boot sector tail bytes |
Key Routines
| Address | Purpose |
|---|---|
| 4203H | Main Entry Point Initialize stack, clear screen, and read directory |
| 4275H | Get Next Decompression Byte Reads from sector buffer and auto-advances sector |
| 429AH | Display Message Outputs characters via ROM 0033H until 03H or 0DH terminator |
| 42AAH | Read Sector Wrapper Sets up FDC registers and calls 42B2H |
| 42B2H | Low-Level FDC Read Sends SEEK then READ SECTOR commands to WD1771 |
Decompression Format
SYS0/SYS is stored on disk in a compressed format. The decompression loop at 423EH reads a type byte, then processes according to the type:
| Type | Format | Action |
|---|---|---|
| 01H | 01 count-lo count-hi addr-lo addr-hi data... | Load a block of count bytes to addr |
| 02H | 02 count byte | Repeat byte into memory count times (fill) |
| 00H | 00 xx addr-lo addr-hi | End of file - jump to addr (execution address) |
Disassembly:
4200H-4228H - Initialize, Clear Screen, Read Directory, and Validate SYS0/SYS
The boot code entry point. The ROM bootstrap jumps to 4203H after loading this sector from Track 0, Sector 0 into 4200H. The code disables interrupts, sets up the stack, clears the screen, selects Drive 0, reads the directory entry for SYS0/SYS from the directory track, and checks whether the file exists. If SYS0/SYS is not found, it branches to the "NO SYSTEM" error handler.
This NOP serves as a marker byte. The BACKUP utility checks this byte to identify the boot sector. A value of 00H (NOP) indicates a valid TRSDOS boot sector.
Disable maskable interrupts. The ROM bootstrap routine jumps here after loading this sector into 4200H. Interrupts must remain disabled during the entire boot process because no interrupt service routine has been set up yet.
422AH-4274H - Extract SYS0/SYS Location and Decompress Into Memory
With SYS0/SYS confirmed in the directory, this section extracts the file's starting track, sector, and granule count from the directory entry at 4D00H, then enters the decompression loop. SYS0/SYS is stored on disk in a compressed format with three record types: type 01H (data block with load address), type 02H (fill/repeat), and type 00H (EOF with execution address). The alternate register set (EXX) is used to track the current disk position (D'=track, E'=sector) and buffer pointer (BC'=4DFFH, the last byte of the sector buffer).
Granule-to-Track/Sector Conversion
The high byte (H') contains the sector count information encoded as: bits 5-7 = number of sectors used in this granule minus 1, and bits 0-4 hold additional flags. The following sequence extracts the starting sector number. TRSDOS 2.3 uses 5 sectors per granule (sectors 0-4 on each track). The conversion rotates the high bits down and multiplies to compute the starting sector within the track.
Main Decompression Loop
The decompression loop reads a type byte, then dispatches based on the value: type 01H = data block (with load address and byte count), type 02H = repeat fill, type 00H = EOF with execution address. Each iteration reads one complete record from the compressed stream.
GOSUB to 4275H to get the next byte from the compressed data stream. On return, Register A contains the record type byte: 01H for a data block, 02H for a fill block, or 00H for end-of-file.
Type 01H - Data Block Handler
Format: 01 count addr-lo addr-hi data... Reads a 2-byte count (B = length in pages, then decremented to get exact count), a 2-byte load address (HL), then copies that many bytes from the compressed stream to the specified address.
Type 02H and 00H Handler
Reached when the record type was not 01H. Register A was decremented once at 4241H. If the original type was 02H, A is now 1. A second DEC at 425BH tests for type 02H (fill block). If neither 01H nor 02H, it must be 00H (EOF).
Type 02H - Repeat Fill Handler
Format: 02 count byte - reads count bytes of the same value and discards them (this appears to be a skip/spacer record that advances the read position without writing to RAM).
Type 00H - End of File / Transfer Control
Format: 00 xx addr-lo addr-hi - reads one throwaway byte, then reads a 2-byte execution address and jumps to it. This terminates the boot process and transfers control to SYS0/SYS.
Jump to the address in HL. This transfers control from the boot sector to SYS0/SYS, which has now been loaded and decompressed into its final memory location. The boot process is complete. SYS0/SYS will initialize the rest of the DOS from this point forward.
4275H-428FH - Get Next Decompression Byte (Sector Buffer Reader)
This routine reads the next byte from the decompressed data stream. It uses the alternate register set to track the current position within the 256-byte sector buffer at 4D00H (via BC') and the current disk position (D'=track, E'=sector). When the buffer is exhausted (C' wraps from FFH to 00H), a new sector is automatically read from disk. The sector numbering advances from 0 through 9 (TRSDOS 2.3 uses 10 sectors per track, numbered 0-9), then wraps to sector 0 of the next track.
Buffer Exhausted - Read Next Sector
C' wrapped to 00H, meaning all 256 bytes of the current sector have been consumed. A new sector must be read from disk. The current track (D') and sector (E') are used, then sector is advanced.
4290H-4299H - Error Display and Halt
Error handler: displays the appropriate error message ("NO SYSTEM" or "DISK ERROR") and halts the CPU. Entry point 4290H is for disk errors (loads the "DISK ERROR" message address). Entry point 4293H is a shared path that can display any message whose address is already in HL.
Halt the CPU. Since interrupts were disabled at 4203H (DI), the HALT instruction will stop the processor permanently. The only recovery is a hardware reset or power cycle.
429AH-42A9H - Display Message Routine
Outputs a string of characters to the screen using the ROM character output routine at 0033H. The string starts at the address in HL and continues until either an ETX (03H) terminator is found (which is not displayed) or a carriage return (0DH) is displayed and then the routine returns.
Fetch the next character from the message string at (HL) into Register A.
42AAH-42E1H - Disk Sector Read Routine
Reads a single 256-byte sector from disk into memory. On entry: D=track, E=sector, BC=destination buffer address. The routine first calls the low-level FDC handler at 42B2H. If the read fails, it restores BC from the stack and retries. The low-level handler at 42B2H sends a SEEK command (1BH) to the WD1771 FDC to position the head to the correct track, waits for the seek to complete, then sends a READ SECTOR command (88H) and transfers the data byte-by-byte from the FDC data register at 37EFH into the buffer. On return, Z FLAG set indicates success.
Low-Level FDC Read Routine
This routine communicates directly with the WD1771 FDC chip on the Model I. The FDC registers are memory-mapped at: 37ECH = Command/Status register, 37EDH = Track register, 37EEH = Sector register, 37EFH = Data register. The sequence is: (1) write the target track and sector to the FDC, (2) send a SEEK command (1BH) and wait for completion, (3) send a READ SECTOR command (88H), (4) poll for DRQ (Data Request) and transfer each byte from 37EFH to the buffer.
| 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 Bit 7-4: Command Code (0001) h: 1=Enable Head Load/Settle, 0=No delay V: 0=No verification r1, r0: 11=15ms stepping rate | |
SEEK Wait Loop
The PUSH AF / POP AF pairs provide a brief delay (approximately 40 T-states each pair) to give the FDC time to process the SEEK command before the status register is polled. The RRCA instruction checks bit 0 of the status (Busy flag) - while bit 0 is set, the FDC is still seeking.
Read the FDC Status register at 37ECH (pointed to by HL) into Register A.
| 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 Bit 7-5: Read Command (100) m: 0=Single Record b: 1=IBM format E: 0=Assume Head Already Engaged, no Delay Remainder: Unused (00) | |
Sector Data Transfer Loop
This tight loop reads 256 bytes from the FDC into the buffer. It polls the FDC Status register for DRQ (bit 1) to determine when a new data byte is available. Each byte is read from the Data register (37EFH) and stored to the buffer at (BC), then BC is incremented. After all bytes are transferred, the final status is checked for errors.
Read Complete - Check Final Status
The FDC Busy flag has cleared, indicating the READ SECTOR operation is complete. The final status register value is checked for error bits.
| 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 Bit 7-4: Command Code (1101) I3: 0=No Immediate Interrupt I2: 0=No Index Pulse Interrupt I1: 0=No Ready-to-Not-Ready I0: 0=No Not-Ready-to-Ready All interrupt flags clear = Terminate without interrupt | |
42E2H-42FFH - Messages and Boot Sector Tail
This area contains the clear-screen control sequence, the two error message strings, and the final bytes of the 256-byte boot sector. The messages are plain ASCII preceded by control bytes that are sent directly to the ROM video driver at 0033H.
Character codes to CLS
"NO SYSTEM" error message.
"DISK ERROR" error message.