TRS-80 DOS - NEWDOS/80 v2.0 for the Model III - BOOT/SYS Disassembled
Page Customization
Page Index
BOOT/SYS
Other Navigation
Introduction/Summary
NEWDOS/80 v2.0 BOOT/SYS Disassembly - The Boot Sector and the System Data Sector (Model III)
BOOT/SYS is the first file of every NEWDOS/80 diskette: the first five sectors of track 0 (one granule, 1,280 bytes). It is not a load module. Sector 0 is the boot sector, sector 1 is a copy of it, sector 2 is the system data sector (the PDRIVE records and the SYSTEM options), and sectors 3 and 4 are unused.
When the computer is reset with a diskette in drive 0, the ROM reads track 0, sector 1 into 4300H-43FFH and jumps to 4300H. The boot sector code then reads SYS0/SYS, which starts at sector 5, sector by sector into a buffer at 5100H-51FFH, copies each load block to its address, and jumps to SYS0/SYS's reset code at 4D01H once it finds A5H at the transfer address 4D00H. A record type of 20H or more, or no A5H, displays NO SYS; a sector that cannot be read in 10 tries displays ERROR. Both stop the computer until RESET is pressed.
The page shows every byte of the file once: sector 0 at the addresses where it runs (4300H-43FFH), sectors 1-4 by their offsets in the file (0100H-04FFH).
How a Sector Is Read
The code works the floppy disk controller through its ports and ends every read on a non maskable interrupt, as the ROM does:
| Step | What the code does |
|---|---|
| Select | Port F4H = 81H (drive 0, double density) or 91H (side 1), after the controller is not busy (4357H) |
| Seek | Track to port F3H (data register), sector to port F2H, command 1BH to port F0H, wait until not busy (435DH) |
| NMI | Status read once to clear the interrupt request, Stack Pointer saved in the operand 43A6H, NMI vector 4049H = JP 43A2H, port E4H = C0H (4370H) |
| Read | Command 88H; the first byte is polled (data request, bit 1 of port F0H), the other 255 are taken with INI while port F4H bit 6 makes the CPU wait for each one (4385H) |
| End | JR 43A0H loops until the controller's interrupt request causes the NMI; 43A2H turns the NMI off, puts the stack back, tests the status (AND FCH), sends Force Interrupt D0H and advances to the next sector or restores the head (0BH) and tries again |
The main register set does the loading (Register Pair HL = the buffer pointer, Register Pair DE = the load address, Register C = the bytes left in the record, Register B = the record type); the alternate set does the reading (Register Pair DE' = track and sector, Register B' = tries left, Register L' = the select byte).
The Five Sectors
| Sector | Contents |
|---|---|
| 0 | The boot sector, 4300H. Bytes 0-1 are 00H FEH, byte 2 is the directory lump (11H), bytes FDH-FFH are bytes +6, +2 and +7 of drive 0's PDRIVE record, which SYS0/SYS's reset takes from the buffer at 4300H. |
| 1 | A copy of sector 0, 0100H. This is the one the ROM reads and runs. |
| 2 | The system data sector, 0200H: PDRIVE records for drives 0-9 (16 bytes each), number options at A0H-A9H and D0H-D1H, A5H at EFH, yes/no options at F0H-F9H. |
| 3-4 | Unused, 0300H: the format pattern 5BH. |
SYS6/SYS (FORMAT, COPY) writes sectors 0 and 1 from its own image of the boot sector, patching the first sector of SYS0/SYS (4304H), the select bytes (434BH, 4355H), the sectors per side and per track (4350H, 43B6H), the first sector of a track (43BBH), the directory lump (4302H) and bytes FDH-FFH for the destination drive. On this diskette drive 0 is double density, one sided, 40 tracks of 18 sectors numbered from 0.
Variables
Memory Outside BOOT/SYS
| Address Size | Contents |
|---|---|
| 4049H-404BH 3 bytes | NMI Vector The ROM jumps here on an NMI (through 0066H). The ROM leaves EDH 45H (RETN); 437CH-437EH store JP 43A2H for every sector read. SYS0/SYS takes it over later. |
| 41D6H-41DFH 10 bytes | Stack Below 41E0H, set at 4308H: the return address into the loader, Register Pairs DE and BC (434DH, 434EH) and the return addresses of 43D7H and 43E2H. |
| 5100H-51FFH 256 bytes | Sector Buffer Each sector of SYS0/SYS in turn (4389H); 4345H takes the bytes from it with Register Pair HL. SYS0/SYS loads its own bytes into 5100H-51EBH behind the bytes still to be read. |
| 4D00H 1 byte | SYS0/SYS Transfer Address Must hold A5H after loading (433AH); the boot sector then jumps to 4D01H. |
BOOT/SYS Data
| Address Size | Contents |
|---|---|
| 4302H 1 byte | Directory Lump Byte 2 of the boot sector, the operand of CP 11H: the lump where the directory starts. Read by SYS0/SYS (4898H) and SYS17/SYS, stored by SYS6/SYS. |
| 43E8H-43EFH 8 bytes | ERROR Message Clear screen, ERROR, 03H. |
| 43F0H-43F8H 9 bytes | NO SYS Message Clear screen, NO SYS, 03H. |
| 43F9H-43FCH 4 bytes | Not Used Not part of SYS6/SYS's boot sector image. |
| 43FDH-43FFH 3 bytes | Drive 0 PDRIVE Bytes +6, +2 and +7 of drive 0's PDRIVE record, read by SYS0/SYS's reset (4D37H, 4D41H). |
Operands Changed at Run Time or by FORMAT
| Address Size | Contents |
|---|---|
| 4305H-4306H 2 bytes | First Sector of SYS0/SYS Sector 05H and track 00H in the LD DE at 4304H; SYS6/SYS 6774H and 676CH add 1 for drives numbered from 1. |
| 434CH 1 byte | Select Byte, Side 0 81H: drive 0, double density (SYS6/SYS 6781H sets bit 7). |
| 4351H 1 byte | Sectors on One Side 12H (18) in the SUB at 4350H (SYS6/SYS 6793H). |
| 4356H 1 byte | Select Byte, Side 1 91H: drive 0, side 1, double density (SYS6/SYS 6786H sets bit 7). |
| 43A6H-43A7H 2 bytes | Saved Stack Pointer Stored by 4372H before each read, loaded by the LD SP at 43A5H in the NMI routine; 0000H in the file. |
| 43B7H 1 byte | Sectors per Track 12H (18) in the SUB at 43B6H (SYS6/SYS 678DH). |
| 43BCH 1 byte | First Sector of a Track 00H in the LD E at 43BBH (SYS6/SYS 6778H stores 01H for sectors numbered from 1). |
Ports
| Address | Contents |
|---|---|
| E4H | NMI mask: C0H (controller interrupt request and motor time-out) for the read at 4383H, 00H in the NMI routine at 43A3H. |
| F0H | Controller command (1BH Seek, 88H Read Sector, D0H Force Interrupt, 0BH Restore) and status (busy bit 0, data request bit 1, errors bits 7-2). |
| F2H, F3H | Controller sector register (4361H) and data register (track for the seek at 435EH, the sector's bytes through INI). |
| F4H | Drive select: 81H or 91H, with bit 6 (40H) for wait states during the transfer. |
Outside Routines
| Address | Contents |
|---|---|
| 0033H | ROM: display the character in Register A (43D2H). |
| 4D01H | SYS0/SYS: its reset code, entered through the RET Z at 433EH. |
Disassembly
4300H - Boot Sector: Entry
The ROM's bootstrap reads track 0, sector 1 of the diskette in drive 0 (double density, select byte 81H) into 4300H-43FFH through its own NMI routine and jumps here from 3513H, when its status test (IN A,(F0H) / AND 1CH at 350EH-3511H) gave 00H. Sector 1 of BOOT/SYS is a copy of sector 0, so the code below is what runs. On entry Register A = 00H, port E4H = 00H (no NMI) and the NMI vector 4049H-404AH holds EDH 45H (RETN), stored by the ROM at 3505H-3508H.
Load Register Pair DE with 0005H: Register D = track 0 (the operand byte at 4306H) and Register E = sector 5 (4305H), the first sector of SYS0/SYS, the sector after BOOT/SYS's five sectors (one granule). SYS6/SYS FORMAT adds 1 to the track at 676CH when the drive's tracks are numbered from 1 and 1 to the sector at 6774H when its sectors are numbered from 1.
430EH - Load SYS0/SYS Record by Record
SYS0/SYS is a load module: records of a type byte, a length byte and the data. Type 01H is a load block (two address bytes, then the length minus 2 data bytes; a length of 02H gives 256), type 02H is the transfer address (two bytes); types 00H and 03H-1FH are passed over; a type of 20H or more means the file is not a load module. The bytes come one at a time from the sector buffer at 5100H-51FFH through 4345H, which reads the next sector when the buffer is used up.
4321H - Type 01H: Copy a Load Block
Register E holds the low byte of the load address and Register C the record length. The block's data bytes are copied one by one from the buffer to their load address.
4333H - Not Type 01H: Transfer Address or Pass Over
Reached from 431FH with Register B = the record type minus 1, Register C = the record length and Register E = the first byte after the length.
433FH - NO SYS: SYS0/SYS Is Not a Load Module
Reached from 4314H (a record type of 20H or more) or by falling through from 433EH (no A5H at the transfer address).
4345H - Fetch the Next Byte of SYS0/SYS
Returns in Register A the next byte of the sector buffer (5100H-51FFH) at Register Pair HL. When the buffer is used up it falls into 4348H, which reads the next sector first.
4348H - Read the Next Sector of SYS0/SYS into 5100H
Reads the sector named by the alternate Register Pair DE' (Register D = track, Register E = sector) of drive 0 into 5100H-51FFH, with up to 10 tries, and advances DE' to the following sector. The transfer ends on the NMI that the controller's interrupt request causes at the end of the command (43A2H). Returns with the main register set, Register Pair HL = 5100H and Register A = the first byte of the sector.
Load Register L with 81H, the byte for port F4H that selects drive 0 (bit 0), side 0 (bit 4 clear), double density (bit 7). The operand at 434CH is 01H in SYS6/SYS's boot sector image; FORMAT sets its bit 7 (SYS6/SYS 6781H) for a double density drive. 43C7H loops back here for another try.
SUBtract 12H (18) from Register A (the sector number). The operand at 4351H is the number of sectors on one side of a track, stored by FORMAT (SYS6/SYS 6793H: the sectors per track, halved for a two sided drive); on this diskette it is 18, the whole track. If the sector number is below it the CARRY FLAG is set.
Load Register L with 91H, the port F4H byte for drive 0, side 1 (bit 4), double density (bit 7). The operand at 4356H is 11H in SYS6/SYS's image; FORMAT sets its bit 7 (SYS6/SYS 6786H) for a double density drive.
| Port F4H: Drive Select and Options | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| D | W | P | S | d3 | d2 | d1 | d0 | D (bit 7): 1 = double density (MFM), 0 = single density (FM) W (bit 6): 1 = wait states while the controller has no data ready P (bit 5): 1 = write precompensation S (bit 4): 0 = side 0, 1 = side 1 d3-d0: one bit per drive, 1 = selected | |
| 1793 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 at the start V = 0: no verify r1 r0 = 11: stepping rate 30 ms; the code ORs in the drive's rate (6 ms, 12 ms, 20 ms or 30 ms) | |
| Port E4H (NMI Mask): C0H (11000000) | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | Bit 7 = 1: NMI from the controller's interrupt request (INTRQ) enabled Bit 6 = 1: NMI from the drive motor time-out enabled Bits 5-0: not used | |
| 1793 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 S = 1: side to compare (used only when C = 1) E = 0: no 15 ms delay C = 0: side compare off | |
43A2H - End of the Read: the NMI Routine
Entered through the NMI vector 4049H (JP 43A2H) when the controller ends the Read Sector command (or the drive motor times out). The NMI's return address on the stack is dropped by the LD SP below.
| Port E4H (NMI Mask): 00H (00000000) | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Bit 7 = 0: NMI from INTRQ disabled Bit 6 = 0: NMI from the motor time-out disabled Bits 5-0: not used | |
Load the Stack Pointer with the value that 4372H stored at 43A6H (0000H in the file): the stack is back to Register Pairs BC and DE saved at 434DH/434EH, above them the return address into the loader. The NMI's return address is dropped.
| 1793 Status after Read/Write Sector, AND FCH | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| N | W | R | F | C | L | 0 | 0 | N: 1 = not ready W: 1 = write protected (write) R: 1 = deleted data mark F8H (read), write fault (write) F: 1 = record not found C: 1 = CRC error L: 1 = lost data Bits 1-0 (data request, busy): removed by AND FCH | |
| 1793 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 without an interrupt | |
SUBtract 12H (18) from Register A (the next sector number). The operand at 43B7H is the number of sectors per track (both sides), stored by FORMAT (SYS6/SYS 678DH). The Z FLAG is set when the track is used up.
Load Register E with 00H, the first sector of the new track. FORMAT (SYS6/SYS 6778H) stores 01H in the operand at 43BCH when the drive's sectors are numbered from 1.
43C0H - A Failed Try: Restore and Retry
Register B = the tries left, Register Pair DE = track and sector (the main set is still the alternate one of the loader).
| 1793 FDC Command: 0BH (00001011) | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | Command=Restore (bits 7-4 = 0000) h = 1: head load at the start V = 0: no verify r1 r0 = 11: stepping rate 30 ms; the code ORs in the drive's rate (6 ms, 12 ms, 20 ms or 30 ms) | |
43CCH - Display a Message and Stop
Entered with Register Pair HL pointing to a message (43E8H ERROR or 43F0H NO SYS). The characters are displayed through the ROM up to the 03H that ends the message, and the computer then loops on that byte without end; the user must press RESET.
43D7H - Wait Until the Controller Is Not Busy
Returns with Register A = the controller's status (port F0H) once bit 0 (busy) is clear.
43E2H - Short Delay
A fixed delay of eight passes through a DEC/JR loop. Register A is the counter and returns 00H with the Z FLAG; no other register and no memory is touched.
43E8H - Messages and the Rest of the Boot Sector (Data)
The two messages displayed by 43CCH, four bytes that are not part of the boot sector image, and three bytes that FORMAT fills in from drive 0's PDRIVE record for SYS0/SYS's reset.
Sector 1: The Copy of the Boot Sector the ROM Runs
The second sector of BOOT/SYS (track 0, sector 1) holds exactly the same 256 bytes as sector 0. SYS6/SYS writes its boot sector image as both sector 0 and sector 1 of every diskette it formats (its 67ACH-67B6H). The ROM reads sector 1 into 4300H-43FFH (it sends 01H to the sector register at 34E3H-34E5H) and runs it, so the instructions documented for sector 0 above are the ones that run; SYS0/SYS reads sector 0 (its 48B6H) when it needs byte 2, the directory lump. The rows show the file offsets 0100H-01FFH; each row's bytes run at 4300H plus the offset within the sector.
Sector 2: The System Data Sector (Data)
The third sector of BOOT/SYS (track 0, sector 2) holds the system data of the diskette: ten 16-byte PDRIVE records (drives 0-9), the number options at A0H-A9H and D0H-D1H, the validity byte EFH and the yes/no options at F0H-F9H. SYS0/SYS's reset reads it into its buffer at 4300H through the DOS FCB at 4480H (NEXT = sector 2, its 4D47H-4D4AH) and copies what it needs; SYS16/SYS (PDRIVE, FCB 510EH) and SYS17/SYS (SYSTEM, FCB 4F16H) read, change and rewrite it; SYS6/SYS FORMAT writes it (666DH). The rows show the file offsets 0200H-02FFH; in the buffer each byte is at 4300H plus its offset within the sector (byte A0H at 43A0H).
Sectors 3 and 4: Unused (Data)
BOOT/SYS is five sectors long because it fills the first granule of the diskette (five sectors). Only sectors 0-2 hold data: sectors 3 and 4 keep the pattern FORMAT writes into the data field of every double density sector (5BH, SYS6/SYS format table line 2 at 6CF5H), since nothing writes them afterwards.