TRS-80 DOS - LDOS 5.3.1 for the Model I - SOLE/CMD Disassembled

Page Customization

Summary:

LDOS 5.3.1 SOLE/CMD Disassembly - Double-Density Boot Installer (Model I)

SOLE/CMD is the MISOSYS utility that converts a single-density LDOS 5.3.1 Model I SYSTEM diskette into one that boots in double density on suitably equipped hardware. It is invoked as SOLE :d; the program loads and runs at 5200H, verifies that drive d holds a ready, single-density, write-enabled 5.25-inch system disk, then writes a double-density boot to track 0 and adjusts the directory so the disk boots in double density.

The work is done in two stages. The installer (5200H-5439H) validates the drive through the resident SYS0 services, copies the drive geometry into a template, and writes three sectors of track 0: sector 0 (the boot sector the ROM runs), sector 5 (the double-density driver, which the boot ROM later loads to 4700H) and sector 6 (the secondary loader, loaded to 4800H). Because track 0 sector N is loaded to memory 4200H plus N times 100H, these are exactly the 4200H, 4700H and 4800H regions documented on the BOOT/SYS page.

The second stage is the boot image itself (5500H-56D4H): a self-contained WD1771 double-density read engine plus the secondary loader that streams the resident system as an LDOS load module. That engine is the companion the BOOT/SYS secondary loader calls at 52D1H/53B0H/53C7H/53CFH, and it also supplies the correct loader preamble the captured single-density BOOT/SYS had lost to fill.

Variable, Buffer and Hardware List

AddressPurpose
37E1H
1 byte
WD1771 drive-select / density latch (write). The double-density adapter reuses spare latch bits to switch the data separator to double density.
37ECH
1 byte
WD1771 Command register (write) / Status register (read).
37EDH
1 byte
WD1771 Track register (target cylinder).
37EEH
1 byte
WD1771 Sector register (target sector).
37EFH
1 byte
WD1771 Data register (byte transfer).
5290H
1 byte
Saved copy of the last value written to the drive-select / density latch (run image).
5327H
1 byte
Selected drive number (0-7), parsed from the command tail; read into Register C by every disk-primitive wrapper.
5700H
256 bytes
Sector work buffer: holds the boot sector and directory sectors during the write, beyond the loaded file image.
547D-54FFH
131 bytes
Run-time install workspace: 547D-5486H the ten-byte DCT copy; 5481H density byte; 5482H current cylinder; 547EH boot base pointer; 54FC-54FFH the sector-5 preamble.
IY
-
Points at the selected drive's ten-byte Drive Code Table entry (from GETDCT 478FH).

Major Routine List

AddressName and Purpose
5200HEntry And Validation
Sign on, parse the drive specifier, and confirm the disk is single density, ready and write-enabled.
527FHBuild And Write The Boot
Build the four-byte sector preambles and write track 0 sectors 5, 6 and 0, then update the directory and Granule Allocation Table.
5311HDisk Primitive Wrappers
Load the drive number into Register C and jump to the resident SYS0 DCT primitives WRSECT (4763H), WRPROT (4768H), RDSECT (4777H) and VERSEC (4772H).
533CHError Handlers
Report a DOS error through @ERROR, or display one of the four abort messages through @LOGOT and @ABORT.
5500HDouble-Density Sector Read Engine
Seek, read and transfer a sector directly through the WD1771, with retries and automatic single/double density detection.
5612HSecondary Loader
Streams the resident system as an LDOS load module and transfers to its entry point (the 4800H loader on a converted disk).

Cross-Reference Notes

SOLE/CMD is listed in the LDOS command set on the Main LDOS Disassembly Page. The boot image it installs is the companion to the BOOT/SYS secondary loader; see the BOOT/SYS 4800H section for the loader side and the 4420H Drive Code Table templates. The resident SVC vectors and DCT disk primitives it calls (44xxH, 47xxH, 4B45H, 402DH, 4030H) live in SYS0/SYS; the ROM delay it uses is at 0060H.

Disassembly:

5200H - Installer: Entry, Validation And Write

SOLE.CMD loads and runs at 5200H as a DOS command. It signs on, validates that the selected drive holds a ready, single-density, write-enabled system disk, then builds and writes the double-density boot to track 0 sectors 0, 5 and 6 (which the boot ROM loads to 4200H, 4700H and 4800H) and updates the directory. All disk access is through the resident SYS0 DCT primitives; all display and error output is through the SYS0 SVC vectors.

5200
PUSH HL E5
SOLE Entry - Sign-On
The DOS command interpreter enters SOLE at 5200H with Register Pair HL pointing at the command line remaining after the word SOLE (the drive specifier the operator typed). Save that command-line pointer (Register Pair HL) on the stack so the sign-on display below can reuse Register Pair HL without losing it.
5201
LD HL,5356H 21 56 53
Point Register Pair HL at 5356H, the start of the sign-on banner string.
5204
GOSUB to @DSPLY (4467H), the resident SYS0 display vector, which prints the carriage-return-terminated string that Register Pair HL points at (the sign-on banner at 5356H).
5207
POP HL E1
Restore the command-line pointer (Register Pair HL) saved on entry; Register Pair HL again points at the operator's drive specifier.
5208
LD A,(HL) 7E
Parse The Drive Specifier
Fetch the next character of the command line (the byte Register Pair HL points at) into Register A.
5209
INC HL 23
Advance the command-line pointer (Register Pair HL) to the following character.
520A
CP 20H FE 20
Compare Register A (the current command-line character) against 20H, an ASCII space, so leading blanks are skipped.
520C
If the Z FLAG is set (Register A held a space), LOOP BACK to 5208H to read the next character.
520E
CP 3AH FE 3A
Compare Register A (the first non-blank character) against 3AH, an ASCII colon; a valid specifier reads :d, so a colon must appear here.
5210
If the NZ FLAG is set (no colon), JUMP to 534DH to load the "Drive spec required!" message and abort.
5213
LD A,(HL) 7E
Fetch the character after the colon (the drive digit) into Register A.
5214
SUB 30H D6 30
SUBtract 30H from Register A to convert the ASCII digit into its binary drive number.
5216
CP 08H FE 08
Compare the binary drive number (Register A) against 08H; the Model I supports drives 0 through 7.
5218
If the NO CARRY FLAG is set (Register A was 8 or greater, invalid), JUMP to 534DH to display "Drive spec required!" and abort.
521B
LD (5327H),A 32 27 53
Store the validated drive number (Register A) at 5327H, the cell the four disk-primitive wrappers read into Register C on every disk call.
521E
LD C,A 4F
Copy the drive number (Register A) into Register C, the register GETDCT expects it in.
521F
GOSUB to GETDCT (478FH), the resident SYS0 routine that sets Register Pair IY to the base of the ten-byte Drive Code Table entry for the drive number in Register C.
5222
BIT 3,(IY+03H) FD CB 03 5E
Reject A Disk That Is Already Double Density
Test bit 3 of DCT+03H, the drive-specification flag byte of the selected drive's Drive Code Table entry; bit 3 marks the drive as double density.
5226
If the NZ FLAG is set (bit 3 of DCT+03H set, already double density), JUMP to 5349H to abort with "Track 0 is not single density!".
5229
BIT 5,(IY+03H) FD CB 03 6E
Test bit 5 of DCT+03H, the drive-specification flag byte; bit 5 also marks a double-density configuration.
522D
If the NZ FLAG is set (bit 5 of DCT+03H set), JUMP to 5349H to abort with "Track 0 is not single density!".
5230
GOSUB to @CKDRV (44B8H), the resident SYS0 check-drive vector, which confirms the selected drive (number at 4308H) is present, ready and formatted, returning the result in the Z, NZ and CARRY flags.
5233
LD A,20H 3E 20
Load Register A with 20H, the @ERROR option meaning "display the message text only", ready for the error path.
5235
If the NZ FLAG is set (@CKDRV reported not ready), JUMP to 533CH to report the DOS error in Register A.
5238
If the CARRY FLAG is set (@CKDRV reported an unformatted disk), JUMP to 5345H to abort with a message.
523B
BIT 7,(IY+04H) FD CB 04 7E
Require A Single-Density Source Disk
Test bit 7 of DCT+04H, the second specification byte; bit 7 records whether track 0 was read as single density.
523F
If the Z FLAG is set (bit 7 clear, not single density), JUMP to 5341H to abort with "Track 0 is not single density!".
5242
LD L,(IY+01H) FD 6E 01
Adapt To The Installed Disk Driver
Load Register L from DCT+01H, the low byte of the disk-driver entry address in the selected drive's Drive Code Table entry.
5245
LD H,(IY+02H) FD 66 02
Load Register H from DCT+02H, the high byte of that driver entry address; Register Pair HL now points at the resident disk driver.
5248
LD DE,0009H 11 09 00
Load Register Pair DE with 0009H, the offset of the driver byte the check below inspects.
524B
ADD HL,DE 19
Add Register Pair DE (9) to Register Pair HL (the driver base); Register Pair HL now points nine bytes into the driver.
524C
LD A,(HL) 7E
Fetch the driver byte at that offset (the byte Register Pair HL points at) into Register A.
524D
CP 0CDH FE CD
Compare Register A against 0CDH, the Z80 CALL opcode; the standard driver has a CALL here, so this detects the expected hook.
524F
If the Z FLAG is set (0CDH, the expected hook), JUMP to 525AH to skip the fallback patch.
5251
LD HL,52DDH 21 DD 52
Self-Modifying Code
The driver hook is absent. Point Register Pair HL at 52DDH, the fallback code path SOLE will use instead.
5254
LD (5504H),HL 22 04 55
Self-Modifying Code
Store the fallback address 52DDH (Register Pair HL) into the operand cell at 5504H, patching the boot image's first driver call.
5257
LD (5608H),HL 22 08 56
Self-Modifying Code
Store the fallback address 52DDH (Register Pair HL) into the operand cell at 5608H, patching the second copy of that call.
525A
PUSH IY FD E5
Copy The Drive Geometry Into The Template
Save the Drive Code Table base pointer (Register Pair IY) by pushing it, to move it into Register Pair HL.
525C
POP HL E1
Pop that value into Register Pair HL; Register Pair HL now points at the ten-byte Drive Code Table entry (the LDIR source).
525D
LD DE,547DH 11 7D 54
Point Register Pair DE at 547DH, the ten-byte local template SOLE stamps into the double-density boot (the LDIR destination).
5260
LD BC,000AH 01 0A 00
Load Register Pair BC with 000AH (10), the length of a Drive Code Table entry (the LDIR count).
5263
LDIR ED B0
Block-copy the 10 geometry bytes from the live Drive Code Table (Register Pair HL) to the template at 547DH (Register Pair DE); Register Pair BC counts down to zero.
5265
LD A,(5481H) 3A 81 54
Fetch the template byte at 5481H (which received DCT+04H) into Register A.
5268
AND 0F0H E6 F0
Mask Register A with 0F0H, clearing the low nibble of that specification byte.
526A
OR 51H F6 51
OR 51H into Register A, setting the density and step-rate bits that mark the template double density.
526C
LD (5481H),A 32 81 54
Store the adjusted specification byte (Register A) back to 5481H in the template.
526F
XOR A AF
Set Register A to zero.
5270
LD (5482H),A 32 82 54
Store zero (Register A) at 5482H, the current-cylinder byte of the template, so the written driver starts at track 0.
5273
LD HL,5700H 21 00 57
Read The Existing Boot Sector
Point Register Pair HL at 5700H, the 256-byte work buffer that will receive track 0 sector 0.
5276
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H; Register E (0) is the sector number to read.
5279
GOSUB to 531FH, the read-sector wrapper, which reads track 0 sector 0 (Register E) of the selected drive into the 5700H buffer (Register Pair HL); this loads the disk's existing boot sector.
527C
If the NZ FLAG is set (the read failed), JUMP to 533CH to report the DOS error in Register A.
527F
LD HL,5200H 21 00 52
Build The Sector 5 Preamble (Becomes 4700H)
Load Register Pair HL with 5200H, SOLE's own load origin and the base used to compute the boot-image pointers.
5282
LD (547EH),HL 22 7E 54
Store 5200H (Register Pair HL) at 547EH, a two-byte work field holding that base pointer.
5285
EX DE,HL EB
Exchange Register Pair DE and Register Pair HL, moving 5200H into Register Pair DE for the arithmetic below.
5286
LD HL,54FFH 21 FF 54
Point Register Pair HL at 54FFH, the top of the four-byte preamble built downward for the sector-5 image (track 0 sector 5, which the boot ROM loads to 4700H).
5289
LD (HL),D 72
Store Register D (52H, the high byte of 5200H) at 54FFH.
528A
DEC HL 2B
Move the build pointer (Register Pair HL) down to 54FEH.
528B
LD (HL),E 73
Store Register E (00H, the low byte of 5200H) at 54FEH; 54FEH-54FFH now hold the little-endian word 5200H.
528C
DEC HL 2B
Move the build pointer (Register Pair HL) down to 54FDH.
528D
LD (HL),0FEH 36 FE
Store 0FEH at 54FDH, the third preamble byte.
528F
DEC HL 2B
Move the build pointer (Register Pair HL) down to 54FCH, the first preamble byte and the start of the sector-5 write buffer.
5290
LD (HL),01H 36 01
Store 01H at 54FCH; the four bytes 54FCH-54FFH now read 01H 0FEH 00H 52H, the preamble leading the sector-5 image (becoming 4700H-4703H when the ROM loads it).
5292
PUSH DE D5
Save Register Pair DE (5200H) on the stack across the write call.
5293
LD DE,0005H 11 05 00
Load Register Pair DE with 0005H; Register E (5) is the sector, track 0 sector 5, which the boot ROM loads to 4700H.
5296
GOSUB to 5311H, the write-sector wrapper, which writes 256 bytes from the buffer Register Pair HL points at (54FCH, the preamble followed by the double-density driver image at 5500H) to track 0 sector 5 (Register E).
5299
POP DE D1
Restore Register Pair DE (5200H) from the stack.
529A
If the NZ FLAG is set (the sector-5 write failed), JUMP to 533CH to report the DOS error.
529D
INC H 24
Build The Sector 6 Preamble (Becomes 4800H)
INCrement Register H, advancing the write-buffer pointer (Register Pair HL) by 100H to the sector-6 image, one 256-byte sector further into SOLE's boot image.
529E
PUSH HL E5
Save that sector-6 buffer pointer (Register Pair HL) on the stack while the preamble words are computed.
529F
LD HL,00FCH 21 FC 00
Load Register Pair HL with 00FCH, the offset of a routine within the 5200H driver block.
52A2
ADD HL,DE 19
Add Register Pair DE (5200H, the driver base) to Register Pair HL, forming the absolute pointer 52FCH in Register Pair HL.
52A3
EX DE,HL EB
Exchange Register Pair DE and Register Pair HL, moving the computed pointer 52FCH into Register Pair DE.
52A4
POP HL E1
Restore the sector-6 buffer pointer (Register Pair HL) from the stack.
52A5
DEC HL 2B
Move the build pointer (Register Pair HL) down to the third byte of the sector-6 preamble.
52A6
LD (HL),D 72
Store Register D (52H, the high byte of the pointer 52FCH) into the preamble.
52A7
DEC HL 2B
Move the build pointer (Register Pair HL) down one byte.
52A8
LD (HL),E 73
Store Register E (0FCH, the low byte of the pointer 52FCH) into the preamble.
52A9
DEC HL 2B
Move the build pointer (Register Pair HL) down one byte to the second preamble byte.
52AA
EX DE,HL EB
Exchange Register Pair DE and Register Pair HL, parking the preamble pointer in Register Pair DE and putting 52FCH back in Register Pair HL.
52AB
LD HL,00D5H 21 D5 00
Load Register Pair HL with 00D5H, the offset of a second driver routine.
52AE
INC HL 23
INCrement Register Pair HL to 00D6H.
52AF
INC HL 23
INCrement Register Pair HL to 00D7H, the value that will fill the second preamble byte.
52B0
EX DE,HL EB
Exchange Register Pair DE and Register Pair HL, moving 00D7H into Register Pair DE and the preamble pointer back into Register Pair HL.
52B1
LD (HL),E 73
Store Register E (0D7H, the low byte of 00D7H) into the second preamble byte.
52B2
DEC HL 2B
Move the build pointer (Register Pair HL) down to the first preamble byte.
52B3
LD (HL),01H 36 01
Store 01H into the first preamble byte; the sector-6 preamble now reads 01H 0D7H 0FCH 52H, matching the LD BC,0FCD7H / LD D,D preamble that leads the 4800H secondary loader on the converted disk.
52B5
LD DE,0006H 11 06 00
Load Register Pair DE with 0006H; Register E (6) is the sector, track 0 sector 6, which the boot ROM loads to 4800H.
52B8
GOSUB to 5311H, the write-sector wrapper, which writes the 256-byte sector-6 image (preamble plus secondary loader) from the buffer Register Pair HL points at to track 0 sector 6 (Register E).
52BB
If the NZ FLAG is set (the sector-6 write failed), JUMP to 533CH to report the DOS error.
52BE
LD HL,421CH 21 1C 42
Patch And Write The Boot Sector (Sector 0)
Load Register Pair HL with 421CH, an address inside Boot Image A that the rebuilt boot sector needs stamped into it.
52C1
LD (5709H),HL 22 09 57
Store 421CH (Register Pair HL) into the 5709H field of the 5700H boot-sector work buffer.
52C4
LD HL,5477H 21 77 54
Point Register Pair HL at 5477H, a sixteen-byte boot patch template held in SOLE.
52C7
LD DE,5716H 11 16 57
Point Register Pair DE at 5716H, the location inside the 5700H boot-sector buffer that receives the template (the LDIR destination).
52CA
LD BC,0010H 01 10 00
Load Register Pair BC with 0010H (16), the template length (the LDIR count).
52CD
LDIR ED B0
Block-copy the 16-byte boot patch template from 5477H (Register Pair HL) into the boot-sector buffer at 5716H (Register Pair DE); Register Pair BC counts down to zero.
52CF
LD HL,5700H 21 00 57
Point Register Pair HL at 5700H, the fully patched boot-sector image.
52D2
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H; Register E (0) is the sector, track 0 sector 0 (the boot sector the ROM runs).
52D5
GOSUB to 5311H, the write-sector wrapper, which writes the 256-byte boot sector from 5700H (Register Pair HL) to track 0 sector 0 (Register E), replacing the disk's boot sector with the double-density boot.
52D8
If the NZ FLAG is set (the boot-sector write failed), JUMP to 533CH to report the DOS error.
52DB
LD HL,5700H 21 00 57
Update The Directory And GAT
Point Register Pair HL at 5700H, the work buffer reused now for directory-track sectors.
52DE
GOSUB to 542CH, the read-directory-sector helper, which reads sector 0 of the directory cylinder (the Granule Allocation Table) into the 5700H buffer, marks track 0 allocated, and writes it back.
52E1
LD E,02H 1E 02
Load Register E with 02H, the sector number of the first directory record on the directory cylinder.
52E3
If the Z FLAG is set (the GAT update succeeded), GOSUB to RDSSEC (4B45H), the resident SYS0 read-directory-sector routine, which reads sector 2 (Register E) of the directory cylinder into the 5700H buffer (Register Pair HL).
52E6
If the NZ FLAG is set (the directory read failed), JUMP to 533CH to report the DOS error.
52E9
LD A,(5714H) 3A 14 57
Fetch the directory bookkeeping byte at 5714H (inside the 5700H buffer) into Register A.
52EC
CP 07H FE 07
Compare Register A against 07H; the value 7 marks a directory already updated for a double-density boot.
52EE
If the Z FLAG is set (already 7, updated on a previous run), JUMP to 5305H to skip to the success message.
52F0
INC A 3C
INCrement Register A once.
52F1
INC A 3C
INCrement Register A again; the bookkeeping byte is advanced by two.
52F2
LD (5714H),A 32 14 57
Store the advanced value (Register A) back to 5714H in the directory-sector buffer.
52F5
LD A,(5717H) 3A 17 57
Fetch the companion bookkeeping byte at 5717H (in the same buffer) into Register A.
52F8
INC A 3C
INCrement Register A by one.
52F9
LD (5717H),A 32 17 57
Store the incremented value (Register A) back to 5717H in the directory-sector buffer.
52FC
GOSUB to 5318H, the write-with-deleted-address-mark wrapper, which writes the updated directory sector from the 5700H buffer back with a deleted-data address mark.
52FF
If the Z FLAG is set (the write succeeded), GOSUB to 532CH to verify the sector and translate the controller status into a DOS result.
5302
If the NZ FLAG is set (the write or verify failed), JUMP to 533CH to report the DOS error.
5305
LD HL,5445H 21 45 54
Success
Point Register Pair HL at 5445H, the "Your double density SYSTEM diskette can now BOOT." completion message.
5308
GOSUB to @DSPLY (4467H), the resident SYS0 display vector, which prints the completion message Register Pair HL points at.
530B
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, the return code handed to DOS (0 meaning no error).
530E
JUMP to @EXIT (402DH), the resident SYS0 exit vector, returning to DOS command level with the success code in Register Pair HL.
5311
LD A,(5327H) 3A 27 53
Write Sector Wrapper
Fetch the selected drive number from 5327H into Register A.
5314
LD C,A 4F
Copy the drive number (Register A) into Register C, the register the SYS0 primitive expects it in.
5315
JUMP to WRSECT (4763H), the resident SYS0 write-sector primitive (operation 0DH); it writes the 256-byte buffer at Register Pair HL to the sector in Register E on the current cylinder of the drive in Register C, and RETurns to SOLE's caller.
5318
LD A,(5327H) 3A 27 53
Write With Deleted Address Mark Wrapper
Fetch the selected drive number from 5327H into Register A.
531B
LD C,A 4F
Copy the drive number (Register A) into Register C.
531C
JUMP to WRPROT (4768H), the resident SYS0 directory-write primitive (operation 0EH); it writes the buffer at Register Pair HL with a deleted-data address mark, the mark every LDOS directory sector carries, and RETurns to SOLE's caller.
531F
LD A,(5327H) 3A 27 53
Read Sector Wrapper
Fetch the selected drive number from 5327H into Register A.
5322
LD C,A 4F
Copy the drive number (Register A) into Register C.
5323
JUMP to RDSECT (4777H), the resident SYS0 read-sector primitive (operation 09H); it reads the sector in Register E on the current cylinder of the drive in Register C into the buffer at Register Pair HL, and RETurns to SOLE's caller.
5326
LD A,00H 3E 00
Verify Sector Wrapper
Load Register A with 00H.
5328
LD C,A 4F
Copy that value (Register A) into Register C as the drive selector for the verify.
5329
JUMP to VERSEC (4772H), the resident SYS0 verify-sector primitive (operation 0AH); it reads the sector identification and CRC without transferring data to confirm the write, and RETurns to SOLE's caller.
532C
Translate Controller Status To A DOS Result
GOSUB to 5326H, the verify-sector wrapper, which returns the controller status in Register A.
532F
If the Z FLAG is set (Register A is zero, no error), JUMP to 5337H to return success.
5331
SUB 06H D6 06
SUBtract 06H from Register A, adjusting the raw controller status into the LDOS error-code numbering.
5333
RET Z C8
If the Z FLAG is set (the adjusted value is zero), RETURN with a clean result.
5334
ADD A,06H C6 06
ADD 06H back to Register A, restoring the error code for the caller to report.
5336
RET C9
RETURN with the error code in Register A and the NZ flag indicating failure.
5337
OR 01H F6 01
OR 01H into Register A so the value is non-zero as a flag, then continue.
5339
LD A,00H 3E 00
Load Register A with 00H, the success error code.
533B
RET C9
RETURN with a zero error code (success).
533C
OR 40H F6 40
Report A DOS Error
OR 40H into Register A, setting the @ERROR option that returns to the caller after display, leaving the error code in the low bits of Register A.
533E
JUMP to @ERROR (4409H), the resident SYS0 error vector, which displays the standard DOS message for the code in Register A and returns to DOS.

The four abort entries below overlap. A validation failure JUMPs one byte into an LD IX instruction so the 0DDH prefix is skipped and the bytes decode as LD HL,nnnn, loading the message address into Register Pair HL for the display at 5350H. Entering at 5341H loads the "Track 0 is not single density!" pointer; 5345H loads "Drive is write protected!"; 5349H loads "Drive must be 5" floppy!"; 534DH loads "Drive spec required!". The fall-through path harmlessly loads Register Pair IX three times before reaching 5350H.

5341
LD HL,53DAH 21 DA 53
Abort With A Message
Point Register Pair HL at 53DAH, the "Track 0 is not single density!" message string.
5344
LD IX,53F9H DD 21 F9 53
Point Register Pair IX at 53F9H, the "Drive is write protected!" message; entered one byte later (5345H) this reads LD HL,53F9H (see the note above).
5348
LD IX,5413H DD 21 13 54
Point Register Pair IX at 5413H, the "Drive must be 5" floppy!" message; entered one byte later (5349H) this reads LD HL,5413H.
534C
LD IX,53C5H DD 21 C5 53
Point Register Pair IX at 53C5H, the "Drive spec required!" message; entered one byte later (534DH) this reads LD HL,53C5H.
5350
GOSUB to @LOGOT (447BH), the resident SYS0 log-and-display vector, which prints the carriage-return-terminated message Register Pair HL points at.
5353
JUMP to @ABORT (4030H), the resident SYS0 abort vector, returning to DOS command level after the error.

5356H - Sign-On And Abort Messages

The sign-on banner and the four abort messages, each terminated by a carriage return. Data, not executed.

5356
DEFM "SOLE - Version 5.3.1 - Double Density BOOTing - Phase 2Copyright (C) 1991 MISOSYS, Inc., All rights reserved" : DEFB 0DH
Sign-On Banner
"SOLE - Version 5.3.1 - Double Density BOOTing - Phase 2" and the MISOSYS copyright line (embedded 0AH line breaks; 0DH terminates). Displayed at 5204H.
53C5
DEFM "Drive spec required!" : DEFB 0DH
Message
"Drive spec required!" - displayed when the drive specifier is missing or out of range.
53DA
DEFM "Track 0 is not single density!" : DEFB 0DH
Message
"Track 0 is not single density!" - the source disk is already double density.
53F9
DEFM "Drive is write protected!" : DEFB 0DH
Message
"Drive is write protected!"
5413
DEFM "Drive must be 5" floppy!" : DEFB 0DH
Message
"Drive must be 5" floppy!"

542CH - Read Directory Sector Helper

Reads sector 0 of the directory cylinder (the Granule Allocation Table), marks track 0 allocated to the boot, and writes it back.

542C
LD D,(IY+09H) FD 56 09
Read A Directory Sector
Load Register D from DCT+09H, the directory-cylinder number of the selected drive's Drive Code Table entry, so the read targets the directory track.
542F
LD E,00H 1E 00
Load Register E with 00H, sector 0 of the directory cylinder (the Granule Allocation Table sector).
5431
GOSUB to RDSSEC (4B45H), the resident SYS0 read-directory-sector routine, which reads the sector on cylinder Register D, sector Register E, into the buffer at Register Pair HL.
5434
LD (HL),0FFH 36 FF
Store 0FFH into the first byte of that buffer (Register Pair HL), marking cylinder 0 fully allocated in the Granule Allocation Table so the boot area is protected.
5436
If the Z FLAG is set (the read succeeded), GOSUB to 5318H, the deleted-address-mark write wrapper, to write the updated GAT sector back.
5439
RET C9
RETURN to the caller.

543AH - Completion Message And Boot Patch Data

The completion message, the boot patch template written into the new boot sector, and the run-time install workspace.

543A
DEFM " complete. " : DEFB 0DH
Message Fragment
" complete. "
5445
DEFM "Your double density SYSTEM diskette can now BOOT." : DEFB 0DH
Completion Message
"Your double density SYSTEM diskette can now BOOT." - displayed on success at 5308H.
5477
DEFB 11H,05H,00H,0C3H,3EH,42H 11 05 00 C3 3E 42
Boot Patch Template
The start of a sixteen-byte template copied into the boot-sector buffer at 5716H by the LDIR at 52CDH.
547D-54FF
Install Workspace
Install Workspace
An unloaded run-time gap. 547D-5486H receives the ten-byte Drive Code Table copy (LDIR at 5263H); 5481H holds the density-adjusted specification byte; 5482H holds the current-cylinder byte (0); 547EH holds the boot base pointer 5200H; 54FC-54FFH hold the four-byte sector-5 preamble built at 5289H.

5500H - Double-Density Boot Image

The boot-time image the build loop writes to track 0 sectors 5 and 6 (loaded by the boot ROM to 4700H and 4800H). It is stored here at 5500H but assembled to run in the 5200H-53FFH range, so its absolute CALL and JP operands (52xxH/53xxH) name routines that appear in this listing 300H higher. It contains the WD1771 double-density read engine (5500H-5611H) and the secondary loader (5612H-56D4H).

5500
CALL 5289H CD 89 52
Double-Density Sector Read Engine
This routine and everything to 56D4H is the boot-time image the build loop wrote to track 0 sectors 5 and 6; it is stored here at 5500H but assembled to run in the 5200H-53FFH range, so its absolute CALL and JP operands (52xxH/53xxH) name routines that appear in this listing 300H higher. Entry reads one sector for the boot. GOSUB to the wait-for-ready routine (shown at 5589H) to let any prior controller command finish.
5503
CALL 52D1H CD D1 52
GOSUB to the sector-register setup routine (shown at 55D1H), which programs the FDC Sector register for the selected side.
5506
LD BC,0588H 01 88 05
Load Register B with 05H, the read-retry count, and Register C with 88H, the WD1771 Read Sector command issued below.
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: 1=Multiple Records, 0=Single Record
b: 1=IBM format, 0=Non-IBM Format
E: 1=Enable HLD/HLT/10ms Delay, 0=Assume Head Already Engaged, no Delay
Remainder: Unused (00)
5509
PUSH BC C5
Retry Loop Start
Save the retry count (Register B) and Read Sector command (Register C) on the stack for the retry path.
550A
CALL 5296H CD 96 52
GOSUB to the seek-and-start-read routine (shown at 5596H), which seeks the target cylinder and programs the FDC Sector register.
550D
PUSH DE D5
Save Register Pair DE (the cylinder/sector working value) on the stack.
550E
PUSH HL E5
Save the caller's buffer pointer (Register Pair HL) on the stack.
550F
LD HL,37EDH 21 ED 37
Point Register Pair HL at 37EDH, the WD1771 Track register.
5512
CALL 5289H CD 89 52
GOSUB to the wait-for-ready routine (shown at 5589H).
5515
LD (HL),D 72
Store the target cylinder (Register D) into the FDC Track register (37EDH, the register Pair HL points at).
5516
DEC HL 2B
Move Register Pair HL down to 37ECH, the FDC Command/Status register.
5517
LD DE,37EFH 11 EF 37
Point Register Pair DE at 37EFH, the WD1771 Data register, the source of each incoming byte.
551A
DI F3
DISABLE INTERRUPTS so the byte-by-byte transfer below is not delayed past the controller's data-request timing.
551B
LD A,C 79
Load Register A with the Read Sector command (Register C, 88H).
551C
CALL 52C8H CD C8 52
GOSUB to the issue-command routine (shown at 55C8H), which ORs the density/step bits into Register A and writes it to the FDC Command register to start the read.
551F
POP BC C1
Restore the retry count and command (Register Pair BC) from the stack.
5520
PUSH BC C5
Save the retry count and command (Register Pair BC) again for the transfer.
5521
LD A,(HL) 7E
Read the FDC status (37ECH, the register Pair HL points at) during the transfer.
1771 Type II Status Register (read 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, 0=Normal
F: 1=Record Not Found, 0=Found
C: 1=CRC Error, 0=No Error
L: 1=Lost Data, 0=No Loss
D: 1=Data Request (DRQ), 0=No Request
B: 1=Busy, 0=Not Busy
5522
AND 03H E6 03
Mask Register A to keep bit 0 (Busy) and bit 1 (Data Request).
5524
JP PO,5221H E2 21 52
If the parity of the masked status (Register A) is odd (exactly one of Busy or Data Request is set), JUMP to the status re-read at 5521H to wait; otherwise fall through to read the ready data byte.
5527
LD A,(DE) 1A
Transfer A Byte
Read one data byte from the FDC Data register (37EFH, the register Pair DE points at) into Register A.
5528
LD (BC),A 02
Store the data byte (Register A) into the caller's buffer at Register Pair BC.
5529
INC BC 03
Advance the buffer pointer (Register Pair BC) to the next byte.
552A
BIT 1,(HL) CB 4E
Data-Request Poll
Test bit 1 (Data Request) of the FDC status (37ECH, Register Pair HL).
552C
JP NZ,5227H C2 27 52
If the NZ FLAG is set (a byte is ready), JUMP to 5527H to transfer it.
552F
BIT 1,(HL) CB 4E
Test bit 1 (Data Request) of the FDC status again.
5531
JP NZ,5227H C2 27 52
If the NZ FLAG is set, JUMP to 5527H to transfer the byte.
5534
BIT 1,(HL) CB 4E
Test bit 1 (Data Request) of the FDC status again (the polls are unrolled for speed).
5536
If the NZ FLAG is set, LOOP BACK to 5527H to transfer the byte.
5538
BIT 1,(HL) CB 4E
Test bit 1 (Data Request) of the FDC status again.
553A
If the NZ FLAG is set, LOOP BACK to 5527H to transfer the byte.
553C
BIT 1,(HL) CB 4E
Test bit 1 (Data Request) of the FDC status again.
553E
If the NZ FLAG is set, LOOP BACK to 5527H to transfer the byte.
5540
BIT 0,(HL) CB 46
Test bit 0 (Busy) of the FDC status (37ECH, Register Pair HL); the command runs while Busy is set.
5542
If the NZ FLAG is set (still Busy), LOOP BACK to 552AH to keep polling for the next Data Request.
5544
LD A,(HL) 7E
The command has finished. Read the final FDC status (37ECH, Register Pair HL) into Register A.
1771 Type II Status Register (read 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, 0=Normal
F: 1=Record Not Found, 0=Found
C: 1=CRC Error, 0=No Error
L: 1=Lost Data, 0=No Loss
D: 1=Data Request (DRQ), 0=No Request
B: 1=Busy, 0=Not Busy
5545
AND 7CH E6 7C
Mask Register A with 7CH, keeping the error bits (Record Type, Record Not Found, CRC Error, Lost Data).
5547
POP HL E1
Restore the caller's buffer pointer (Register Pair HL) from the stack.
5548
POP DE D1
Restore Register Pair DE from the stack.
5549
POP BC C1
Restore the retry count and command (Register Pair BC) from the stack.
554A
RET Z C8
If the Z FLAG is set (no error bits, a clean read), RETURN to the caller.
554B
BIT 2,A CB 57
Test bit 2 (Lost Data) of the error result in Register A.
554D
If the NZ FLAG is set (data was lost), LOOP BACK to 5509H to retry the whole read.
554F
PUSH AF F5
Save the error result (Register A) on the stack.
5550
AND 18H E6 18
Mask Register A with 18H, isolating CRC Error (bit 3) and Record Not Found (bit 4).
5552
JR Z,555FH 28 0B
If the Z FLAG is set (neither error), JUMP to 555FH to fall through without a density change.
5554
BIT 4,A CB 67
Test bit 4 (Record Not Found) of the error result in Register A.
5556
PUSH BC C5
Save the retry count/command (Register Pair BC) on the stack.
5557
CALL NZ,52EDH C4 ED 52
If the NZ FLAG is set (Record Not Found, the sector was not located in the current density), GOSUB to the density-toggle routine (shown at 55EDH), which flips between single and double density and re-seeks for the retry.
555A
POP BC C1
Restore the retry count/command (Register Pair BC) from the stack.
555B
POP AF F1
Restore the error result (Register A) from the stack.
555C
DECrement the retry count (Register B) and LOOP BACK to 5509H while retries remain.
555E
LD B,0F1H 06 F1
Retries Exhausted
Load Register B with 0F1H, the hard-error indicator returned when all read attempts fail.
5560
LD B,A 47
Convert Drive Number To A Select Bit
Copy the drive number (Register A) into Register B, the shift counter.
5561
LD A,01H 3E 01
Load Register A with 01H, the seed for the drive-0 select bit.
5563
RRC B CB 08
Shift Loop Start
Rotate Register B right through carry; the drive number is counted down one bit at a time.
5565
RET C D8
If the CARRY FLAG is set (the drive number is fully counted), RETURN with the single select bit for that drive in Register A.
5566
INC A 3C
INCrement Register A, doubling the select bit for the next drive position.
5567
LOOP BACK to 5563H to continue building the select bit. Shift Loop End
5569
CALL 5289H CD 89 52
Select The Drive And Density
GOSUB to the wait-for-ready routine (shown at 5589H) so the latch change does not disturb an active command.
556C
RLCA 07
Rotate Register A left (moving the ready flag aside for the test below).
556D
PUSH AF F5
Save Register A and the flags on the stack.
556E
LD A,(IY+03H) FD 7E 03
Fetch DCT+03H, the drive-specification byte of the selected drive's Drive Code Table entry, into Register A.
5571
AND 10H E6 10
Mask Register A with 10H, isolating the density bit.
5573
RRCA 0F
Rotate Register A right, moving the density bit into position for the latch.
5574
OR (IY+04H) FD B6 04
OR in DCT+04H, the second specification byte holding the drive-select bits, combining density and drive selection in Register A.
5577
AND 0FH E6 0F
Mask Register A with 0FH, keeping the four low bits (drive select plus density) written to the latch.
5579
LD (5290H),A 32 90 52
Store the combined latch value (Register A) at 5290H, the driver's saved copy of the last latch value.
557C
LD (37E1H),A 32 E1 37
Write the combined value (Register A) to the drive-select / density latch at 37E1H, selecting the drive and setting the WD1771 data separator for the correct density.
Model I Drive-Select / Density Latch write (37E1H)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
----d3d2d1d0Drive-Select Latch (37E0H-37E3H are one physical latch)
Bits 0-3: Drive 0-3 select
The double-density adapter reuses spare bits of this latch to switch the WD1771 data separator to double density.
557F
POP AF F1
Restore Register A and the flags from the stack.
5580
RET NC D0
If the NO CARRY FLAG is set (no motor-start delay is needed), RETURN.
5581
PUSH BC C5
Save the retry count/command (Register Pair BC) on the stack.
5582
LD B,0FFH 06 FF
Load Register B with 0FFH, the motor-settle delay count.
5584
GOSUB to the Model I ROM delay routine at 0060H to let the drive motor reach speed.
5587
POP BC C1
Restore the retry count/command (Register Pair BC) from the stack.
5588
RET C9
RETURN to the caller.
5589
LD A,(37ECH) 3A EC 37
Wait For The Controller Ready
Read the WD1771 status register (37ECH) into Register A.
1771 Type I Status Register (read after Seek/Restore)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
NWHSCTIBType I Command Status Register
N: 1=Not Ready, 0=Ready
W: 1=Write Protected, 0=Not Protected
H: 1=Head Loaded, 0=Not Loaded
S: 1=Seek Error, 0=No Error
C: 1=CRC Error, 0=No Error
T: 1=Track 0, 0=Not Track 0
I: 1=Index Mark, 0=No Index
B: 1=Busy, 0=Not Busy
558C
BIT 0,A CB 47
Test bit 0 (Busy) of the status in Register A.
558E
RET Z C8
If the Z FLAG is set (Busy clear, the controller is idle), RETURN.
558F
LD A,01H 3E 01
Load Register A with 01H, the drive-0 select bit, to keep the drive asserted while waiting.
5591
LD (37E1H),A 32 E1 37
Write it to the drive-select latch at 37E1H so the motor stays on during the wait.
Model I Drive-Select / Density Latch write (37E1H)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
----d3d2d1d0Drive-Select Latch (37E0H-37E3H are one physical latch)
Bits 0-3: Drive 0-3 select
The double-density adapter reuses spare bits of this latch to switch the WD1771 data separator to double density.
5594
LOOP BACK to 5589H to re-read the status until the controller is no longer Busy.
5596
CALL 5289H CD 89 52
Seek The Cylinder And Program The Sector
GOSUB to the wait-for-ready routine (shown at 5589H).
5599
LD A,(IY+05H) FD 7E 05
Fetch DCT+05H, the current-cylinder byte of the selected drive's Drive Code Table entry, into Register A.
559C
LD (37EDH),A 32 ED 37
Write the current cylinder (Register A) to the FDC Track register (37EDH).
559F
LD A,(IY+07H) FD 7E 07
Fetch DCT+07H, the geometry byte holding the sectors-per-track field, into Register A.
55A2
AND 1FH E6 1F
Mask Register A with 1FH, keeping the sectors-per-track count.
55A4
INC A 3C
INCrement Register A so it holds the true sector count.
55A5
RES 4,(IY+03H) FD CB 03 A6
Clear bit 4 (the side flag) of DCT+03H before deciding which side the target sector is on.
55A9
SUB E 93
SUBtract the requested sector (Register E) from the sectors-per-track count (Register A) to test which side the sector falls on.
55AA
NEG ED 44
NEGate Register A, forming the signed sector offset for the side test.
55AC
PUSH DE D5
Save Register Pair DE (the requested sector) on the stack.
55AD
JP M,52B5H FA B5 52
If the result is negative (the sector is on side 1), JUMP to 55B5H to program the sector register for that side.
55B0
SET 4,(IY+03H) FD CB 03 E6
The sector is on side 0. Set bit 4 (the side flag) of DCT+03H.
55B4
LD E,A 5F
Move the adjusted sector number (Register A) into Register E for the sector register.
55B5
LD (37EEH),DE ED 53 EE 37
Write Register Pair DE to the FDC Sector register (37EEH): Register E becomes the target sector and Register D goes to the Data register (37EFH).
55B9
POP DE D1
Restore the requested sector (Register Pair DE) from the stack.
55BA
LD (IY+05H),D FD 72 05
Store the cylinder (Register D) back to DCT+05H, the current-cylinder byte, recording where the head now is.
55BD
LD B,18H 06 18
Load Register B with 18H, the WD1771 Seek command with head load enabled.
55BF
CALL 5269H CD 69 52
GOSUB to the select-drive-and-density routine (shown at 5569H).
55C2
LD A,(IY+03H) FD 7E 03
Fetch DCT+03H, the drive-specification byte, into Register A.
55C5
AND 03H E6 03
Mask Register A with 03H, keeping the stepping-rate bits.
55C7
OR B B0
OR the command in Register B (the Seek command) into Register A, forming the full FDC command with the drive's step rate.
55C8
LD (37ECH),A 32 EC 37
Issue The FDC Command
Write the assembled command (Register A) to the WD1771 Command register at 37ECH, starting the seek (or, from the read path, the read).
55CB
LD B,08H 06 08
Load Register B with 08H, a short settle-delay count.
55CD
DECrement Register B and loop on itself until zero, a brief delay while the command begins.
55CF
XOR A AF
Set Register A to zero (a clean status), and continue.
55D0
RET C9
RETURN to the caller.
55D1
LD A,(IY+03H) FD 7E 03
Program The Sector Register For The Side
Fetch DCT+03H, the drive-specification byte, into Register A.
55D4
AND 40H E6 40
Mask Register A with 40H, isolating the side bit.
55D6
RRCA 0F
Rotate Register A right, moving the side bit into position.
55D7
XOR 0A0H EE A0
Exclusive-OR Register A with 0A0H to form the side-adjusted sector-register value.
55D9
LD (37EEH),A 32 EE 37
Write the result (Register A) to the FDC Sector register at 37EEH.
55DC
RET C9
RETURN to the caller.
55DD
LD A,(IY+03H) FD 7E 03
Reset The Controller
Fetch DCT+03H, the drive-specification byte, into Register A.
55E0
RLCA 07
Rotate Register A left.
55E1
RLCA 07
Rotate Register A left again, positioning the density bits.
55E2
OR 0FEH F6 FE
OR Register A with 0FEH, forming a Restore-type command with the drive's density.
55E4
LD (37ECH),A 32 EC 37
Write it to the WD1771 Command register at 37ECH.
55E7
LD A,0D0H 3E D0
Load Register A with 0D0H, the WD1771 Force Interrupt command.
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 next Index Pulse
I1: 1=Interrupt on Ready to Not Ready
I0: 1=Interrupt on Not Ready to Ready
All 0: Terminate with no interrupt
55E9
LD (37ECH),A 32 EC 37
Write the Force Interrupt (Register A) to the Command register at 37ECH, terminating any command in progress.
55EC
RET C9
RETURN to the caller.
55ED
PUSH HL E5
Toggle Density And Reseed The Geometry
Save the caller's buffer pointer (Register Pair HL) on the stack.
55EE
LD A,(IY+03H) FD 7E 03
Fetch DCT+03H, the drive-specification byte, into Register A.
55F1
XOR 40H EE 40
Exclusive-OR Register A with 40H, flipping the density selection so a failed read can be retried in the other density.
55F3
LD (IY+03H),A FD 77 03
Store the toggled specification byte (Register A) back to DCT+03H.
55F6
LD HL,2409H 21 09 24
Point Register Pair HL at 2409H, the driver-relocation constant used for single density.
55F9
BIT 6,A CB 77
Test bit 6 (the density bit just toggled) of Register A.
55FB
If the Z FLAG is set (single density), JUMP to 5600H keeping 2409H.
55FD
LD HL,4511H 21 11 45
Double density selected. Point Register Pair HL at 4511H, the double-density relocation constant instead.
5600
LD (IY+07H),L FD 75 07
Store Register L (the low relocation byte) into DCT+07H of the Drive Code Table entry.
5603
LD (IY+08H),H FD 74 08
Store Register H (the high relocation byte) into DCT+08H of the Drive Code Table entry.
5606
POP HL E1
Restore the caller's buffer pointer (Register Pair HL) from the stack.
5607
CALL 52D1H CD D1 52
GOSUB to the sector-register setup routine (shown at 55D1H) to reprogram the FDC for the new density.
560A
LD (IY+05H),00H FD 36 05 00
Store 00H into DCT+05H, the current-cylinder byte, forcing a seek to track 0 on the retry.
560E
LD B,08H 06 08
Load Register B with 08H, the head-settle delay count.
5610
JUMP to 55BFH to re-select the drive/density and reissue the command in the new density.
5612
LD A,(IY+07H) FD 7E 07
Secondary Loader
This is the loader written to track 0 sector 6 (which the boot ROM loads to 4800H); it is the same streaming loader documented on the BOOT/SYS page, running here in the 5300H image space. Fetch DCT+07H, the geometry byte of the drive being booted, into Register A.
5615
LD D,A 57
Copy the geometry byte (Register A) into Register D for the granule arithmetic.
5616
AND 1FH E6 1F
Mask Register A with 1FH, keeping the sectors-per-granule field.
5618
LD E,A 5F
Copy that field (Register A) into Register E.
5619
INC E 1C
INCrement Register E to the true sectors-per-granule value.
561A
XOR D AA
Exclusive-OR Register D (the full geometry byte) into Register A to expose the granules-per-track field.
561B
RLCA 07
Rotate Register A left (first of three) to shift the granules-per-track field down.
561C
RLCA 07
Rotate Register A left (second of three).
561D
RLCA 07
Rotate Register A left (third of three); the granules-per-track count now sits in the low bits of Register A.
561E
INC A 3C
INCrement Register A to the true granules-per-track value.
561F
LD B,A 47
Copy the granules-per-track count (Register A) into Register B, the multiply loop counter.
5620
XOR A AF
Set Register A to zero to accumulate the product.
5621
ADD A,E 83
Multiply Loop Start
Add the sectors-per-granule value (Register E) to the running total in Register A.
5622
DECrement Register B and LOOP BACK to 5621H, forming sectors-per-track in Register A. Multiply Loop End
5624
LD BC,5100H 01 00 51
Point Register Pair BC at 5100H, the sector buffer used while streaming the system file.
5627
PUSH BC C5
Save the buffer pointer (Register Pair BC) on the stack.
5628
PUSH AF F5
Save the sectors-per-track total (Register A and flags) on the stack.
5629
LD D,(IY+09H) FD 56 09
Load Register D from DCT+09H, the directory cylinder of the drive being booted.
562C
LD E,C 59
Copy Register C (0, from the 5100H buffer low byte) into Register E as the directory sector number.
562D
CALL 53C7H CD C7 53
GOSUB to the read-sector helper (shown at 56C7H) to read the directory sector into the 5100H buffer.
5630
POP AF F1
Restore the sectors-per-track total (Register A and flags) from the stack.
5631
LD HL,51CDH 21 CD 51
Point Register Pair HL at 51CDH, a byte within the directory buffer holding a configuration flag.
5634
BIT 5,(HL) CB 6E
Test bit 5 of the byte at 51CDH, the double-sided-media flag.
5636
If the Z FLAG is set (single-sided), JUMP to 5639H without doubling.
5638
ADD A,A 87
Double Register A (the sectors-per-track total) to account for both sides of a double-sided disk.
5639
LD (53BFH),A 32 BF 53
Self-Modifying Code
Store the sectors-per-track total (Register A) at 53BFH, patching the loader's per-track sector count used when the sector number wraps to the next cylinder.
563C
LD E,04H 1E 04
Load Register E with 04H, the directory sector holding the resident system's directory record.
563E
POP BC C1
Restore the 5100H buffer pointer (Register Pair BC) from the stack.
563F
PUSH BC C5
Save the buffer pointer (Register Pair BC) again for the read.
5640
CALL 53C7H CD C7 53
GOSUB to the read-sector helper (shown at 56C7H) to read the system's directory record into the 5100H buffer.
5643
POP HL E1
Restore the buffer pointer into Register Pair HL, pointing at the start of the directory record just read.
5644
BIT 4,(HL) CB 66
Test bit 4 (the in-use flag) of the directory record's attribute byte (the byte Register Pair HL points at).
5646
If the Z FLAG is set (the entry is not in use, so there is no system file), JUMP to Boot Image A's 4229H to display No System and halt.
5649
EXX D9
Compute The Starting Sector
Switch to the ALTERNATE register set, which holds the streaming position (cylinder, sector, buffer index).
564A
LD HL,(5116H) 2A 16 51
Load Register Pair HL from 5116H, the first extent field of the directory record (starting cylinder in Register L, granule byte in Register H).
564D
LD A,H 7C
Copy the granule byte (Register H) into Register A to extract the starting granule.
564E
RLCA 07
Rotate Register A left (first of three) to move the starting-granule field toward the low bits.
564F
RLCA 07
Rotate Register A left (second of three).
5650
RLCA 07
Rotate Register A left (third of three); the starting granule number is now in the low bits of Register A.
5651
AND 07H E6 07
Mask Register A with 07H, isolating the three-bit starting granule number.
5653
LD E,A 5F
Copy the starting granule (Register A) into Register E of the alternate set.
5654
LD A,(IY+08H) FD 7E 08
Fetch DCT+08H, the allocation byte, into Register A.
5657
AND 1FH E6 1F
Mask Register A with 1FH, keeping the sectors-per-granule field.
5659
INC A 3C
INCrement Register A to the true sectors-per-granule value.
565A
LD D,A 57
Copy sectors-per-granule (Register A) into Register D, the multiplier.
565B
INC E 1C
INCrement Register E (the granule count) for the multiply-by-repeated-addition below.
565C
NEG ED 44
NEGate Register A to set up the accumulation.
565E
ADD A,D 82
Multiply Loop Start
Add sectors-per-granule (Register D) to Register A.
565F
DEC E 1D
DECrement Register E, the remaining granule count.
5660
If the NZ FLAG is set, LOOP BACK to 565EH. Multiply Loop End
5662
LD E,A 5F
Copy the resulting starting sector offset (Register A) into Register E of the alternate set.
5663
LD D,L 55
Copy the starting cylinder (Register L) into Register D of the alternate set.
5664
LD BC,51FFH 01 FF 51
Load Register Pair BC of the alternate set with 51FFH, priming the buffer index so the first fetch forces a sector read.
5667
EXX D9
Switch back to the MAIN register set to run the record interpreter.
5668
CALL 53B0H CD B0 53
Load-Record Interpreter
GOSUB to the get-next-byte routine (shown at 56B0H) to read the next LDOS load-record type byte into Register A.
566B
DEC A 3D
DECrement Register A to test for record type 01H (a load block); Register A becomes zero when the type was 01H.
566C
If the NZ FLAG is set (not a load block), JUMP to 5685H to test the remaining record types.
566E
CALL 53B0H CD B0 53
GOSUB to the get-next-byte routine (shown at 56B0H) to read the record length into Register A.
5671
LD B,A 47
Copy the record length (Register A) into Register B, the byte counter.
5672
CALL 53B0H CD B0 53
GOSUB to the get-next-byte routine (shown at 56B0H) to read the load-address low byte into Register A.
5675
LD L,A 6F
Store the load-address low byte (Register A) into Register L.
5676
DEC B 05
DECrement Register B for the address-low byte consumed.
5677
CALL 53B0H CD B0 53
GOSUB to the get-next-byte routine (shown at 56B0H) to read the load-address high byte into Register A.
567A
LD H,A 67
Store the load-address high byte (Register A) into Register H; Register Pair HL is now the destination address.
567B
DEC B 05
DECrement Register B again; Register B now holds the count of data bytes in the block.
567C
CALL 53B0H CD B0 53
Load Block Loop Start
GOSUB to the get-next-byte routine (shown at 56B0H) to read one data byte into Register A.
567F
LD (HL),A 77
Store the data byte (Register A) at the destination in Register Pair HL.
5680
INC HL 23
Advance the destination pointer (Register Pair HL).
5681
DECrement Register B and LOOP BACK to 567CH while data bytes remain. Load Block Loop End
5683
LOOP BACK to 5668H for the next load record.
5685
DEC A 3D
DECrement Register A a second time to test for record type 02H (the transfer record).
5686
If the Z FLAG is set (type 02H), JUMP to 5693H to take the transfer address.
5688
CALL 53B0H CD B0 53
GOSUB to the get-next-byte routine (shown at 56B0H) to read the length of an unrecognized record into Register A.
568B
LD B,A 47
Copy the length (Register A) into Register B, the skip counter.
568C
CALL 53B0H CD B0 53
Skip Loop Start
GOSUB to the get-next-byte routine (shown at 56B0H) to read and discard one byte.
568F
DECrement Register B and LOOP BACK to 568CH until the record is skipped. Skip Loop End
5691
LOOP BACK to 5668H for the next record.
5693
CALL 53B0H CD B0 53
Transfer To The Loaded System
GOSUB to the get-next-byte routine (shown at 56B0H) to read and discard the transfer record's length byte.
5696
CALL 53B0H CD B0 53
GOSUB to the get-next-byte routine (shown at 56B0H) to read the entry-address low byte into Register A.
5699
LD L,A 6F
Store the entry-address low byte (Register A) into Register L.
569A
CALL 53B0H CD B0 53
GOSUB to the get-next-byte routine (shown at 56B0H) to read the entry-address high byte into Register A.
569D
LD H,A 67
Store the entry-address high byte (Register A) into Register H; Register Pair HL is now the loaded system's entry point.
569E
PUSH HL E5
Save the entry point (Register Pair HL) on the stack.
569F
PUSH IY FD E5
Save the Drive Code Table pointer (Register Pair IY) on the stack so it can be moved into Register Pair HL.
56A1
POP HL E1
Pop that value into Register Pair HL; Register Pair HL now points at the ten-byte DCT entry to install.
56A2
LD DE,4700H 11 00 47
Point Register Pair DE at 4700H, the DCT$ base, the destination for the drive-0 entry.
56A5
LD BC,000AH 01 0A 00
Load Register Pair BC with 000AH (10), the DCT entry length.
56A8
LDIR ED B0
Block-copy the 10-byte DCT entry from (Register Pair HL) to the DCT$ base 4700H (Register Pair DE), installing the running drive-0 entry.
56AA
POP HL E1
Restore the loaded system's entry point (Register Pair HL) from the stack.
56AB
LD IY,0000H FD 21 00 00
Clear Register Pair IY before entering the loaded system.
56AF
JP (HL) E9
JUMP to the loaded system's entry point (Register Pair HL), handing off control; the boot's work is done.
56B0
EXX D9
Get Next File Byte
Switch to the ALTERNATE register set, which holds the streaming position: Register D = cylinder, Register E = sector, Register C = in-buffer index into the 5100H buffer.
56B1
INC C 0C
INCrement the in-buffer index (Register C) through 00H-0FFH.
56B2
If the NZ FLAG is set (the buffer is not exhausted), JUMP to 56C4H to fetch the byte.
56B4
PUSH BC C5
The buffer is exhausted. Save the buffer index (Register Pair BC) on the stack.
56B5
CALL 53C7H CD C7 53
GOSUB to the read-sector helper (shown at 56C7H) to read the next sector into the 5100H buffer.
56B8
If the NZ FLAG is set (the read failed), JUMP to Boot Image A's 4294H to display Disk Error and halt.
56BB
POP BC C1
Restore the buffer index (Register Pair BC) from the stack.
56BC
INC E 1C
INCrement the sector number (Register E) for the next read.
56BD
LD A,E 7B
Copy the sector number (Register E) into Register A.
56BE
SUB 00H D6 00
Self-Modifying Code
SUBtract the per-track sector count from Register A; the 00H operand is patched at 5639H (53BFH in the run image) with the sectors-per-track value computed at load time.
56C0
If the NZ FLAG is set (still within the track), JUMP to 56C4H to fetch the byte.
56C2
LD E,A 5F
Store 0 (Register A) into the sector number (Register E), wrapping to sector 0.
56C3
INC D 14
INCrement the cylinder number (Register D) to step to the next track.
56C4
LD A,(BC) 0A
Fetch the file byte from the 5100H buffer at Register Pair BC into Register A.
56C5
EXX D9
Switch back to the MAIN register set.
56C6
RET C9
RETURN with the file byte in Register A.
56C7
PUSH HL E5
Read-Sector Helper
Save Register Pair HL on the stack.
56C8
LD H,B 60
Copy Register B into Register H...
56C9
LD L,C 69
...and Register C into Register L, so Register Pair HL points at the sector buffer.
56CA
CALL 53CFH CD CF 53
GOSUB to the DCT driver vector (shown at 56CFH), which reads one sector through the installed disk driver.
56CD
POP HL E1
Restore Register Pair HL from the stack.
56CE
RET C9
RETURN to the caller.
56CF
JP (IY) FD E9
Disk Driver Vector
JUMP through the Drive Code Table driver vector (Register Pair IY), entering the installed double-density read routine to perform the sector read.
56D1
DEFB 02H,02H,12H,53H 02 02 12 53
Driver Vector Template
Four bytes (02H 02H 12H 53H) that trail the loader; the head of the Drive Code Table driver-vector template carried in this image.