TRS-80 DOS - VTOS 4.0.2 for the Model I - BOOT/SYS Disassembled

Page Customization

Introduction/Summary

VTOS 4.0.2 BOOT/SYS Disassembly - The Boot Sectors and the System Information Sector (Model I)

BOOT/SYS is the first file of every VTOS diskette: granule 0 of cylinder 0. Its directory record (the first record of sector 2 of the directory cylinder) gives it 4 records, sectors 0-3, so the file is 1024 bytes. It is not a load module. Sector 0 is the boot sector the ROM runs, sector 1 is a boot sector for a boot through a disk driver, sector 2 is the system information sector and sector 3 is a copy of a granule allocation table. The fifth sector of the granule is not part of the file: FORMAT/CMD writes it with the sector number 7CH in its address mark instead of 4 (its 60CDH-60DBH, on side 0 of cylinder 0), so a sector read of cylinder 0, sector 4 does not find it.

When the computer is reset with a diskette in drive 0, the ROM reads cylinder 0, sector 0 into 4200H-42FFH and jumps to 4200H. The boot sector reads sector 4 of the directory cylinder (the cylinder number is byte 2 of the sector, 4202H), checks that the directory record of SYS0/SYS there holds a file, works out where the file's first extent starts, reads it sector by sector into a buffer at 5100H-51FFH, copies each load block to its address and jumps to the transfer address, 4E00H, the reset of SYS0/SYS. A free directory record displays NO SYSTEM; a sector that cannot be read in two tries displays DISK ERROR. Both wait for a line from the keyboard and stop the computer until RESET is pressed.

SYS0/SYS's reset then reads sector 2 over the boot sector at 4200H. It checks the 64 bytes C0H-FFH, displays the serial number in bytes C0H-C7H after the words VTOS SERIAL #, takes byte 01H as the switch that loads the configuration file CONFIG/SYS, and copies the drive code tables of drives 1-7 from bytes 2AH-6FH to 470AH-474FH.

All four sectors are shown at 4200H-42FFH: sectors 0 and 1 where they run, sectors 2 and 3 where SYS0/SYS, SYS2/SYS and SYS6/SYS read the system information sector and the allocation table. Rows of sectors 1-3 carry ids that name the sector (s1-4246H, for example).

FORMAT/CMD on this diskette carries both boot sectors as images (6A00H and 6B00H) and fills in the directory cylinder (byte 2) and the bootstrap stepping rate (42BCH in sector 0, 4219H in sector 1) when it formats a diskette. Its image of sector 0 differs from the sector 0 on this page in six bytes besides those: the patch it carries named FASBOOT2 puts EX (SP),HL at 42BDH-42C0H and 42CBH-42CCH where this sector has PUSH AF / POP AF twice and PUSH BC / POP BC, a longer delay before the controller's status is read.

How Sector 0 Reads a Sector

Sector 0 works the floppy disk controller through its memory mapped registers, polling the status:

StepWhat the code does
Select01H to the drive select latch 37E1H before the directory read and before every sector of SYS0/SYS (4211H, 427EH)
SeekSector to 37EEH, cylinder to the data register 37EFH, command 1BH to 37ECH; bits 1-0 of the command are the bootstrap stepping rate FORMAT/CMD puts there (42B4H)
ReadCommand 88H, then each byte is taken from 37EFH when the status shows DATA REQUEST, until BUSY goes off (42C5H)
CheckStatus AND 5CH (deleted data mark, record not found, CRC error, lost data); on an error D0H (Force Interrupt) to 37ECH and one more try (42DCH, 42ACH)

The main register set does the loading (Register Pair HL = the load address, Register B = the bytes left in the record); the alternate set does the reading (Register D' = cylinder, Register E' = sector, Register Pair BC' = the buffer pointer). Sector 0 takes a granule as 5 sectors and a cylinder as 10; sector 1 takes both from the drive code table.

The Four Sectors

SectorContents
0The boot sector the ROM runs, 4200H. Byte 2 is the directory cylinder (11H), the operand at 42BCH carries the bootstrap stepping rate. It sets Index Register IY to 0000H, which tells SYS0/SYS's reset to keep its own drive code table of drive 0.
1The boot sector for a boot through a disk driver, 4200H: entered with Index Register IY pointing at drive 0's drive code table, it reads through the driver (function 09H) and works out the geometry from bytes +07H and +08H of the table. It writes the directory cylinder into +09H and the bootstrap stepping rate (the operand at 4219H) into bits 1-0 of +03H; SYS0/SYS's reset copies the table to 4700H. No program on this diskette runs it.
2The system information sector, 4200H: the configuration flag, eight drive code tables (drives 0-7), the serial number QS91215N and the 64 bytes the reset checks. SYS0/SYS reads it into 4200H at every boot.
3A copy of a granule allocation table, 4200H: 35 cylinders of 2 granules, the name VTOS40:F and the date 08/21/80. It is not this diskette's table, which is on the directory cylinder.

The Drive Code Table

Both boot sectors and sector 2 deal with the drive code table, 10 bytes a drive, drives 0-7 at 4700H-474FH in SYS0/SYS. Byte by byte, as the code of this diskette uses it:

ByteContents
+00H-+02HJP to the disk driver (C3H 00H 46H = JP 4600H, SYS0/SYS's floppy driver); C9H in +00H marks a drive that is not in the system. Sector 1 reads through this jump (42D1H).
+03HBits 1-0: the stepping rate (6, 12, 20 or 40 ms on a 5 inch drive). Bit 2: 1 = the shorter wait for a drive that is not ready. Bit 3: a rigid disk. Bit 4: the side being accessed. Bit 5: an 8 inch drive. Bit 6: double density. Bit 7: set in drive 0's table in SYS0/SYS (83H).
+04HBits 3-0: the drive's select bit for the latch at 37E1H. Bit 5: two sides.
+05HThe cylinder the head is on; SYS0/SYS's driver writes it to the track register before a seek.
+06HThe last cylinder (22H = 34 for 35 cylinders).
+07HBits 4-0: the highest sector number of a track (09H: 10 sectors). Bits 7-5: a count less one that multiplies the sectors of a track to give the sectors of a cylinder.
+08HBits 4-0: the sectors of a granule less one. Bits 7-5: the granules of a cylinder less one (24H: 5 sectors, 2 granules).
+09HThe directory cylinder (11H = 17).

Variables

Memory Outside BOOT/SYS

Address
Size
Contents
37E1H
1 byte
Drive Select Latch
Written with 01H (drive 0) by sector 0 at 4213H and 4280H; each write restarts the time-out that keeps the drive motors running. Sector 1 leaves the selecting to the driver.
37ECH
1 byte
Controller Command and Status
Commands 1BH (Seek), 88H (Read Sector) and D0H (Force Interrupt) are written here by sector 0; reading gives the status (bit 0 BUSY, bit 1 DATA REQUEST, bit 2 LOST DATA, bit 3 CRC ERROR, bit 4 RECORD NOT FOUND, bit 6 a deleted data mark).
37EEH
1 byte
Controller Sector Register
The sector to read, stored with the cylinder by LD (37EEH),DE at 42B4H.
37EFH
1 byte
Controller Data Register
The cylinder for the seek (42B4H), then each byte of the sector as it is read (42D7H).
41D2H-41DFH
14 bytes
Stack (Sector 0)
Below 41E0H, set at 4204H: return addresses and the pushes of Register Pairs AF, BC and DE during a read. SYS0/SYS loads nothing there and sets the Stack Pointer to 41E0H again at its 4E03H.
4156H-415FH
10 bytes
Stack (Sector 1)
Below 4160H, set at 4204H: return addresses and the pushes of Register Pairs BC and HL down to the call into the driver; the driver's own pushes go below 4156H.
4200H-42FFH
256 bytes
Boot Sector
The sector the boot runs from. SYS0/SYS's reset reads the system information sector (sector 2) into the same place (its 4F6BH-4F73H), then the allocation table of the directory cylinder (4F9AH-4FA2H).
5100H-51FFH
256 bytes
Sector Buffer
The directory sector of SYS0/SYS (5100H the attribute byte, 5116H-5117H the first extent) and then each sector of SYS0/SYS.
4700H-474FH
80 bytes
Drive Code Tables
In SYS0/SYS, 10 bytes a drive. SYS0/SYS's reset copies the table at Index Register IY to 4700H-4709H after a boot by sector 1 (4E6EH-4E7BH) and bytes 2AH-6FH of sector 2 to 470AH-474FH (4F87H-4F90H).
3CD1H-3CE5H
21 bytes
Serial Number Line
In video memory. SYS0/SYS loads VTOS SERIAL # at 3CD1H-3CDDH and copies bytes C0H-C7H of sector 2 to 3CDEH-3CE5H.

BOOT/SYS Data and Changed Operands

Address
Size
Contents
4202H
1 byte
Directory Cylinder (Sectors 0 and 1)
Byte 2 of each boot sector, the operand of CP 11H: 11H. Read at 4216H (sector 0) and 420DH, 4230H (sector 1); FORMAT/CMD writes it from byte +09H of the drive code table.
42BCH
1 byte
Seek Command (Sector 0)
1BH; bits 1-0 are the bootstrap stepping rate (3). FORMAT/CMD writes the rate into them.
4219H
1 byte
Bootstrap Stepping Rate (Sector 1)
The operand of OR 03H at 4218H: 03H on this diskette. FORMAT/CMD writes it; sector 1 puts it into bits 1-0 of byte +03H of the drive code table.
42A5H
1 byte
Sectors per Cylinder (Sector 1)
The operand of SUB 00H at 42A4H, stored at 422DH from byte +07H of the drive code table.
42E4H-42FFH
28 bytes
Sector 0 Texts
Clear screen (42E4H), NO SYSTEM (42E7H), DISK ERROR (42F3H), each ended by 03H.
42E2H-42FDH
28 bytes
Sector 1 Texts
Clear screen (42E2H), NO SYSTEM (42E5H), DISK ERROR (42F1H), each ended by 03H.

System Information Sector (Sector 2, at 4200H)

Address
Size
Contents
4200H
1 byte
Byte 00H
40H, as FORMAT/CMD writes it. SYS0/SYS does not read it.
4201H
1 byte
Configuration Flag
00H: SYS0/SYS's reset loads CONFIG/SYS; C9H: it does not. Written by SYSTEM (SYSGEN) in SYS6/SYS.
4220H-426FH
80 bytes
Drive Code Tables
Drives 0-7, 10 bytes each, written by BACKUP/CMD with its DRIVER parameter; SYS0/SYS's reset copies drives 1-7 (422AH-426FH) to 470AH-474FH.
42C0H-42C7H
8 bytes
Serial Number
QS91215N, shown by SYS0/SYS's reset at 3CDEH.
42C0H-42FFH
64 bytes
Checked Bytes
SYS0/SYS's reset XORs them with FFH and goes on only when the result is 00H.

Allocation Table Layout (Sector 3, at 4200H)

Address
Size
Contents
4200H-425FH
96 bytes
Allocation Bytes
One byte a cylinder, one bit a granule, 1 = in use.
4260H-42BFH
96 bytes
Lockout Bytes
One byte a cylinder; FORMAT/CMD copies the allocation bytes there after formatting.
42CCH
1 byte
Cylinders Past 35
00H here: 35 cylinders.
42CDH
1 byte
Geometry
Bits 2-0: granules of a cylinder less one; bit 5: two sides.
42CEH-42CFH
2 bytes
Master Password Hash
42E0H here.
42D0H-42DFH
16 bytes
Name and Date
VTOS40:F and 08/21/80 here.
42E0H-42FFH
32 bytes
AUTO Command Line
0DH and 31 spaces here: no command.

Outside Routines

AddressContents
0033HROM: display the character in Register A (42A4H; 42BDH in sector 1).
0040HROM: wait for a line from the keyboard into the buffer at Register Pair HL, at most Register B characters (429AH; 42B3H in sector 1).
4E00HSYS0/SYS: its reset code, the transfer address of SYS0/SYS on this diskette.
4600HSYS0/SYS: the floppy disk driver the drive code tables jump to; sector 1 reaches the driver of drive 0's table through JP (IY).

Disassembly

4200H - Sector 0: Boot Sector Entry

When the computer is reset with a diskette in drive 0, the ROM reads cylinder 0, sector 0 into 4200H-42FFH and jumps to 4200H. This sector finds SYS0/SYS through its directory record (the first record of sector 4 of the directory cylinder), reads the file's first extent sector by sector into the buffer at 5100H-51FFH, copies each load block to its address and jumps to the transfer address (4E00H on this diskette). It works the floppy disk controller directly through its memory mapped registers at 37ECH-37EFH and the drive select latch at 37E1H.

4200
NOP 00
No operation. Byte 0 of the boot sector is 00H; execution passes to 4201H.
4201
CP 11H FE 11
Compare Register A against 11H. The flags are never tested: the instruction only steps over byte 2 of the sector (4202H), which is data: 11H, the cylinder that holds the directory (17). FORMAT/CMD stores the directory cylinder of the new diskette there (its 627BH-627EH put drive code table byte +09H into 6A02H, byte 2 of its image of this sector); the LD A,(4202H) at 4216H below reads it.
4203
DI F3
Disable interrupts. No clock interrupt may run through the RST 38H vector at 4012H while SYS0/SYS loads its blocks over 4000H-40FFH; interrupts stay off until SYS0/SYS's reset turns them on again (its EI at 4E93H).
4204
LD SP,41E0H 31 E0 41
Load the Stack Pointer with 41E0H. The stack holds the return addresses and the pushes of the routines below, at most 14 bytes (41D2H-41DFH) during a sector read called from the byte fetch at 4279H. SYS0/SYS loads nothing at 41D2H-41DFH, and its reset sets the Stack Pointer to 41E0H again (4E03H).
4207
LD IY,0000H FD 21 00 00
Load Index Register IY with 0000H. SYS0/SYS's reset tests Index Register IY (4E6EH-4E73H): 0000H tells it that this sector loaded it, so it keeps the drive code table of drive 0 that it loads at 4700H-4709H; any other value is taken as the address of a drive code table whose 10 bytes it copies to 4700H.
420B
LD HL,42E4H 21 E4 42
Point Register Pair HL to 42E4H, the text 1CH 1FH 03H: cursor to the top left corner, clear to the end of the screen, end of text.
420E
GOSUB to 429EH to display the text at Register Pair HL (42E4H) through the ROM: the screen is cleared.
4211
LD A,01H 3E 01
Load Register A with 01H, the select bit of drive 0.
Drive Select Latch: 01H (00000001)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
00000001Bits 0-3: one bit per drive
drive 0 selected
4213
LD (37E1H),A 32 E1 37
Store Register A (01H) to the drive select latch at 37E1H (37E0H-37E3H all reach the same latch): drive 0 is selected and the drive motors run.
4216
LD A,(4202H) 3A 02 42
Fetch the directory cylinder from 4202H (byte 2 of this sector, 11H on this diskette) into Register A.
4219
LD D,A 57
Copy Register A (the directory cylinder) into Register D, the cylinder for the sector read at 42ACH.
421A
LD E,04H 1E 04
Load Register E with 04H: sector 4 of the directory cylinder, whose first directory record (bytes 00H-1FH) is the record of SYS0/SYS. FORMAT/CMD writes the record of BOOT/SYS into sector 2 and that of DIR/SYS into sector 3 (its 6366H, 6396H); sectors 0 and 1 hold the granule allocation table and the hash index table.
421C
LD BC,5100H 01 00 51
Point Register Pair BC to 5100H, the 256 byte buffer the sector is read into.
421F
GOSUB to 42ACH to read cylinder Register D (11H), sector Register E (04H) into the buffer at Register Pair BC (5100H). On return the Z FLAG is set if one of the two tries succeeded, Register Pair HL holds 5100H and Register Pair BC points past the last byte read.
4222
If the NZ FLAG is set (the directory sector could not be read in two tries), JUMP to 4294H to display DISK ERROR and stop.
4224
LD A,(5100H) 3A 00 51
Fetch byte 00H of the directory record from 5100H into Register A: the attribute byte of SYS0/SYS's record (5FH on this diskette).
4227
AND 10H E6 10
Mask Register A to bit 4, the bit that marks a directory record as holding a file (BACKUP/CMD takes a record with bit 4 clear as free: its 6589H-658DH). The Z FLAG is set when the record is free, that is when the diskette holds no SYS0/SYS.
4229
LD HL,42E7H 21 E7 42
Point Register Pair HL to 42E7H, the text NO SYSTEM, in case the record is free. LD does not change the flags of the AND above.
422C
If the Z FLAG is set (bit 4 of the attribute byte in Register A is 0: no SYS0/SYS on the diskette), JUMP to 4297H to display NO SYSTEM (Register Pair HL = 42E7H) and stop.

422EH - Locate SYS0/SYS on the Diskette

Byte 16H of the directory record is the cylinder of the file's first extent; byte 17H holds the first granule on that cylinder in bits 7-5 and the number of granules less one in bits 4-0 (SYS0/SYS's record on this diskette: 00H and 23H, cylinder 0, granule 1, four granules). This code works the granule into a sector number at 5 sectors a granule and sets up the alternate register set, which does all the reading from here on: Register D' holds the cylinder and Register E' the sector of the next sector to read, Register Pair BC' the pointer into the buffer. Only the first extent is used, read as consecutive sectors.

422E
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set. The values worked out below go into the alternate set, which only the byte fetch at 4279H uses.
422F
LD HL,(5116H) 2A 16 51
Fetch the first extent of SYS0/SYS from 5116H-5117H into Register Pair HL: Register L = byte 16H (the cylinder, 00H here) and Register H = byte 17H (the first granule in bits 7-5, the number of granules less one in bits 4-0: 23H here).
4232
LD D,L 55
Copy Register L (the cylinder of the first extent) into Register D, the cylinder of the first sector to read.
4233
LD A,H 7C
Copy Register H (byte 17H of the record: the first granule in bits 7-5) into Register A.
4234
RLCA 07
Rotate Register A left one bit (bit 7 goes to bit 0 and to the CARRY FLAG): the first of three rotations that bring the first granule from bits 7-5 down to bits 2-0.
4235
RLCA 07
Rotate Register A left one bit again: the second of three rotations that bring the first granule from bits 7-5 down to bits 2-0.
4236
RLCA 07
Rotate Register A left one bit again: bits 7-5 of byte 17H are now bits 2-0 of Register A.
4237
AND 07H E6 07
Mask Register A to bits 2-0: Register A now holds the number of the first granule on the cylinder (1 for SYS0/SYS on this diskette).
4239
LD H,A 67
Copy Register A (the granule number) into Register H, to be added once more below.
423A
RLCA 07
Rotate Register A left one bit: Register A = granule x 2 (bits 2-0 hold at most 7, so no bit is lost).
423B
RLCA 07
Rotate Register A left one bit again: Register A = granule x 4.
423C
ADD A,H 84
ADD Register H (the granule number) to Register A: Register A = granule x 5, the first sector of the granule, since a granule here is 5 sectors (5 for granule 1).
423D
LD E,A 5F
Copy Register A (the first sector of the extent) into Register E. Register Pair DE' now holds the cylinder (Register D) and sector (Register E) of the first sector of SYS0/SYS.
423E
LD BC,51FFH 01 FF 51
Point Register Pair BC to 51FFH, the last byte of the buffer, as the read pointer. The first fetch at 4279H increments Register C to 00H and so reads the first sector before it hands over a byte.
4241
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set again: the main set is back in use and the alternate set keeps the reading state (Register Pair BC' = 51FFH, Register Pair DE' = the first cylinder and sector).

4242H - Load Record Loop

SYS0/SYS is a load module. Each record starts with a type byte and a length byte. Type 01H is a load block: two address bytes and then the data, the length counting the address bytes, so a length of 2 gives no data and a length of 0 or 1 gives 254 or 255 data bytes. Type 02H is the transfer record. Every other type is skipped by its length. The main register set does the loading: Register Pair HL is the load address and Register B the bytes left in the record.

4242
GOSUB to 4279H to fetch the next byte of SYS0/SYS into Register A: the type byte of a record.
4245
DEC A 3D
DECrement Register A (the type byte) by 1. The Z FLAG is set when the type was 01H, a load block.
4246
If the NZ FLAG is set (the type in Register A was not 01H), JUMP to 425FH to test for the transfer record or skip the record.
4248
GOSUB to 4279H to fetch the length byte of the load block into Register A.
424B
LD B,A 47
Copy Register A (the length: the address bytes plus the data bytes) into Register B, the count of the bytes left in the record.
424C
GOSUB to 4279H to fetch the low byte of the load address into Register A.
424F
LD L,A 6F
Copy Register A (the low byte of the load address) into Register L.
4250
DEC B 05
DECrement Register B (the count of the bytes left) by 1 for the low address byte.
4251
GOSUB to 4279H to fetch the high byte of the load address into Register A.
4254
LD H,A 67
Copy Register A (the high byte of the load address) into Register H. Register Pair HL now holds the address the data goes to.
4255
DEC B 05
Loop Start
DECrement Register B (the count of the bytes left in the record) by 1: for the high address byte on the first pass, then for each data byte stored.
4256
If the Z FLAG is set (Register B reached 0: the record is finished), JUMP to 4242H to read the next record.
4258
GOSUB to 4279H to fetch the next data byte of the load block into Register A.
425B
LD (HL),A 77
Store Register A (the data byte) to the load address at Register Pair HL.
425C
INC HL 23
INCrement Register Pair HL (the load address) to the next byte.
425D
Loop End
JUMP to 4255H to count the byte and store the next one.
425F
DEC A 3D
DECrement Register A again: the type byte less 2. The Z FLAG is set when the type was 02H, the transfer record.
4260
If the Z FLAG is set (the type in Register A was 02H), JUMP to 426DH to take the transfer address.
4262
GOSUB to 4279H to fetch the length byte of a record of any other type into Register A.
4265
LD B,A 47
Copy Register A (the length of the record) into Register B, the count of the bytes to skip. A length of 0 skips 256 bytes.
4266
Loop Start
GOSUB to 4279H to fetch the next byte of the record into Register A. The byte is not used: the record is being skipped.
4269
Loop End
DECrement Register B (the bytes left to skip) and LOOP BACK to 4266H while it is not zero.
426B
JUMP to 4242H to read the type byte of the next record.

426DH - Transfer Record: Start SYS0/SYS

The transfer record is the type byte 02H, a length byte and the two byte address SYS0/SYS starts at (4E00H on this diskette, its reset). The jump leaves interrupts off, Index Register IY = 0000H and the stack at 41E0H.

426D
GOSUB to 4279H to fetch the length byte of the transfer record into Register A (02H in SYS0/SYS). It is not used.
4270
GOSUB to 4279H to fetch the low byte of the transfer address into Register A.
4273
LD L,A 6F
Copy Register A (the low byte of the transfer address) into Register L.
4274
GOSUB to 4279H to fetch the high byte of the transfer address into Register A.
4277
LD H,A 67
Copy Register A (the high byte of the transfer address) into Register H. Register Pair HL now holds 4E00H, the reset of SYS0/SYS.
4278
JP (HL) E9
JUMP to the address in Register Pair HL (4E00H), the reset code of SYS0/SYS, which takes over the computer. The boot sector is done; SYS0/SYS later reads cylinder 0, sector 2 over it at 4200H (its 4F6BH-4F73H).

4279H - Fetch the Next Byte of SYS0/SYS

Returns the next byte of the file in Register A. All its work is done in the alternate register set: Register Pair BC' points into the buffer at 5100H-51FFH and Register Pair DE' holds the cylinder and sector of the next sector to read. When the buffer is used up, the next sector is read into it, 10 sectors to a cylinder. The main Register Pairs BC, DE and HL are not changed.

4279
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: Register Pair BC (now the alternate one) is the buffer pointer and Register Pair DE the next cylinder and sector.
427A
INC C 0C
INCrement Register C, the low byte of the buffer pointer in Register Pair BC. After the last byte of the buffer (51FFH) Register C wraps to 00H and Register B stays 51H, so Register Pair BC is 5100H again and the Z FLAG is set.
427B
If the NZ FLAG is set (Register Pair BC still points inside the buffer), JUMP to 4291H to fetch the byte.
427D
PUSH BC C5
Save Register Pair BC (5100H, the start of the buffer) to the stack: the read below advances Register Pair BC through the buffer.
427E
LD A,01H 3E 01
Load Register A with 01H, the select bit of drive 0.
Drive Select Latch: 01H (00000001)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
00000001Bits 0-3: one bit per drive
drive 0 selected
4280
LD (37E1H),A 32 E1 37
Store Register A (01H) to the drive select latch at 37E1H again before every sector: each write restarts the time-out that keeps the drive motors running, so the motors stay on while SYS0/SYS loads.
4283
GOSUB to 42ACH to read cylinder Register D, sector Register E (the next sector of SYS0/SYS) into the buffer at Register Pair BC (5100H). The Z FLAG is set on return if one of the two tries succeeded.
4286
If the NZ FLAG is set (the sector could not be read in two tries), JUMP to 4294H to display DISK ERROR and stop. Register Pair BC is left on the stack, which does not matter, since the computer stops there.
4288
POP BC C1
Restore Register Pair BC (5100H, the first byte of the sector just read) from the stack.
4289
INC E 1C
INCrement Register E (the sector number) to the next sector.
428A
LD A,E 7B
Copy Register E (the next sector number) into Register A.
428B
SUB 0AH D6 0A
SUBtract 0AH from Register A (the next sector number): a cylinder has 10 sectors, 0-9. The Z FLAG is set when the next sector would be 10, past the end of the cylinder.
428D
If the NZ FLAG is set (the next sector in Register E is still on this cylinder), JUMP to 4291H to fetch the byte.
428F
LD E,A 5F
Copy Register A (00H, the result of the SUB) into Register E: the next sector is sector 0 ...
4290
INC D 14
... of the next cylinder: INCrement Register D (the cylinder number) by 1.
4291
LD A,(BC) 0A
Fetch the byte at the buffer pointer in Register Pair BC into Register A: the next byte of SYS0/SYS.
4292
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: the main registers of the loader are back, and the reading state stays in the alternate set for the next fetch.
4293
RET C9
RETurn to the caller with the byte of SYS0/SYS in Register A.

4294H - Display an Error and Stop

Entered at 4294H when a sector cannot be read and at 4297H with Register Pair HL pointing to NO SYSTEM. The text is displayed, the ROM waits for a line from the keyboard and the computer stops; only RESET starts it again.

4294
LD HL,42F3H 21 F3 42
Point Register Pair HL to 42F3H, the text DISK ERROR.
4297
GOSUB to 429EH to display the text at Register Pair HL (42F3H, DISK ERROR, or 42E7H, NO SYSTEM, when 422CH jumps here).
429A
GOSUB to the ROM routine at 0040H, which takes a line from the keyboard into the buffer at Register Pair HL (the text just displayed, which is no longer needed) until ENTER or BREAK is pressed. Register B is the most characters it accepts: 51H or 52H, the high byte of the buffer pointer the failed read left in Register Pair BC (or, from 4286H, in the alternate set's Register Pair BC, which is active there). The line is not used: the call only waits for a key.
429D
HALT 76
HALT. Interrupts are off (4203H), so the processor stays halted until RESET is pressed.

429EH - Display a Text

Displays the text at Register Pair HL through the ROM, character by character, up to the end byte 03H (not displayed). Register Pair HL is unchanged on return.

429E
PUSH HL E5
Save Register Pair HL (the start of the text) to the stack, so the caller gets it back.
429F
LD A,(HL) 7E
Loop Start
Fetch the next character of the text at Register Pair HL into Register A.
42A0
CP 03H FE 03
Compare Register A (the character) against 03H, the end of text byte. If it is 03H, the Z FLAG is set.
42A2
If the Z FLAG is set (Register A holds 03H: the text is finished), JUMP to 42AAH to return.
42A4
GOSUB to the ROM routine at 0033H to display the character in Register A at the cursor. The ROM treats 1CH (cursor home), 1FH (clear to the end of the screen) and 17H (32 characters a line) as controls and C0H-FFH as that many spaces less C0H; it returns with Register Pair HL unchanged.
42A7
INC HL 23
INCrement Register Pair HL (the text pointer) to the next character.
42A8
Loop End
JUMP to 429FH to display the next character.
42AA
POP HL E1
Restore Register Pair HL (the start of the text) from the stack.
42AB
RET C9
RETurn to the caller, with Register Pair HL back at the start of the text it displayed.

42ACH - Read a Sector, Two Tries

Reads cylinder Register D, sector Register E of drive 0 into the buffer at Register Pair BC. The first try is the CALL 42B4H; when it fails, the code falls into 42B4H for the second try, which returns straight to the caller. On return the Z FLAG is set if the sector was read, Register Pair HL holds the buffer address and Register Pair BC points past the last byte stored.

42AC
PUSH BC C5
Save Register Pair BC (the buffer address) to the stack: the read at 42B4H advances Register Pair BC through the buffer.
42AD
GOSUB to 42B4H for the first try at reading cylinder Register D, sector Register E into the buffer at Register Pair BC. The Z FLAG is set on return if it succeeded.
42B0
POP HL E1
Restore the buffer address from the stack into Register Pair HL. POP does not change the flags of the read.
42B1
RET Z C8
If the Z FLAG is set (the first try succeeded), RETurn to the caller with Register Pair HL = the buffer address.
42B2
LD B,H 44
Copy Register H (the high byte of the buffer address) into Register B ...
42B3
LD C,L 4D
... and Register L (its low byte) into Register C. Register Pair BC again holds the buffer address, and the code falls into 42B4H for the second and last try, which returns to this routine's caller.

42B4H - Seek and Read One Sector

Seeks the head to cylinder Register D and reads sector Register E into the buffer at Register Pair BC, taking each byte from the controller as it signals DATA REQUEST. Returns with the Z FLAG set if the sector was read without error.

42B4
LD (37EEH),DE ED 53 EE 37
Store Register Pair DE to 37EEH-37EFH: Register E (the sector) goes to the controller's sector register at 37EEH and Register D (the cylinder) to its data register at 37EFH, where the seek command takes the cylinder to move to. The track register (37EDH) is not written: it holds the cylinder the head is on.
42B8
LD HL,37ECH 21 EC 37
Point Register Pair HL to 37ECH, the controller's command register (written) and status register (read).
42BB
LD (HL),1BH 36 1B
Store 1BH to the command register at Register Pair HL (37ECH): Seek to the cylinder in the data register, with the head loaded. Bits 1-0 of the command byte (42BCH) are the bootstrap stepping rate: FORMAT/CMD writes the rate it asks for into them (its 6285H-628CH, through the pointer at 6800H to 6ABCH, this byte in its image of the sector). 3 is the slowest rate.
1771 FDC Command: 1BH (00011011)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
00011011Command=Seek (bits 7-4 = 0001)
h = 1: head load and settle delay
V = 0: no verify
r1 r0 = 11: 40 ms stepping rate
42BD
PUSH AF F5
Save Register Pair AF to the stack. The push and the pops that follow only spend time: the controller does not show BUSY in its status at once after a command is written. FORMAT/CMD on this diskette writes EX (SP),HL into these four bytes instead (its image at 6ABDH-6AC0H, changed by the patch it carries named FASBOOT2).
42BE
POP AF F1
Restore Register Pair AF from the stack (the delay continues; Register A and the flags are unchanged).
42BF
PUSH AF F5
Save Register Pair AF to the stack again, still only to spend time before the status is read.
42C0
POP AF F1
Restore Register Pair AF from the stack. The delay ends.
42C1
LD A,(HL) 7E
Loop Start
Fetch the controller's status from 37ECH (Register Pair HL) into Register A.
42C2
RRCA 0F
Rotate Register A right one bit: bit 0 of the status (BUSY) goes into the CARRY FLAG.
42C3
Loop End
If the CARRY FLAG is set (the controller is still busy with the seek), LOOP BACK to 42C1H. Seek errors are not tested: a wrong cylinder makes the read below fail.
42C5
LD (HL),88H 36 88
Store 88H to the command register at Register Pair HL (37ECH): Read Sector, the sector in the sector register on the cylinder just reached.
1771 FDC Command: 88H (10001000)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
10001000Command=Read Sector (bits 7-5 = 100)
m = 0: one sector
b = 1: IBM sector length
E = 0: no head load delay
42C7
PUSH DE D5
Save Register Pair DE (the cylinder and sector) to the stack: Register Pair DE is needed for the data register address.
42C8
LD DE,37EFH 11 EF 37
Point Register Pair DE to 37EFH, the controller's data register, where each byte of the sector arrives.
42CB
PUSH BC C5
Save Register Pair BC (the buffer pointer) to the stack. With the POP that follows it only spends time before the first status read. FORMAT/CMD on this diskette writes EX (SP),HL into these two bytes instead (its image at 6ACBH-6ACCH, the FASBOOT2 patch).
42CC
POP BC C1
Restore Register Pair BC (the buffer pointer) from the stack. The delay ends.
42CD
JUMP to 42DAH, whose JUMP goes on to 42D2H: two more jumps of delay before the status is read for the first time.
42CF
RRCA 0F
Rotate Register A (the status just read at 42D2H, with DATA REQUEST clear) right one bit: bit 0 (BUSY) goes into the CARRY FLAG.
42D0
If the NO CARRY FLAG is set (the controller is no longer busy: the sector is finished or the read failed), JUMP to 42DCH to check the result.
42D2
LD A,(HL) 7E
Loop Start
Fetch the controller's status from 37ECH (Register Pair HL) into Register A. 42CDH, 42D5H and 42DAH come here.
42D3
BIT 1,A CB 4F
Test bit 1 of Register A (the status): DATA REQUEST, a byte waiting in the data register. The Z FLAG is set when no byte is waiting.
42D5
If the Z FLAG is set (no byte in the data register yet), JUMP to 42CFH to check whether the controller has finished.
42D7
LD A,(DE) 1A
Fetch the byte from the controller's data register at Register Pair DE (37EFH) into Register A. Reading it clears DATA REQUEST.
42D8
LD (BC),A 02
Store Register A (the byte of the sector) into the buffer at Register Pair BC.
42D9
INC BC 03
INCrement Register Pair BC (the buffer pointer) to the next byte of the buffer.
42DA
Loop End
JUMP to 42D2H to wait for the next byte or the end of the read.
42DC
LD A,(HL) 7E
Fetch the controller's final status from 37ECH (Register Pair HL) into Register A.
42DD
AND 5CH E6 5C
Mask Register A to bits 6, 4, 3 and 2 of the status. The Z FLAG is set when none of them is on: the sector was read.
1771 Status after Read Sector, AND 5CHFunction Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
01011100Bits kept by AND 5CH:
6: F9H or F8H data mark
4: record not found
3: CRC error
2: lost data
Bit 5 (FAH or F8H mark) is not kept
42DF
POP DE D1
Restore Register Pair DE (the cylinder and sector) from the stack. POP does not change the flags.
42E0
RET Z C8
If the Z FLAG is set (no error bit in the status in Register A), RETurn to the caller: the sector is in the buffer.
42E1
LD (HL),D0H 36 D0
Store D0H to the command register at Register Pair HL (37ECH): Force Interrupt, which ends any command still running so that the next try starts clean.
1771 FDC Command: D0H (11010000)Function Description
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0Summary of Bits
11010000Command=Force Interrupt (bits 7-4 = 1101)
I3-I0 = 0000: end the command, no interrupt
42E3
RET C9
RETurn with the NZ FLAG set (the AND above found an error bit in Register A; the store does not change the flags): the read failed.
42E4-42E6
DEFB 1CH, 1FH, 03H 1C 1F 03
The text displayed by 420EH at the start: 1CH moves the cursor to the top left corner, 1FH clears to the end of the screen, 03H ends the text.
42E7-42E8
DEFB 17H, E8H 17 E8
Start of the NO SYSTEM text (4229H): 17H switches the screen to 32 characters a line, E8H displays 40 spaces (E8H less C0H), which puts the message on the second line, 8 characters in.
42E9-42F1
DEFM "NO SYSTEM" 4E 4F 20 53 59 53 54 45 4D
The message displayed when the directory record of SYS0/SYS is not in use (4224H-422CH).
42F2
DEFB 03H 03
End of the NO SYSTEM text: 429EH stops at this byte and does not display it.
42F3-42F4
DEFB 17H, E8H 17 E8
Start of the DISK ERROR text (4294H): 17H switches the screen to 32 characters a line, E8H displays 40 spaces, which puts the message on the second line.
42F5-42FE
DEFM "DISK ERROR" 44 49 53 4B 20 45 52 52 4F 52
The message displayed when a sector cannot be read in two tries (4222H, 4286H).
42FF
DEFB 03H 03
End of the DISK ERROR text, and the last byte of sector 0.

Sector 1: Boot Sector for a Boot Through a Disk Driver

Sector 1 is a second boot sector, shown at 4200H-42FFH where it runs. It is not run by the ROM and no program on this diskette jumps to it: it is entered with Index Register IY pointing to the drive code table of drive 0, whose first three bytes (+00H-+02H) jump to a disk driver. All its reads go through that driver (function 09H, read a sector, the function SYS0/SYS's own driver at 4600H serves with the controller's Read Sector command). It takes the geometry from the drive code table instead of fixed values, writes the directory cylinder and the bootstrap stepping rate into it, and leaves Index Register IY pointing at it, so that SYS0/SYS's reset copies the table to 4700H (its 4E6EH-4E7BH). BACKUP/CMD's DRIVER parameter asks for the interface type of each drive and loads a driver file to fill its drive code table (59B8H-5A2DH); the VTOS addendum names LOBO as such an interface.

4200
NOP 00
No operation. Byte 0 of sector 1 is 00H; execution passes to 4201H.
4201
CP 11H FE 11
Compare Register A against 11H. The flags are never tested: the instruction only steps over byte 2 of the sector (4202H), which is data: 11H, the directory cylinder. FORMAT/CMD stores it there (its 62A4H-62A7H put drive code table byte +09H into 6B02H, byte 2 of its image of this sector); 420DH and 4230H below read it.
4203
DI F3
Disable interrupts. No clock interrupt may run through the RST 38H vector at 4012H while SYS0/SYS loads its blocks over 4000H-40FFH; SYS0/SYS's reset turns interrupts on again (its EI at 4E93H).
4204
LD SP,4160H 31 60 41
Load the Stack Pointer with 4160H. The stack holds the return addresses and pushes of the routines below, 10 bytes (4156H-415FH) down to the JP (IY) into the driver, plus whatever the driver pushes below 4156H.
4207
LD HL,42E2H 21 E2 42
Point Register Pair HL to 42E2H, the text 1CH 1FH 03H: cursor to the top left corner, clear to the end of the screen, end of text.
420A
GOSUB to 42B7H to display the text at Register Pair HL (42E2H) through the ROM: the screen is cleared.
420D
LD A,(4202H) 3A 02 42
Fetch the directory cylinder from 4202H (byte 2 of this sector, 11H) into Register A.
4210
LD (IY+09H),A FD 77 09
Store Register A (the directory cylinder, 11H) to byte +09H of the drive code table at Index Register IY, the byte that holds the directory cylinder of the drive (BACKUP/CMD and FORMAT/CMD read the directory cylinder from +09H: their 5362H and 6323H).
4213
LD A,(IY+03H) FD 7E 03
Fetch byte +03H of the drive code table at Index Register IY into Register A. Bits 1-0 of +03H are the drive's stepping rate, which SYS0/SYS's driver puts into every seek and step command (its 4669H-466EH).
4216
AND FCH E6 FC
Mask Register A (byte +03H of the drive code table) to bits 7-2: the old stepping rate in bits 1-0 is cleared.
4218
OR 03H F6 03
OR Register A with 03H, the bootstrap stepping rate: the operand at 4219H, which FORMAT/CMD writes with the rate it asks for (its 62AEH-62B5H, through the pointer at 6802H to 6B19H, this byte in its image of the sector). 3 is the slowest rate; it is 03H on this diskette.
421A
LD (IY+03H),A FD 77 03
Store Register A (byte +03H with the bootstrap stepping rate in bits 1-0) back to byte +03H of the drive code table at Index Register IY.
421D
LD A,(IY+07H) FD 7E 07
Fetch byte +07H of the drive code table at Index Register IY into Register A: bits 4-0 are the highest sector number of a track (09H in SYS0/SYS's table of drive 0: sectors 0-9), bits 7-5 a count less one that multiplies the sectors of a track (0 there).
4220
LD D,A 57
Copy Register A (byte +07H) into Register D, to be used again below.
4221
AND 1FH E6 1F
Mask Register A to bits 4-0 of byte +07H: the highest sector number of a track.
4223
LD E,A 5F
Copy Register A (the highest sector number) into Register E.
4224
INC E 1C
INCrement Register E: Register E now holds the number of sectors on a track (10 for byte +07H = 09H).
4225
XOR D AA
XOR Register A (bits 4-0 of byte +07H) with Register D (all of byte +07H): the bits 4-0 cancel out, and Register A keeps bits 7-5 of byte +07H.
4226
RLCA 07
Rotate Register A left one bit: the first of three rotations that bring bits 7-5 of byte +07H down to bits 2-0.
4227
RLCA 07
Rotate Register A left one bit again: the second of three rotations that bring bits 7-5 of byte +07H down to bits 2-0.
4228
RLCA 07
Rotate Register A left one bit again: bits 7-5 of byte +07H are now bits 2-0 of Register A.
4229
INC A 3C
INCrement Register A: the count kept in bits 7-5 of byte +07H, plus one (1 for byte +07H = 09H).
422A
GOSUB to 42D3H to multiply Register A (the count, 1) by Register E (the sectors on a track, 10): Register A returns the sectors on a cylinder (10).
422D
LD (42A5H),A 32 A5 42
Store Register A (the sectors on a cylinder) to 42A5H, the operand of SUB 00H at 42A4H in the byte fetch below, which tests when the next sector is past the end of the cylinder.
4230
LD A,(4202H) 3A 02 42
Fetch the directory cylinder from 4202H (11H) into Register A again.
4233
LD D,A 57
Copy Register A (the directory cylinder) into Register D, the cylinder for the read at 42C5H.
4234
LD E,04H 1E 04
Load Register E with 04H: sector 4 of the directory cylinder, whose first directory record is the record of SYS0/SYS.
4236
LD BC,5100H 01 00 51
Point Register Pair BC to 5100H, the 256 byte buffer the sector is read into.
4239
GOSUB to 42C5H to read cylinder Register D (11H), sector Register E (04H) into the buffer at Register Pair BC (5100H) through the driver. The result is not tested: when the driver fails, the code goes on with whatever the buffer holds.
423C
LD A,(5100H) 3A 00 51
Fetch byte 00H of the directory record from 5100H into Register A: the attribute byte of SYS0/SYS's record.
423F
AND 10H E6 10
Mask Register A to bit 4, the bit that marks a directory record as holding a file. The Z FLAG is set when the record is free: the diskette holds no SYS0/SYS.
4241
LD HL,42E5H 21 E5 42
Point Register Pair HL to 42E5H, the text NO SYSTEM, in case the record is free. LD does not change the flags of the AND above.
4244
If the Z FLAG is set (bit 4 of the attribute byte in Register A is 0: no SYS0/SYS), JUMP to 42B0H to display NO SYSTEM (Register Pair HL = 42E5H) and stop.

4246H - Locate SYS0/SYS (Sector 1)

Bytes 16H and 17H of the directory record give the cylinder and the first granule of SYS0/SYS's first extent. Sector 1 works the granule into a sector with the sectors per granule from byte +08H of the drive code table (bits 4-0, the sectors of a granule less one) and sets up the alternate register set for the byte fetch at 4297H: Register D' the cylinder, Register E' the sector, Register Pair BC' the buffer pointer.

4246
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set. The values worked out below go into the alternate set, which only the byte fetch at 4297H uses.
4247
LD HL,(5116H) 2A 16 51
Fetch the first extent of SYS0/SYS from 5116H-5117H into Register Pair HL: Register L = byte 16H (the cylinder, 00H on this diskette) and Register H = byte 17H (the first granule in bits 7-5, the number of granules less one in bits 4-0: 23H).
424A
LD A,H 7C
Copy Register H (byte 17H: the first granule in bits 7-5) into Register A.
424B
RLCA 07
Rotate Register A left one bit: the first of three rotations that bring the first granule from bits 7-5 down to bits 2-0.
424C
RLCA 07
Rotate Register A left one bit again: the second of three rotations that bring the first granule from bits 7-5 down to bits 2-0.
424D
RLCA 07
Rotate Register A left one bit again: bits 7-5 of byte 17H are now bits 2-0 of Register A.
424E
AND 07H E6 07
Mask Register A to bits 2-0: Register A now holds the number of the first granule on the cylinder (1 for SYS0/SYS on this diskette).
4250
LD E,A 5F
Copy Register A (the first granule) into Register E, the multiplier for 42D3H.
4251
LD A,(IY+08H) FD 7E 08
Fetch byte +08H of the drive code table at Index Register IY into Register A: bits 4-0 are the sectors of a granule less one, bits 7-5 the granules of a cylinder less one (24H in SYS0/SYS's table of drive 0: 5 sectors, 2 granules).
4254
AND 1FH E6 1F
Mask Register A to bits 4-0 of byte +08H: the sectors of a granule less one (04H).
4256
INC A 3C
INCrement Register A: the sectors of a granule (5).
4257
GOSUB to 42D3H to multiply Register A (the sectors of a granule) by Register E (the first granule): Register A returns the first sector of the extent (5).
425A
LD E,A 5F
Copy Register A (the first sector of the extent) into Register E.
425B
LD D,L 55
Copy Register L (byte 16H of the record: the cylinder of the first extent) into Register D. Register Pair DE' now holds the cylinder and sector of the first sector of SYS0/SYS.
425C
LD BC,51FFH 01 FF 51
Point Register Pair BC to 51FFH, the last byte of the buffer, as the read pointer. The first fetch at 4297H increments Register C to 00H and so reads the first sector before it hands over a byte.
425F
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set again: the main set is back in use and the alternate set keeps the reading state for the byte fetch.

4260H - Load Record Loop (Sector 1)

The same loader as sector 0's at 4242H, fetching through 4297H: type 01H records are load blocks (the length counts the two address bytes, so 0 or 1 gives 254 or 255 data bytes), type 02H is the transfer record, every other type is skipped by its length. Register Pair HL is the load address and Register B the bytes left in the record.

4260
GOSUB to 4297H to fetch the next byte of SYS0/SYS into Register A: the type byte of a record.
4263
DEC A 3D
DECrement Register A (the type byte) by 1. The Z FLAG is set when the type was 01H, a load block.
4264
If the NZ FLAG is set (the type in Register A was not 01H), JUMP to 427DH to test for the transfer record or skip the record.
4266
GOSUB to 4297H to fetch the length byte of the load block into Register A.
4269
LD B,A 47
Copy Register A (the length: the address bytes plus the data bytes) into Register B, the count of the bytes left in the record.
426A
GOSUB to 4297H to fetch the low byte of the load address into Register A.
426D
LD L,A 6F
Copy Register A (the low byte of the load address) into Register L.
426E
DEC B 05
DECrement Register B (the count of the bytes left) by 1 for the low address byte.
426F
GOSUB to 4297H to fetch the high byte of the load address into Register A.
4272
LD H,A 67
Copy Register A (the high byte of the load address) into Register H. Register Pair HL now holds the address the data goes to.
4273
DEC B 05
Loop Start
DECrement Register B (the count of the bytes left in the record) by 1: for the high address byte on the first pass, then for each data byte stored.
4274
If the Z FLAG is set (Register B reached 0: the record is finished), JUMP to 4260H to read the next record.
4276
GOSUB to 4297H to fetch the next data byte of the load block into Register A.
4279
LD (HL),A 77
Store Register A (the data byte) to the load address at Register Pair HL.
427A
INC HL 23
INCrement Register Pair HL (the load address) to the next byte.
427B
Loop End
JUMP to 4273H to count the byte and store the next one.
427D
DEC A 3D
DECrement Register A again: the type byte less 2. The Z FLAG is set when the type was 02H, the transfer record.
427E
If the Z FLAG is set (the type in Register A was 02H), JUMP to 428BH to take the transfer address.
4280
GOSUB to 4297H to fetch the length byte of a record of any other type into Register A.
4283
LD B,A 47
Copy Register A (the length of the record) into Register B, the count of the bytes to skip. A length of 0 skips 256 bytes.
4284
Loop Start
GOSUB to 4297H to fetch the next byte of the record into Register A. The byte is not used: the record is being skipped.
4287
Loop End
DECrement Register B (the bytes left to skip) and LOOP BACK to 4284H while it is not zero.
4289
JUMP to 4260H to read the type byte of the next record.

428BH - Transfer Record: Start SYS0/SYS (Sector 1)

The transfer record gives the address SYS0/SYS starts at (4E00H on this diskette). The jump leaves interrupts off and Index Register IY pointing at the drive code table this sector was entered with, which SYS0/SYS's reset copies to 4700H.

428B
GOSUB to 4297H to fetch the length byte of the transfer record into Register A (02H). It is not used.
428E
GOSUB to 4297H to fetch the low byte of the transfer address into Register A.
4291
LD L,A 6F
Copy Register A (the low byte of the transfer address) into Register L.
4292
GOSUB to 4297H to fetch the high byte of the transfer address into Register A.
4295
LD H,A 67
Copy Register A (the high byte of the transfer address) into Register H. Register Pair HL now holds 4E00H, the reset of SYS0/SYS.
4296
JP (HL) E9
JUMP to the address in Register Pair HL (4E00H), the reset code of SYS0/SYS. Index Register IY still points to the drive code table, so the reset copies it to 4700H as drive 0's table.

4297H - Fetch the Next Byte of SYS0/SYS (Sector 1)

Returns the next byte of the file in Register A, working in the alternate register set (Register Pair BC' the buffer pointer, Register Pair DE' the next cylinder and sector). When the buffer at 5100H-51FFH is used up, the next sector is read through the driver; the sectors of a cylinder come from the operand at 42A5H that 422DH stored.

4297
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: Register Pair BC (now the alternate one) is the buffer pointer and Register Pair DE the next cylinder and sector.
4298
INC C 0C
INCrement Register C, the low byte of the buffer pointer in Register Pair BC. After the last byte of the buffer (51FFH) Register C wraps to 00H and Register Pair BC is 5100H again, with the Z FLAG set.
4299
If the NZ FLAG is set (Register Pair BC still points inside the buffer), JUMP to 42AAH to fetch the byte.
429B
PUSH BC C5
Save Register Pair BC (5100H, the start of the buffer) to the stack.
429C
GOSUB to 42C5H to read cylinder Register D, sector Register E (the next sector of SYS0/SYS) into the buffer at Register Pair BC (5100H) through the driver. The Z FLAG is set on return if the driver read it.
429F
If the NZ FLAG is set (the driver could not read the sector), JUMP to 42ADH to display DISK ERROR and stop.
42A1
POP BC C1
Restore Register Pair BC (5100H, the first byte of the sector just read) from the stack.
42A2
INC E 1C
INCrement Register E (the sector number) to the next sector.
42A3
LD A,E 7B
Copy Register E (the next sector number) into Register A.
42A4
SUB 00H D6 00
SUBtract the sectors on a cylinder from Register A (the next sector number). Self-Modifying Code
The operand at 42A5H is 00H in the file; 422DH stores the sectors on a cylinder there (10 with SYS0/SYS's table of drive 0). The Z FLAG is set when the next sector would be past the end of the cylinder.
42A6
If the NZ FLAG is set (the next sector in Register E is still on this cylinder), JUMP to 42AAH to fetch the byte.
42A8
LD E,A 5F
Copy Register A (00H, the result of the SUB) into Register E: the next sector is sector 0 ...
42A9
INC D 14
... of the next cylinder: INCrement Register D (the cylinder number) by 1.
42AA
LD A,(BC) 0A
Fetch the byte at the buffer pointer in Register Pair BC into Register A: the next byte of SYS0/SYS.
42AB
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: the main registers of the loader are back, and the reading state stays in the alternate set.
42AC
RET C9
RETurn to the caller with the byte of SYS0/SYS in Register A.

42ADH - Display an Error and Stop (Sector 1)

Entered at 42ADH when the driver cannot read a sector and at 42B0H with Register Pair HL pointing to NO SYSTEM. The text is displayed, the ROM waits for a line from the keyboard and the computer stops until RESET.

42AD
LD HL,42F1H 21 F1 42
Point Register Pair HL to 42F1H, the text DISK ERROR.
42B0
GOSUB to 42B7H to display the text at Register Pair HL (42F1H, DISK ERROR, or 42E5H, NO SYSTEM, when 4244H jumps here).
42B3
GOSUB to the ROM routine at 0040H, which takes a line from the keyboard into the buffer at Register Pair HL (the text just displayed) until ENTER or BREAK is pressed; Register B is the most characters it accepts: 09H, the driver function 42C8H loaded on both roads here. The line is not used: the call only waits for a key.
42B6
HALT 76
HALT. Interrupts are off (4203H), so the processor stays halted until RESET is pressed.

42B7H - Display a Text (Sector 1)

Displays the text at Register Pair HL through the ROM up to the end byte 03H (not displayed). Register Pair HL is unchanged on return.

42B7
PUSH HL E5
Save Register Pair HL (the start of the text) to the stack, so the caller gets it back.
42B8
LD A,(HL) 7E
Loop Start
Fetch the next character of the text at Register Pair HL into Register A.
42B9
CP 03H FE 03
Compare Register A (the character) against 03H, the end of text byte. If it is 03H, the Z FLAG is set.
42BB
If the Z FLAG is set (Register A holds 03H: the text is finished), JUMP to 42C3H to return.
42BD
GOSUB to the ROM routine at 0033H to display the character in Register A at the cursor (1CH, 1FH and 17H are controls, C0H-FFH spaces); it returns with Register Pair HL unchanged.
42C0
INC HL 23
INCrement Register Pair HL (the text pointer) to the next character.
42C1
Loop End
JUMP to 42B8H to display the next character.
42C3
POP HL E1
Restore Register Pair HL (the start of the text) from the stack.
42C4
RET C9
RETurn to the caller, with Register Pair HL back at the start of the text it displayed.

42C5H - Read a Sector Through the Driver

Reads cylinder Register D, sector Register E of drive 0 into the buffer at Register Pair BC by calling the driver through the drive code table at Index Register IY. The driver is given the buffer in Register Pair HL, the function in Register B and the drive in Register C; it returns the Z FLAG set when the sector was read.

42C5
PUSH HL E5
Save Register Pair HL (the caller's value: a text pointer or the load address) to the stack.
42C6
LD H,B 60
Copy Register B (the high byte of the buffer address) into Register H ...
42C7
LD L,C 69
... and Register C (its low byte) into Register L: Register Pair HL now holds the buffer address (5100H), where the driver puts the sector.
42C8
LD B,09H 06 09
Load Register B with 09H, the driver function: read a sector. SYS0/SYS's driver at 4600H takes a function with bit 3 set and bit 2 clear as a read (its 4678H-467EH: the controller command 88H).
42CA
LD C,00H 0E 00
Load Register C with 00H, drive 0. BACKUP/CMD and FORMAT/CMD also pass the drive in Register C when they call a driver (their 5455H-545AH and 6464H).
42CC
GOSUB to 42D1H, which jumps into the driver through the drive code table, so that the driver's RETurn comes back to 42CFH.
42CF
POP HL E1
Restore Register Pair HL (the caller's value) from the stack. POP does not change the flags the driver returned.
42D0
RET C9
RETurn to the caller with the driver's result in the flags (the Z FLAG set when the sector was read).
42D1
JP (IY) FD E9
JUMP to the drive code table at Index Register IY: its bytes +00H-+02H are a JP to the disk driver (C3H 00H 46H, JP 4600H, in SYS0/SYS's own table of drive 0).

42D3H - Multiply Register A by Register E

An 8 bit multiply by shifts and adds: Register A returns the low 8 bits of Register A x Register E. Register D is left holding the old Register A and Register E is shifted to 00H; Register Pair BC is kept.

42D3
PUSH BC C5
Save Register Pair BC to the stack: Register B is used as the bit counter.
42D4
LD D,A 57
Copy Register A (the multiplicand) into Register D.
42D5
XOR A AF
Set Register A, the product, to ZERO and clear all flags.
42D6
LD B,08H 06 08
Load Register B with 08H, the count of the 8 bits of Register E (the multiplier).
42D8
ADD A,A 87
Loop Start
ADD Register A to itself: the product so far is doubled, making room for the next bit of the multiplier.
42D9
SLA E CB 23
Shift Register E (the multiplier) left one bit: its top bit goes into the CARRY FLAG.
42DB
If the NO CARRY FLAG is set (that bit of the multiplier in Register E was 0), JUMP to 42DEH and add nothing.
42DD
ADD A,D 82
ADD Register D (the multiplicand) to Register A (the product), for the 1 bit of the multiplier.
42DE
Loop End
DECrement Register B (the bits left) and LOOP BACK to 42D8H while it is not zero.
42E0
POP BC C1
Restore Register Pair BC (the caller's value) from the stack; Register B was the bit counter.
42E1
RET C9
RETurn to the caller with the product in Register A.
42E2-42E4
DEFB 1CH, 1FH, 03H 1C 1F 03
The text displayed by 420AH at the start: 1CH moves the cursor to the top left corner, 1FH clears to the end of the screen, 03H ends the text.
42E5-42E6
DEFB 17H, E8H 17 E8
Start of the NO SYSTEM text (4241H): 17H switches the screen to 32 characters a line, E8H displays 40 spaces (E8H less C0H), which puts the message on the second line, 8 characters in.
42E7-42EF
DEFM "NO SYSTEM" 4E 4F 20 53 59 53 54 45 4D
The message displayed when the directory record of SYS0/SYS is not in use (423CH-4244H).
42F0
DEFB 03H 03
End of the NO SYSTEM text: 42B7H stops at this byte and does not display it.
42F1-42F2
DEFB 17H, E8H 17 E8
Start of the DISK ERROR text (42ADH): 32 characters a line, then 40 spaces.
42F3-42FC
DEFM "DISK ERROR" 44 49 53 4B 20 45 52 52 4F 52
The message displayed when the driver cannot read a sector of SYS0/SYS (429FH).
42FD
DEFB 03H 03
End of the DISK ERROR text: 42B7H stops at this byte and does not display it.
42FE-42FF
DEFB FFH, FFH FF FF
The last two bytes of sector 1, FFH FFH. No code of this sector uses them.

Sector 2: The System Information Sector

Sector 2 is shown at 4200H-42FFH, where SYS0/SYS's reset reads it at every boot (its 4F6BH-4F73H read cylinder 0, sector 2 of drive 0 over the boot sector). The reset checks bytes C0H-FFH (4F45H-4F4EH), takes byte 01H as an instruction (4F76H-4F79H), shows bytes C0H-C7H on the screen (4F7CH-4F85H) and copies the drive code tables of drives 1-7 (4F87H-4F90H). FORMAT/CMD writes the sector as 40H and 255 bytes of 00H (62E5H-62F5H); BACKUP/CMD copies it from the source diskette to the destination (660CH-6627H) and, with its DRIVER parameter, writes the drive code tables into it (5287H-52B2H); SYSTEM (SYSGEN) in SYS6/SYS writes byte 01H.

4200
DEFB 40H 40
Byte 00H: 40H. FORMAT/CMD writes it (its 62EDH-62F0H store 40H at 6C00H, the start of the sector it writes, after clearing the other 255 bytes). SYS0/SYS's reset does not read it.
4201
DEFB 00H 00
Byte 01H: the configuration flag. SYS0/SYS's reset stores it at 4FE1H as an instruction byte (4F76H-4F79H). 00H (NOP) lets the reset run on into 4FE2H, which loads CONFIG/SYS (the file specification at 4338H) through 4430H unless bit 1 of 3860H is set (the CLEAR key held during the boot); C9H (RET) returns there, and no configuration is loaded. SYSTEM (SYSGEN) in SYS6/SYS writes 00H here after it has written the configuration file (its 52BBH) and SYSTEM (SYSGEN=OFF) writes C9H (its 5349H). 00H on this diskette.
4202-421F
DEFB 00H x 30 00 x 30
Bytes 02H-1FH: 30 bytes of 00H, as FORMAT/CMD writes them. SYS0/SYS's reset does not read them.
4220-4229
DEFB C3H, 00H, 46H, 86H, 01H, 13H, 22H, 09H, 24H, 11H C3 00 46 86 01 13 22 09 24 11
Bytes 20H-29H: the drive code table of drive 0, the first of eight tables of 10 bytes (drives 0-7, bytes 20H-6FH) that BACKUP/CMD with its DRIVER parameter copies here from memory (4700H-474FH). SYS0/SYS's reset does not copy this one: drive 0's table comes from SYS0/SYS (4700H) or from the table sector 1 was entered with. +00H-+02H JP 4600H (SYS0/SYS's floppy disk driver); +03H 86H (bits 1-0 = 2, the stepping rate, 20 ms; bit 2 set, the shorter wait for a drive that is not ready, shown as DLY=.5 by SYS6/SYS's drive display; bit 7 set, as in drive 0's table in SYS0/SYS); +04H 01H (bits 3-0, the select bit of drive 0); +05H 13H (the cylinder the head was on, 19); +06H 22H (the last cylinder, 34: 35 cylinders); +07H 09H (the highest sector number of a track, 9: 10 sectors); +08H 24H (bits 4-0 = 4, the sectors of a granule less one; bits 7-5 = 1, the granules of a cylinder less one); +09H 11H (the directory cylinder, 17).
422A-4233
DEFB C3H, 00H, 46H, 03H, 02H, 11H, 22H, 09H, 24H, 11H C3 00 46 03 02 11 22 09 24 11
Bytes 2AH-33H: the drive code table of drive 1. SYS0/SYS's reset copies bytes 2AH-6FH (drives 1-7, 70 bytes) to 470AH-474FH at every boot (4F87H-4F90H). +00H-+02H JP 4600H; +03H 03H (stepping rate 3, 40 ms; bit 2 clear, the longer wait for a drive that is not ready, DLY=1); +04H 02H (the select bit of drive 1); +05H 11H (the cylinder the head was on, 17); +06H 22H (35 cylinders); +07H 09H (10 sectors a track); +08H 24H (5 sectors a granule, 2 granules a cylinder); +09H 11H (the directory cylinder).
4234-423D
DEFB C3H, 00H, 46H, 03H, 04H, 00H, 22H, 09H, 24H, 11H C3 00 46 03 04 00 22 09 24 11
Bytes 34H-3DH: the drive code table of drive 2, copied to 4714H-471DH by SYS0/SYS's reset. +00H-+02H JP 4600H; +03H 03H (stepping rate 40 ms, the longer wait for a drive that is not ready); +04H 04H (the select bit of drive 2); +05H 00H (the head on cylinder 0); +06H 22H (35 cylinders); +07H 09H (10 sectors a track); +08H 24H (5 sectors a granule, 2 granules a cylinder); +09H 11H (the directory cylinder).
423E-4247
DEFB C3H, 00H, 46H, 03H, 08H, 11H, 22H, 09H, 24H, 11H C3 00 46 03 08 11 22 09 24 11
Bytes 3EH-47H: the drive code table of drive 3, copied to 471EH-4727H by SYS0/SYS's reset. +00H-+02H JP 4600H; +03H 03H (stepping rate 40 ms, the longer wait for a drive that is not ready); +04H 08H (the select bit of drive 3); +05H 11H (the head on cylinder 17); +06H 22H (35 cylinders); +07H 09H (10 sectors a track); +08H 24H (5 sectors a granule, 2 granules a cylinder); +09H 11H (the directory cylinder).
4248-4251
DEFB C9H, 00H x 9 C9 00 00 00 00 00 00 00 00 00
Bytes 48H-51H: the drive code table of drive 4, copied to 4728H-4731H. C9H (RET) in byte +00H marks a drive that is not in the system: BACKUP/CMD writes C9H there for drives 4-7 when its interface question is answered with BREAK (its 59D9H-59E1H; drives 0-3 get the standard table JP 4600H instead), and SYS2/SYS goes no further with a table whose +00H is not C3H (its 514CH-5151H). The other nine bytes are 00H.
4252-425B
DEFB C9H, 00H x 9 C9 00 00 00 00 00 00 00 00 00
Bytes 52H-5BH: the drive code table of drive 5, copied to 4732H-473BH: C9H (no drive) and nine bytes of 00H.
425C-4265
DEFB C9H, 00H x 9 C9 00 00 00 00 00 00 00 00 00
Bytes 5CH-65H: the drive code table of drive 6, copied to 473CH-4745H: C9H (no drive) and nine bytes of 00H.
4266-426F
DEFB C9H, 00H x 9 C9 00 00 00 00 00 00 00 00 00
Bytes 66H-6FH: the drive code table of drive 7, copied to 4746H-474FH: C9H (no drive) and nine bytes of 00H. This is the last byte SYS0/SYS's reset copies.
4270-42BF
DEFB 00H x 80 00 x 80
Bytes 70H-BFH: 80 bytes of 00H, as FORMAT/CMD writes them. SYS0/SYS's reset does not read them.
42C0-42C7
DEFM "QS91215N" 51 53 39 31 32 31 35 4E
Bytes C0H-C7H: the serial number of the diskette, QS91215N. SYS0/SYS's reset copies these 8 bytes into video memory at 3CDEH-3CE5H (4F7CH-4F85H), after the words VTOS SERIAL # that SYS0/SYS loads at 3CD1H-3CDDH, so the number is shown on the fourth line of the screen at every boot. They are also the first 8 of the 64 bytes the reset checks.
42C8
DEFB 75H 75
Byte C8H: 75H, one of the 64 bytes (C0H-FFH) that SYS0/SYS's reset checks: it XORs all 64 bytes with FFH and goes on only when the result is 00H, that is when the XOR of the 64 bytes is FFH (4F45H-4F4EH). When the check fails, the reset clears the date, displays --NO DATE-- and reads the sector again, and it does not get past this point until the check passes. On this diskette the XOR of bytes C0H-FFH is FFH. The reset uses this byte for nothing else.
42C9-42CD
DEFB 00H x 5 00 x 5
Bytes C9H-CDH: five bytes of 00H inside the 64 bytes SYS0/SYS's reset checks (C0H-FFH). The reset uses them for nothing else.
42CE-42CF
DEFB 40H, 01H 40 01
Bytes CEH-CFH: 40H 01H, two of the 64 bytes SYS0/SYS's reset checks (C0H-FFH). The reset uses them for nothing else.
42D0-42D2
DEFB 4EH, 16H, 32H 4E 16 32
Bytes D0H-D2H: 4EH 16H 32H, three of the 64 bytes SYS0/SYS's reset checks (C0H-FFH). The reset uses them for nothing else.
42D3-42D7
DEFB 00H x 5 00 x 5
Bytes D3H-D7H: five bytes of 00H inside the 64 bytes SYS0/SYS's reset checks (C0H-FFH). The reset uses them for nothing else.
42D8-42DF
DEFB 52H, 46H, FDH, BFH, C0H, 3CH, 45H, 3CH 52 46 FD BF C0 3C 45 3C
Bytes D8H-DFH: 52H 46H FDH BFH C0H 3CH 45H 3CH, eight of the 64 bytes SYS0/SYS's reset checks (C0H-FFH). The reset uses them for nothing else.
42E0-42FF
DEFB 00H x 32 00 x 32
Bytes E0H-FFH: 32 bytes of 00H, the last of the 64 bytes SYS0/SYS's reset checks (C0H-FFH), and the end of sector 2.

Sector 3: A Copy of a Granule Allocation Table

Sector 3 has the layout of the granule allocation table, the first sector of the directory cylinder; it is shown at 4200H-42FFH, the buffer where SYS2/SYS and SYS6/SYS read that table. FORMAT/CMD writes its new table here as well (62CDH-62E2H write its buffer at 6900H to cylinder 0, sector 3 before 6306H-631DH fill in bytes CCH and CDH and write the table to the directory cylinder). SYS0/SYS does not read this sector: it reads the table on the directory cylinder (4F9AH-4FA2H). The copy on this diskette is not this diskette's table: it holds 35 cylinders, the name VTOS40:F and the date 08/21/80, where the table on the directory cylinder (sector 0 of DIR/SYS) holds 42 cylinders, the name VTOS4.02 and the date 00/00/00.

4200-4209
DEFB FFH x 10 FF x 10
Bytes 00H-09H: the allocation bytes of cylinders 0-9, one byte a cylinder, one bit a granule (bit 0 granule 0, bit 1 granule 1), 1 = in use. SYS6/SYS counts the free granules by the 0 bits (its 52A6H-52B7H). FFH: both granules of each of these cylinders in use; bits 7-2 are always 1, since a cylinder has only 2 granules.
420A
DEFB FDH FD
Byte 0AH: cylinder 10, FDH: granule 0 in use (bit 0 = 1), granule 1 free (bit 1 = 0).
420B-420F
DEFB FCH x 5 FC x 5
Bytes 0BH-0FH: cylinders 11-15, FCH: both granules free (bits 1-0 = 00).
4210-421A
DEFB FFH x 11 FF x 11
Bytes 10H-1AH: cylinders 16-26, FFH: both granules in use. Cylinder 17 (11H) is the directory cylinder, which FORMAT/CMD marks as wholly in use (its 6272H-6279H store FFH at 6900H plus the directory cylinder).
421B
DEFB FDH FD
Byte 1BH: cylinder 27, FDH: granule 0 in use, granule 1 free.
421C-4222
DEFB FCH x 7 FC x 7
Bytes 1CH-22H: cylinders 28-34, FCH: both granules free. Cylinder 34 is the last of the 35 cylinders this table describes (byte CCH below).
4223-425F
DEFB FFH x 61 FF x 61
Bytes 23H-5FH: the allocation bytes of cylinders 35-95, which this table's diskette does not have: FFH, nothing to allocate. The allocation bytes run from 00H to 5FH.
4260-4282
DEFB FCH x 35 FC x 35
Bytes 60H-82H: the lockout table of cylinders 0-34, one byte a cylinder at 60H plus the cylinder. FORMAT/CMD copies the allocation bytes there after it has formatted and verified every cylinder (its 61C2H-61CEH), so a cylinder FORMAT/CMD has marked FFH while formatting (61E8H-61EBH) stays locked out; BACKUP/CMD compares the two diskettes' lockout bytes (LOCKOUT TABLE MISMATCH!). FCH: every granule of the 35 cylinders is usable.
4283-42BF
DEFB FFH x 61 FF x 61
Bytes 83H-BFH: the lockout bytes of cylinders 35-95, which the diskette does not have: FFH, every granule locked out. The lockout table runs from 60H to BFH.
42C0-42CA
DEFB FFH x 11 FF x 11
Bytes C0H-CAH: 11 bytes of FFH after the lockout table. No code of this diskette reads them.
42CB
DEFB 40H 40
Byte CBH: 40H, the value of FORMAT/CMD's template at 69CBH. No code of this diskette reads it.
42CC
DEFB 00H 00
Byte CCH: the number of cylinders past 35: 00H, so the diskette has 35 cylinders. SYS2/SYS sets byte +06H (the last cylinder) of the drive code table to 22H plus this byte (its 5185H-518CH), and SYS6/SYS counts free granules over 23H plus this byte cylinders (its 52A6H-52ABH). FORMAT/CMD writes it as byte +06H less 22H (its 6306H-630BH).
42CD
DEFB 01H 01
Byte CDH: the geometry byte. Bits 2-0 = 1: the granules of a cylinder less one (2 granules), which FORMAT/CMD takes from bits 7-5 of byte +08H of the drive code table, with bits 7-5 from bits 7-5 of byte +04H (its 630EH-631DH). SYS2/SYS sets bit 5 of byte +04H (two sides) from bit 5 of this byte (its 5193H-5197H); it is 0 here, one side.
42CE-42CF
DEFW 42E0H E0 42
Bytes CEH-CFH: E0H 42H, the hash of the diskette's master password. FORMAT/CMD hashes the password it is given (the MPW parameter or its MASTER PASSWORD ? question) with request E4H and stores the result here (its 6DF1H-6DF8H). SYS6/SYS compares these 18 bytes, CEH-DFH (the hash, the name and the date), with the ones it saved to tell one diskette from another (its 5372H-537AH and 538FH-5397H).
42D0-42D7
DEFM "VTOS40:F" 56 54 4F 53 34 30 3A 46
Bytes D0H-D7H: the name of the diskette, VTOS40:F, 8 characters. SYS6/SYS copies bytes D0H-D7H and D8H-DFH to its display buffers (its 528DH-529EH).
42D8-42DF
DEFM "08/21/80" 30 38 2F 32 31 2F 38 30
Bytes D8H-DFH: the date of the diskette, 08/21/80, in the form MM/DD/YY of FORMAT/CMD's template (69D8H-69DFH).
42E0
DEFB 0DH 0D
Byte E0H: 0DH, the end of an empty AUTO command line. In the table on the directory cylinder SYS0/SYS's reset reads bytes E0H-FFH as the AUTO command line (4FA8H-4FD3H: a first byte of 2AH, an asterisk, is skipped and makes the reset pass over its tests of the keys held at the boot; 32 bytes go to 4318H). FORMAT/CMD's template gives 0DH and 31 spaces.
42E1-42FF
DEFB 20H x 31 20 x 31
Bytes E1H-FFH: 31 spaces after the 0DH, the rest of the AUTO command line area of FORMAT/CMD's template (69E1H-69FFH), and the end of sector 3 and of BOOT/SYS.