TRS-80 DOS - PerCom MicroDOS Version 2.20 for the Model I - Boot Sector Disassembled

Page Customization

Introduction/Summary:

PerCom MicroDOS 2.20 Boot Sector Disassembly (Model I)

The PerCom MicroDOS boot sector is the first 256 bytes of any MicroDOS-formatted floppy. It lives at Track 0, Sector 0, and is loaded into RAM at 4200H by the Model I floppy boot ROM (the "boot strap" code). After loading the sector, the boot ROM transfers control to 4200H, and the code documented on this page takes over.

MicroDOS was written by James W. Stutsman and sold by PerCom Data Company in 1979 as a smaller, faster alternative to TRSDOS for users who wanted a Disk BASIC environment without the overhead of TRSDOS' supervisor calls and overlays. The entire resident operating system is just 4,608 bytes long; the boot sector that loads it is correspondingly compact, fitting the disk-detection signature, the MICRODOS / DISK ERROR / NO MICRODOS messages, the chained-sector reader, and the entire WD1771 FDC driver into 220 bytes of code plus 36 bytes of data, all within a single 256-byte sector.

The boot sector performs four jobs in sequence: (1) it sets up a stack at 41FCH and clears the screen via the Level II BASIC ROM CLS routine at 01C9H; (2) it reads Track 0 / Sector 1 into a buffer at 4300H and verifies that the eight-byte signature MICRODOS appears at offset 4 of the buffer (i.e., at 4304H); (3) on a successful match, it walks a chain of sectors starting at T0/S1, copying each one to the OS load area at 4400H, with each sector's first byte serving as a length-and-continuation marker; and (4) on the final sector, it transfers control to 4400H, which holds a JP 4727H to the MicroDOS resident entry point.

The chained-sector mechanism is the key trick. Each sector that participates in the OS load begins with a single byte: FFH means "I am a continuation; copy my remaining 255 bytes and read the next sector," and any other value N means "I am the final sector; copy my next N bytes, then jump to 4400H to start the OS." On this disk, the chain runs T0/S1 through T0/S9, then T1/S0 through T1/S8 (all with FFH markers), and ends at T1/S9 (with marker 12H = 18 bytes), giving a total OS image of 18 sectors x 255 bytes + 18 bytes = 4,608 bytes loaded contiguously at 4400H through 55FFH. What this means is that a straight review of the hex of the DMK is not relevant. The hex needs to be interleaved in sector order to present a disassemblable program.

If the MICRODOS signature is missing at 4304H, control falls through to the NO MICRODOS error path at 42A7H, which clears the screen, prints the message, and waits for any key before rebooting via JP 0000H. If any FDC operation returns an error status (bits 9CH set after a Read Sector, or bits 98H set after a Seek), control falls through to the DISK ERROR path at 42A2H, which displays the message and reboots in the same way.

The Boot Sector

The first bytes are a sector header table. 0000H-04B0H contains 2,901 entries of 3 bytes each. Each entry has the form TT SS FF where TT is the track number, SS is the sector number, and FF is a flags byte. Unused entries are filled with FFH FFH FFH. Order in the table is the on-disk order, which on a Model I single-density disk is the 5:1 interleave (S0, S5, S1, S6, S2, S7, S3, S8, S4, S9 within each track).

This MicroDOS disk uses 400 of the 2,901 available header entries (40 tracks x 10 sectors = 400 sectors), so file offsets 0000H-04AFH contain the active table and offsets 04B0H-21FEH are filled with FFH (free entries). The first ten entries describe the ten sectors of Track 0 in physical (interleaved) order:

File OffsetBytesMeaning
0000H-0002H00 00 00Track 0, Sector 0 (the boot sector), 256 bytes, single density, side 0. Sector data lives at file offset 2200H.
0003H-0005H00 05 00Track 0, Sector 5. Sector data lives at file offset 2300H.
0006H-0008H00 01 00Track 0, Sector 1 (first OS sector). Sector data lives at file offset 2400H.
0009H-000BH00 06 00Track 0, Sector 6. Sector data lives at file offset 2500H.
000CH-000EH00 02 00Track 0, Sector 2.
000FH-0011H00 07 00Track 0, Sector 7.
0012H-0014H00 03 00Track 0, Sector 3.
0015H-0017H00 08 00Track 0, Sector 8.
0018H-001AH00 04 00Track 0, Sector 4.
001BH-001DH00 09 00Track 0, Sector 9.

The 5:1 interleave (S0, S5, S1, S6, S2, S7, S3, S8, S4, S9) is the standard Model I single-density layout: by the time the WD1771 finishes reading sector S0 and the CPU finishes processing it, the disk has rotated to where sector S1 is just arriving at the head, so the system reads sectors in numerical order without ever waiting a full rotation. The same pattern repeats for tracks 1 through 39, occupying file offsets 001EH-04AFH (390 more entries x 3 bytes = 1,170 bytes).

Memory Map

The boot sector occupies the entirety of memory page 42H. The buffer at 4300H and the OS load area starting at 4400H are also reserved by the boot sector's design.

Address RangeLabelContents
4200H-42DCHBOOTBoot sector executable code (221 bytes). Loaded by the Model I boot ROM from Track 0 / Sector 0.
42DDHTRACKOne-byte storage holding the track number to be loaded next. Initialized to 00H so the first FDC seek targets Track 0; updated by the load loop at 4246H as the chain advances.
42DEHSECTOROne-byte storage holding the sector number to be loaded next. Initialized to 01H so the first read fetches Track 0 / Sector 1; updated by the load loop at 423FH as the chain advances and rolled back to 00H by 4243H when it passes 9.
42DFH-42EBHDISKERRThe DISK ERROR message, prefixed by 17H E8H (a HOME / cursor-position byte sequence) and terminated by 00H. Displayed when an FDC operation returns an error.
42ECH-42F0HNOMDOSThe lead-in of the NO MICRODOS message, prefixed by 17H E8H (HOME and a graphics marker) and continuing with the three characters NO followed by a space. Continues into the SIG label below, which holds the shared MICRODOS tail.
42F1H-42F8HSIGThe eight-byte ASCII string MICRODOS, used by the loader at 421DH to verify that the disk holds a real PerCom MicroDOS image, and simultaneously serving as the tail of the NO MICRODOS error message at 42ECH. The boot sector deliberately overlaps the signature and the error string to save eight bytes.
42F9H-One pad byte (00H), the NUL terminator for the NO MICRODOS error message.
42FAH-42FFH-The six-byte string $STEPH. This is the tail of an internal label name that ran past the end of the source's last DEFM directive when MicroDOS was assembled, and is meaningless at runtime; it is never read by any code.
4300H-43FFHBUFFER256-byte sector read buffer. Each FDC Read Sector call fills this buffer; the loader then either copies its contents (minus the first byte) into the OS load area or compares its contents against the MICRODOS signature.
4400H-55FFHMICRODOSThe resident MicroDOS operating system, 4,608 bytes total, loaded by the boot sector from the chain T0/S1 -> T0/S9 -> T1/S0 -> T1/S9. The first three bytes at 4400H are JP 4727H, the entry point that the boot sector's final JP NZ,4400H transfers to.
41FCH-41FFHSTACKInitial stack location set by 4202H. The boot sector's CALLs and PUSHes use this region; once MicroDOS takes over at 4727H, it relocates the stack to 41F8H.

Self-Modifying Workspace Variables

The boot sector keeps two single-byte variables in the data region following its code. Both are written by the load-loop advance code at 423FH-4246H and read by the FDC seek setup at 428BH-4294H.

AddressLabelSizeDescription
42DDHTRACK1Holds the track number passed to the WD1771 Seek command. Initialized in the source to 00H. Incremented by the INC (HL) at 4246H whenever the sector counter wraps from 9 to 0. After the load completes, it holds the track number of the final sector read (01H on a stock disk).
42DEHSECTOR1Holds the sector number written to the WD1771 Sector Register at 4294H. Initialized in the source to 01H. Incremented by the INC (HL) at 423FH on each loop iteration; reset to 00H by the LD (HL),0 at 4243H when it would otherwise reach 0AH. After the load completes, it holds the sector number of the final sector read (09H on a stock disk).

Major Routines

AddressLabelFunction / Entry-Exit
4200HBOOT Entry Point
Receives control from the Model I boot ROM. Sets up the stack, clears the screen, initializes the FDC pointer registers in the alternate set, reads Track 0 / Sector 1, verifies the MICRODOS signature, and falls through to the load loop.
422CHSector Load Loop
Top of the chained-sector copy loop. Examines the first byte of the buffer at 4300H to decide whether to copy 255 bytes and continue (FFH marker) or copy N bytes and jump to 4400H (any other marker). Loops via 424AH back to 422CH.
424CHRead Sector Routine
Calls 4275H to seek the head and select the drive, issues the WD1771 Read Sector command (88H), polls the FDC status register for Data Request flags, and transfers each data byte from 37EFH into the sector buffer. Returns with BC restored to 4300H. On error (FDC status bits 9CH set), jumps to 42A2H.
4275HSeek and Drive-Select Routine
Reads the FDC status, ensures drive 0 is selected at 37E1H, optionally calls the Level II BASIC ROM delay routine at 0060H if the drive is not yet ready, writes the track number from 42DDH into the FDC data register at 37EFH, writes the sector number from 42DEH into the sector register at 37EEH, and issues the WD1771 Seek command (17H). Returns with the Z flag set if the seek completed without error; otherwise the caller transfers control to the DISK ERROR path.
42A2HDisk Error Handler
Loads HL with a pointer to the DISK ERROR message at 42DFH and falls through to the message-display path at 42AAH.
42A7HNo-MicroDOS Handler
Loads HL with a pointer to the NO MICRODOS message at 42ECH and falls through to the message-display path at 42AAH.
42AAHMessage Display and Reboot
Calls the Level II BASIC ROM CLS routine at 01C9H, calls the print-string routine at 42D4H, calls the Level II BASIC ROM keyboard scan at 002BH in a loop until any key is pressed, and then jumps to 0000H to reboot the system.
42B9HSend FDC Command Routine
Saves the command byte (in Register A) on the stack, calls 42C7H to wait for the FDC to be ready, restores the command byte, and writes it through the alternate-register pointer in Register Pair DE' (37ECH) to the FDC command register. Polls bit 0 of the status register until the busy flag clears.
42C7HWait for FDC Not Busy
Loops, repeatedly writing 01H to the drive-select latch at 37E1H and reading the FDC status register, until bit 0 (busy) goes low. The repeated drive-select writes are necessary because the Model I drive-select latch is not a true latch: it is a one-shot driven by the system clock, and if the routine takes too long, the drive deselects itself.
42D4HPrint NUL-Terminated String
Walks the byte stream pointed at by Register Pair HL, calling the Level II BASIC ROM character-output routine at 0033H for each non-zero byte and returning when a zero byte is reached.

Cross-References and Analysis Notes

The boot sector's only external dependencies are four routines in the Level II BASIC ROM: 0033H (display character), 002BH (keyboard scan), 0060H (timing delay), and 01C9H (clear screen). Every other call and jump is internal to the boot sector itself.

The boot sector also depends on the Model I boot ROM's pre-conditions: when 4200H receives control, the boot ROM has just read Track 0 / Sector 0 from drive 0 using a Restore-then-Read-Sector sequence, so the WD1771 head is already on Track 0, drive 0 is already selected, and the FDC's busy flag is clear. The very first instruction (CP 0 at 4200H) does not assume any particular value in Register A; it is a one-byte placeholder so that the boot ROM's entry point lands cleanly on a Z80 instruction boundary, while preserving the option of testing A on entry should a future revision want to.

The sector load loop at 422CH-424AH is unusually compact for a Model I bootstrap. Compare TRSDOS 1.3, TRSDOS 2.3, NEWDOS/80, and LDOS, all of which reserve at least 512 bytes (two sectors) for their bootstrap because they need to fit a directory-aware loader; MicroDOS sidesteps the entire directory mechanism by chaining sectors physically across track boundaries with a one-byte length prefix in each sector. This restricts the resident OS image to a contiguous run starting at T0/S1, but it also means the bootstrap is correspondingly smaller.

Disassembly:

4200H - BOOT - Boot Entry Point and Stack Setup

The Model I floppy boot ROM has just loaded Track 0 / Sector 0 (the boot sector) into RAM at 4200H-42FFH and jumped here. On entry, drive 0 is selected, the WD1771 head is at Track 0, and the FDC busy flag is clear. The first job is to set up a stack, clear the screen, and stash the FDC register addresses in the alternate register set so they survive the upcoming string-comparison loop.

4200
CP 00H FE 00
Compare the value held in Register A against 00H. The result of this comparison is never read by the following code; the two bytes FE 00 serve as a placeholder at the boot ROM's transfer-of-control address so that future revisions can examine Register A on entry without having to relocate the code that follows. The Z and CARRY FLAGs are set as side effects but are immediately overwritten by the LD SP that follows.
4202
LD SP,41FCH 31 FC 41
Let Register Pair SP equal 41FCH, placing the stack four bytes below the start of the boot sector at 4200H. The stack will grow downward into the unused RAM at 41FBH and below. The four bytes between 41FCH and 41FFH are reserved for the first PUSH AF that the boot sector performs (at 42B9H during FDC command issue).
4205
CALL 01C9H CD C9 01
GOSUB to 01C9H.
NOTE: 01C9H is the Level II BASIC ROM CLS (Clear Screen) routine. It fills video RAM at 3C00H-3FFFH with 1024 spaces (20H) and homes the cursor to 3C00H. Uses Registers A, B, and HL.
4208
LD BC,4300H 01 00 43
Let Register Pair BC equal 4300H, the address of the 256-byte sector read buffer that lives just above the boot sector. The Read Sector routine at 424CH expects BC to point at this buffer when it is invoked.
420B
LD DE,37ECH 11 EC 37
Let Register Pair DE equal 37ECH, the memory-mapped address of the WD1771 Floppy Disk Controller's Command/Status register. Writes to DE issue commands; reads from DE return status. Storing this address in DE here lets the FDC routines access the status register with a single LD A,(DE) (one byte, four T-states) rather than LD A,(37ECH) (three bytes, thirteen T-states).
420E
LD HL,37EFH 21 EF 37
Let Register Pair HL equal 37EFH, the memory-mapped address of the WD1771 Data register. Reads from HL fetch bytes from the FDC after a Read Sector or Read Address command; writes to HL pass parameters (such as the desired track number) to the FDC.
4211
EXX D9
EXchange the primary BC, DE, and HL registers with their alternate counterparts BC', DE', and HL'. After this instruction, BC' = 4300H (sector buffer), DE' = 37ECH (FDC command/status), and HL' = 37EFH (FDC data); the primary BC, DE, and HL are now free for use by the upcoming string comparison and load-loop bookkeeping. The FDC routines re-execute EXX whenever they need to access the FDC, and again to switch back.
4212
CALL 424CH CD 4C 42
GOSUB to 424CH to issue an FDC Read Sector command for the track and sector held at 42DDH (00H, set by the source) and 42DEH (01H, set by the source). The 256 bytes of Track 0 / Sector 1 are read into the buffer at 4300H. On return, the buffer holds the first sector of the MicroDOS resident image, and BC has been restored to 4300H.

4215H - SIGCHK - MICRODOS Signature Verification

The buffer at 4300H now holds the first sector of what should be the MicroDOS resident image. To guard against trying to boot a non-MicroDOS disk, the loader compares the eight-byte ASCII string MICRODOS held in the boot sector at 42F1H-42F8H against the eight bytes at 4304H-430BH (the buffer offset 4 through 11). On a match, control falls through to the banner-print and load-loop code; on a mismatch, control jumps to the NO MICRODOS error handler at 42A7H.

4215
LD DE,42F1H 11 F1 42
Let Register Pair DE equal 42F1H, the address within the boot sector that holds the eight-byte ASCII signature MICRODOS. DE will be the source pointer for the string compare loop.
4218
LD HL,4304H 21 04 43
Let Register Pair HL equal 4304H, the address within the sector buffer where the MICRODOS signature should appear if this disk is a valid MicroDOS image. The first four bytes of the buffer (4300H-4303H) hold the chain marker byte (FFH) followed by a JP 4727H instruction that becomes the OS entry point once the buffer contents are copied to 4400H. The signature begins at offset 4 of the sector data.
421B
LD B,08H 06 08
Let Register B equal 8, the loop counter for the eight-byte signature compare. The DJNZ at 4224H decrements this register on each iteration; when it reaches zero, the compare has succeeded.

Loop Start
Compare each byte of the MICRODOS signature in the boot sector against the corresponding byte at offset 4 of the sector buffer.

421D
LD A,(DE) 1A
Fetch the next byte of the MICRODOS signature (held in the memory location pointed to by Register Pair DE, which on the first iteration is 42F1H = M, on the second 42F2H = I, and so on) and store it into Register A.
421E
CP (HL) BE
Compare the value held in Register A (the next signature byte) against the byte held in the memory location pointed to by Register Pair HL (the corresponding byte from the sector buffer at 4304H + iteration). If the two bytes match, the Z FLAG is set; otherwise the NZ FLAG is set.
421F
JP NZ,42A7H C2 A7 42
If the NZ FLAG is set (the signature byte and the buffer byte do not match, meaning this disk is not a MicroDOS disk), JUMP to 42A7H to load the NO MICRODOS message pointer and fall into the error display path.
4222
INC DE 13
INCrement the SIGNATURE POINTER (stored in Register Pair DE) by 1 to advance to the next byte of the MICRODOS string in the boot sector.
4223
INC HL 23
INCrement the BUFFER POINTER (stored in Register Pair HL) by 1 to advance to the next byte of the candidate signature in the sector buffer.
4224
DECrement Register B; if the result is NOT zero, JUMP back to 421DH to compare the next signature byte. When Register B reaches zero, all eight bytes have matched and execution falls through to 4226H.

Loop End
Signature verified: this disk is a valid MicroDOS image. Continue with banner display and OS load.

4226H - LOADLP - OS Load Loop

With the signature verified, the boot sector now copies the MicroDOS resident image into memory at 4400H. The first sector (T0/S1) has already been read into the buffer at 4300H by the call at 4212H. The loop walks each sector's first byte: FFH means "this is a continuation sector, copy bytes 1-255 to the OS load area and read the next sector," and any other value N means "this is the final sector, copy bytes 1-N and jump to 4400H to start the OS." The same one-byte marker is used as both the continuation flag and the byte count via the trick that LDIR with B=0 and C=FFH copies 255 bytes (00FFH = 255), and INC A on FFH rolls the byte over to 00H, setting the Z flag.

4226
CALL 42D4H CD D4 42
GOSUB to 42D4H to print the NUL-terminated string pointed at by Register Pair HL. After the signature compare loop, HL points to 430CH (the byte immediately after the signature in the sector buffer); 430CH holds the byte 41H, which is the first character (A) of the MicroDOS banner string A SIMPLE, POWERFUL DOS / WRITTEN BY JAMES W. STUTSMAN / FOR PERCOM DATA COMPANY that begins at offset 0CH of T0/S1. The print routine walks the buffer until it hits the 00H terminator at offset 59H of the buffer (4359H), printing the banner to the cleared screen.
4229
LD DE,4400H 11 00 44
Let Register Pair DE equal 4400H, the destination address for the first byte of the resident MicroDOS image. Each successive sector copy advances DE by the number of bytes copied, so by the time the final sector is reached, DE points at the address one past the last byte of the OS image.

Loop Start
Top of the load loop. Each iteration copies one sector's data to the OS load area. The loop terminates when a non-FFH first byte indicates the final sector.

422C
LD B,00H 06 00
Let Register B equal 0, the high byte of the LDIR byte count. Combined with the byte loaded into Register C at 4231H (which on continuation sectors is FFH), this gives a count of 00FFH = 255 bytes for the LDIR at 4234H.
422E
LD HL,4300H 21 00 43
Let Register Pair HL equal 4300H, the address of the sector read buffer. The buffer's first byte is the chain marker, and the bytes that follow are the sector's payload to be copied to the OS load area.
4231
LD C,(HL) 4E
Fetch the chain marker (held in the memory location pointed to by Register Pair HL = 4300H, the first byte of the sector buffer) and store it into Register C. On a continuation sector this is FFH; on the final sector this is the count of remaining bytes (12H = 18 on this disk's last OS sector at T1/S9).
4232
LD A,(HL) 7E
Fetch the same chain marker (held at 4300H) and store it into Register A as well. Register A keeps the marker available for the INC A test at 4236H, while Register C carries it into the LDIR's BC count.
4233
INC HL 23
INCrement the SOURCE POINTER (stored in Register Pair HL) by 1 to point past the marker byte at the start of the buffer. HL now points at 4301H, the first payload byte of the sector.
4234
LDIR ED B0
Transfers a byte of data from the memory location pointed to by HL to the memory location pointed to by DE. Then HL and DE are incremented and BC is decremented. If BC is not zero, this operation is repeated. Interrupts can trigger while this instruction is processing.
Source = HL = 4301H (first payload byte of the buffer); Destination = DE = current OS load offset (initially 4400H, advances with each sector); Byte count = BC = 00FFH on continuation sectors (255 bytes) or 00xxH on the final sector (xx = the marker value, in this case 12H = 18 bytes).
4236
INC A 3C
INCrement Register A by 1. Register A still holds the chain marker fetched at 4232H. If the marker was FFH (continuation sector), INC A rolls the value over to 00H and the Z FLAG is set; if the marker was anything else (final sector), INC A produces a non-zero result and the Z FLAG is clear. This single instruction is what discriminates between continuation and final sectors.
4237
JP NZ,4400H C2 00 44
If the NZ FLAG is set (the chain marker was not FFH, so this was the final sector), JUMP to 4400H to enter the resident MicroDOS image. The first three bytes at 4400H are JP 4727H, which transfers control to the MicroDOS initialization routine.
NOTE: 4400H is the start of the MicroDOS resident image just loaded by this loop. The byte at 4400H is C3 (JP), at 4401H is 27H, and at 4402H is 47H, decoding as JP 4727H.
423A
LD HL,42DEH 21 DE 42
Let Register Pair HL equal 42DEH, the address of the SECTOR variable that the FDC seek setup at 4291H reads when constructing the next Read Sector command. This LD prepares HL for the INC (HL) at 423FH that advances the sector counter.
423D
LD A,09H 3E 09
Let Register A equal 9, the highest valid sector number on a Model I single-density disk (sectors 0-9). Register A will be used as the comparand for the CP (HL) at 4240H to decide whether the just-incremented sector counter has overflowed past 9 and needs to wrap.
423F
INC (HL) 34
INCrement the SECTOR variable (held in the memory location pointed to by Register Pair HL = 42DEH) by 1. After the call to 4212H this was 01H; after the first iteration here it is 02H, and so on, advancing one sector per loop pass.
4240
CP (HL) BE
Compare the value held in Register A (09H) against the byte held in the memory location pointed to by Register Pair HL (the SECTOR variable just incremented). If the new sector number is less than or equal to 9, the result is A >= (HL) and the NC FLAG is set. If the new sector number is 10 (i.e., it overflowed), the result is A < (HL) and the CARRY FLAG is set.
4241
If the NC FLAG is set (the sector counter is still in the valid range 0-9), JUMP to 4247H to skip the wrap-and-increment-track logic and go straight to reading the next sector.
4243
LD (HL),00H 36 00
Store the value 00H into the memory location pointed to by Register Pair HL (the SECTOR variable at 42DEH). This wraps the sector counter back to 0 after it overflowed past 9.
4245
DEC HL 2B
DECrement Register Pair HL by 1, moving HL from 42DEH (SECTOR) to 42DDH (TRACK).
4246
INC (HL) 34
INCrement the TRACK variable (held in the memory location pointed to by Register Pair HL = 42DDH) by 1. The seek routine at 4275H will now target the next track on the upcoming Read Sector call.
4247
CALL 424CH CD 4C 42
GOSUB to 424CH to issue an FDC Read Sector command for the track and sector held at 42DDH and 42DEH, filling the sector buffer at 4300H with the next OS sector.
424A
JR 422CH 18 E0
JUMP back to 422CH to process the just-read sector. The loop terminates when the sector's chain marker is something other than FFH, at which point the JP NZ,4400H at 4237H transfers control out of this loop into the MicroDOS resident image.

Loop End
Control leaves this loop only via the JP NZ,4400H at 4237H, which is taken when the final sector's chain marker is reached.

424CH - RDSEC - Read One Sector via the WD1771 FDC

Issues a WD1771 Read Sector command for the track and sector held at 42DDH and 42DEH, transferring 256 bytes from the disk into the sector buffer pointed at by BC' (4300H, set up at 4208H and saved into the alternate register set by the EXX at 4211H). The routine works in the alternate register set so that DE' = 37ECH (FDC command/status) and HL' = 37EFH (FDC data) need not be reloaded on every call. On a successful read, returns with BC restored to 4300H ready for the next iteration of the load loop. On error, jumps to 42A2H to display DISK ERROR and reboot.

424C
CALL 4275H CD 75 42
GOSUB to 4275H to select drive 0, optionally wait for it to spin up, write the track and sector numbers from 42DDH and 42DEH into the WD1771 registers, and issue a Seek command. On return, the head is positioned over the desired track and the Sector register holds the desired sector number; the FDC is ready to receive a Read Sector command.
424F
LD A,88H 3E 88
Let Register A equal 88H, the WD1771 Read Sector command with bit 4 (m, multiple records) clear and bit 3 (b, IBM format) set. This is the standard single-sector read used by all Model I DOSes for non-IBM-format (TRSDOS-compatible) disks.
1771 FDC Command: 88H (10001000)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
100mbE00Command=Read Sector
Bit 7-5: Read Command (100)
m: 0=Single Record, 1=Multiple Records
b: 1=IBM format, 0=Non-IBM Format
E: 0=Assume Head Already Engaged, no Delay, 1=Enable HLD, HLT, and 10ms Delay
Remainder: Unused (00)
4251
CALL 42B9H CD B9 42
GOSUB to 42B9H to wait for the FDC to be not busy, then write the Read Sector command (88H) from Register A to the FDC command register at 37ECH. On return, the FDC is busy executing the read and will start raising the Data Request flag (bit 1 of the status register) once each byte arrives at the data register.
4254
EXX D9
EXchange the primary BC, DE, and HL registers with their alternate counterparts. After this instruction, DE = 37ECH (FDC command/status), HL = 37EFH (FDC data), and BC = 4300H (sector buffer pointer). The byte-fetch loop that follows uses these primary registers for fast LD A,(DE) status polling and LD A,(HL) data fetching.
4255
JR 425DH 18 06
JUMP to 425DH to enter the byte-fetch loop. This unconditional jump skips over the end-of-sector test at 4257H on the first iteration: at this point the FDC has just been commanded to read but no data has yet arrived, so checking the status for end-of-record would be premature.

Status Test
Reached at the end of each byte-fetch iteration. If both busy and DRQ are clear in the masked status, the sector has finished transferring and control falls through to 4267H. Otherwise control loops back to the data-byte fetch.

4257
AND 81H E6 81
Mask Register A (the FDC status byte just read) against 81H, isolating bit 7 (Not Ready) and bit 0 (Busy). All other bits are cleared. After this instruction, A = 81H if the drive is both not ready and busy, 80H if only not ready, 01H if only busy, and 00H if neither.
4259
XOR 01H EE 01
XOR Register A with 01H, flipping bit 0 (Busy). After this instruction, A is zero exactly when the drive was ready (bit 7 was clear) and the FDC was busy (bit 0 was set), the normal mid-transfer condition. A is non-zero when the FDC has finished (busy clear) or the drive went not ready (bit 7 set), both of which mean the sector transfer is complete or has failed.
425B
If the NZ FLAG is set (the FDC has stopped being busy or the drive has gone not ready, indicating the end of the sector or a hardware error), JUMP to 4267H to read the final FDC status and check for error conditions.

Data Request Wait
The FDC is still busy and the drive is still ready. Spin until the next data byte arrives.

425D
LD A,(DE) 1A
Fetch the FDC STATUS BYTE (held in the memory location pointed to by Register Pair DE = 37ECH, the WD1771 status register) and store it into Register A.
425E
BIT 1,A CB 4F
Test bit 1 of Register A (the Data Request flag in the status byte). If a byte has arrived at the FDC data register and is waiting to be read, bit 1 is set and the NZ FLAG is set. Otherwise bit 1 is clear and the Z FLAG is set.
4260
If the Z FLAG is set (no data byte ready yet), JUMP back to 4257H to mask the just-read status against busy and not-ready, then fall back through to read the status again. The loop continues until either a data byte arrives or the FDC stops being busy.
4262
LD A,(HL) 7E
Fetch the next DATA BYTE (held in the memory location pointed to by Register Pair HL = 37EFH, the WD1771 data register) and store it into Register A. Reading the data register has the side effect of clearing the Data Request flag in the status byte, so the FDC will start asserting it again when the next byte arrives.
4263
LD (BC),A 02
Store the value held in Register A (the data byte just fetched) into the memory location pointed to by Register Pair BC (the sector buffer offset).
4264
INC BC 03
INCrement the BUFFER POINTER (stored in Register Pair BC) by 1 to advance to the next byte of the sector buffer. After 256 increments BC will hold 4400H, but the loop exits before that by way of the busy-clear test at 425BH when the FDC finishes the sector.
4265
JR 425DH 18 F6
JUMP back to 425DH to wait for the next byte. The loop runs once per byte for 256 iterations on a normal sector read.

End of Sector
The FDC has cleared its busy flag, indicating the Read Sector command has completed (successfully or with an error).

4267
LD A,(DE) 1A
Fetch the FINAL FDC STATUS BYTE (held in the memory location pointed to by Register Pair DE = 37ECH, the WD1771 status register) and store it into Register A. This is a Type II Status Register read, since the just-completed command was Read Sector.
1771 FDC Status Register (after Read Sector)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
NWRFCLDBType II Command Status Register
N: 1=Not Ready, 0=Ready
W: 1=Write Protected, 0=Not Protected
R: 1=Record Type/Deleted Data, 0=Normal Data
F: 1=Record Not Found, 0=Record Found
C: 1=CRC Error, 0=No Error
L: 1=Lost Data, 0=No Data Lost
D: 1=Data Request (DRQ), 0=No Request
B: 1=Busy, 0=Not Busy
4268
EX DE,HL EB
EXchange the value stored in Register Pair HL with the value stored in Register Pair DE. After this instruction, HL = 37ECH (FDC command/status) and DE = 37EFH (FDC data). HL has to point at the command register because the next instruction issues a Force Interrupt command, which the WD1771 only accepts at the command port; HL was used because the LD (HL),nn instruction is one byte shorter than LD (37ECH),A.
4269
LD (HL),0D0H 36 D0
Store the value 0D0H into the memory location pointed to by Register Pair HL (the WD1771 command register at 37ECH). Command D0H is Force Interrupt with no condition bits set, the canonical "tell the FDC the host is done, abort whatever you are doing" command. This puts the FDC into a known idle state for the next operation.
1771 FDC Command: D0H (11010000)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
1101I3I2I1I0Command=Force Interrupt
Bit 7-4: Command Code (1101)
I3: 1=Interrupt Immediately
I2: 1=Interrupt on the next Index Pulse
I1: 1=Interrupt the next time Ready goes to Not Ready
I0: 1=Interrupt the next time Not Ready goes to Ready
All condition bits 0: Terminate command and clear busy
426B
EX DE,HL EB
EXchange Register Pair HL with Register Pair DE again, restoring HL = 37EFH (FDC data) and DE = 37ECH (FDC command/status) to their original assignments for the alternate-register convention used by the FDC routines.
426C
AND 9CH E6 9C
Mask Register A (the final FDC status fetched at 4267H) against 9CH = 10011100B, isolating bit 7 (Not Ready), bit 4 (Record Not Found), bit 3 (CRC Error), and bit 2 (Lost Data). If any of these bits is set, the read failed; if all are clear, the read succeeded.
426E
If the NZ FLAG is set (one or more of the masked error bits is set), JUMP to 42A2H to load the DISK ERROR message pointer and fall into the error display path.
4270
LD BC,4300H 01 00 43
Let Register Pair BC equal 4300H, restoring the sector buffer pointer to the start of the buffer for the next iteration of the load loop. During the byte-fetch loop above, BC has been incremented 256 times from 4300H to 4400H; resetting it here lets the load loop at 422CH-422EH read the just-loaded sector's chain marker.
4273
EXX D9
EXchange the primary BC, DE, and HL registers with their alternate counterparts, restoring the boot sector's working register set (with BC unused, DE = 4400H + offset for OS load, HL free) and stashing the FDC pointers (DE = 37ECH, HL = 37EFH) and the buffer pointer (BC = 4300H) back into the alternate set for the next FDC call.
4274
RET C9
RETurn to the caller (the load loop at 422CH or the initial signature read at 4215H, depending on where this routine was invoked from).

4275H - SETSEC - Drive Select, Seek, and Sector Setup

Called by the Read Sector routine at 424CH before each Read Sector command, this routine ensures the FDC is positioned correctly for the read. It selects drive 0 by writing 01H to 37E1H, optionally calls the ROM delay at 0060H if the drive was not ready (giving the spindle time to come up to speed), writes the desired track number from 42DDH into the FDC data register, writes the desired sector number from 42DEH into the FDC sector register, and issues a WD1771 Seek command (17H) to position the head over the requested track. On a successful seek, returns with the Z flag set; on a seek error, jumps to 42A2H.

4275
LD A,(37ECH) 3A EC 37
Fetch the FDC STATUS BYTE (held in the memory location pointed to by 37ECH, the WD1771 status register) and store it into Register A. This is a Type I status read, returning the status of the most recent Type I command (Restore, Seek, Step, Step In, or Step Out); the most recent such command was the Restore that the boot ROM issued before reading T0/S0.
4278
RLCA 07
Rotate Register A Left Circular. After this instruction, the original bit 7 (Not Ready) has rotated into both the CARRY FLAG and bit 0 of Register A. The CARRY FLAG is set if the drive was not ready, clear if the drive was ready. The remaining bits of Register A are now meaningless and ignored.
4279
LD A,01H 3E 01
Let Register A equal 01H, the drive-select bit pattern for drive 0. The Model I select latch at 37E1H takes a one-hot pattern: 01H selects drive 0, 02H selects drive 1, 04H selects drive 2, and 08H selects drive 3.
427B
LD (37E1H),A 32 E1 37
Store the value held in Register A (01H, the drive-0 select pattern) into memory location 37E1H, the Model I drive-select latch. This activates drive 0 and starts its motor if it is not already running. The latch is actually a one-shot, not a true latch; its output decays after roughly 30 milliseconds unless re-asserted, which is why every FDC routine in the boot sector re-writes 01H here whenever it polls the FDC.
427E
If the NC FLAG is set (the original status byte's bit 7 was clear, meaning the drive was already ready), JUMP to 428BH to skip the spin-up delay and proceed directly to writing the track number.

Drive Spin-Up Delay
The drive was not yet ready. Use the ROM keypress-loop routine at 0060H to wait for the spindle to come up to speed, then re-select the drive.

4280
LD BC,0000H 01 00 00
Let Register Pair BC equal 0000H, the maximum loop count for the ROM delay routine at 0060H. The ROM routine decrements BC and loops back as long as BC is non-zero or as long as no key is pressed; setting BC to 0000H gives the maximum delay (about 0.5 seconds at the Model I 1.77MHz clock), which is sufficient to bring a Shugart-style 5.25-inch drive up from a stopped state.
4283
CALL 0060H CD 60 00
GOSUB to 0060H.
NOTE: 0060H is the Level II BASIC ROM keyboard-poll-with-delay routine. It loops up to BC times, reading the keyboard on each pass and returning early if any key is pressed (with the keycode in Register A). When called with BC = 0000H from a boot context where no user is expected to be pressing keys, it serves as a calibrated 0.5-second delay.
4286
LD A,01H 3E 01
Let Register A equal 01H, the drive-0 select pattern (same as at 4279H). After the ROM delay, Register A has been overwritten by the keyboard scan, so it must be reloaded.
4288
LD (37E1H),A 32 E1 37
Store the value held in Register A (01H) into memory location 37E1H, re-asserting drive 0's select line so that the upcoming Seek command finds the drive selected. Without this re-write the one-shot latch would have decayed during the 0.5-second delay.
428B
LD A,(42DDH) 3A DD 42
Fetch the TRACK variable (held in memory location 42DDH, initialized to 00H by the source and updated by the load loop at 4246H) and store it into Register A.
428E
LD (37EFH),A 32 EF 37
Store the value held in Register A (the desired track number) into memory location 37EFH, the WD1771 data register. The Seek command issued at 4297H will compare this value against its internal track register and step the head until they match. The boot ROM left the FDC's track register at 0 (because the boot's Restore-then-Read-Sector sequence ended with the head on track 0), so on the first call this value is 0 and the Seek is effectively a no-op; subsequent calls cause the head to step inward.
4291
LD A,(42DEH) 3A DE 42
Fetch the SECTOR variable (held in memory location 42DEH, initialized to 01H by the source and updated by the load loop at 423FH) and store it into Register A.
4294
LD (37EEH),A 32 EE 37
Store the value held in Register A (the desired sector number) into memory location 37EEH, the WD1771 sector register. The Read Sector command issued by 424FH will look for an ID address mark whose sector field matches this value before asserting the Data Request flag.
4297
LD A,17H 3E 17
Let Register A equal 17H, the WD1771 Seek command with bit 4 (h, head load) set, bit 2 (V, verify) set, and bits 1-0 (r1 r0) set to 11 (15 millisecond stepping rate, the slowest available, used for compatibility with the early TRS-80 drives that could not reliably step at faster rates).
1771 FDC Command: 17H (00010111)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
0001hVr1r0Command=Seek
Bit 7-4: Command Code (0001)
h: 0=No delay, 1=Enable Head Load/Settle
V: 1=Verify Destination Track ID, 0=No verification
r1, r0: Stepping Motor Rate (00=3ms, 01=6ms, 10=10ms, 11=15ms)
4299
CALL 42B9H CD B9 42
GOSUB to 42B9H to wait for the FDC to be not busy, then write the Seek command (17H) from Register A to the FDC command register at 37ECH. On return, the FDC has issued the seek and the head is now at the requested track.
429C
CALL 42C7H CD C7 42
GOSUB to 42C7H to wait for the FDC busy flag to clear, leaving the most recent status byte in Register A on return. This effectively confirms that the Seek has finished executing.
429F
AND 98H E6 98
Mask Register A (the post-Seek FDC status) against 98H = 10011000B, isolating bit 7 (Not Ready), bit 4 (Record Not Found, which after a Seek means Seek Error), and bit 3 (CRC Error). If any of these is set the seek failed; if all are clear the head is correctly positioned.
42A1
RET Z C8
If the Z FLAG is set (none of the masked error bits is set, the seek succeeded), RETurn to the caller (the Read Sector routine at 424FH). If the Z FLAG is clear, fall through to the disk error path.

42A2H - DSKERR - Disk Error and No-MicroDOS Error Display

Reached either by falling through from the Seek error test at 42A1H, by the JR NZ,42A2H from the Read Sector error test at 426EH, or by the JP NZ,42A7H from the MICRODOS signature compare at 421FH. Loads HL with a pointer to the appropriate error message, displays it on a cleared screen, waits for any key, and reboots the system. The two entry points 42A2H (DISK ERROR) and 42A7H (NO MICRODOS) differ only in which message they display.

42A2
LD HL,42DFH 21 DF 42
Let Register Pair HL equal 42DFH, the address of the DISK ERROR message in the boot sector. The bytes at 42DFH-42EBH are 17H E8H 44H 49H 53H 4B H 20H 45H 52H 52H 4F H 52H 00H, which is HOME ESC followed by DISK ERROR followed by a NUL terminator.
42A5
JR 42AAH 18 03
JUMP to 42AAH to skip the NO MICRODOS pointer load and proceed directly to the message display path.
42A7
LD HL,42ECH 21 EC 42
Let Register Pair HL equal 42ECH, the address of the NO MICRODOS message in the boot sector. The bytes at 42ECH-42F0H are 17H E8H 4EH 4FH 20H 4DH 49H 43H 52H 4FH 44H 4FH 53H 00H, which is HOME ESC followed by NO MICRODOS followed by a NUL terminator.
42AA
CALL 01C9H CD C9 01
GOSUB to 01C9H.
NOTE: 01C9H is the Level II BASIC ROM CLS routine. It clears video RAM at 3C00H-3FFFH and homes the cursor.
42AD
CALL 42D4H CD D4 42
GOSUB to 42D4H to print the NUL-terminated string pointed at by Register Pair HL (the error message just selected). On return, the message is on the screen and the cursor is positioned past it.

Wait for Keypress
Spin until the user presses any key, then reboot.

42B0
CALL 002BH CD 2B 00
GOSUB to 002BH.
NOTE: 002BH is the Level II BASIC ROM keyboard-scan entry point. It returns with the ASCII code of the pressed key in Register A, or 00H if no key is currently pressed.
42B3
OR A,A B7
Since a LD command (or in this case a CALL) does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG). The Z FLAG is set if Register A is zero (no key pressed), clear otherwise.
42B4
If the Z FLAG is set (no key was pressed), JUMP back to 42B0H to scan the keyboard again. The loop terminates when the user presses any key.
42B6
JP 0000H C3 00 00
JUMP to 0000H, the Level II BASIC ROM cold start. This restarts the system as if power had just been cycled, giving the user a chance to insert a different disk and reboot.

42B9H - SNDCMD - Send Command to FDC

Writes the byte held in Register A to the WD1771 command register at 37ECH after waiting for the FDC to be not busy. Used by both the Read Sector routine at 4251H (which passes 88H = Read Sector) and the Seek and Drive Select routine at 4299H (which passes 17H = Seek). On entry, the FDC may be busy with a previous command; on exit, the new command has been issued and the routine has waited for the resulting busy state to begin.

42B9
PUSH AF F5
Save the contents of Register Pair AF (the FDC command byte in A, plus the FLAGS in F which are about to be clobbered) to the top of the stack. The 42C7H routine called next preserves no registers; pushing AF here keeps the command byte safe across the call.
42BA
CALL 42C7H CD C7 42
GOSUB to 42C7H to wait for the FDC busy flag to clear (any previous Type I or Type II command has now finished). On return, the FDC is ready to accept a new command.
42BD
POP AF F1
Restore Register Pair AF from the top of the stack, and then remove the entry from the stack. Register A again holds the command byte that the caller passed in.
42BE
EXX D9
EXchange the primary BC, DE, and HL registers with their alternate counterparts. After this instruction, DE = 37ECH (FDC command/status), HL = 37EFH (FDC data), and BC = 4300H (sector buffer), the FDC pointer set originally established by the EXX at 4211H.
42BF
LD (DE),A 12
Store the value held in Register A (the FDC command byte) into the memory location pointed to by Register Pair DE (37ECH, the WD1771 command register). The FDC immediately begins executing the command and asserts its busy flag.

Busy Wait
Spin reading the status register until the busy flag goes high. The FDC takes a small number of microseconds to actually start executing after the command write; this loop ensures the caller does not see the old (clear) busy flag and assume the command is already done.

42C0
LD A,(DE) 1A
Fetch the FDC STATUS BYTE (held in the memory location pointed to by Register Pair DE = 37ECH, the WD1771 status register) and store it into Register A.
42C1
BIT 0,A CB 47
Test bit 0 of Register A (the busy flag in the status byte). If the FDC has begun executing the new command, bit 0 is set and the NZ FLAG is set; otherwise the Z FLAG is set.
42C3
If the Z FLAG is set (the FDC has not yet asserted busy), JUMP back to 42C0H to read the status again. The loop terminates as soon as the busy flag goes high, confirming the command is being executed.
42C5
EXX D9
EXchange the primary and alternate register sets, restoring the boot sector's working register set and stashing the FDC pointers back into the alternate set.
42C6
RET C9
RETurn to the caller (the Read Sector routine at 4254H or the Seek routine at 429CH).

42C7H - WAITNB - Wait for FDC Not Busy

Loops reading the FDC status register, re-asserting drive 0's select line on each iteration, until the busy flag (bit 0) goes low. Used by 42BAH before sending a new command (to ensure the previous command has finished) and by 429CH after issuing a Seek (to wait for the seek to complete). On exit, Register A holds the most recent status byte read.

42C7
EXX D9
EXchange the primary BC, DE, and HL registers with their alternate counterparts. After this instruction, DE = 37ECH (FDC command/status), HL = 37EFH (FDC data), and BC = 4300H (sector buffer pointer).

Loop Start
Each iteration re-selects drive 0 (because the latch is a one-shot) and re-reads the status. The loop terminates when the busy bit goes low.

42C8
LD A,01H 3E 01
Let Register A equal 01H, the drive-0 select pattern, in preparation for re-asserting the select latch.
42CA
LD (37E1H),A 32 E1 37
Store the value held in Register A (01H) into memory location 37E1H, the Model I drive-select latch. This is essential because the latch is a one-shot that decays after roughly 30 milliseconds; without periodic re-assertion, drive 0 would deselect itself partway through a long seek and the FDC would interpret the resulting Not Ready as a seek error.
42CD
LD A,(DE) 1A
Fetch the FDC STATUS BYTE (held in the memory location pointed to by Register Pair DE = 37ECH, the WD1771 status register) and store it into Register A.
42CE
BIT 0,A CB 47
Test bit 0 of Register A (the busy flag). If the FDC is still busy, bit 0 is set and the NZ FLAG is set; if the command has completed, bit 0 is clear and the Z FLAG is set.
42D0
If the NZ FLAG is set (the FDC is still busy), JUMP back to 42C8H to re-select the drive and read the status again. The loop terminates when the busy bit goes low, indicating the previous command has finished.

Loop End
The FDC has cleared its busy flag. Register A holds the final status byte for inspection by the caller.

42D2
EXX D9
EXchange the primary and alternate register sets, restoring the caller's register set with the final FDC status byte still in Register A.
42D3
RET C9
RETurn to the caller, with Register A holding the final FDC status byte.

42D4H - PRINTS - Print NUL-Terminated String

Walks the byte stream pointed at by Register Pair HL, calling the Level II BASIC ROM character output routine at 0033H for each non-zero byte and returning when a zero byte is reached. Used three times in the boot sector: at 4226H to print the MicroDOS banner from the just-read first OS sector, at 42ADH to print the DISK ERROR message, and at 42ADH again to print the NO MICRODOS message. The first byte of every message is 17H (the Model I VDU control code for HOME), and the second is E8H (the high bit of which switches the next character into reverse video on Model I systems with the optional video-modification kit; on stock systems it is treated as a graphics character and is harmless).

42D4
LD A,(HL) 7E
Fetch the next CHARACTER (held in the memory location pointed to by Register Pair HL) and store it into Register A.
42D5
OR A,A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG). The Z FLAG is set if the byte is the NUL terminator (00H), clear otherwise.
42D6
RET Z C8
If the Z FLAG is set (the just-fetched byte is the NUL terminator), RETurn to the caller. The string has been fully printed.
42D7
CALL 0033H CD 33 00
GOSUB to 0033H.
NOTE: 0033H is the Level II BASIC ROM character-output routine. It takes the character in Register A and writes it to the current video cursor position, advancing the cursor and handling control codes (CR, LF, HOME, etc.) as appropriate.
42DA
INC HL 23
INCrement the STRING POINTER (stored in Register Pair HL) by 1 to advance to the next character of the string.
42DB
JR 42D4H 18 F7
JUMP back to 42D4H to fetch and process the next character. The loop terminates via the RET Z at 42D6H when the NUL terminator is reached.

42DDH - DATA - Workspace Variables and Message Strings

The remainder of the boot sector holds the two workspace variables (the track and sector numbers used by the FDC seek routine), the two error message strings, and the eight-byte MICRODOS signature used for disk identification. None of this data is executable; the disassembler's interpretation of these bytes as Z80 instructions is meaningless and is replaced here with DB / DEFM directives showing the actual contents.

42DD
DB 00H 00
The TRACK variable. Holds the next track number to be read by the FDC seek routine. Initialized to 00H so that the first seek targets track 0 (where T0/S1, the first OS sector, lives). Updated by the INC (HL) at 4246H whenever the sector counter wraps from 9 to 0. Read by the LD A,(42DDH) at 428BH and written into the WD1771 data register.
42DE
DB 01H 01
The SECTOR variable. Holds the next sector number to be read by the FDC seek routine. Initialized to 01H so that the first read targets T0/S1 (the first OS sector, since T0/S0 is the boot sector itself). Updated by the INC (HL) at 423FH on each loop iteration and reset to 00H by the LD (HL),00H at 4243H whenever it would otherwise reach 0AH. Read by the LD A,(42DEH) at 4291H and written into the WD1771 sector register.
42DF
DB 17H 17
First byte of the DISK ERROR message. The byte 17H is the Model I VDU control code for HOME, repositioning the cursor to the upper-left corner of the screen so the message displays at a known location.
42E0
DB E8H E8
Second byte of the DISK ERROR message. The byte E8H falls in the Model I graphics range (80H-FFH) and prints as a graphics block; it serves as a visual marker preceding the error text. (Some PerCom hardware kits remap this byte to a reverse-video attribute, in which case the following text is displayed inverted.)
42E1
DEFM "DISK ERROR" 44 49 53 4B 20 45 52 52 4F 52
The body of the DISK ERROR message: the ten ASCII characters spelling out the words DISK ERROR.
42EB
DB 00H 00
NUL terminator for the DISK ERROR message. The print routine at 42D4H stops fetching characters when it reads this byte.
42EC
DB 17H 17
First byte of the NO MICRODOS message. As at 42DFH, the byte 17H is the Model I VDU control code for HOME.
42ED
DB E8H E8
Second byte of the NO MICRODOS message, the same graphics-block marker used for the DISK ERROR prefix.
42EE
DEFM "NO " 4E 4F 20
The first three characters of the NO MICRODOS message: N, O, and a space.
42F1
DEFM "MICRODOS" 4D 49 43 52 4F 44 4F 53
The eight-byte ASCII string MICRODOS. This sequence serves two purposes simultaneously: it completes the NO MICRODOS error message that begins at 42ECH, and it is the disk-identification signature compared by the loop at 421DH-4224H against bytes 4-11 of the first OS sector. The 4215H instruction LD DE,42F1H deliberately points into the middle of the error message string to reuse the eight bytes that already spell MICRODOS, saving the eight bytes that an independent signature would have cost. A successful match against this signature certifies that the disk is a valid MicroDOS image; a mismatch causes a JP NZ,42A7H to the NO MICRODOS error path which reads the entire string starting at 42ECH including this shared tail.
42F9
DB 00H 00
NUL terminator for the NO MICRODOS message.
42FA
DEFM "$STEPH" 24 53 54 45 50 48
Six bytes of source-tail data with no runtime function. This is the beginning of an internal symbol name ($STEPH being a label in the original source) that overflowed past the source's last DEFM directive when the boot sector was assembled. The assembler emitted these bytes as residual padding to fill the sector to its 256-byte boundary; nothing in the boot code reads them.