TRS-80 DOS - NEWDOS/80 v2.0 for the Model I - SYS0/SYS Disassembled

Page Customization

Introduction/Summary

NEWDOS/80 v2.0 SYS0/SYS Disassembly - the Resident DOS (Model I)

SYS0/SYS is the resident part of NEWDOS/80: it stays in memory from 4000H to 4CFFH while the DOS runs. It holds the DOS entry vectors, the sector level disk I/O, the drive selection, the FCB routines for reading, writing and positioning files, the directory sector routines, the RST 28H dispatcher that loads and calls the overlays SYS1-SYS21, the program loader, the interrupt handler with the clock and the timer routine chain, a keyboard and a display driver, and the ROUTE hook. Its file also carries the reset code (4D00H-4FA7H), which runs once and is then overwritten by the overlays.

The file has eight load blocks: 400CH-4014H, 402DH-4035H, 403EH-405CH, 4063H-407FH, 4308H-4317H, 4368H-43A8H, 43B2H-43DFH and 4400H-51DAH (3,752 bytes), with 4D00H as the transfer address. BOOT/SYS loads it at every reset and jumps to 4D01H after checking that 4D00H holds A5H. The file on the system diskette has the mandatory zaps applied (see Zaps). The page shows every loaded byte once, in address order; the areas between the load blocks are shown as DEFS rows without a byte column.

Memory Map

Address RangeContents
400CH-4014HThe RST 28H, RST 30H and RST 38H vectors (4000H).
402DH-4035HThe DOS exits 402DH and 4030H, and the ROM's device hook 4033H (402DH).
403EH-407FHClock, date and HIMEM (403EH), the disk interrupt check (4053H), the hexadecimal conversion (4063H) and the clock limits.
4200H-42FFHNot in the file: the DOS sector buffer.
4300H-43FFHDrive variables, the BREAK hook, the overlay number (4308H), the command buffer, flags, SYSTEM options and the PDRIVE table (4368H), the ROUTE entries and the system file FCB (43B2H).
4400H-447FHThe DOS entry vectors (4400H).
4480H-4515HThe DOS FCB (4480H), time and date to text, the clock and cursor timer routines, the display driver.
4516H-462FHThe keyboard driver (4516H), the key combinations D-F-G, 1-2-3 and J-K-L (45BEH), the interrupt handler (45F2H), DEBUG entry and the timer tick.
4630H-4808HSector read and write (4630H), seek commands, drive selection (476EH) and the diskette test.
4809H-497FHFinding the sector for an FCB's NEXT (4809H), directory sector reads and writes (48F3H).
4980H-4B46HThe DOS function wrapper (4980H), READ, WRITE, byte I/O and the ROUTE list (4ADBH).
4B47H-4CFFHPositioning, message display, the RST 28H dispatcher (4BC2H), the program loader (4C28H), arithmetic, keyword and separator tests, the delay.
4D00H-51DAHThe reset code and its messages (4D00H). Overwritten by the overlays (4D00H-51FFH) once the DOS is up.

RST 28H Codes and the Overlays

The overlays are called with LD A,code / RST 28H. Bits 0-2 of the code are the directory sector minus 2 and bits 3-4 the file's place in that sector: together (bits 0-4) they are the file's directory slot, which is also the number kept at 4317H. BOOT/SYS is slot 00H, DIR/SYS 01H, SYS0 02H, SYS1 03H and so on to SYS21 17H. Bits 5-7 are the function number, 1-7. The dispatcher (4BC2H) finds the file's directory entry from the slot, so the system files must sit in the first three entries of directory sectors 2-9, each in one extent. Codes below 20H go to the BREAK hook at 4312H. The codes SYS0 itself uses:

CodeFunction
23H, 43H, 63H, 83H, A3H, C3H, E3HSYS1: DOS READY (4400H), error already displayed (4030H), execute a command (4405H), extract a filespec (441CH), default extension (4473H), DOS-CALL (4419H), function 7 with a sub-function in Register C (4 = MINI-DOS, from D-F-G).
24H, 44H, 64H, A4H, C4HSYS2: open (4424H), open or create (4420H), allocate a granule (from 48BDH), load (4430H), load and run (4433H).
25H, 45H, 65H, 85H, A5H, C5HSYS3: close (4428H), kill (442CH), enqueue and dequeue a timer routine (4410H, 4413H), print the screen (J-K-L), write the EOF (4451H).
26H, 46HSYS4: display a DOS error (4409H), and an error during the reset.
27HSYS5: DEBUG (440DH, RST 30H, 1-2-3).
2BH, 4BH, CBHSYS9: enqueue and dequeue a *name routine (4461H, 4464H), a key from the chain file (keyboard driver).

SYSTEM Options

The SYSTEM command (SYS17) keeps its options in the system data sector, sector 2 of the system diskette. Its table at SYS17 4F24H gives the place of each option; the reset code reads them from there. Yes/no options are single bits:

Sector ByteBits and Use
F0H (to 436CH)Bit 7 AA passwords, bit 6 AB RUN-ONLY, bit 5 AG BREAK is a key, bit 4 AI lower case hardware, bit 1 AR, bit 0 AS.
F1H (to 436DH)Bit 7 AT, bit 6 BC, bit 5 BE, bit 4 BK.
F8HBit 7 AC debounce, bit 6 AD J-K-L, bit 5 AE 1-2-3, bit 4 AF D-F-G, bit 2 AQ CLEAR key, bit 1 AJ keyboard intercept, bit 0 AU repeat key.
F9HBit 7 AY and bit 6 AZ date and time questions, bit 5 BA ROUTE,DO,NL at reset, bit 3 BD ENTER skips the AUTO command, bit 2 BF lower case driver, bit 1 BG lower case keyboard input, bit 0 BH blinking cursor.
FAHBit 7 BN, write directory sectors with data address mark F8H.

Numeric options are bytes: A0H AL (drives), A1H AW (write tries), A2H AN, A3H AO, A5H BI (cursor character), A6H AM (disk I/O tries), A7H AV (first repeat delay), A8H AX, A9H BJ (CPU speed), and D0H-D1H AP (HIMEM). Options AH, AK, BB, BL and BM have no entry in this SYS17's table. The sector also holds the ten PDRIVE records (00H-9FH) and the mark A5H in byte EFH. The reset code puts each option in place by storing values into the resident code itself, so most of the SYSTEM options appear on this page as Self-Modifying Code; see 4D27H and 4DF6H.

PDRIVE Records

SYS0 keeps the first ten bytes of the PDRIVE record of each drive at 4371H (drives 0-3), and a copy of the current drive's first eight bytes at 430AH-4311H.

ByteContents
+0The lump where the directory starts on the diskette now in the drive. Brought up to date from byte 2 of the diskette's boot sector when a directory read fails (48F3H).
+1Number of lumps.
+2Bits 0-1 TSR (stepping rate), bits 2-4 the interface type (must not be 0), bit 5 TI flag M, bit 6 TI flag K, bit 7 TI flag H (head settle delay, 47D4H).
+3Track count.
+4Sectors per track.
+5Granules per lump.
+6The value written to the sector register when the drive is selected (47C0H).
+7Disk I/O flags: bit 0 double density, bit 1 tracks numbered from 1, bit 2 double step, bit 4 sectors numbered from 1, bit 6 double sided.
+8, +9DDSL and DDGA, the default place and size of the directory.

FCB Layout

The 32-byte FCB of an open file, as SYS0 uses it (manual section 5.9):

ByteContents
+0Bit 7 open. Bit 1: NEXT and EOF are sector numbers of the whole diskette. Bit 0: write with the directory mark. Bit 2 set is refused with error 2DH.
+1Bit 7 record mode (LRL not 0, or byte I/O). Bit 6 EOF only moves forward. Bit 5 the buffer does not hold the sector at NEXT. Bit 4 the buffer has changes waiting. Bit 3 opened by NEWDOS/80 version 2 (needed for the extents at +22). Bits 0-2 the access level.
+2Bit 5: the file's FPDE has been marked updated.
+3, +4The buffer address.
+5NEXT, low byte.
+6The drive.
+7The DEC of the file's FPDE.
+8EOF, low byte.
+9LRL (0 = 256).
+10, +11NEXT, middle and high bytes.
+12, +13EOF, middle and high bytes.
+14 to +21The file's first four extents (from the FPDE). An extent is a lump number and a byte with the first granule in the lump (bits 5-7) and the granule count minus 1 (bits 0-4); FFH ends the list.
+22, +23The number of granules before the extents at +24.
+24 to +31Four more extents, copied from an FXDE when they are needed (48D5H).

Error Codes Returned by SYS0

Disk errors (4730H): 03H-08H for a read and 0BH-10H for a write, from the controller's status. Directory: 11H read error, 12H write error, 31H a sector without the directory mark, 2CH bad directory data. Files: 1CH end of file, 1DH past end of file, 25H access level, 26H FCB not open, 2DH bad FCB data, 3EH a read past the last granule. Loading: 22H bad record type, 24H memory that does not read back, 2EH system file not found. Others: 14H track number too high, 20H bad drive number, 08H no diskette turning, 27H bad system data at reset, 2AH illegal DOS function, 34H keyword or separator. The message texts are in SYS4.

Zaps

The file has these SYS0 zaps from the official zap list applied: 020 (ROUTE: 4AE1H, 4B17H-4B44H and 4CF8H-4CFFH), 043 (the NL target at 43B7H), 060 (4053H and 45FAH) and 062 (4B6EH and 4B71H). The optional zaps 004 (motor start delay, 47CAH), 055 (keyboard modification) and 077 (write precompensation) are not applied.

Variables

Resident Variables

Address
Size
Contents
4040H
1 byte
Tick counter, counted up every 25 ms by 4610H.
4041H-4043H
3 bytes
The clock: seconds, minutes, hours (binary). Advanced by 44CDH, set by the reset (4F59H) and by TIME (SYS7).
4044H-4046H
3 bytes
The date: year, day, month (binary). Only the day is advanced by the clock routine (44E9H).
4049H-404AH
2 bytes
HIMEM: the top of memory found at reset (4D13H), or option AP (4DC4H).
407CH-407EH
3 bytes
Clock limits 59, 59, 23, read by 44E0H.
4300H-4303H
4 bytes
Not in the file: the track register value of drives 0-3, saved when another drive is selected (478EH) and put back at 47BEH.
4308H
1 byte
The current drive (0-3).
4309H
1 byte
The select latch value of the current drive (01H, 02H, 04H, 08H; bit 3 = side 2), output by 4767H.
430AH-4311H
8 bytes
Bytes 0-7 of the current drive's PDRIVE record, copied by 47ABH.
4312H-4314H
3 bytes
The BREAK key hook: JP 45B0H (BREAK ignored) or a RET at 4312H (BREAK is a key).
4317H
1 byte
The directory slot of the overlay in 4D00H-51FFH (00H = none).
4318H-4367H
80 bytes
Not in the file: the DOS command buffer (the AUTO command at reset, the date and time answers).
4369H
1 byte
DOS flags: bit 6 overlay function running, bits 2, 3, 5, 6 stop the key combinations, bit 5 with 3 and 6 clear = chain keys, bit 4 option AG.
436CH-436FH
4 bytes
Bytes F0H-F3H of the system data sector (options AA-AS, AT-BK, and two bytes SYS0 does not use).
4370H
1 byte
Option AX, the highest printable character.
4371H-4398H
40 bytes
The PDRIVE table: bytes 0-9 of the records of drives 0-3.
4399H-439AH
2 bytes
The address of the current drive's record in 4371H-4398H.
439FH
1 byte
Option AL, the number of drives.
43A0H
1 byte
Option AN, the default drive of DIR.
43A1H
1 byte
Option AO, the first drive for a new file.
43A2H
1 byte
Option BJ, the CPU speed factor.
43A9H-43AAH
2 bytes
Not in the file: the top of memory found at reset.
43ABH
1 byte
Not in the file: A5H once the DOS is active (4F18H).
43ACH-43B1H
6 bytes
Not in the file: the copy of the clock and date made every second (44D7H).
43B2H-43CDH
28 bytes
Four ROUTE entries of 7 bytes: device served, saved type, link, target device.
43CEH-43DFH
18 bytes
The FCB used to load system files (buffer 4200H, drive 0, one extent at 43DCH).
4403H-4404H
2 bytes
A parameter left for the program that called through DOS-CALL or a *name command.
4480H-449FH
32 bytes
The DOS FCB, as loaded set to read sector 2 of drive 0 into 4200H.
44A0H-44A3H
4 bytes
The CLOCK command's timer block (link, interval 28H, countdown); its routine starts at 44A4H.
44C9H-44CCH
4 bytes
The clock routine's timer block (link 44EBH, interval 28H).
44EBH-44EEH
4 bytes
The cursor routine's timer block (link 0000H, interval 14H).
505BH-5062H
8 bytes
Reset only: the copy of bytes F8H-FFH of the system data sector (505CH = byte F9H, option BD).

Self-Modified Operands

Address
Size
Contents
4501H
1 byte
The cursor character, option BI (4E2EH).
4502H
1 byte
RET, or RET Z for a blinking cursor (4E70H, BLINK in SYS3).
4505H
1 byte
JR, or JR C with the lower case driver (4E5EH, LCDVR in SYS3).
452AH-452BH
2 bytes
The row image address of the last key (4565H).
452FH
1 byte
The first repeat delay, option AV (4E25H).
4537H
1 byte
The repeat countdown (4581H; counted down by 461BH).
4538H
1 byte
JR, or JR NZ when option AU is Y (4E1CH).
4573H
1 byte
The last key number (4574H, 453EH).
4578H
1 byte
The first repeat delay, option AV (4E22H).
457DH
1 byte
JR Z (debounce), or 3EH when option AC is N (4E79H).
4580H
1 byte
The delay for a repeat of the same key (4532H, 4586H).
4590H
1 byte
1FH (CLEAR filtered), or 00H when option AQ is Y (4E93H).
4593H
1 byte
RET, or LD C,A with the lower case driver (4E59H).
45B4H
1 byte
RET (case flip) or NOP (upper case): option BG (4E67H), LC (SYS3), SHIFT-0 (45AFH).
45BEH
1 byte
NOP, or RET while the keyboard driver scans (4526H, 458DH, 4BD5H).
45CCH
1 byte
JR, or JR NZ when option AF is Y (4E8BH).
45D8H
1 byte
JR, or JR NZ when option AE is Y (4E9CH).
45EEH
1 byte
RET, or RET NZ when option AD is Y (4E82H).
461DH-461EH
2 bytes
The head of the timer routine chain (44C9H as loaded; SYS3, SYS14).
463DH
1 byte
The directory write command A9H, ABH with option BN (4DFFH).
465AH
1 byte
The disk I/O tries, option AM (4D86H).
46C4H
1 byte
The FDC command of the transfer (4642H, 4687H).
46E8H
1 byte
The second byte of a write (46DEH).
46FCH-46FDH
2 bytes
The two opcodes of the transfer loop (4655H).
4731H
1 byte
The error code base, 00H read or 08H write (4652H).
477AH
1 byte
The number of drives, option AL (4D69H).
47E4H
1 byte
The status delay, 6 x option BJ (4D9FH).
47F4H-47F5H
2 bytes
The index pulse time-out, 2400H x option BJ (4DAAH).
486AH
1 byte
The DEC of the file entry being walked (48A0H); SYS2 reads it.
48BBH
1 byte
The JR offset at 48BAH: 00H allocate, B6H read (4810H).
4930H
1 byte
The directory sector in 4200H (4C74H).
49A6H-49A7H
2 bytes
The address of the code run as a DOS function (4989H).
49CEH-49CFH
2 bytes
The Stack Pointer of the running DOS function (499BH, 49A9H).
4A88H-4A8AH
3 bytes
LD A,(IX+01H), or NOP / LD A,0FFH (VERIFY in SYS3).
4A8BH
1 byte
AND (E6H) or OR (F6H) for 4439H/443CH (4A38H).
4ABAH
1 byte
The write tries, option AW (4D74H).
4ADCH-4ADDH
2 bytes
The head of the ROUTE list (4EB8H, ROUTE in SYS14).
4C1EH-4C1FH
2 bytes
The overlay's transfer address (4C09H).
4C6AH-4C6BH
2 bytes
The FCB of the file being loaded (4C28H).
4CEFH
1 byte
The delay passes, option BJ (4D8FH).
4FA0H
1 byte
The expected separator of the date or time answer (4F6FH).

Outside Addresses Used

Address
Size
Contents
37E0H
1 byte
The interrupt latch: bit 7 clock, bit 6 disk controller (45F6H).
37E1H
1 byte
The drive select latch (476AH).
37ECH
1 byte
FDC command and status register.
37EDH
1 byte
FDC track register.
37EEH
1 byte
FDC sector register.
37EFH
1 byte
FDC data register.
3801H-3880H
128 bytes
The keyboard: 3801H row 0, 3802H row 1, 3810H row 4, 3840H row 6, 387FH rows 0-6 together, 3880H row 7 (SHIFT).
3C00H-3FFFH
1024 bytes
The screen: 3C00H (lower case test), 3C35H (CLOCK display).
4016H-4017H
2 bytes
The keyboard driver address in its control block (4E3FH).
401DH-4024H
8 bytes
The display control block: 401EH-401FH the driver (4E45H), 4020H-4021H the cursor address, 4022H the cursor byte.
4025H-402CH
8 bytes
The printer control block (4BBDH).
4036H-403CH
7 bytes
The ROM's keyboard row images.
4200H-42FFH
256 bytes
The DOS sector buffer: the boot sector and system data sector at reset, directory sectors, system files being loaded.

DOS Routines

The documented entry points are the vectors at 4400H. The overlays and several utilities also call these routines directly:

AddressRoutine
4063H / 4068HStore DE (four digits) or A (two digits) in hexadecimal at HL.
45B5HConvert a lower case letter in A to upper case.
4630H / 4634H / 463CH / 4640HRead, verify read, write with the directory mark, write the sector DE of the current drive, buffer HL.
4747H / 4750H / 4767HIssue a seek type command C and wait / wait / write the select latch.
476EH / 4773H / 4776HSelect the FCB's drive / the current drive / drive A.
47E3H / 47ECHShort delay and read the status / test for a turning diskette.
4813HFind the sector for NEXT of the FCB at IX (inside a DOS function).
490AH / 491FH / 4922HRead directory sector A / write the directory sector in 4200H / write directory sector A.
492FH / 4936H / 494BHPoint HL to the entry of DEC A (reading its sector if needed / always) / read and check an FCB's FPDE.
4980H / 49CDHRun the rest of a routine as a DOS function / leave it with an error.
49DDHCall the overlay function in A and return.
4A62HWrite an FCB's buffer if it has changes waiting.
4C28HLoad a program file through an open FCB.
4C92H / 4C94H / 4C9DH / 4CB2H / 4CB4HMultiply L or HL by A / HL by A into H, L, C / divide HL by 5 or by A.
4CC5H / 4CD5H / 4CD9HCompare a keyword / test for the end of the line / step over a separator.
4CEDHDelay B x 256 loops.

Disassembly

4000H - RST Vectors

The Model I ROM sends every RST instruction from 0008H to 0038H through a jump in RAM. The ROM sets up 4000H-400BH itself (RST 08H to RST 20H, used by BASIC). SYS0's file starts at 400CH and replaces the three vectors that belong to the DOS: RST 28H, RST 30H and RST 38H.

4000-400B
DEFS 12
Not in the file. The ROM's jumps for RST 08H, RST 10H, RST 18H and RST 20H (4000H, 4003H, 4006H, 4009H), set up by the ROM at power-on and used by Level II BASIC.
400C
RST 28H vector: JUMP to 4BC2H, the overlay dispatcher. Every DOS function reached through RST 28H goes there with Register A = the function code (bits 0-4 the overlay's directory slot, bits 5-7 the function), and so does the ROM's keyboard driver with Register A = 01H when BREAK is pressed.
400F
RST 30H vector: JUMP to 4609H to enter DEBUG. A breakpoint (the byte F7H, RST 30H, written by DEBUG at 404BH/404EH's addresses) arrives here with the breakpoint's address + 1 on the stack.
4012
RST 38H vector (the maskable interrupt, Interrupt Mode 1): JUMP to 45F2H, the interrupt handler, which reads the interrupt latch at 37E0H for the 25 ms clock and the disk controller.
4015-402C
DEFS 24
Not in the file. The ROM's device control blocks: keyboard 4015H-401CH, display 401DH-4024H and printer 4025H-402CH. When SYSTEM option AJ is Y, 4E31H puts SYS0's keyboard driver 4516H into 4016H-4017H and its display driver 4505H into 401EH-401FH. The cursor address is at 4020H-4021H and the cursor state at 4022H.

402DH - DOS Exits

The two fixed exits of every program (manual sections 3.2 and 3.3) and the ROM's device dispatch hook.

402D
No-error exit (manual 3.2): JUMP to 4400H, the DOS READY vector. A program ends with JP 402DH to return to the DOS command prompt.
4030
LD A,43H 3E 43
Error-already-displayed exit (manual 3.3): load Register A with 43H, the RST 28H code of SYS1 (slot 03H) function 2, the exit taken after an error message has been shown.
4032
RST 28H EF
RST 28H with Register A = 43H: call SYS1 function 2 through the dispatcher at 4BC2H. SYS1 ends at DOS READY, so nothing returns here.
4033
The ROM's device dispatcher at 03C2H jumps here when the type byte of the device control block pointed to by Register Pair DE does not match the requested operation. JUMP to 4ADBH, which handles routed devices (type C0H) and FCBs used as devices (Register Pair DE pointing to an FCB).
4036-403D
DEFS 8
Not in the file. The ROM's keyboard row image (4036H-403CH, one byte per keyboard row, kept by the ROM's keyboard scan; SYS0 reads 403CH at 4529H) and 403DH.

403EH - Clock, Date and Memory Size

Variables of the resident DOS. The time and date are binary values.

403E-403F
DEFB 00H, 00H 00 00
Two bytes of zeros. No instruction in SYS0 reads or writes 403EH or 403FH.
4040
DEFB 00H 00
4040H: the tick counter, incremented on every 25 ms timer interrupt by 4610H (INC (HL) at 4613H).
4041-4043
DEFB 00H, 00H, 00H 00 00 00
The clock: seconds (4041H), minutes (4042H) and hours (4043H). Advanced once a second by 44CDH, copied to 43ACH-43AEH by 44C9H, converted to text by 446DH (44A7H), restored from 43ACH by a warm reset (4D1FH).
4044-4046
DEFB 00H, 00H, 00H 00 00 00
The date: year (4044H), day (4045H) and month (4046H), binary. Converted to text MM/DD/YY by 4470H (44C2H), set by the date question at reset or by DATE (SYS7).
4047-4048
DEFB 00H, 52H 00 52
Two bytes, 00H and 52H. No instruction in SYS0 reads or writes 4047H or 4048H.
4049-404A
DEFW FFFFH FF FF
HIMEM, the highest memory address the DOS lets programs use (manual 2.24). Set at reset to the top of memory found (4D10H) or to SYSTEM option AP (4DB3H); changed by HIMEM (SYS7) and CLEAR (SYS14).
404B-4052
DEFB 00H x 8 00 x 8
404BH-4050H: DEBUG's (SYS5) two breakpoint entries (address and original byte); 4051H-4052H: the head of SYS9's *name routine list (0000H = empty). SYS0 does not use these bytes.

4053H - Disk Interrupt Check

Added by zap 060. The interrupt handler (45FAH) calls it with Register A = the interrupt latch (37E0H) shifted left once, so that bit 7 of Register A holds the latch's disk controller bit (bit 6). The controller's status is read only when that bit is set, which clears the disk interrupt.

4053
PUSH AF F5
Save Register Pair AF onto the stack: Register A holds the shifted interrupt latch and the CARRY FLAG the clock bit, which the caller at 45FDH still needs.
4054
RLCA 07
Rotate Register A (the shifted interrupt latch) left: bit 7, the disk controller's interrupt bit, goes into the CARRY FLAG.
4055
If the CARRY FLAG is set (the disk controller requested the interrupt), GOSUB to 47E8H to read the FDC status register at 37ECH, which resets the controller's interrupt request. Register A is changed there; it is restored below.
4058
POP AF F1
Restore Register Pair AF from the stack: Register A = the shifted interrupt latch and the CARRY FLAG = the clock bit, as they were on entry.
4059
RET C9
RETurn to the interrupt handler (45FDH) with Register Pair AF unchanged.
405A-405C
DEFB 00H x 3 00 x 3
Three bytes of zeros after the zap 060 routine. No instruction in SYS0 uses 405AH-405CH.
405D-4062
DEFS 6
Not in the file: DEBUG's (SYS5) three memory window addresses 405DH, 405FH and 4061H.

4063H - Convert DE or A to Hexadecimal Text

Two entry points used by DEBUG, SYSTEM and other overlays. 4063H stores Register Pair DE as four hexadecimal digits at Register Pair HL, 4068H stores Register A as two. Register Pair HL is left pointing after the digits; Register A is changed.

4063
LD A,D 7A
Load Register A with Register D, the high byte of the value in Register Pair DE, whose two digits come first.
4064
GOSUB to 4068H to store the two hexadecimal digits of Register A (the high byte) at Register Pair HL; Register Pair HL comes back advanced by 2.
4067
LD A,E 7B
Load Register A with Register E, the low byte of the value in Register Pair DE, and fall into 4068H for its two digits.
4068
PUSH AF F5
Save Register Pair AF onto the stack: Register A holds the byte to convert, needed again for its low digit at 4070H.
4069
RRCA 0F
Rotate Register A (the byte) right once. Four RRCAs exchange its two nibbles, bringing the high digit into bits 0-3.
406A
RRCA 0F
Rotate Register A right again (second of four), moving the high nibble towards bits 0-3.
406B
RRCA 0F
Rotate Register A right again (third of four).
406C
RRCA 0F
Rotate Register A right a fourth time: the high nibble of the byte is now in bits 0-3 of Register A.
406D
GOSUB to 4071H to store the digit for bits 0-3 of Register A (the byte's high nibble) at Register Pair HL.
4070
POP AF F1
Restore Register Pair AF from the stack: Register A = the original byte, whose low nibble is the second digit. Fall into 4071H.
4071
AND 0FH E6 0F
AND Register A with 0FH, keeping the nibble to convert (0-15).
4073
ADD A,90H C6 90
ADD 90H to Register A (the nibble). This starts the standard nibble-to-ASCII conversion.
4075
DAA 27
Decimal adjust Register A: 90H-99H stay (nibbles 0-9, no carry), 9AH-9FH become 00H-05H with the CARRY FLAG set (nibbles A-F).
4076
ADC A,40H CE 40
ADD 40H and the CARRY FLAG to Register A: 0-9 give D0H-D9H, A-F give 41H-46H.
4078
DAA 27
Decimal adjust Register A again: D0H-D9H become 30H-39H (ASCII 0-9); 41H-46H stay (ASCII A-F). Register A is now the digit character.
4079
LD (HL),A 77
Store Register A (the ASCII digit) at Register Pair HL, the caller's text buffer.
407A
INC HL 23
INCrement Register Pair HL to the next byte of the text buffer.
407B
RET C9
RETurn to the caller with Register Pair HL pointing after the digit.

407CH - Clock Limits

The highest value of each clock byte, used by the once-a-second clock routine at 44CDH.

407C-407E
DEFB 3BH, 3BH, 17H 3B 3B 17
The clock limits read by 44D9H: 3BH (59) for the seconds, 3BH (59) for the minutes and 17H (23) for the hours. A clock byte that passes its limit is set to 0 and the next one is advanced.
407F
DEFB 00H 00
One byte of zero after the clock limits. No instruction in SYS0 uses 407FH.
4080-41FF
DEFS 384
Not in the file: the ROM's and Level II BASIC's own variables (4080H-41FFH), which SYS0 does not load over.
4200-42FF
DEFS 256
Not in the file: the DOS sector buffer. It holds the boot sector when SYS0 starts, then the system data sector (4D3BH), and later the directory sector numbered at 4930H and the sectors of system files being loaded (the FCB at 43CEH).
4300-4307
DEFS 8
Not in the file. 4300H plus the drive number holds the last track register value of each drive, saved when another drive is selected (478AH) and put back into the FDC track register when the drive is selected again.

4308H - Drive Selection and Overlay Variables

The state of the current drive, the BREAK key hook and the number of the overlay in 4D00H-51FFH.

4308
DEFB 00H 00
4308H: the current drive number (0-3), stored by the select routine at 4783H and read by 4773H to select the current drive again.
4309
DEFB 00H 00
4309H: the value written to the drive select latch at 37E1H for the current drive: 01H, 02H, 04H or 08H (1 shifted left by the drive number), plus bit 3 (side 2) during a transfer on the second side. Set by 4798H, output by 4767H.
430A-4311
DEFB 11H, 23H, 03H, 23H, 0AH, 02H, 00H, 00H 11 23 03 23 0A 02 00 00
A copy of bytes 0-7 of the current drive's PDRIVE record, made by 4776H on every drive select: 430AH directory lump, 430BH lumps, 430CH TSR and TI flags (bit 7 = TI flag H), 430DH track count, 430EH sectors per track, 430FH granules per lump, 4310H sector register value, 4311H disk I/O flags (bit 0 double density, bit 1 tracks numbered from 1, bit 2 double step, bit 4 sectors numbered from 1, bit 6 double sided).
4312
BREAK key hook: JUMP to 45B0H, which clears Register A so that BREAK is ignored. The ROM's keyboard driver executes RST 28H with Register A = 01H when BREAK is pressed, and the dispatcher sends every code below 20H here. The BREAK command (SYS3) and DOS READY (from SYSTEM option AG) store C3H here (disabled, this JP) or C9H (enabled: a RET that leaves 01H in Register A).
4315-4316
DEFB 01H, 00H 01 00
The bytes after the BREAK hook's JP, 01H and 00H. No instruction in SYS0 reads or writes 4315H or 4316H.
4317
DEFB 00H 00
4317H: the overlay now in 4D00H-51FFH, the low five bits of its RST 28H code (the directory slot: BOOT 00H, DIR 01H, SYS0 02H ... SYS21 17H), 00H for none. Checked and set by the dispatcher at 4BD8H; cleared by overlays that use their own memory as a buffer (SYS3, SYS9) so that they are reloaded.
4318-4367
DEFS 80
Not in the file. The DOS command buffer (4318H-4367H, 80 bytes). At reset the AUTO command is copied here from the GAT (4F08H); the date and time answers are typed here too (4F67H). SYS1 reads every DOS command into it.

4368H - System Flags, Options and the PDRIVE Table

Most of these bytes are filled in at reset from the system data sector (sector 2 of the system diskette) by the reset code at 4D4CH-4E31H.

4368
DEFB A5H A5
4368H holds A5H in the file. No instruction in SYS0 reads or writes it.
4369
DEFB 40H 40
4369H: DOS flags. Bit 6 is set while an overlay function runs (4BCDH, cleared at 4C21H). The keyboard combinations D-F-G, 1-2-3 and J-K-L are ignored while any of bits 2, 3, 5 or 6 is set (45BFH); bit 2 is set for RUN-ONLY (option AB), bit 3 by FORMAT and COPY, bit 7 by DEBUG. When bit 5 is set and bits 3 and 6 are clear, the keyboard driver asks SYS9 for the key (4516H). Bit 4 is set at reset when option AG is Y.
436A
DEFB 00H 00
436AH: DOS state flags used by SYS1, SYS4, SYS9 and other overlays: bit 7 MINI-DOS, bit 6 DOS-CALL, bit 5 at DOS READY, bit 4 chaining under DOS-CALL, bit 2 an error at reset (set by SYS4 function 2). SYS0 does not use them.
436B
DEFB 00H 00
436BH: temporary flags used by the overlays (bit 0 set by SYS2 while it takes extra granules, bits 1 and 2 by SYS6). SYS0 does not use them.
436C-436D
DEFB 00H, 00H 00 00
SYSTEM options, copied from bytes F0H-F1H of the system data sector by 4D5AH. 436CH: bit 7 AA (passwords), bit 6 AB (RUN-ONLY), bit 5 AG (BREAK is a key), bit 4 AI (lower case hardware), bit 1 AR, bit 0 AS. 436DH: bit 7 AT, bit 6 BC, bit 5 BE, bit 4 BK.
436E-436F
DEFB 00H, 00H 00 00
436EH-436FH: copies of bytes F2H-F3H of the system data sector, stored at reset by 4D60H. No instruction in SYS0 reads them afterwards.
4370
DEFB 5AH 5A
4370H: SYSTEM option AX, the highest character code the printer is sent as is (manual 2.46), stored at reset by 4DB0H. 5AH in the file.
4371-437A
DEFB 11H, 23H, 03H, 23H, 0AH, 02H, 00H, 00H, 11H, 02H 11 23 03 23 0A 02 00 00 11 02
The PDRIVE record of drive 0: bytes 0-9 of its 16-byte record in the system data sector, copied at reset by 4DC8H. 4776H copies bytes 0-7 of the selected drive's record to 430AH-4311H. At reset 4D2BH first puts bytes +2, +6 and +7 from the boot sector here.
437B-4384
DEFB FFH, 01H, 00H, 01H, 00H, 00H, 00H, 00H, FFH, 00H FF 01 00 01 00 00 00 00 FF 00
The PDRIVE record of drive 1 (10 bytes, filled in at reset). Index Register IY points to 4380H inside this record while DOS functions run (4986H); it is only a base for IY+d addressing of the variables around it.
4385-438E
DEFB FFH, 01H, 00H, 01H, 00H, 00H, 00H, 00H, FFH, 00H FF 01 00 01 00 00 00 00 FF 00
The PDRIVE record of drive 2 (10 bytes of the 16-byte record in the system data sector, copied at reset by 4DC8H).
438F-4398
DEFB FFH, 01H, 00H, 01H, 00H, 00H, 00H, 00H, FFH, 00H FF 01 00 01 00 00 00 00 FF 00
The PDRIVE record of drive 3 (10 bytes of the 16-byte record in the system data sector, copied at reset by 4DC8H).
4399-439A
DEFW 4371H 71 43
4399H-439AH: the address of the current drive's PDRIVE record (4371H + 10 x drive), set by 479BH and read by 47A3H, 48F6H and 4C79H.
439B-439E
DEFB 00H, 00H, 00H, 00H 00 00 00 00
Four bytes of zeros after the PDRIVE table. No instruction in SYS0 reads or writes 439BH-439EH.
439F
DEFB 04H 04
439FH: SYSTEM option AL, the number of drives, stored at reset by 4D66H (also as the operand at 477AH).
43A0
DEFB 01H 01
43A0H: SYSTEM option AN, the default drive of DIR, stored at reset by 4D7AH.
43A1
DEFB 00H 00
43A1H: SYSTEM option AO, the first drive searched for a free directory entry when a file is created, stored at reset by 4D80H.
43A2
DEFB 01H 01
43A2H: SYSTEM option BJ, the CPU speed multiplier for the timing loops, stored at reset by 4D8CH.
43A3-43A8
DEFB 00H, 01H, 00H, 00H, 0DH, 0DH 00 01 00 00 0D 0D
43A3H-43A8H: 43A4H is DEBUG's display form (01H X form), 43A5H SYS9's chain character read ahead, 43A7H-43A8H SYS1's copy of the previous command's first two characters (0DH 0DH). SYS0 does not use these bytes.
43A9-43AA
DEFS 2
Not in the file. 43A9H-43AAH: the top of memory found at reset (stored by 4D10H). HIMEM (SYS7) and CLEAR (SYS14) may not set 4049H above it.
43AB
DEFS 1
Not in the file. 43ABH: A5H while the DOS is active: set at the end of the reset (4F15H) and tested by the next reset (4D16H, 4ED3H) to tell a restart from a power-on.
43AC-43B1
DEFS 6
Not in the file. 43ACH-43B1H: a copy of the clock and date (4041H-4046H), made every second by 44D1H and put back by a reset while the DOS was active (4D1FH).

43B2H - ROUTE Entries and the System File FCB

Four seven-byte ROUTE entries, then the FCB used to load system files. A ROUTE entry holds the address of the device control block it serves (+0), a copy of that block's original type byte (+2), the address of the next entry for the same device (+3, 0000H at the end) and the address of the device control block the I/O is sent to (+5). The list is searched by 4B17H; the entries are managed by the ROUTE command (SYS14).

43B2-43B8
DEFB 00H, 00H, 00H, FFH, FFH, FCH, 4CH 00 00 00 FF FF FC 4C
ROUTE entry 1. Its target 4CFCH, the control block of the NL device, was put here by zap 043. When SYSTEM option BA is Y, 4EB5H fills in the display's control block 401DH and ends the list, which routes the display to NL. A link of FFFFH marks the entry free.
43B9-43BF
DEFB 00H, 00H, 00H, FFH, FFH, 00H, 00H 00 00 00 FF FF 00 00
ROUTE entry 2: free (link FFFFH). Filled in by the ROUTE command (SYS14).
43C0-43C6
DEFB 00H, 00H, 00H, FFH, FFH, 00H, 00H 00 00 00 FF FF 00 00
ROUTE entry 3: free (link FFFFH). Filled in by the ROUTE command (SYS14).
43C7-43CD
DEFB 00H, 00H, 00H, FFH, FFH, 00H, 00H 00 00 00 FF FF 00 00
ROUTE entry 4: free (link FFFFH). Filled in by the ROUTE command (SYS14).
43CE-43DF
DEFB 80H, 28H, 00H, 00H, 42H, 00H, 00H, FFH, 00H, 00H, 00H, 00H, 40H, 00H, 00H, 00H, FFH, FFH 80 28 00 00 42 00 00 FF 00 00 00 00 40 00 00 00 FF FF
The FCB the dispatcher uses to load a system file into memory (4C03H): +0 80H open; +1 28H (buffer empty, FCB+1 bit 3 set, sector mode); +3/+4 buffer 4200H; +6 drive 0; +12/+13 EOF 4000H (64 sectors). The dispatcher clears NEXT (43D8H) and stores the file's first extent at 43DCH-43DDH; 43DEH-43DFH (FFH FFH) ends the extent list, so a system file must be in one extent.
43E0-43FF
DEFS 32
Not in the file. 43E0H-43FFH: SYS9's chain file FCB (copied from 4480H by CHAIN/DO; byte 0 = 00H when no chain file runs). SYS0 does not use it.

4400H - DOS Entry Vectors

The fixed entry points documented in chapter 3 of the manual. Most of them load an RST 28H code into Register A and execute RST 28H: the dispatcher at 4BC2H throws away the RST's own return address, loads the overlay if needed and calls it, so the overlay returns straight to the program that called the vector. The code's bits 0-2 are the directory sector minus 2, bits 3-4 the file in that sector, and bits 5-7 the function number.

4400
LD A,23H 3E 23
DOS READY (the same as 402DH): load Register A with 23H, the RST 28H code of SYS1 function 1 (the DOS READY prompt and command loop).
4402
RST 28H EF
RST 28H with Register A = 23H: call SYS1 function 1 through the dispatcher at 4BC2H. SYS1 never returns here.
4403-4404
DEFB 00H, 00H 00 00
4403H-4404H: a two-byte parameter a program may leave here for the program that ran it through DOS-CALL or a *name command (manual 3.11 and 3.31). SYS2 also stores the transfer address of every program it loads here (SYS2 4DB3H).
4405
LD A,63H 3E 63
Enter DOS and execute the command at Register Pair HL (manual 3.5): load Register A with 63H, the RST 28H code of SYS1 function 3.
4407
RST 28H EF
RST 28H with Register A = 63H: call SYS1 function 3, which executes the command at Register Pair HL and ends at DOS READY. It does not return here.
4408
RET Z C8
If the Z FLAG is set, RETurn. Reached only as a return address: SYS1 pushes 402DH and then 4408H, so that a command ending with the Z FLAG set RETurns to 402DH (DOS READY), and one ending with the NZ FLAG set falls into the error exit at 4409H with the error code in Register A. ASPOOL/MAS looks for this return address on the stack.
4409
PUSH AF F5
DOS error exit (manual 3.6), entered with the error code in Register A (bit 7 set = display the message and return to the caller). Save Register Pair AF (the error code) onto the stack, where SYS4 picks it up.
440A
LD A,26H 3E 26
Load Register A with 26H, the RST 28H code of SYS4 function 1, which displays the error whose code is on the stack, or leaves through the DOS-CALL level.
440C
RST 28H EF
RST 28H with Register A = 26H: call SYS4 function 1 with the error code on the stack. With bit 7 of the error code set, SYS4 displays the message and returns to the caller of 4409H; otherwise it does not return.
440D
Enter DEBUG (manual 3.7): JUMP to 4609H, the same entry as RST 30H (400FH). The 1-2-3 key combination (45DFH) and SYS2's load-and-run with DEBUG on also come here.
4410
LD A,65H 3E 65
Enqueue a user timer routine, Register Pair DE = the routine (manual 3.8): load Register A with 65H, the RST 28H code of SYS3 function 3.
4412
RST 28H EF
RST 28H with Register A = 65H: call SYS3 function 3, which links the routine at Register Pair DE into the timer chain whose head is the operand at 461DH.
4413
LD A,85H 3E 85
Dequeue a user timer routine, Register Pair DE = the routine (manual 3.9): load Register A with 85H, the RST 28H code of SYS3 function 4.
4415
RST 28H EF
RST 28H with Register A = 85H: call SYS3 function 4, which unlinks the routine at Register Pair DE from the timer chain.
4416
Keep the drives rotating (manual 3.10): JUMP to 4762H, which outputs the current select latch value (4309H) to 37E1H again.
4419
LD A,C3H 3E C3
DOS-CALL, execute the command at Register Pair HL and return (manual 3.11): load Register A with C3H, the RST 28H code of SYS1 function 6.
441B
RST 28H EF
RST 28H with Register A = C3H: call SYS1 function 6, which runs the command at Register Pair HL and returns to the caller of 4419H.
441C
LD A,83H 3E 83
Extract a filespec from the text at Register Pair HL into the FCB at Register Pair DE (manual 3.12): load Register A with 83H, the RST 28H code of SYS1 function 4.
441E
RST 28H EF
RST 28H with Register A = 83H: call SYS1 function 4. The overlay returns to the caller of 441CH.
441F
NOP 00
No operation. Not executed: the RST 28H before it never returns here, because the dispatcher drops its return address. It only fills the vector to 4 bytes.
4420
LD A,44H 3E 44
Open a file, creating it if it does not exist (manual 3.13), Register Pair DE = the FCB: load Register A with 44H, the RST 28H code of SYS2 function 2.
4422
RST 28H EF
RST 28H with Register A = 44H: call SYS2 function 2, which returns to the caller of 4420H.
4423
NOP 00
No operation. Not executed (the RST 28H before it does not return here); it fills the vector to 4 bytes.
4424
LD A,24H 3E 24
Open an existing file (manual 3.14), Register Pair DE = the FCB: load Register A with 24H, the RST 28H code of SYS2 function 1.
4426
RST 28H EF
RST 28H with Register A = 24H: call SYS2 function 1, which returns to the caller of 4424H.
4427
ADD A,D 82
ADD Register D to Register A. Not executed (the RST 28H before it does not return here); the byte 82H only fills the vector to 4 bytes.
4428
LD A,25H 3E 25
Close a file (manual 3.15), Register Pair DE = the FCB: load Register A with 25H, the RST 28H code of SYS3 function 1.
442A
RST 28H EF
RST 28H with Register A = 25H: call SYS3 function 1, which returns to the caller of 4428H.
442B
LD BC,453EH 01 3E 45
Load Register Pair BC with 453EH. Overlapping Instructions
Not executed as this instruction: the kill vector 442CH (manual 3.16) starts inside it, so its bytes 3EH 45H at 442CH-442DH are executed as LD A,45H, loading Register A with the RST 28H code of SYS3 function 2 (KILL); the RST 28H follows at 442EH.
442E
RST 28H EF
RST 28H with Register A = 45H (from the kill vector at 442CH): call SYS3 function 2, which kills the file whose FCB is at Register Pair DE and returns to the caller.
442F
NOP 00
No operation. Not executed (the RST 28H before it does not return here); it fills the vector to 4 bytes.
4430
LD A,A4H 3E A4
Load a program file (manual 3.17), Register Pair DE = the FCB: load Register A with A4H, the RST 28H code of SYS2 function 5.
4432
RST 28H EF
RST 28H with Register A = A4H: call SYS2 function 5, which loads the program and returns to the caller with Register Pair HL = its transfer address.
4433
LD A,C4H 3E C4
Load and run a program file (manual 3.18), Register Pair DE = the FCB: load Register A with C4H, the RST 28H code of SYS2 function 6.
4435
RST 28H EF
RST 28H with Register A = C4H: call SYS2 function 6, which loads the program and jumps to its transfer address.
4436
READ a sector or a logical record (manual 3.19), Register Pair DE = the FCB: JUMP to 49FCH.
4439
WRITE a sector or a logical record (manual 3.20), Register Pair DE = the FCB: JUMP to 4A36H.
443C
WRITE with verify (manual 3.21), Register Pair DE = the FCB: JUMP to 4A32H.
443F
Position to the start of the file (manual 3.22), Register Pair DE = the FCB: JUMP to 4B4CH.
4442
Position to the record number in Register Pair BC (manual 3.23), Register Pair DE = the FCB: JUMP to 4B73H.
4445
Position back one record (manual 3.24), Register Pair DE = the FCB: JUMP to 4B62H.
4448
Position to the end of file (manual 3.25), Register Pair DE = the FCB: JUMP to 4B54H.
444B
Allocate file space up to NEXT (manual 3.26), Register Pair DE = the FCB: JUMP to 4809H.
444E
Position to the byte address in Registers H, L and C (high, middle, low; manual 3.27), Register Pair DE = the FCB: JUMP to 4B47H.
4451
LD A,C5H 3E C5
Write the EOF to the directory (manual 3.28), Register Pair DE = the FCB: load Register A with C5H, the RST 28H code of SYS3 function 6.
4453
RST 28H EF
RST 28H with Register A = C5H: call SYS3 function 6, which writes the FCB's EOF into the file's directory entry and returns to the caller of 4451H.
4454-4456
DEFB 00H x 3 00 x 3
Not executed (after the RST 28H at 4453H, which does not return here). Three bytes of zeros that end the vector.
4457
LD A,2AH 3E 2A
Load Register A with error code 2AH (ILLEGAL DOS FUNCTION), returned by the unused vector at 447CH.
4459
JUMP to 4409H, the DOS error exit, with Register A = 2AH (ILLEGAL DOS FUNCTION).
445B
Select and power up the drive whose number is in Register A (manual 3.29): JUMP to 4776H.
445E
Test for a mounted diskette in the drive whose number is in Register A (manual 3.30): JUMP to 47ECH.
4461
LD A,2BH 3E 2B
Enqueue a *name routine, Register Pair DE = its block (manual 3.31): load Register A with 2BH, the RST 28H code of SYS9 function 1.
4463
RST 28H EF
RST 28H with Register A = 2BH: call SYS9 function 1, which links the block at Register Pair DE into the *name list headed at 4051H.
4464
LD A,4BH 3E 4B
Dequeue a *name routine, Register Pair DE = its block (manual 3.32): load Register A with 4BH, the RST 28H code of SYS9 function 2.
4466
RST 28H EF
RST 28H with Register A = 4BH: call SYS9 function 2, which unlinks the block at Register Pair DE from the *name list.
4467
Display the message at Register Pair HL, ended by 03H or 0DH (manual 3.33): JUMP to 4BA6H.
446A
Print the message at Register Pair HL, ended by 03H or 0DH (manual 3.34): JUMP to 4BBCH.
446D
Put the time as HH:MM:SS at Register Pair HL (manual 3.35): JUMP to 44A7H.
4470
Put the date as MM/DD/YY at Register Pair HL (manual 3.36): JUMP to 44C2H.
4473
LD A,A3H 3E A3
Insert the default name extension at Register Pair HL into the filespec in the FCB at Register Pair DE (manual 3.37): load Register A with A3H, the RST 28H code of SYS1 function 5.
4475
RST 28H EF
RST 28H with Register A = A3H: call SYS1 function 5, which returns to the caller of 4473H.
4476-447A
DEFB 00H x 5 00 x 5
Five bytes of zeros after the 4473H vector. No instruction or vector uses 4476H-447AH.
447B
DEFB 00H 00
447BH: a zero byte between the vectors. No NEWDOS/80 Model I system file reads or writes 447BH.
447C
JUMP to 4457H: this vector returns error 2AH (ILLEGAL DOS FUNCTION) in Register A through the error exit at 4409H.
447E
XOR A AF
Set Register A to 00H and clear the flags (Z FLAG set). No module jumps or calls here; it is a spare XOR A / RET.
447F
RET C9
RETurn with Register A = 00H. Not referenced by any module.

4480H - The DOS FCB

A 32-byte FCB that overlays use for their own files (SYS1 puts filespecs here). As loaded it is already open and addresses sector 2 of the diskette in drive 0 with buffer 4200H, so that the reset code can read the system data sector with one call of 4436H (at 4D3BH).

4480
DEFB 82H 82
FCB+0 (4480H) = 82H: bit 7 open; bit 1 NEXT and EOF are sector numbers of the whole diskette, not of a file (as the reset code needs to read sector 2).
4481
DEFB 20H 20
FCB+1 (4481H) = 20H: bit 5 set, the buffer does not hold the NEXT sector yet; bit 7 clear (sector mode); access level 0 (FULL).
4482
DEFB 00H 00
FCB+2 (4482H) = 00H: no FPDE byte 1 flags (the extent flags of a file opened through SYS2).
4483-4484
DEFW 4200H 00 42
FCB+3/+4 (4483H-4484H) = 4200H: the buffer address, the DOS sector buffer.
4485
DEFB 00H 00
FCB+5 (4485H) = 00H: NEXT, the low byte (the byte offset within the sector).
4486
DEFB 00H 00
FCB+6 (4486H) = 00H: the drive the FCB works on, drive 0 (the system diskette).
4487
DEFB FFH FF
FCB+7 (4487H) = FFH: the DEC of the file's directory entry (FFH, none).
4488
DEFB 00H 00
FCB+8 (4488H) = 00H: EOF, the low byte (byte offset within the last sector).
4489
DEFB 00H 00
FCB+9 (4489H) = 00H: the logical record length (LRL, 00H = 256).
448A-448B
DEFW 0002H 02 00
FCB+10/+11 (448AH-448BH) = 0002H: NEXT, middle and high byte: sector 2, the system data sector.
448C-448D
DEFW FFFFH FF FF
FCB+12/+13 (448CH-448DH) = FFFFH: EOF, middle and high byte, so every sector of the diskette is below the EOF.
448E-449F
DEFB FFH x 18 FF x 18
FCB+14 to +31 (448EH-449FH): the extents, all FFH (none). Not used, because FCB+0 bit 1 makes NEXT a diskette sector.
44A0-44A3
DEFB 00H, 00H, 28H, 01H 00 00 28 01
The timer routine block of the CLOCK command. CLOCK (SYS3) enqueues it with 4410H (Register Pair DE = 44A0H) or dequeues it with 4413H. Bytes 0-1 are the chain link, byte 2 the interval (28H = 40 ticks, one second) and byte 3 the countdown. The routine starts at 44A4H.
44A4
LD HL,3C35H 21 35 3C
Point Register Pair HL to 3C35H, a position near the top right of the screen (row 0, column 53), and fall into 44A7H to put the time there as HH:MM:SS.

44A7H - Convert the Time or Date to Text

446DH and 4470H come here. Three binary bytes, read downward from Register Pair DE, are stored at Register Pair HL as two decimal digits each, separated by the character in Register B. On exit Register Pair HL points after the last digit.

44A7
LD DE,4043H 11 43 40
Time: point Register Pair DE to 4043H, the hours; the loop then reads the minutes (4042H) and the seconds (4041H) going down.
44AA
LD B,3AH 06 3A
Load Register B with 3AH (ASCII colon), the separator stored between the time's values.
44AC
LD C,03H 0E 03
Load Register C with 03H, the number of values (two digits each) to convert. 44C7H joins here for the date.

Value Loop
Register Pair DE = the binary value, Register Pair HL = the text position, Register C = values left, Register B = the separator.

44AE
LD (HL),2FH 36 2F
Store 2FH (one below ASCII 0) at Register Pair HL, the tens digit of this value; it is counted up once for every 10 below.
44B0
LD A,(DE) 1A
Fetch the binary value at Register Pair DE (hours, minutes, seconds, or month, day, year) into Register A.
44B1
INC (HL) 34
INCrement the tens digit at Register Pair HL by 1 (2FH becomes 30H, ASCII 0, on the first pass).
44B2
SUB 0AH D6 0A
SUBtract 0AH (10) from Register A, the rest of the value. The CARRY FLAG is set when Register A was below 10.
44B4
If the NO CARRY FLAG is set (Register A was 10 or more), LOOP BACK to 44B1H to count the tens digit at Register Pair HL up again.
44B6
INC HL 23
INCrement Register Pair HL to the units digit position.
44B7
ADD A,3AH C6 3A
ADD 3AH to Register A (the units minus 10, after the subtraction that borrowed): 0AH of it restores the units and 30H makes it ASCII 0-9.
44B9
LD (HL),A 77
Store Register A (the units digit) at Register Pair HL.
44BA
INC HL 23
INCrement Register Pair HL past the units digit.
44BB
DEC DE 1B
DECrement Register Pair DE to the next (lower) value byte: hours to minutes to seconds, or month to day to year.
44BC
DEC C 0D
DECrement Register C, the count of values left. The Z FLAG is set after the third value.
44BD
RET Z C8
If the Z FLAG is set (Register C = 0, all three values done), RETurn with Register Pair HL pointing after the last digit.
44BE
LD (HL),B 70
Store Register B (the separator, colon or slash) at Register Pair HL.
44BF
INC HL 23
INCrement Register Pair HL past the separator.
44C0
JUMP to 44AEH to convert the next value at Register Pair DE.
44C2
LD DE,4046H 11 46 40
Date: point Register Pair DE to 4046H, the month; the loop then reads the day (4045H) and the year (4044H) going down.
44C5
LD B,2FH 06 2F
Load Register B with 2FH (ASCII slash), the separator stored between the date's values.
44C7
JUMP to 44ACH to set Register C = 3 and convert the three values at Register Pair DE.

44C9H - Once-a-Second Clock Routine

The first entry of the timer routine chain, whose head is the operand of the instruction at 461CH. The timer tick (4610H) runs it every 40 ticks, once a second.

44C9-44CC
DEFB EBH, 44H, 28H, 01H EB 44 28 01
Timer block of the clock routine: link 44EBH (the cursor routine, next in the chain), interval 28H (40 ticks of 25 ms, one second), countdown 01H. The routine follows at 44CDH.
44CD
LD HL,4041H 21 41 40
Point Register Pair HL to 4041H, the seconds byte of the clock (4041H seconds, 4042H minutes, 4043H hours).
44D0
PUSH HL E5
Save Register Pair HL (4041H) onto the stack for the update loop at 44DCH.
44D1
LD DE,43ACH 11 AC 43
Point Register Pair DE to 43ACH, the copy of the clock and date kept for a warm reset.
44D4
LD BC,0006H 01 06 00
Load Register Pair BC with 0006H: six bytes, the time (4041H-4043H) and the date (4044H-4046H).
44D7
LDIR ED B0
Copy the 6 bytes from Register Pair HL (4041H) to Register Pair DE (43ACH), counting Register Pair BC down to 0, so that a reset while the DOS is active can put them back (4D1FH). Register C is 0 afterwards.
44D9
LD DE,407CH 11 7C 40
Point Register Pair DE to 407CH, the clock limits (59, 59, 23).
44DC
POP HL E1
Restore Register Pair HL from the stack: 4041H, the seconds.
44DD
LD B,03H 06 03
Load Register B with 03H, the three clock values: seconds, minutes, hours.

Carry Loop
Register Pair HL = the clock value, Register Pair DE = its limit, Register B = values left, Register C = 00H (from the LDIR).

44DF
INC (HL) 34
INCrement the clock value at Register Pair HL by 1.
44E0
LD A,(DE) 1A
Fetch its limit at Register Pair DE (407CH-407EH) into Register A.
44E1
SUB (HL) 96
SUBtract the new value at Register Pair HL from Register A (the limit). The CARRY FLAG is set only when the value has passed the limit.
44E2
RET NC D0
If the NO CARRY FLAG is set (the value is not past its limit), RETurn: the clock is updated.
44E3
LD (HL),C 71
Store Register C (00H since the LDIR) at Register Pair HL: the value passed its limit and starts again at 0.
44E4
INC DE 13
INCrement Register Pair DE to the next limit.
44E5
INC HL 23
INCrement Register Pair HL to the next clock value (minutes, then hours).
44E6
DECrement Register B (the values left) and, if it is not 0, LOOP BACK to 44DFH to carry 1 into the next value at Register Pair HL.
44E8
INC HL 23
The hours passed 23 and Register Pair HL points to 4044H, the year: INCrement Register Pair HL to 4045H, the day.
44E9
INC (HL) 34
INCrement the day at Register Pair HL (4045H). The month and year are not advanced and the day is not checked against the month.
44EA
RET C9
RETurn to the timer tick routine (462DH) with the clock and the day advanced.

44EBH - Cursor Routine

The second entry of the timer routine chain, run every half second. It shows the cursor character, and when blinking is on (SYSTEM option BH, or the BLINK command) it alternates the cursor and the character under it.

44EB-44EE
DEFB 00H, 00H, 14H, 01H 00 00 14 01
Timer block of the cursor routine: link 0000H (the end of the chain), interval 14H (20 ticks, half a second), countdown 01H. The routine follows at 44EFH.
44EF
PUSH IX DD E5
Save Index Register IX onto the stack. IX holds the device control block the interrupted code was working on (the ROM's drivers are entered with IX = their block).
44F1
POP HL E1
Restore that value into Register Pair HL: Register Pair HL = Index Register IX of the interrupted code.
44F2
LD DE,401DH 11 1D 40
Point Register Pair DE to 401DH, the display's device control block.
44F5
RST 18H DF
RST 18H: compare Register Pair HL (the interrupted code's IX) with Register Pair DE (401DH) through the ROM. The Z FLAG is set if they are equal.
44F6
RET Z C8
If the Z FLAG is set (the display driver itself was interrupted), RETurn and leave the cursor alone, since the driver is changing the screen.
44F7
LD A,(4022H) 3A 22 40
Fetch the cursor byte at 4022H into Register A: 00H when the cursor is off, otherwise the character the cursor covers.
44FA
OR A B7
OR Register A with itself to test the cursor byte. The Z FLAG is set if it is 00H.
44FB
RET Z C8
If the Z FLAG is set (Register A = 00H, the cursor is off), RETurn.
44FC
LD HL,(4020H) 2A 20 40
Load Register Pair HL with the cursor's screen address from 4020H-4021H.
44FF
CP (HL) BE
Compare Register A (the character under the cursor) against the byte on the screen at Register Pair HL. The Z FLAG is set if the screen shows the character, so the cursor is not showing.
4500
LD (HL),5FH 36 5F
Store 5FH (the cursor character) on the screen at Register Pair HL. Self-Modifying Code
The operand at 4501H is replaced at reset by SYSTEM option BI when it is not 0 (4E28H). LD does not change the flags of the CP.
4502
RET C9
RETurn. Self-Modifying Code
Changed to RET Z (C8H) for a blinking cursor, at reset by option BH (4E6AH) or by the BLINK command (SYS3). With RET Z the routine returns only if the Z FLAG from 44FFH is set (the screen showed the covered character, so the cursor was just put up).
4503
LD (HL),A 77
Blinking, and the cursor was showing: store Register A (the covered character) back on the screen at Register Pair HL, replacing the cursor just stored.
4504
RET C9
RETurn to the timer tick routine with the covered character on the screen.

4505H - Display Driver

Put into the display's control block (401EH) at reset when SYSTEM option AJ is Y (4E31H). The ROM's dispatcher at 03C2H enters a driver with Index Register IX pointing to the control block, Register C holding the character, and the flags of CP 02H on the request type: the CARRY FLAG set for input (reading the character at the cursor), clear for output. As loaded, everything goes to the ROM's driver. With the lower case driver on (SYSTEM option BF, or the LCDVR command in SYS3), 4505H becomes JR C,4513H and characters 20H-7FH are put on the screen by the ROM's store routine, so lower case letters are not changed to upper case.

4505
JUMP to 4513H (the ROM's display driver) for every request. Self-Modifying Code
Changed to JR C,4513H (38H) by 4E5CH (option BF) or by LCDVR (SYS3), so that only input requests (CARRY FLAG set) go straight to the ROM.
4507
Output: GOSUB to 4853H to load Register Pair HL with the cursor address from bytes 3-4 of the control block at Index Register IX (401DH); Register A becomes 00H.
450A
LD A,C 79
Load Register A with Register C, the character to display.
450B
SUB 20H D6 20
SUBtract 20H from Register A (the character), so that 20H-7FH become 00H-5FH.
450D
CP 60H FE 60
Compare Register A (the character minus 20H) against 60H. The CARRY FLAG is set for a character in the range 20H-7FH.
450F
LD A,C 79
Load Register A with Register C (the character) again. LD does not change the CARRY FLAG.
4510
If the CARRY FLAG is set (Register A is a character 20H-7FH), JUMP to the ROM at 047DH, which stores Register A at the cursor address in Register Pair HL and advances the cursor, keeping lower case letters.
4513
JUMP to the ROM's display driver at 0458H with Register C = the character and Index Register IX = the control block; it handles control codes, graphics, and folds lower case to upper case.

4516H - Keyboard Driver

Put into the keyboard's control block (4016H) at reset when SYSTEM option AJ is Y, unless the up-arrow key is held (4E31H). It scans the keyboard like the ROM's driver but adds the repeat key (options AU and AV), the debounce (option AC), a CLEAR key filter (option AQ), the key combinations D-F-G, 1-2-3 and J-K-L (45BFH) and, with the lower case driver on, the letter case handling at 4594H. It returns the key in Register A, or 00H for none.

4516
LD A,(4369H) 3A 69 43
Fetch the DOS flags at 4369H into Register A (bit 5 chaining, bit 3 FORMAT/COPY running, bit 6 an overlay function running).
4519
XOR 20H EE 20
XOR Register A (the 4369H flags) with 20H, inverting bit 5 (chaining) so that it reads 0 when chaining is on.
451B
AND 68H E6 68
AND Register A with 68H, keeping bits 3, 5 (inverted) and 6. The Z FLAG is now set only when chaining is on and neither FORMAT/COPY nor an overlay function is running.
451D
LD A,CBH 3E CB
Load Register A with CBH, the RST 28H code of SYS9 function 6, which gives the next key from the chain file. LD does not change the Z FLAG.
451F
If the Z FLAG is set (the chain file supplies the keys), GOSUB to 49DDH, which executes RST 28H with Register A = CBH and returns: SYS9 answers with the key in Register A and the Z FLAG set, or the NZ FLAG to let the real keyboard answer.
4522
RET Z C8
If the Z FLAG is set (SYS9 supplied a key in Register A), RETurn with it to the ROM's keyboard input routine.
4523
LD HL,45BEH 21 BE 45
Point Register Pair HL to 45BEH, the first byte of the key combination check.
4526
LD (HL),C9H 36 C9
Store C9H (RET) at Register Pair HL (45BEH), so that the timer interrupt (4600H) does not look for the key combinations while the keyboard is being scanned here.
4528
PUSH HL E5
Save Register Pair HL (45BEH) onto the stack; 458CH takes it back to put the NOP there again.
4529
LD HL,4036H 21 36 40
Point Register Pair HL to the saved row image of the last key found. Self-Modifying Code
The operand at 452AH is stored by 4565H with the address of that key's row image (4036H-403CH); as loaded it is 4036H.
452C
LD A,(HL) 7E
Fetch the row image at Register Pair HL (the last key's row as last scanned) into Register A.
452D
OR A B7
OR Register A with itself. The NZ FLAG is set if a key in that row is still down.
452E
LD A,00H 3E 00
Load Register A with the first repeat delay. Self-Modifying Code
The operand at 452FH is SYSTEM option AV (the ticks before the first repeat), stored at reset. LD does not change the flags.
4530
If the NZ FLAG is set (the last key is still down), JUMP to 4535H and keep the current repeat delay.
4532
LD (4580H),A 32 80 45
The key was released: store Register A (the first delay, option AV) as the operand at 4580H, so that the next held key waits the full first delay before repeating.
4535
XOR A AF
Set Register A to 00H and clear the flags, ready to OR in the repeat countdown at 4536H.
4536
OR 00H F6 00
OR Register A (00H) with the repeat countdown. Self-Modifying Code
The operand at 4537H is the repeat countdown itself: stored by 4581H and counted down every tick by 4614H. The Z FLAG is set when it has run out.
4538
JUMP to 4543H to scan normally (no repeat key). Self-Modifying Code
Changed to JR NZ,4543H (20H) when SYSTEM option AU is Y (4E1AH): the scan then goes on normally while the countdown in Register A is not 0, and falls through to make a repeat when it has run out.
453A
OR (HL) B6
The countdown has run out: OR Register A (00H) with the last key's row image at Register Pair HL. The NZ FLAG is set if a key in that row is still down.
453B
If the NZ FLAG is set (the key is still held), JUMP to 4541H to make it look newly pressed.
453D
DEC A 3D
The key is up: DECrement Register A from 00H to FFH.
453E
LD (4573H),A 32 73 45
Store Register A (FFH, no key) as the last key number, the operand at 4573H, so that the next key starts a new repeat sequence.
4541
LD (HL),00H 36 00
Store 00H into the row image at Register Pair HL, so that the scan below sees the held key as a new key press and returns it again (the repeat).
4543
LD L,36H 2E 36
Load Register L with 36H: Register Pair HL = 4036H, the first of the seven saved keyboard row images (Register H is 40H from either path).
4545
LD BC,3801H 01 01 38
Load Register Pair BC with 3801H, the memory address that reads keyboard row 0 (@ A B C D E F G).
4548
LD D,FFH 16 FF
Load Register D with FFH: the key number counter, one below row 0's first key.

Row Scan Loop
Register Pair BC = the keyboard row address (3801H, 3802H, 3804H ... 3840H), Register Pair HL = its saved image (4036H-403CH), Register D = key number so far.

454A
LD A,(BC) 0A
Read the keyboard row at Register Pair BC into Register A (bits set for keys that are down).
454B
LD E,A 5F
Copy Register A (the row's keys now) into Register E.
454C
XOR (HL) AE
XOR Register A with the saved image at Register Pair HL: the bits set are the keys that changed since the last scan.
454D
LD (HL),E 73
Store Register E (the row as read now) at Register Pair HL as the new saved image.
454E
AND E A3
AND Register A (the changed keys) with Register E (the keys down now): keep only keys newly pressed. The NZ FLAG is set if there is one.
454F
If the NZ FLAG is set (a key was newly pressed in this row), JUMP to 455EH to find which one.
4551
LD A,D 7A
Load Register A with Register D, the key number counter.
4552
ADD A,08H C6 08
ADD 08H to Register A: the next row's keys are numbered 8 higher.
4554
LD D,A 57
Store Register A back into Register D, the key number counter.
4555
INC L 2C
INCrement Register L: Register Pair HL points to the next row's saved image.
4556
RLC C CB 01
Rotate Register C left: the row address in Register Pair BC moves to the next row (3801H, 3802H, 3804H ... 3840H, 3880H). The SIGN FLAG is set when bit 7 is reached (row 7, the SHIFT row).
4558
If the SIGN FLAG is clear (Register C has not reached 80H), LOOP BACK to 454AH to scan the next row. Row 7 (the SHIFT keys) is not scanned for new keys.
455B
XOR A AF
No key was newly pressed: set Register A to 00H (no key).
455C
JUMP to 456DH with Register A = 00H, which takes the no-key path.
455E
LD E,A 5F
Copy Register A (the newly pressed keys of this row) into Register E.

Find the Key's Bit
Register A is shifted right until the lowest set bit reaches the CARRY FLAG, counting Register D up once per bit.

455F
INC D 14
INCrement Register D, the key number: it becomes row x 8 + bit number when the loop ends.
4560
RRCA 0F
Rotate Register A right; bit 0 goes into the CARRY FLAG.
4561
If the NO CARRY FLAG is set (that bit was not the key), LOOP BACK to 455FH.
4563
PUSH BC C5
Save Register Pair BC (the row address) onto the stack.
4564
PUSH DE D5
Save Register Pair DE (Register D = the key number, Register E = the key's row bits) onto the stack.
4565
LD (452AH),HL 22 2A 45
Store Register Pair HL (the address of this row's saved image) as the operand at 452AH, used by the repeat test next time.
4568
GOSUB to the ROM at 040BH, the second half of the ROM's keyboard driver, which turns the key number in Register D into its character in Register A (using SHIFT, after the ROM's debounce delay).
456B
POP HL E1
Restore Register Pair HL from the stack: Register H = the key number and Register L = the key's row bits (pushed as Register Pair DE at 4564H).
456C
POP BC C1
Restore Register Pair BC from the stack: the row address.
456D
OR A B7
OR Register A with itself to test the character. The Z FLAG is set for 00H (no key).
456E
LD D,A 57
Copy Register A (the character, or 00H) into Register D for 45BFH.
456F
If the Z FLAG is set (no character), JUMP to 4589H with Register D = 00H.
4571
LD A,H 7C
Load Register A with Register H, the key number of this key.
4572
CP FFH FE FF
Compare Register A (the key number) with the last key number. Self-Modifying Code
The operand at 4573H is stored by 4574H (and FFH, none, by 453EH). The Z FLAG is set for the same key again.
4574
LD (4573H),A 32 73 45
Store Register A (this key number) as the operand at 4573H, the last key number for next time. LD does not change the flags.
4577
LD A,00H 3E 00
Load Register A with the first repeat delay. Self-Modifying Code
The operand at 4578H is SYSTEM option AV, stored at reset.
4579
If the NZ FLAG is set (a different key from last time), JUMP to 4581H to start the countdown with the first delay in Register A.
457B
LD A,(BC) 0A
The same key again: read its row at Register Pair BC into Register A.
457C
AND L A5
AND Register A with Register L (the key's bit). The Z FLAG is set if the key is no longer down.
457D
Debounce: if the Z FLAG is set (the key bounced up), JUMP to 456DH with Register A = 00H, giving no key. Self-Modifying Code
When SYSTEM option AC is N, 4E77H changes the opcode at 457DH to 3EH: the two bytes become LD A,EEH, which 457FH overwrites at once, so the debounce test is skipped.
457F
LD A,FFH 3E FF
Load Register A with the repeat delay for the same key. Self-Modifying Code
The operand at 4580H is FFH as loaded, the first delay (option AV) when stored by 4532H, and 02H after a key has been returned (4586H).
4581
LD (4537H),A 32 37 45
Store Register A (the delay in ticks) at 4537H, the operand of the OR at 4536H: the repeat countdown, counted down by the timer tick.
4584
LD A,02H 3E 02
Load Register A with 02H: once the first repeat has come, the key repeats every 2 ticks.
4586
LD (4580H),A 32 80 45
Store Register A (02H) as the operand at 4580H, the delay used for the next repeat of the same key.
4589
GOSUB to 45BFH to check the key combinations (D-F-G, 1-2-3, J-K-L). It returns the character from Register D in Register A.
458C
POP HL E1
Restore Register Pair HL from the stack: 45BEH, pushed at 4528H.
458D
LD (HL),00H 36 00
Store 00H (NOP) at Register Pair HL (45BEH): the timer interrupt may look for the key combinations again.
458F
CP 1FH FE 1F
Compare Register A (the character) against 1FH, the CLEAR key. Self-Modifying Code
The operand at 4590H is changed to 00H when SYSTEM option AQ is Y (4E92H), which lets CLEAR through.
4591
If the Z FLAG is set (Register A is CLEAR and CLEAR is disabled), JUMP to 45B0H to return 00H (no key) instead.
4593
RET C9
RETurn with the character in Register A. Self-Modifying Code
With the lower case driver on (SYSTEM option BF, or LCDVR in SYS3) this byte is LD C,A (4FH): Register C gets a copy of the character and the letter case handling at 4594H follows.

4594H - Letter Case Handling

Reached from 4593H only while the lower case driver is on, with the character in Registers A and C. Letters have their case flipped, so that an unshifted letter gives lower case, and SHIFT-0 switches upper case only mode on and off. When the upper case only mode is on (45B4H holds a NOP), letters are converted to upper case instead.

4594
AND DFH E6 DF
AND Register A (the character) with DFH, clearing bit 5 so that lower case letters become upper case for the test.
4596
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A, so that the letters A-Z become 00H-19H.
4598
CP 1AH FE 1A
Compare Register A against 1AH (26). The CARRY FLAG is set only for a letter.
459A
LD A,C 79
Load Register A with Register C, the character as it came from the keyboard. LD does not change the CARRY FLAG.
459B
If the CARRY FLAG is set (Register A is a letter), JUMP to 45B2H to flip its case.
459D
CP 20H FE 20
Compare Register A (the character) against 20H. Only the character 20H is examined further, as a possible SHIFT-0.
459F
RET NZ C0
If the NZ FLAG is set (Register A is not 20H), RETurn with the character unchanged.
45A0
LD HL,387FH 21 7F 38
Point Register Pair HL to 387FH, the keyboard address that reads rows 0-6 at once (their bits ORed together).
45A3
LD A,(HL) 7E
Fetch the combined rows at Register Pair HL (387FH) into Register A. Bit 0 is set if any key of column 0 (@, H, P, X, 0, 8, ENTER) is down.
45A4
INC HL 23
INCrement Register Pair HL to 3880H, keyboard row 7 (bit 0 = the left SHIFT key).
45A5
AND (HL) A6
AND Register A with row 7 at Register Pair HL (3880H): bit 0 stays set only when a column-0 key and the left SHIFT key are down together.
45A6
RRCA 0F
Rotate Register A right: bit 0 goes into the CARRY FLAG.
45A7
LD A,C 79
Load Register A with Register C, the character (20H) again. LD does not change the CARRY FLAG.
45A8
RET NC D0
If the NO CARRY FLAG is set (not SHIFT-0), RETurn with Register A = 20H, a space.
45A9
LD HL,45B4H 21 B4 45
SHIFT-0: point Register Pair HL to 45B4H, the RET or NOP that selects the case mode.
45AC
LD A,(HL) 7E
Fetch the byte at Register Pair HL (45B4H: C9H RET or 00H NOP) into Register A.
45AD
XOR C9H EE C9
XOR Register A with C9H, switching it between C9H (RET, letters flipped) and 00H (NOP, upper case only).
45AF
LD (HL),A 77
Store Register A (the new mode byte) back at Register Pair HL (45B4H). Fall into 45B0H to return no key for SHIFT-0.
45B0
XOR A AF
Set Register A to 00H (no key) and clear the flags. Also reached from 4591H (CLEAR disabled) and from 4312H, where the BREAK hook turns the BREAK code into no key.
45B1
RET C9
RETurn to the keyboard input caller with Register A = 00H, meaning no key.
45B2
XOR 20H EE 20
XOR Register A (the letter) with 20H, flipping its case: an unshifted letter (upper case from the ROM) becomes lower case and a shifted one upper case.
45B4
RET C9
RETurn with the case-flipped letter in Register A. Self-Modifying Code
Changed to a NOP (00H) by SYSTEM option BG = N (4E65H), by the LC command (SYS3) or by SHIFT-0 (45AFH): the letter then falls into 45B5H and is made upper case.

45B5H - Convert Lower Case to Upper Case

Converts a lower case letter in Register A to upper case; any other value is returned unchanged. Used by many overlays.

45B5
CP 61H FE 61
Compare Register A (the character) against 61H (ASCII a). The CARRY FLAG is set if it is below a.
45B7
RET C D8
If the CARRY FLAG is set (Register A is below a, not a lower case letter), RETurn with it unchanged.
45B8
CP 7BH FE 7B
Compare Register A against 7BH, the code after z. The NO CARRY FLAG is set if it is above z.
45BA
RET NC D0
If the NO CARRY FLAG is set (Register A is above z), RETurn with it unchanged.
45BB
SUB 20H D6 20
SUBtract 20H from Register A, turning the lower case letter a-z into A-Z.
45BD
RET C9
RETurn with the upper case letter in Register A.

45BEH - Check for D-F-G, 1-2-3 and J-K-L

Called by the timer interrupt (4600H) and by the keyboard driver (4589H). D-F-G enters MINI-DOS, 1-2-3 enters DEBUG, J-K-L prints the screen. Each combination is off until the reset code turns it on from SYSTEM options AF, AE and AD, by changing an unconditional JR into JR NZ (or the final RET into RET NZ). On return, Register A holds Register D (the keyboard driver's character).

45BE
NOP 00
No operation: the entry for the timer interrupt. Self-Modifying Code
A RET (C9H) while the keyboard driver is scanning (stored at 4526H, put back to NOP at 458DH) and while an overlay function runs (the dispatcher stores the NOP again at 4BD5H when it starts one).
45BF
LD HL,4369H 21 69 43
Entry for the keyboard driver. Point Register Pair HL to 4369H, the DOS flags.
45C2
LD A,(HL) 7E
Fetch the DOS flags at Register Pair HL (4369H) into Register A.
45C3
AND 6CH E6 6C
AND Register A with 6CH, keeping bits 2 (RUN-ONLY), 3 (FORMAT/COPY), 5 (chaining) and 6 (overlay function running). The NZ FLAG is set if any of them is set.
45C5
If the NZ FLAG is set (Register A shows one of those states), JUMP to 45EDH: no key combinations; return the character.
45C7
LD A,(3801H) 3A 01 38
Read keyboard row 0 at 3801H (@ A B C D E F G) into Register A.
45CA
CP D0H FE D0
Compare Register A (row 0) against D0H: D, F and G (bits 4, 6 and 7) down and nothing else in the row. The Z FLAG is set if so.
45CC
JUMP to 45D3H (D-F-G off). Self-Modifying Code
Changed to JR NZ,45D3H (20H) when SYSTEM option AF is Y (4E89H), so that the Z FLAG from 45CAH falls through to MINI-DOS.
45CE
LD A,E3H 3E E3
D-F-G: load Register A with E3H, the RST 28H code of SYS1 function 7.
45D0
LD C,04H 0E 04
Load Register C with 04H, SYS1 function 7's sub-function 4: MINI-DOS.
45D2
RST 28H EF
RST 28H with Register A = E3H and Register C = 04H: call SYS1 function 7 sub-function 4 (MINI-DOS). The dispatcher drops the RST's return address, so when SYS1 returns it returns to the caller of 45BEH/45BFH.
45D3
LD A,(3810H) 3A 10 38
Read keyboard row 4 at 3810H (0 1 2 3 4 5 6 7) into Register A.
45D6
CP 0EH FE 0E
Compare Register A (row 4) against 0EH: 1, 2 and 3 (bits 1, 2 and 3) down and nothing else in the row. The Z FLAG is set if so.
45D8
JUMP to 45E8H (1-2-3 off). Self-Modifying Code
Changed to JR NZ,45E8H (20H) when SYSTEM option AE is Y (4E9AH).
45DA
LD A,(45BEH) 3A BE 45
1-2-3: fetch the byte at 45BEH into Register A: C9H (RET) if the keyboard driver is the caller, 00H (NOP) if the timer interrupt is.
45DD
SUB C9H D6 C9
SUBtract C9H from Register A. The Z FLAG is set if 45BEH holds a RET, so the keyboard driver called.
45DF
If the Z FLAG is set (called from the keyboard driver), JUMP to 440DH to enter DEBUG; DEBUG returns into the keyboard driver at 458CH.
45E2
POP AF F1
Called from the interrupt: restore Register Pair AF from the stack. This takes the return address into the interrupt handler (4603H) off the stack; the value in Register Pair AF is not used.
45E3
POP BC C1
Restore Register Pair BC from the stack, as the interrupt handler saved it at 45F5H (the interrupted program's BC).
45E4
POP DE D1
Restore Register Pair DE from the stack, as saved at 45F4H (the interrupted program's DE).
45E5
POP HL E1
Restore Register Pair HL from the stack, as saved at 45F3H (the interrupted program's HL).
45E6
JUMP to 460AH. The interrupted program's AF (pushed at 45F2H) and then its return address are on the stack, so DEBUG is entered as if the interrupted instruction had been a RST 30H followed by PUSH AF.
45E8
LD A,(3802H) 3A 02 38
Read keyboard row 1 at 3802H (H I J K L M N O) into Register A.
45EB
CP 1CH FE 1C
Compare Register A (row 1) against 1CH: J, K and L (bits 2, 3 and 4) down and nothing else in the row. The Z FLAG is set if so.
45ED
LD A,D 7A
Load Register A with Register D, the keyboard driver's character (or whatever Register D held at the interrupt). LD does not change the flags.
45EE
RET C9
RETurn with Register A = the character. Self-Modifying Code
Changed to RET NZ (C0H) when SYSTEM option AD is Y (4E80H): with J-K-L down (Z FLAG from 45EBH) execution falls into 45EFH.
45EF
LD A,A5H 3E A5
J-K-L: load Register A with A5H, the RST 28H code of SYS3 function 5 (print the screen).
45F1
RST 28H EF
RST 28H with Register A = A5H: call SYS3 function 5, which prints the screen and returns to the caller of 45BEH/45BFH.

45F2H - Interrupt Handler

The RST 38H vector at 4012H jumps here on every interrupt (Interrupt Mode 1). The interrupt latch at 37E0H tells which device interrupted: bit 7 the 25 ms clock, bit 6 the disk controller.

45F2
PUSH AF F5
Save Register Pair AF of the interrupted program onto the stack.
45F3
PUSH HL E5
Save Register Pair HL of the interrupted program onto the stack.
45F4
PUSH DE D5
Save Register Pair DE of the interrupted program onto the stack.
45F5
PUSH BC C5
Save Register Pair BC of the interrupted program onto the stack.
45F6
LD A,(37E0H) 3A E0 37
Read the interrupt latch at 37E0H into Register A: bit 7 = clock interrupt, bit 6 = disk controller interrupt.
45F9
RLCA 07
Rotate Register A left: bit 7 (the clock bit) goes into the CARRY FLAG, and bit 6 (the disk bit) moves to bit 7.
45FA
GOSUB to 4053H with Register A = the shifted latch: it reads the FDC status if bit 7 of Register A (the disk bit) is set, which clears the disk interrupt. Register Pair AF is preserved.
45FD
If the CARRY FLAG is set (the clock interrupted), GOSUB to 4610H, the timer tick.
4600
GOSUB to 45BEH to check the key combinations D-F-G, 1-2-3 and J-K-L (45BEH is a RET while the keyboard driver scans).
4603
POP BC C1
Restore Register Pair BC of the interrupted program from the stack.
4604
POP DE D1
Restore Register Pair DE of the interrupted program from the stack.
4605
POP HL E1
Restore Register Pair HL of the interrupted program from the stack.
4606
POP AF F1
Restore Register Pair AF of the interrupted program from the stack.
4607
EI FB
Enable interrupts again (the CPU disabled them when it took the interrupt).
4608
RET C9
RETurn to the interrupted program, with all its registers as they were.

4609H - Enter DEBUG

Reached through RST 30H (400FH, a breakpoint) and through 440DH; 45E6H enters at 460AH with Register Pair AF already on the stack.

4609
PUSH AF F5
Save Register Pair AF (the program's registers, for DEBUG's register display) onto the stack.
460A
LD A,27H 3E 27
Load Register A with 27H, the RST 28H code of SYS5 function 1 (DEBUG).
460C
RST 28H EF
RST 28H with Register A = 27H: call SYS5 (DEBUG). DEBUG resumes the program itself through 4C20H with the registers restored; it does not return here.
460D
LD (HL),B 70
Store Register B (the routine's interval) at Register Pair HL (byte 3 of the timer block, its countdown): reload the countdown. Called from 462AH when the countdown reached 0.
460E
INC HL 23
INCrement Register Pair HL to byte 4 of the timer block, the first instruction of the routine.
460F
JP (HL) E9
JUMP to the routine at Register Pair HL. It RETurns to 462DH, the return address of the CALL at 462AH.

4610H - Timer Tick

Called for every clock interrupt, every 25 ms. Counts the ticks, counts down the repeat key delay and walks the chain of timer routines. The chain is the one the manual describes in section 3.8: each routine starts with a two-byte chain link, its interval and its countdown, and its code follows at byte 4.

4610
LD HL,4040H 21 40 40
Point Register Pair HL to 4040H, the tick counter.
4613
INC (HL) 34
INCrement the tick counter at Register Pair HL (4040H).
4614
LD HL,4537H 21 37 45
Point Register Pair HL to 4537H, the repeat key countdown (the operand of the OR at 4536H).
4617
LD A,(HL) 7E
Fetch the repeat countdown at Register Pair HL (4537H) into Register A.
4618
OR A B7
OR Register A with itself to test the countdown. The Z FLAG is set if it is 0.
4619
If the Z FLAG is set (the countdown in Register A is already 0), JUMP to 461CH and leave it at 0.
461B
DEC (HL) 35
DECrement the repeat countdown at Register Pair HL (4537H) by 1.
461C
LD HL,44C9H 21 C9 44
Point Register Pair HL to the first timer block of the chain. Self-Modifying Code
The operand at 461DH-461EH is the chain head: 44C9H (the clock routine) as loaded, changed by SYS3's enqueue and dequeue functions (4410H, 4413H) and by CLEAR (SYS14).

Timer Chain Loop
Register Pair HL = the current timer block (0000H ends the chain); the next block's address is kept on the stack across the routine.

461F
LD A,H 7C
Load Register A with Register H, the high byte of the block address in Register Pair HL.
4620
OR L B5
OR Register A with Register L. The Z FLAG is set if Register Pair HL is 0000H, the end of the chain.
4621
RET Z C8
If the Z FLAG is set (Register Pair HL = 0000H), RETurn to the interrupt handler: every routine has been looked at.
4622
LD E,(HL) 5E
Fetch the low byte of the block's chain link at Register Pair HL into Register E.
4623
INC HL 23
INCrement Register Pair HL to the link's high byte.
4624
LD D,(HL) 56
Fetch the high byte of the chain link at Register Pair HL into Register D. Register Pair DE = the next timer block.
4625
PUSH DE D5
Save Register Pair DE (the next block) onto the stack, since the routine may change any register.
4626
INC HL 23
INCrement Register Pair HL to byte 2 of the block, the interval.
4627
LD B,(HL) 46
Fetch the interval at Register Pair HL into Register B.
4628
INC HL 23
INCrement Register Pair HL to byte 3, the countdown.
4629
DEC (HL) 35
DECrement the countdown at Register Pair HL. The Z FLAG is set when it reaches 0.
462A
If the Z FLAG is set (the countdown ran out), GOSUB to 460DH with Register B = the interval and Register Pair HL = the countdown: reload it and run the routine.
462D
POP HL E1
Restore Register Pair HL from the stack: the next timer block (pushed at 4625H).
462E
LOOP BACK to 461FH to process the timer block at Register Pair HL.

4630H - Read or Write a Sector

The sector level disk I/O. Register Pair DE = the sector number on the diskette (counted from 0 across all tracks), Register Pair HL = the 256-byte buffer, the drive is the current drive (4308H). On exit the Z FLAG is set if all went well; otherwise Register A holds the DOS error code. Register Pair BC is preserved. Entry points: 4630H read, 4634H verify read, 463CH write with the directory mark, 4640H write.

4630
LD A,88H 3E 88
Read entry: load Register A with 88H, the FDC Read Sector command (single record).
4632
JUMP to 4642H with Register A = 88H to set up the transfer.
4634
PUSH HL E5
Verify read entry, used after a write with verify: save Register Pair HL (the caller's buffer address) onto the stack.
4635
LD H,01H 26 01
Load Register H with 01H: the buffer in Register Pair HL now points into the ROM at 01xxH, where the bytes read are thrown away. The read still checks the sector's CRC and address marks.
4637
GOSUB to 4630H to read the sector in Register Pair DE into the ROM address in Register Pair HL. Register A and the flags return the result.
463A
POP HL E1
Restore Register Pair HL from the stack: the caller's buffer address.
463B
RET C9
RETurn with the read's result: the Z FLAG set if the sector reads back without error, otherwise the error code in Register A.
463C
LD A,A9H 3E A9
Write with the directory mark: load Register A with the FDC Write Sector command A9H (data address mark FAH, the directory mark that the SYS0 read at 4907H tests for as error 06H). Self-Modifying Code
4DFDH changes the operand at 463DH to ABH (data address mark F8H) when SYSTEM option BN is Y.
463E
JUMP to 4642H with Register A = the directory write command.
4640
LD A,A8H 3E A8
Write entry: load Register A with A8H, the FDC Write Sector command with the normal data address mark FBH.
4642
LD (46C4H),A 32 C4 46
Store Register A (the FDC command) at 46C4H, the operand of the LD (HL),n at 46C3H that issues it.
4645
AND 20H E6 20
AND Register A with 20H. Bit 5 is set only for the write commands, so the Z FLAG is set for a read; Register A becomes 00H for a read.
4647
PUSH BC C5
Save Register Pair BC (the caller's) onto the stack; it is restored at 4738H.
4648
LD BC,021AH 01 1A 02
Load Register Pair BC with 021AH: Register C = 1AH (LD A,(DE)) and Register B = 02H (LD (BC),A), the two opcodes of the read transfer loop. Register A (00H for a read) is the error code base. LD does not change the flags.
464B
If the Z FLAG is set (a read), JUMP to 4652H with Register A = 00H and Register Pair BC = 021AH.
464D
LD A,08H 3E 08
A write: load Register A with 08H, the error code base for writes (a write error code is 8 higher than the read error for the same status bit).
464F
LD BC,A12H 01 12 0A
Load Register Pair BC with 0A12H: Register C = 12H (LD (DE),A) and Register B = 0AH (LD A,(BC)), the two opcodes of the write transfer loop.
4652
LD (4731H),A 32 31 47
Store Register A (the error code base, 00H or 08H) as the operand at 4731H, read by 4730H when an error code is made.
4655
LD (46FCH),BC ED 43 FC 46
Store Register Pair BC at 46FCH-46FDH: Register C goes to 46FCH and Register B to 46FDH, the two instructions of the transfer loop (read: LD A,(DE) / LD (BC),A; write: LD (DE),A / LD A,(BC)).
4659
LD B,0AH 06 0A
Load Register B with the number of tries. Self-Modifying Code
The operand at 465AH is SYSTEM option AM, stored at reset (4D83H); the file has 0AH (10).
465B
GOSUB to 4773H to select the current drive (4308H). It returns the Z FLAG, or the NZ FLAG with Register A = 20H for a drive number at or above option AL.
465E
If the NZ FLAG is set (the drive could not be selected, Register A = 20H), JUMP to 4678H to return that error.

Retry Loop
Register B = tries left, Register Pair DE = the sector number on the diskette, Register Pair HL = the buffer. 473FH comes back here for each new try.

4660
PUSH BC C5
Save Register Pair BC (Register B = tries left) onto the stack.
4661
PUSH DE D5
Save Register Pair DE (the sector number on the diskette) onto the stack.
4662
PUSH HL E5
Save Register Pair HL (the buffer address) onto the stack.
4663
LD A,(430EH) 3A 0E 43
Load Register A with the sectors per track of the current drive from 430EH (PDRIVE byte +4).
4666
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the sector number on the diskette, Register Pair DE = the buffer address.
4667
GOSUB to 4CB4H to divide Register Pair HL (the sector number) by Register A (the sectors per track): Register Pair HL = the track, Register A = the sector within the track, Register C = the sectors per track, Register B = 0.
466A
LD D,L 55
Copy Register L (the track number) into Register D.
466B
LD E,A 5F
Copy Register A (the sector within the track) into Register E.
466C
LD HL,430DH 21 0D 43
Point Register Pair HL to 430DH, the track count of the current drive (PDRIVE byte +3).
466F
LD A,D 7A
Load Register A with Register D, the track number.
4670
CP (HL) BE
Compare Register A (the track) against the track count at Register Pair HL (430DH). The CARRY FLAG is set if the track is on the diskette.
4671
If the CARRY FLAG is set (Register A is below the track count), JUMP to 467CH to do the transfer.
4673
LD A,14H 3E 14
Load Register A with error code 14H (TRACK # TOO HIGH).
4675
POP HL E1
Restore Register Pair HL from the stack (the buffer address, pushed at 4662H).
4676
POP DE D1
Restore Register Pair DE from the stack (the sector number, pushed at 4661H).
4677
POP BC C1
Restore Register Pair BC from the stack (the tries, pushed at 4660H).
4678
OR A B7
OR Register A (the error code, 14H or 20H) with itself to set the NZ FLAG.
4679
JUMP to 4737H to enable interrupts, restore the caller's Register Pair BC and return the error in Register A.
467C
LD A,(4311H) 3A 11 43
Load Register A with the disk I/O flags of the current drive from 4311H (PDRIVE byte +7).
467F
LD B,A 47
Copy Register A (the disk I/O flags) into Register B, tested bit by bit below.
4680
BIT 0,B CB 40
Test bit 0 of Register B (double density). The Z FLAG is set for a single density drive.
4682
If the Z FLAG is set (single density), JUMP to 4689H.
4684
LD HL,46C4H 21 C4 46
Point Register Pair HL to 46C4H, the FDC command stored for this transfer.
4687
RES 1,(HL) CB 8E
Clear bit 1 of the FDC command at Register Pair HL (46C4H). On the single density controller bits 0-1 of a write command choose the data address mark; the double density controller needs them clear.
4689
LD HL,4309H 21 09 43
Point Register Pair HL to 4309H, the select latch value of the current drive.
468C
BIT 1,B CB 48
Test bit 1 of Register B (the disk I/O flags): tracks numbered from 1. The Z FLAG is set if they are numbered from 0.
468E
If the Z FLAG is set (tracks from 0), JUMP to 4691H.
4690
INC D 14
INCrement Register D, the track number: the sector headers on this diskette count the tracks from 1.
4691
PUSH DE D5
Save Register Pair DE onto the stack: Register D = the track as written in the sector headers, Register E = the sector within the track.
4692
BIT 2,B CB 50
Test bit 2 of Register B (the disk I/O flags): double step. The Z FLAG is set if not.
4694
If the Z FLAG is set (no double step), JUMP to 4698H.
4696
RLC D CB 02
Rotate Register D (the track) left: the head must be moved to track x 2 (a 40 track diskette in an 80 track drive).
4698
BIT 6,B CB 70
Test bit 6 of Register B (the disk I/O flags): double sided. The Z FLAG is set for a single sided drive.
469A
If the Z FLAG is set (single sided), JUMP to 46A5H.
469C
RRC C CB 09
Rotate Register C (the sectors per track, left there by 4CB4H) right: it now holds the sectors on one side.
469E
LD A,E 7B
Load Register A with Register E, the sector within the track.
469F
SUB C 91
SUBtract Register C (the sectors per side) from Register A. The CARRY FLAG is set if the sector is on the first side.
46A0
If the CARRY FLAG is set (the sector in Register E is on side 1), JUMP to 46A5H.
46A2
LD E,A 5F
Copy Register A (the sector number on side 2) into Register E.
46A3
SET 3,(HL) CB DE
Set bit 3 of the select latch value at Register Pair HL (4309H): the side 2 select.
46A5
GOSUB to 4767H to write the select latch value from 4309H to 37E1H (drive and side).
46A8
BIT 4,B CB 60
Test bit 4 of Register B (the disk I/O flags): sectors numbered from 1. The Z FLAG is set if they are numbered from 0.
46AA
If the Z FLAG is set (sectors from 0), JUMP to 46ADH.
46AC
INC E 1C
INCrement Register E, the sector: this diskette numbers its sectors from 1.
46AD
LD (37EEH),DE ED 53 EE 37
Store Register Pair DE at 37EEH: Register E (the sector) into the FDC sector register (37EEH) and Register D (the physical track) into the FDC data register (37EFH), the destination of the Seek.
46B1
LD C,18H 0E 18
Load Register C with 18H, the FDC Seek command (head load, no verify; the stepping rate is added by 4747H).
46B3
GOSUB to 4747H to issue the Seek in Register C with the drive's stepping rate and wait until it ends.
46B6
POP AF F1
Restore Register Pair AF from the stack: it takes the word pushed at 4691H, so Register A = the track number as written in the sector headers (the Register D pushed there).
46B7
POP BC C1
Restore Register Pair BC from the stack: the buffer address (Register Pair HL pushed at 4662H).
46B8
PUSH BC C5
Save Register Pair BC (the buffer address) back onto the stack for 471DH.
46B9
LD (37EDH),A 32 ED 37
Store Register A (the header track) in the FDC track register at 37EDH, so that the Read or Write finds the sector headers even when the head is on the doubled track.
46BC
PUSH DE D5
Save Register Pair DE onto the stack: Register D = the physical track, which 471BH puts back into the track register afterwards.
46BD
LD DE,37EFH 11 EF 37
Point Register Pair DE to 37EFH, the FDC data register.
46C0
LD HL,37ECH 21 EC 37
Point Register Pair HL to 37ECH, the FDC command/status register.
46C3
LD (HL),00H 36 00
Issue the FDC command to the register at Register Pair HL (37ECH). Self-Modifying Code
The operand at 46C4H is the Read or Write command stored by 4642H (and changed by 4687H for double density).
46C5
GOSUB to 47E3H to wait a moment (so the status is valid) and read the status into Register A.
46C8
DI F3
Disable interrupts for the transfer: the data bytes must be moved within microseconds.
46C9
BIT 0,(HL) CB 46
Test bit 0 (busy) of the FDC status at Register Pair HL (37ECH). The Z FLAG is set if the FDC is not busy.
46CB
If the Z FLAG is set (the command has already ended, an error such as write protect), JUMP to 4717H to fetch the status.
46CD
LD A,(46C4H) 3A C4 46
Fetch the FDC command from 46C4H into Register A.
46D0
BIT 5,A CB 6F
Test bit 5 of Register A (the command): set for Write Sector. The Z FLAG is set for a read.
46D2
If the Z FLAG is set (a read), JUMP to 46F6H.

Write: Wait for the First Data Request
Register Pair BC = the buffer, Register Pair DE = 37EFH, Register Pair HL = 37ECH.

46D4
LD A,83H 3E 83
Load Register A with 83H, the status mask for not ready (bit 7), data request (bit 1) and busy (bit 0).
46D6
AND (HL) A6
AND Register A with the FDC status at Register Pair HL (37ECH). The P/V FLAG shows odd parity while only the busy bit is set.
46D7
If the PO FLAG is set (parity odd: only busy, no data request yet), LOOP BACK to 46D4H.
46DA
LD A,(BC) 0A
Fetch the first byte of the buffer at Register Pair BC into Register A.
46DB
LD (DE),A 12
Store Register A (the first byte) into the FDC data register at Register Pair DE (37EFH).
46DC
INC BC 03
INCrement Register Pair BC to the second byte of the buffer.
46DD
LD A,(BC) 0A
Fetch the second byte of the buffer at Register Pair BC into Register A.
46DE
LD (46E8H),A 32 E8 46
Store Register A (the second byte) as the operand at 46E8H, so that it can be given at once when the FDC asks.
46E1
INC BC 03
INCrement Register Pair BC to the third byte of the buffer.
46E2
LD A,01H 3E 01
Load Register A with 01H, the status value busy without a data request.
46E4
CP (HL) BE
Compare Register A (01H) against the FDC status at Register Pair HL (37ECH). The Z FLAG is set while the FDC is busy and does not yet want the next byte.
46E5
If the Z FLAG is set (status still 01H), LOOP BACK to 46E4H.
46E7
LD A,00H 3E 00
Load Register A with the second byte of the buffer. Self-Modifying Code
The operand at 46E8H is stored by 46DEH.
46E9
LD (DE),A 12
Store Register A (the second byte) into the FDC data register at Register Pair DE (37EFH).
46EA
LD A,(BC) 0A
Fetch the third byte at Register Pair BC into Register A, ready for the next data request.
46EB
INC BC 03
INCrement Register Pair BC to the fourth byte of the buffer.
46EC
BIT 1,(HL) CB 4E
Test bit 1 (data request) of the FDC status at Register Pair HL (37ECH).
46EE
If the NZ FLAG is set (the FDC wants the byte in Register A), JUMP to 46FCH, the transfer loop.
46F0
BIT 1,(HL) CB 4E
Test bit 1 (data request) of the FDC status at Register Pair HL (37ECH) again.
46F2
If the NZ FLAG is set (data request), JUMP to 46FCH.
46F4
JUMP to 46FFH to keep testing the status at Register Pair HL inside the transfer loop.

Read: Wait for the First Data Request

46F6
LD A,83H 3E 83
Load Register A with 83H, the status mask for not ready, data request and busy.
46F8
AND (HL) A6
AND Register A with the FDC status at Register Pair HL (37ECH). The parity is odd while only the busy bit is set.
46F9
If the PO FLAG is set (only busy, no byte yet), LOOP BACK to 46F6H.

Transfer Loop
Register Pair BC = the buffer, Register Pair DE = 37EFH (data), Register Pair HL = 37ECH (status). The data request bit is tested three times in a row so that the loop keeps up with the FDC.

46FC
LD A,(DE) 1A
Read: LD A,(DE) takes the byte from the FDC data register at Register Pair DE into Register A. Self-Modifying Code
For a write this byte is 12H, LD (DE),A, which gives the waiting byte in Register A to the FDC. Stored with 46FDH by 4655H.
46FD
LD (BC),A 02
Read: LD (BC),A stores Register A (the byte from the diskette) in the buffer at Register Pair BC. Self-Modifying Code
For a write this byte is 0AH, LD A,(BC), which fetches the next byte from the buffer.
46FE
INC BC 03
INCrement Register Pair BC to the next byte of the buffer.
46FF
BIT 1,(HL) CB 4E
Test bit 1 (data request) of the FDC status at Register Pair HL (37ECH).
4701
If the NZ FLAG is set (the FDC has the next byte or wants one), LOOP BACK to 46FCH.
4703
BIT 1,(HL) CB 4E
Test bit 1 (data request) of the FDC status at Register Pair HL (37ECH) again.
4705
If the NZ FLAG is set (data request), LOOP BACK to 46FCH.
4707
BIT 1,(HL) CB 4E
Test bit 1 (data request) of the FDC status at Register Pair HL (37ECH) a third time.
4709
If the NZ FLAG is set (data request), LOOP BACK to 46FCH.
470B
BIT 0,(HL) CB 46
Test bit 0 (busy) of the FDC status at Register Pair HL (37ECH). The Z FLAG is set once the command has ended.
470D
If the Z FLAG is set (the FDC is no longer busy), JUMP to 4717H to check the result.
470F
BIT 1,(HL) CB 4E
Test bit 1 (data request) of the FDC status at Register Pair HL (37ECH) once more.
4711
If the NZ FLAG is set (data request), LOOP BACK to 46FCH.
4713
BIT 7,(HL) CB 7E
Test bit 7 (not ready) of the FDC status at Register Pair HL (37ECH). The Z FLAG is set while the drive is ready.
4715
If the Z FLAG is set (the drive is ready), LOOP BACK to 46FFH to keep waiting for data requests.
4717
LD A,(HL) 7E
Fetch the final FDC status at Register Pair HL (37ECH) into Register A.
4718
LD (HL),D0H 36 D0
Store D0H (Force Interrupt, no condition) into the FDC command register at Register Pair HL, ending the command if it is still running.
471A
INC HL 23
INCrement Register Pair HL to 37EDH, the FDC track register.
471B
POP BC C1
Restore Register Pair BC from the stack: Register B = the physical track (Register D pushed at 46BCH).
471C
LD (HL),B 70
Store Register B (the physical track) in the FDC track register at Register Pair HL (37EDH), replacing the header track written at 46B9H.
471D
POP HL E1
Restore Register Pair HL from the stack: the buffer address (pushed at 46B8H).
471E
POP DE D1
Restore Register Pair DE from the stack: the sector number on the diskette (pushed at 4661H).
471F
POP BC C1
Restore Register Pair BC from the stack: Register B = the tries left (pushed at 4660H).
4720
EI FB
Enable interrupts again; the transfer is over.
4721
AND FCH E6 FC
AND Register A (the final status) with FCH, dropping the busy and data request bits. The Z FLAG is set if no error bit is left.
4723
If the Z FLAG is set (no error; Register A = 00H), JUMP to 4737H to return success.
4725
LD C,A 4F
Copy Register A (the error bits of the status) into Register C.
4726
AND 9CH E6 9C
AND Register A with 9CH, keeping the bits worth a retry: not ready (7), record not found (4), CRC error (3) and lost data (2).
4728
If the Z FLAG is set (only bits 5 or 6 are set in Register C: record type, write fault or write protect), JUMP to 4730H to make the error code without a retry.
472A
LD C,A 4F
Copy Register A (the retry-worthy bits) into Register C, for the error code.
472B
ADD A,A 87
ADD Register A to itself, shifting bit 7 (not ready) out. The Z FLAG is set if not ready was the only bit.
472C
If the Z FLAG is set (only not ready), JUMP to 4730H: no retry for a drive that is not ready.
472E
DECrement Register B (the tries left) and, if it is not 0, JUMP to 473AH to try again.
4730
LD A,00H 3E 00
Load Register A with the error code base. Self-Modifying Code
The operand at 4731H is 00H for a read and 08H for a write, stored by 4652H.

Error Code Loop
Register A = error code being built, Register C = the status bits; the code is the base plus the number of the lowest set bit plus 1.

4732
INC A 3C
INCrement Register A, the error code being built.
4733
RRC C CB 09
Rotate Register C (the status bits) right: its lowest bit goes into the CARRY FLAG.
4735
If the NO CARRY FLAG is set (that bit was clear), LOOP BACK to 4732H. When the loop ends Register A = 03H/0BH lost data, 04H/0CH CRC error, 05H/0DH record not found, 06H/0EH bit 5 (read: the directory mark; write: write fault), 07H/0FH bit 6 (write protected), 08H/10H not ready.
4737
EI FB
Enable interrupts (they are still off on the error paths from 4679H).
4738
POP BC C1
Restore Register Pair BC from the stack: the caller's BC, saved at 4647H.
4739
RET C9
RETurn: the Z FLAG with Register A = 00H for success, or the NZ FLAG with Register A = the error code.
473A
BIT 4,C CB 61
Test bit 4 of Register C (the status bits): record not found. The NZ FLAG is set if it is set.
473C
If the NZ FLAG is set (record not found), GOSUB to 4742H, which restores the head to track 0 on every second try (Register B odd).
473F
JUMP to 4660H to try the transfer again with Register B = the tries left.
4742
BIT 0,B CB 40
Test bit 0 of Register B (the tries left). The Z FLAG is set when it is even.
4744
RET Z C8
If the Z FLAG is set (Register B even), RETurn without restoring.
4745
LD C,08H 0E 08
Load Register C with 08H, the FDC Restore command, and fall into 4747H to issue it.

4747H - Issue a Seek Type Command and Wait

Register C holds a Restore (08H), Seek (18H) or Step In (58H) command. The current drive's stepping rate is added, the command is issued, and the routine waits until the controller is no longer busy, reselecting the drive meanwhile so that its motor keeps running. Used by SYS6 as well.

4747
LD A,(430CH) 3A 0C 43
Load Register A with the TSR byte of the current drive from 430CH (PDRIVE byte +2).
474A
AND 03H E6 03
AND Register A with 03H, keeping bits 0-1, the drive's stepping rate (TSR).
474C
OR C B1
OR Register C (the command) into Register A: the command with the stepping rate in bits 0-1.
474D
LD (37ECH),A 32 EC 37
Store Register A (the command) into the FDC command register at 37ECH. 4760H also comes here with Register A = D0H.

Wait While Busy

4750
GOSUB to 47E3H to wait a moment and read the FDC status into Register A.
4753
BIT 0,A CB 47
Test bit 0 of Register A (busy). The Z FLAG is set when the FDC is idle.
4755
RET Z C8
If the Z FLAG is set (the command has ended), RETurn with Register A = the FDC status.
4756
RLCA 07
Rotate Register A (the status) left: bit 7 (not ready) goes into the CARRY FLAG.
4757
If the CARRY FLAG is set (the drive is not ready), JUMP to 475EH to stop the command.
4759
GOSUB to 4767H to write the select latch value from 4309H to 37E1H again, which keeps the drive motor running.
475C
LOOP BACK to 4750H to read and test the FDC status again until the command ends.
475E
LD A,D0H 3E D0
Load Register A with D0H, the FDC Force Interrupt command (no condition): it stops any command. Also called by 4780H and 47C4H to make the FDC idle.
4760
JUMP to 474DH to issue Register A (D0H) and wait until the FDC is idle.

4762H - Keep the Drives Rotating

4416H comes here (manual 3.10). If the drives are rotating, the current drive is reselected. 4767H writes the select latch.

4762
LD A,(37ECH) 3A EC 37
Read the FDC status at 37ECH into Register A.
4765
RLCA 07
Rotate Register A (the status) left: bit 7 (not ready, the motors have stopped) goes into the CARRY FLAG.
4766
RET C D8
If the CARRY FLAG is set (not ready), RETurn without starting the motors.
4767
LD A,(4309H) 3A 09 43
Load Register A with the select latch value of the current drive from 4309H (01H, 02H, 04H or 08H, plus bit 3 for side 2).
476A
LD (37E1H),A 32 E1 37
Store Register A into the drive select latch at 37E1H, which selects the drive and restarts its motor timer.
476D
RET C9
RETurn with Register A = the select latch value.

476EH - Select a Drive

Enter at 476EH for the drive of the FCB at Index Register IX, at 4773H for the current drive, or at 4776H with the drive in Register A (445BH, manual 3.29). The drive becomes the current drive: its PDRIVE record is copied to 430AH-4311H, the controller's track and sector registers are set for it, and its motor is started. A motor that was stopped gets a half second to come up to speed. On exit the Z FLAG is set, or the NZ FLAG with error code 20H (ILLEGAL OR MISSING DRIVE #). Register Pairs HL, DE and BC are preserved.

476E
LD A,(IX+06H) DD 7E 06
Load Register A with the FCB's drive number from (IX+06H), byte +6 of the FCB at Index Register IX.
4771
JUMP to 4776H to select the drive in Register A.
4773
LD A,(4308H) 3A 08 43
Load Register A with the current drive number from 4308H.
4776
PUSH HL E5
Save Register Pair HL (the caller's) onto the stack.
4777
PUSH DE D5
Save Register Pair DE (the caller's) onto the stack.
4778
PUSH BC C5
Save Register Pair BC (the caller's) onto the stack.
4779
CP 01H FE 01
Compare Register A (the drive number) against the number of drives. Self-Modifying Code
The operand at 477AH is SYSTEM option AL, stored at reset (4D69H); the file has 01H. The NO CARRY FLAG is set if the drive number is too high.
477B
LD C,A 4F
Copy Register A (the drive number) into Register C. LD does not change the flags.
477C
LD A,20H 3E 20
Load Register A with 20H, error code ILLEGAL OR MISSING DRIVE #.
477E
If the NO CARRY FLAG is set (the drive in Register C is at or above option AL), JUMP to 47DEH to return error 20H in Register A.
4780
GOSUB to 475EH to stop any FDC command (Force Interrupt D0H) and wait until the FDC is idle.
4783
LD HL,4308H 21 08 43
Point Register Pair HL to 4308H, the current drive number.
4786
LD A,(HL) 7E
Fetch the old current drive number at Register Pair HL (4308H) into Register A.
4787
LD (HL),C 71
Store Register C (the new drive number) at Register Pair HL (4308H).
4788
CP C B9
Compare Register A (the old drive) against Register C (the new drive). The Z FLAG is set if it is the same drive.
4789
PUSH AF F5
Save Register Pair AF onto the stack: the Z FLAG (same drive) is tested at 47D2H.
478A
LD L,A 6F
Copy Register A (the old drive) into Register L: Register Pair HL = 4300H + the old drive (Register H is 43H).
478B
LD A,(37EDH) 3A ED 37
Read the FDC track register at 37EDH into Register A: the track the old drive's head is on.
478E
LD (HL),A 77
Store Register A (the old drive's track) at Register Pair HL (4300H + old drive).
478F
LD L,C 69
Copy Register C (the new drive) into Register L: Register Pair HL = 4300H + the new drive.
4790
PUSH HL E5
Save Register Pair HL (4300H + new drive) onto the stack, for 47BCH.
4791
LD B,C 41
Copy Register C (the new drive) into Register B.
4792
LD A,80H 3E 80
Load Register A with 80H; one rotate makes it 01H.
4794
INC B 04
INCrement Register B: the rotate loop runs drive + 1 times.

Make the Select Bit

4795
RLCA 07
Rotate Register A left: 80H becomes 01H on the first pass, then 02H, 04H, 08H.
4796
DECrement Register B and, if it is not 0, LOOP BACK to 4795H. Register A is now 01H, 02H, 04H or 08H for drive 0-3, and Register B = 0.
4798
LD (4309H),A 32 09 43
Store Register A (the select bit) at 4309H, the select latch value of the current drive.
479B
LD A,C 79
Load Register A with Register C, the drive number.
479C
RLCA 07
Rotate Register A left: the drive number x 2.
479D
RLCA 07
Rotate Register A left again: the drive number x 4.
479E
ADD A,C 81
ADD Register C (the drive number) to Register A: the drive number x 5.
479F
ADD A,A 87
ADD Register A to itself: the drive number x 10.
47A0
ADD A,71H C6 71
ADD 71H to Register A: the low byte of 4371H + 10 x drive.
47A2
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the drive's PDRIVE record in 4371H-4398H (Register H is 43H).
47A3
LD (4399H),HL 22 99 43
Store Register Pair HL (the drive's PDRIVE record) at 4399H.
47A6
LD C,08H 0E 08
Load Register C with 08H; with Register B = 0, Register Pair BC = 8 bytes to copy.
47A8
LD DE,430AH 11 0A 43
Point Register Pair DE to 430AH, the copy of the current drive's PDRIVE record.
47AB
LDIR ED B0
Copy 8 bytes from Register Pair HL (the PDRIVE record) to Register Pair DE (430AH-4311H), counting Register Pair BC down to 0.
47AD
LD HL,37ECH 21 EC 37
Point Register Pair HL to 37ECH, the FDC status register.
47B0
LD E,(HL) 5E
Fetch the FDC status at Register Pair HL into Register E: bit 7 (not ready) is set if the motors had stopped.
47B1
DI F3
Disable interrupts while the FDC is set up for the new drive.
47B2
LD A,(4311H) 3A 11 43
Load Register A with the disk I/O flags of the new drive from 4311H (bit 0 = double density).
47B5
OR FEH F6 FE
OR Register A with FEH: Register A becomes FEH for single density and FFH for double density.
47B7
LD (HL),A 77
Store Register A (FEH or FFH) into the FDC command register at Register Pair HL (37ECH): the density select of the double density adapters (not a 1771 command).
47B8
LD (HL),D0H 36 D0
Store D0H (Force Interrupt, no condition) into the FDC command register at Register Pair HL (37ECH).
47BA
EI FB
Enable interrupts again: the density byte and the Force Interrupt have both been written to 37ECH.
47BB
INC HL 23
INCrement Register Pair HL to 37EDH, the FDC track register.
47BC
POP BC C1
Restore Register Pair BC from the stack: 4300H + the new drive (pushed at 4790H).
47BD
LD A,(BC) 0A
Fetch the new drive's last track number from Register Pair BC (4300H + drive) into Register A.
47BE
LD (HL),A 77
Store Register A (the new drive's track) into the FDC track register at Register Pair HL (37EDH).
47BF
INC HL 23
INCrement Register Pair HL to 37EEH, the FDC sector register.
47C0
LD A,(4310H) 3A 10 43
Load Register A with byte +6 of the drive's PDRIVE record from 4310H (the drive select byte some interfaces read from the sector register).
47C3
LD (HL),A 77
Store Register A (the drive select byte) into the FDC sector register at Register Pair HL (37EEH).
47C4
GOSUB to 475EH to issue Force Interrupt D0H and wait until the FDC is idle.
47C7
GOSUB to 4759H to write the select latch from 4309H to 37E1H and wait while the FDC is busy.
47CA
LD B,80H 06 80
Load Register B with 80H, the motor start delay for 4CEDH (B x 256 passes, about half a second). Optional zap 004 changes it to FFH; it is not applied.
47CC
BIT 7,E CB 7B
Test bit 7 of Register E (the status read at 47B0H): not ready means the motors had stopped.
47CE
If the NZ FLAG is set (the motors were stopped), GOSUB to 4CEDH to wait Register B (80H) x 256 delay passes for them to come up to speed.
47D1
POP AF F1
Restore Register Pair AF from the stack: the Z FLAG from 4788H (the same drive as before).
47D2
If the Z FLAG is set (the same drive), JUMP to 47DDH: no head settle delay is needed.
47D4
LD A,(430CH) 3A 0C 43
A different drive: load Register A with its TSR byte from 430CH (PDRIVE byte +2, bit 7 = TI flag H).
47D7
RLCA 07
Rotate Register A left: bit 7 (TI flag H) goes into the CARRY FLAG.
47D8
LD B,0CH 06 0C
Load Register B with 0CH, the head settle delay for 4CEDH.
47DA
If the CARRY FLAG is set (TI flag H), GOSUB to 4CEDH to wait Register B (0CH) x 256 delay passes.
47DD
XOR A AF
Set Register A to 00H (success) and clear the flags; 47E1H sets the Z FLAG from it.
47DE
POP BC C1
Restore Register Pair BC from the stack (the caller's, saved at 4778H).
47DF
POP DE D1
Restore Register Pair DE from the stack (the caller's, saved at 4777H).
47E0
POP HL E1
Restore Register Pair HL from the stack (the caller's, saved at 4776H).
47E1
OR A B7
OR Register A with itself: the Z FLAG for 00H (success), the NZ FLAG for an error code (20H).
47E2
RET C9
RETurn with Register A = 00H and the Z FLAG, or Register A = 20H and the NZ FLAG.

47E3H - Short Delay and Read the Status

Waits a few microseconds (the controller needs time after a command before its status is valid), then reads the status. 47E8H only reads it.

47E3
LD A,06H 3E 06
Load Register A with the delay loop count. Self-Modifying Code
The operand at 47E4H is 6 x SYSTEM option BJ, stored at reset (4D9EH); the file has 06H.
47E5
DEC A 3D
DECrement Register A, the delay count. The Z FLAG is set when it reaches 0.
47E6
If the NZ FLAG is set (Register A has not reached 0), LOOP BACK to 47E5H.
47E8
LD A,(37ECH) 3A EC 37
Read the FDC status register at 37ECH into Register A. Reading it also clears the FDC's interrupt request (4055H calls here for that).
47EB
RET C9
RETurn to the caller with Register A = the FDC status read from 37ECH.

47ECH - Test for a Mounted Diskette

445EH comes here (manual 3.30). Selects the drive in Register A, then waits for the index pulse bit to change, which shows that a diskette is in the drive and turning. On exit the Z FLAG is set, or the NZ FLAG with error code 08H (DEVICE NOT AVAILABLE) or 20H.

47EC
GOSUB to 4776H to select the drive whose number is in Register A. It returns the Z FLAG, or the NZ FLAG with Register A = 20H for a drive number at or above option AL.
47EF
RET NZ C0
If the NZ FLAG is set (the drive number is too high), RETurn with Register A = 20H (ILLEGAL OR MISSING DRIVE #).
47F0
PUSH HL E5
Save Register Pair HL (the caller's) onto the stack; 47E0H restores it.
47F1
PUSH DE D5
Save Register Pair DE (the caller's) onto the stack; 47DFH restores it.
47F2
PUSH BC C5
Save Register Pair BC (the caller's) onto the stack; 47DEH restores it.
47F3
LD DE,0000H 11 00 00
Load Register Pair DE with the time-out count. Self-Modifying Code
The operand at 47F4H-47F5H is 2400H x SYSTEM option BJ, stored at reset (4DAAH); the file has 0000H.
47F6
LD HL,37ECH 21 EC 37
Point Register Pair HL to 37ECH, the FDC status register.
47F9
LD B,(HL) 46
Fetch the first FDC status at Register Pair HL (37ECH) into Register B, to compare the index bit against.

Index Pulse Loop
Register B = the first status, Register Pair DE = the time-out count.

47FA
LD A,(HL) 7E
Read the FDC status at Register Pair HL (37ECH) into Register A.
47FB
XOR B A8
XOR Register A with Register B (the first status): the bits set are those that have changed.
47FC
AND 02H E6 02
AND Register A with 02H, keeping bit 1, the index pulse (the hole in the diskette passing the sensor). The NZ FLAG is set if it changed.
47FE
If the NZ FLAG is set (the index bit changed, a diskette is turning), JUMP to 47DDH to clear Register A, restore the registers and return with the Z FLAG set.
4800
DEC DE 1B
DECrement Register Pair DE, the time-out count.
4801
LD A,D 7A
Load Register A with Register D, the high byte of the time-out count.
4802
OR E B3
OR Register E (the low byte) into Register A. The Z FLAG is set when Register Pair DE has reached 0000H.
4803
If the NZ FLAG is set (Register Pair DE is not 0), LOOP BACK to 47FAH to read the status again.
4805
LD A,08H 3E 08
The index bit never changed: load Register A with error code 08H (DEVICE NOT AVAILABLE).
4807
JUMP to 47DEH to restore Register Pairs BC, DE and HL and return the NZ FLAG with Register A = 08H.

4809H - Allocate, and Find the Sector for NEXT

444BH comes here (manual 3.26). The part from 4810H is used by every read and write: it turns the FCB's NEXT position into a sector number on the diskette. It looks through the extents kept in the FCB, then through the file's directory entries (FPDE and FXDEs), and when the sector lies past the file's last granule it calls SYS2 to allocate more (a read gets error 3EH instead). On exit Register Pair DE = the sector number, Register Pair HL = the FCB's buffer, Register A = 00H and the Z FLAG is set; errors leave through 49CDH.

4809
GOSUB to 4980H: the rest of this routine runs as a DOS function, with Index Register IX = the FCB (Register Pair DE on entry) and Index Register IY = 4380H; an error at any depth leaves through 49CDH.
480C
Entry used by the write routines (4A67H, 4A9BH). GOSUB to 49B7H: the file's access level (FCB+1 bits 0-2, Index Register IX) must be below 5 (writing allowed), else error 25H.
480F
XOR A AF
Set Register A to 00H: when NEXT is past the end of the file's space, more space is to be allocated.
4810
LD (48BBH),A 32 BB 48
Entry from the read routine (4A21H) with Register A = B6H. Store Register A at 48BBH, the offset of the JR at 48BAH: 00H lets the allocation at 48BCH run, B6H turns the JR into a jump to 4872H with error 3EH.

Search Loop
48E6H comes back here after copying a directory entry's extents into the FCB.

4813
GOSUB to 476EH to select the drive of the FCB, (IX+06H). Register A returns 20H with the NZ FLAG for a bad drive number.
4816
If the NZ FLAG is set (the drive cannot be selected, Register A = the error), JUMP to 4872H to leave the DOS function with it.
4818
GOSUB to 4968H: Register C = NEXT's low byte (the byte in the sector) and Register Pair HL = NEXT's middle and high bytes, the sector of the file (the flags from its EOF comparison are not used here).
481B
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the relative sector number from NEXT.
481C
LD A,(IX+00H) DD 7E 00
Fetch FCB+0 from (IX+00H) (Index Register IX = the FCB) into Register A: bit 1 = NEXT is a sector of the whole diskette, bit 2 = a bad FCB.
481F
RRCA 0F
Rotate Register A (FCB+0) right: bit 0 goes out.
4820
RRCA 0F
Rotate Register A right again: bit 1 of FCB+0 goes into the CARRY FLAG.
4821
If the CARRY FLAG is set (FCB+0 bit 1: NEXT is already a sector of the whole diskette, Register Pair DE), JUMP to 4853H to load Register Pair HL with the buffer and return.
4823
RRCA 0F
Rotate Register A right again: bit 2 of FCB+0 goes into the CARRY FLAG.
4824
LD A,2DH 3E 2D
Load Register A with error code 2DH (BAD FCB DATA). 487CH also jumps here with the CARRY FLAG set.
4826
If the CARRY FLAG is set (FCB+0 bit 2, or an FCB from an older NEWDOS/80 at 487CH), JUMP to 4872H to leave with Register A = 2DH.
4828
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the relative sector number.
4829
GOSUB to 4CB2H to divide Register Pair HL by 5: Register Pair HL = the granule within the file, Register A = the sector within the granule (0-4), Register B = 0.
482C
LD C,0EH 0E 0E
Load Register C with 0EH: with Register B = 0, Register Pair BC = 14, the offset of the FCB's first extent.
482E
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the granule within the file.
482F
PUSH IX DD E5
Save Index Register IX (the FCB address) onto the stack.
4831
POP HL E1
Restore it into Register Pair HL: Register Pair HL = the FCB.
4832
ADD HL,BC 09
ADD Register Pair BC (14) to Register Pair HL: Register Pair HL = FCB+14, the first of the extents kept in the FCB.
4833
PUSH AF F5
Save Register Pair AF onto the stack: Register A = the sector within the granule.
4834
PUSH HL E5
Save Register Pair HL (FCB+14) onto the stack.
4835
PUSH DE D5
Save Register Pair DE (the granule within the file) onto the stack.
4836
LD A,08H 3E 08
Load Register A with 08H, the number of extents kept in the FCB (FCB+14 to +21 and FCB+24 to +31).

FCB Extent Loop
Register Pair HL = the extent (2 bytes: the lump, then bits 5-7 first granule and bits 0-4 count minus 1), Register Pair DE = the granules still to go, AF' = extents left.

4838
EX AF,AF' 08
Exchange Register Pair AF with the alternate AF': the count of extents left is kept in Register A'.
4839
LD A,(HL) 7E
Fetch the extent's lump number at Register Pair HL into Register A (FFH = no more extents).
483A
INC A 3C
INCrement Register A (the lump). The Z FLAG is set if it was FFH.
483B
INC HL 23
INCrement Register Pair HL to the extent's second byte. INC HL does not change the flags.
483C
If the Z FLAG is set (the lump was FFH: no more extents in the FCB), JUMP to 4892H to look through the directory entries.
483E
LD A,(HL) 7E
Fetch the extent's second byte at Register Pair HL into Register A: bits 5-7 = the first granule in the lump, bits 0-4 = the number of granules minus 1.
483F
GOSUB to 48E9H, which subtracts the extent's granule count (Register Pair BC) from the granules to go (Register Pair DE): it returns Register Pair HL = the difference, Register Pair DE = the extent pointer, Register A = bits 0-4 of the second byte, and the CARRY FLAG set if the granule is in this extent.
4842
If the NO CARRY FLAG is set (the granule lies beyond this extent), JUMP to 4875H to try the next one.
4844
ADD HL,BC 09
ADD Register Pair BC (the extent's granule count) back to Register Pair HL: Register Pair HL = the granule's position within this extent.
4845
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the position in the extent, Register Pair HL = the extent's second byte.
4846
XOR (HL) AE
XOR Register A (bits 0-4 of the second byte) with the second byte at Register Pair HL: Register A keeps bits 5-7, the extent's first granule in the lump.
4847
RLCA 07
Rotate Register A left: bits 5-7 move towards bits 0-2 (three rotates in all).
4848
RLCA 07
Rotate Register A left again (second of three).
4849
RLCA 07
Rotate Register A left a third time: Register A = the extent's first granule in the lump (0-7).
484A
ADD A,E 83
ADD Register E (the position in the extent) to Register A: the granule within the lump.
484B
LD E,A 5F
Copy Register A (the granule within the lump) into Register E for 4C7CH.
484C
POP AF F1
Restore Register Pair AF from the stack to drop the granule within the file (pushed at 4835H).
484D
POP AF F1
Restore Register Pair AF from the stack again to drop FCB+14 (pushed at 4834H).
484E
POP AF F1
Restore Register Pair AF from the stack: Register A = the sector within the granule (pushed at 4833H).
484F
DEC HL 2B
DECrement Register Pair HL back to the extent's first byte, the lump number.
4850
GOSUB to 4C7CH with Register Pair HL = the lump byte, Register E = the granule within the lump and Register A = the sector in the granule: it returns Register Pair DE = (lump x granules per lump + Register E) x 5 + Register A, the sector on the diskette.
4853
LD L,(IX+03H) DD 6E 03
Load Register L with the low byte of the FCB's buffer address from (IX+03H) (Index Register IX = the FCB). 4B0BH and ASPOOL/MAS call this part too, and the display driver (4507H) uses it to fetch the cursor address from bytes 3-4 of a device control block.
4856
LD H,(IX+04H) DD 66 04
Load Register H with the high byte of the buffer address from (IX+04H) (Index Register IX = the FCB). Register Pair HL = the buffer (or the cursor address).
4859
XOR A AF
Set Register A to 00H and set the Z FLAG: success.
485A
RET C9
RETurn with Register Pair DE = the sector on the diskette, Register Pair HL = the buffer and the Z FLAG set.

FXDE Link
Reached from 48B6H when an entry's extent list ends in FEH: Register A = the DEC of the FXDE that continues the file, Register Pair DE = the granules still to go.

485B
POP BC C1
Restore Register Pair BC from the stack to drop the entry's extent pointer (pushed at 48ADH).
485C
POP BC C1
Restore Register Pair BC from the stack: the granules in the file before this entry (pushed at 48A8H).
485D
POP HL E1
Restore Register Pair HL from the stack: the granules to go when this entry was started (pushed at 48A7H).
485E
SBC HL,DE ED 52
SUBtract Register Pair DE (the granules still to go) from Register Pair HL (with the CARRY FLAG, clear after the CP FEH): Register Pair HL = the granules in this entry.
4860
ADD HL,BC 09
ADD Register Pair BC (the granules before this entry) to Register Pair HL: the granules before the next entry.
4861
LD B,H 44
Copy Register H into Register B: Register Pair BC = the granules before the next entry (high byte).
4862
LD C,L 4D
Copy Register L into Register C (the low byte).
4863
PUSH AF F5
Save Register Pair AF onto the stack: Register A = the DEC of the FXDE.
4864
GOSUB to 492FH to read the FXDE's directory sector (only if it is not already in 4200H): Register Pair HL returns the address of the FXDE.
4867
If the NZ FLAG is set (a read error or a bad entry, Register A = the error code), JUMP to 4872H to leave with it.
4869
LD A,FFH 3E FF
Load Register A with the DEC of the entry that pointed here. Self-Modifying Code
The operand at 486AH is stored by 48A0H for every entry looked at; SYS2's allocation (64H) also reads it as the DEC of the file's last entry.
486B
INC HL 23
INCrement Register Pair HL to the FXDE's byte 1, the DEC of the entry before it (the back link).
486C
CP (HL) BE
Compare Register A (the DEC of the entry that pointed here) against the back link at Register Pair HL. The Z FLAG is set if the chain is consistent.
486D
DEC HL 2B
DECrement Register Pair HL back to the FXDE's byte 0.
486E
If the Z FLAG is set (the back link matches), JUMP to 489FH to go on with this FXDE.
4870
LD A,2CH 3E 2C
Load Register A with error code 2CH (BAD DIRECTORY DATA). Also reached from 48A5H (an entry not in use) and 48C8H (a real extent in the fifth element).
4872
JUMP to 49CDH to leave the DOS function with the error code in Register A; 49CDH restores the Stack Pointer saved by 4980H.
4875
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the extent's second byte, Register Pair DE = the granules still to go (after this extent).
4876
INC HL 23
INCrement Register Pair HL to the next extent in the FCB.
4877
BIT 3,(IX+01H) DD CB 01 5E
Test bit 3 of FCB+1 at (IX+01H) (Index Register IX = the FCB): set when the FCB was opened by NEWDOS/80 version 2, which keeps the extents at FCB+22 and up.
487B
SCF 37
Set the CARRY FLAG, for the error path to 4824H. SCF does not change the Z FLAG.
487C
If the Z FLAG is set (FCB+1 bit 3 clear: an FCB without the second extent set), JUMP to 4824H to leave with error 2DH (the CARRY FLAG is set).
487E
EX AF,AF' 08
Exchange Register Pair AF with the alternate AF': Register A = the extents left.
487F
CP 05H FE 05
Compare Register A (the extents left) against 05H. The Z FLAG is set after the first four extents (FCB+14 to +21).
4881
If the NZ FLAG is set (not at the end of the first four), JUMP to 488FH to count this extent.
4883
LD C,(HL) 4E
Load Register C with the low byte of FCB+22 at Register Pair HL: the number of granules in the file before the extents kept at FCB+24.
4884
INC HL 23
INCrement Register Pair HL to FCB+23, the high byte of the granules before the second extent set.
4885
LD B,(HL) 46
Load Register B with the high byte at Register Pair HL (FCB+23). Register Pair BC = the granules before the second set of extents.
4886
INC HL 23
INCrement Register Pair HL to FCB+24, the first extent of the second set.
4887
POP DE D1
Restore Register Pair DE from the stack: the granule within the file (pushed at 4835H).
4888
PUSH DE D5
Save Register Pair DE back onto the stack; it is needed again at 4895H.
4889
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the granule within the file, Register Pair DE = FCB+24.
488A
SBC HL,BC ED 42
SUBtract Register Pair BC (the granules before the second set) from Register Pair HL (the CARRY FLAG is clear after the CP). The CARRY FLAG is set if the granule lies before them.
488C
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the granule relative to the second set, Register Pair HL = FCB+24.
488D
If the CARRY FLAG is set (the granule is in a directory entry between the two sets), JUMP to 4892H to look through the directory.
488F
DEC A 3D
DECrement Register A, the count of FCB extents still to look at.
4890
If the NZ FLAG is set (Register A is not 0, extents are left), LOOP BACK to 4838H for the next extent at Register Pair HL.

Directory Entry Search
The granule is not in the FCB's extents: walk the FPDE and its FXDEs. Register Pair BC = the granules before the entry, Register Pair DE = the granules to go.

4892
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H: no granules lie before the FPDE.
4895
POP DE D1
Restore Register Pair DE from the stack: the granule within the file (pushed at 4835H), the granules still to go.
4896
GOSUB to 494BH to read the file's FPDE (the FCB's DEC) and check that it is an FPDE in use belonging to this FCB. Register Pair HL returns the entry.
4899
If the NZ FLAG is set (Register A = the error), JUMP to 4867H, which goes on to 4872H to leave with it.
489B
LD A,(IX+07H) DD 7E 07
Load Register A with the FCB's DEC from (IX+07H) (Index Register IX = the FCB), the DEC of the FPDE.
489E
PUSH AF F5
Save Register Pair AF (Register A = the FPDE's DEC) onto the stack, so that 489FH finds it as it finds an FXDE's DEC from 4863H.
489F
POP AF F1
Restore Register Pair AF from the stack: Register A = the DEC of the entry about to be looked at (the FPDE, or the FXDE from 4863H).
48A0
LD (486AH),A 32 6A 48
Store Register A (the entry's DEC) at 486AH, the operand of 4869H: the next FXDE's back link must name it, and SYS2 takes it as the last entry when it allocates.

Entry Loop
Register Pair HL = the directory entry in 4200H.

48A3
BIT 4,(HL) CB 66
Test bit 4 of the entry's byte 0 at Register Pair HL (in use). The Z FLAG is set if the entry is free.
48A5
If the Z FLAG is set (the entry is not in use), JUMP to 4870H to leave with error 2CH.
48A7
PUSH DE D5
Save Register Pair DE (the granules to go at the start of this entry) onto the stack.
48A8
PUSH BC C5
Save Register Pair BC (the granules before this entry) onto the stack.
48A9
LD A,L 7D
Load Register A with Register L, the low byte of the entry's address.
48AA
ADD A,16H C6 16
ADD 16H (22) to Register A: the offset of the entry's first extent element.
48AC
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the entry's first extent element.
48AD
PUSH HL E5
Save Register Pair HL (the entry's extent elements) onto the stack.

Element Loop

48AE
LD A,(HL) 7E
Fetch the element's first byte at Register Pair HL into Register A: a lump number, FEH (an FXDE follows) or FFH (the end).
48AF
CP FEH FE FE
Compare Register A against FEH. The CARRY FLAG is set for a lump number, the Z FLAG for FEH.
48B1
INC HL 23
INCrement Register Pair HL to the element's second byte. INC HL does not change the flags.
48B2
LD A,(HL) 7E
Fetch the second byte at Register Pair HL into Register A: the granule bits, or the FXDE's DEC after FEH.
48B3
INC HL 23
INCrement Register Pair HL to the next element.
48B4
If the CARRY FLAG is set (a real extent, Register A = its second byte), JUMP to 48C6H.
48B6
If the Z FLAG is set (FEH: Register A = the DEC of the FXDE that continues the file), JUMP to 485BH.
48B8
LD A,3EH 3E 3E
FFH, the end of the file's elements: the granule is past the file's last granule. Load Register A with error code 3EH (CAN'T EXTEND FILE VIA READ).
48BA
JUMP to 48BCH to allocate. Self-Modifying Code
The offset at 48BBH is stored by 4810H: 00H here, or B6H for a read, which makes it a jump to 4872H to leave with Register A = 3EH.
48BC
POP AF F1
Restore Register Pair AF from the stack to drop the entry's extent pointer (pushed at 48ADH).
48BD
LD A,64H 3E 64
Load Register A with 64H, the RST 28H code of SYS2 function 3: allocate granules to the file. SYS2 takes Register Pair DE = the granules missing minus 1 and 486AH = the DEC of the file's last entry.
48BF
GOSUB to 49DDH to call SYS2 with Register A = 64H. SYS2 returns Register Pair HL = the last entry again (with its new extents), or leaves through 49CDH with an error.
48C2
POP BC C1
Restore Register Pair BC from the stack: the granules before this entry (pushed at 48A8H).
48C3
POP DE D1
Restore Register Pair DE from the stack: the granules to go at the start of this entry (pushed at 48A7H).
48C4
JUMP to 48A3H to look through the entry at Register Pair HL again, now with the new granules.
48C6
BIT 4,L CB 65
A real extent: test bit 4 of Register L. Register Pair HL now points past the element; bit 4 is clear only when it has gone past byte 31, so this element was the fifth (bytes 30-31), which may only hold FEH or FFH.
48C8
If the Z FLAG is set (a real extent in the fifth element), JUMP to 4870H to leave with error 2CH.
48CA
GOSUB to 48E9H with Register A = the element's second byte: subtract its granule count from the granules to go in Register Pair DE. Register Pair HL returns the difference and Register Pair DE the element pointer.
48CD
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the granules still to go, Register Pair HL = the next element.
48CE
If the NO CARRY FLAG is set (the granule lies beyond this element), LOOP BACK to 48AEH for the next element at Register Pair HL.
48D0
POP BC C1
Found in this entry. Restore Register Pair BC from the stack: the entry's first extent element (pushed at 48ADH).
48D1
POP DE D1
Restore Register Pair DE from the stack: the granules before this entry (pushed at 48A8H as Register Pair BC).
48D2
POP AF F1
Restore Register Pair AF from the stack to drop the granules to go (pushed at 48A7H).
48D3
POP HL E1
Restore Register Pair HL from the stack: FCB+14 (pushed at 4834H).
48D4
POP AF F1
Restore Register Pair AF from the stack to drop the sector within the granule (pushed at 4833H); the search is redone from 4813H.
48D5
PUSH BC C5
Save Register Pair BC (the entry's extent elements) onto the stack.
48D6
LD BC,0008H 01 08 00
Load Register Pair BC with 0008H: four elements of two bytes are copied into the FCB.
48D9
LD A,D 7A
Load Register A with Register D, the high byte of the granules before this entry.
48DA
OR E B3
OR Register E (the low byte) into Register A. The Z FLAG is set if no granules lie before the entry, so it is the FPDE.
48DB
If the Z FLAG is set (the FPDE), JUMP to 48E2H to copy its elements to FCB+14 (Register Pair HL).
48DD
ADD HL,BC 09
ADD Register Pair BC (8) to Register Pair HL: Register Pair HL = FCB+22.
48DE
LD (HL),E 73
Store Register E (the low byte of the granules before this entry) at Register Pair HL (FCB+22).
48DF
INC HL 23
INCrement Register Pair HL to FCB+23, for the high byte of the count.
48E0
LD (HL),D 72
Store Register D (the high byte of the granules before this entry) at Register Pair HL (FCB+23).
48E1
INC HL 23
INCrement Register Pair HL to FCB+24, where the FXDE's elements go.
48E2
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the destination in the FCB (FCB+14 or FCB+24).
48E3
POP HL E1
Restore Register Pair HL from the stack: the entry's extent elements (pushed at 48D5H).
48E4
LDIR ED B0
Copy Register Pair BC (8) bytes from Register Pair HL (the entry's elements) to Register Pair DE (the FCB).
48E6
JUMP to 4813H to look for the granule again, now in the FCB's extents.

48E9H - Subtract an Extent's Granule Count

Entered with Register A = the extent's second byte, Register Pair DE = the granules to go and Register Pair HL = the extent pointer. Returns Register Pair BC = the extent's granule count, Register Pair HL = the granules to go minus that count, Register Pair DE = the extent pointer, and the CARRY FLAG set if the granule lies in this extent.

48E9
AND 1FH E6 1F
AND Register A (the extent's second byte) with 1FH, keeping bits 0-4, the number of granules minus 1. This also clears the CARRY FLAG for the SBC below.
48EB
LD C,A 4F
Copy Register A (the count minus 1) into Register C.
48EC
LD B,00H 06 00
Load Register B with 00H: Register Pair BC = the count minus 1.
48EE
INC BC 03
INCrement Register Pair BC: the extent's granule count (1-32).
48EF
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the granules to go, Register Pair DE = the extent pointer.
48F0
SBC HL,BC ED 42
SUBtract Register Pair BC (the extent's granule count) from Register Pair HL (the granules to go). The CARRY FLAG is set if the granule lies inside this extent.
48F2
RET C9
RETurn with Register Pair HL = the difference and the CARRY FLAG set for a granule in this extent.

48F3H - Read a Directory Sector

Enter at 490AH to read directory sector A (0 = GAT, 1 = HIT, 2 and up = FDE sectors) of the current drive into 4200H, or at 48FDH for one attempt. Directory sectors carry the directory mark, so a good read returns controller error 06H; a sector without it gives error 31H (WRONG DISKETTE RECORD TYPE). If the read fails, the boot sector is read to find where the directory is (byte 2, the directory's lump), the drive's PDRIVE record is updated and the read is tried again. On exit the Z FLAG is set, or the NZ FLAG with error 11H (DIRECTORY READ ERROR). Register Pairs DE and BC are preserved.

48F3
LD A,(4202H) 3A 02 42
Fetch byte 2 of the boot sector now in the buffer, at 4202H, into Register A: the lump where the directory starts (DDSL).
48F6
LD HL,(4399H) 2A 99 43
Load Register Pair HL with the address of the current drive's PDRIVE record from 4399H.
48F9
LD (HL),A 77
Store Register A (the directory lump from the boot sector) at Register Pair HL: byte 0 of the drive's PDRIVE record in 4371H-4398H.
48FA
LD A,(4930H) 3A 30 49
Load Register A with the directory sector wanted from 4930H (stored by 4C74H on the first attempt).
48FD
GOSUB to 4C74H with Register A = the directory sector: it stores Register A at 4930H and returns Register Pair DE = its sector number on the diskette and Register Pair HL = 4200H.
4900
GOSUB to 4630H to read sector Register Pair DE into the buffer at Register Pair HL (4200H). Register A returns the error code with the NZ FLAG, or 00H with the Z FLAG.
4903
If the NZ FLAG is set (an error code in Register A), JUMP to 4907H to see whether it is the directory mark. 4AD4H also jumps here after a verify read.
4905
OR 31H F6 31
The read had no error, so the sector has no directory mark: OR 31H into Register A (00H), giving error 31H (WRONG DISKETTE RECORD TYPE) and the NZ FLAG.
4907
CP 06H FE 06
Compare Register A (the error code) against 06H, the error a read returns for a sector with the directory mark. The Z FLAG is set for a good directory read.
4909
RET C9
RETurn: the Z FLAG for a directory sector read correctly, or the NZ FLAG with Register A = the error code.
490A
PUSH DE D5
Save Register Pair DE (the caller's) onto the stack.
490B
PUSH BC C5
Save Register Pair BC (the caller's) onto the stack.
490C
GOSUB to 48FDH to read directory sector Register A into 4200H.
490F
If the Z FLAG is set (the directory sector was read), JUMP to 491CH to restore the registers and return.
4911
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, sector 0 of the diskette: the boot sector. 4F02H also jumps here.
4914
GOSUB to 4630H to read the boot sector into the buffer at Register Pair HL (4200H, from 4C74H).
4917
If the Z FLAG is set (the boot sector was read), GOSUB to 48F3H to take the directory's lump from its byte 2 into the PDRIVE record and read the directory sector (4930H) again.
491A
LD A,11H 3E 11
Load Register A with error code 11H (DIRECTORY READ ERROR). LD does not change the flags: the Z FLAG from 4917H's read means success and the code is ignored.
491C
POP BC C1
Restore Register Pair BC from the stack (saved at 490BH or 4923H).
491D
POP DE D1
Restore Register Pair DE from the stack (saved at 490AH or 4922H).
491E
RET C9
RETurn: the Z FLAG for success, or the NZ FLAG with Register A = 11H (or 12H from 492BH).

491FH - Write a Directory Sector

Enter at 491FH to write back the directory sector now in 4200H, or at 4922H with its number in Register A. The sector is written with the directory mark and the verify read. On exit the Z FLAG is set, or the NZ FLAG with error 12H (DIRECTORY WRITE ERROR).

491F
LD A,(4930H) 3A 30 49
Load Register A with the number of the directory sector now in 4200H, from 4930H.
4922
PUSH DE D5
Save Register Pair DE (the caller's) onto the stack.
4923
PUSH BC C5
Save Register Pair BC (the caller's) onto the stack.
4924
GOSUB to 4C74H with Register A = the directory sector: Register Pair DE = its sector number, Register Pair HL = 4200H.
4927
OR H B4
OR Register H (42H) into Register A: the NZ FLAG is set, which tells 4AB8H to write with the directory mark.
4928
GOSUB to 4AB8H to write the buffer at Register Pair HL (4200H) to sector Register Pair DE with the directory mark, verify it, and retry as option AW allows.
492B
LD A,12H 3E 12
Load Register A with error code 12H (DIRECTORY WRITE ERROR). LD does not change the flags of the write.
492D
JUMP to 491CH to restore Register Pairs BC and DE and return.

492FH - Read the Directory Sector of an Entry

Register A holds a DEC (bits 0-4 the FDE sector minus 2, bits 5-7 the entry in the sector). 492FH reads the sector only if it is not already in 4200H, 4936H always reads it, 4933H always reads the sector of the FCB's DEC (FCB+7). On exit Register Pair HL points to the entry, Register A = its offset in the sector, and the Z FLAG is set.

492F
LD L,FFH 2E FF
Load Register L with the number of the directory sector now in 4200H. Self-Modifying Code
The operand at 4930H is stored by 4C74H every time a directory sector is read or written; FFH for none.
4931
JUMP to 4938H with Register L = the sector in 4200H.
4933
LD A,(IX+07H) DD 7E 07
Load Register A with the FCB's DEC from (IX+07H), byte +7 of the FCB at Index Register IX.
4936
LD L,FFH 2E FF
Load Register L with FFH, a sector number that never matches, so the sector is always read.
4938
PUSH AF F5
Save Register Pair AF (Register A = the DEC) onto the stack.
4939
AND 1FH E6 1F
AND Register A (the DEC) with 1FH, keeping bits 0-4: the FDE sector minus 2.
493B
INC A 3C
INCrement Register A (the FDE sector minus 2) by 1.
493C
INC A 3C
INCrement Register A again: Register A = the directory sector (2 and up).
493D
CP L BD
Compare Register A (the directory sector wanted) against Register L (the sector in 4200H). The Z FLAG is set if it is already there.
493E
If the NZ FLAG is set (not in the buffer), GOSUB to 490AH to read directory sector Register A into 4200H.
4941
POP HL E1
Restore Register Pair HL from the stack: Register H = the DEC (pushed as Register A at 4938H). POP does not change the flags.
4942
RET NZ C0
If the NZ FLAG is set (the read failed, Register A = 11H), RETurn with the error.
4943
LD A,E0H 3E E0
Load Register A with E0H, the mask for bits 5-7 of the DEC.
4945
AND H A4
AND Register H (the DEC) into Register A: bits 5-7 = the entry number x 32, which is the entry's offset in the sector.
4946
LD L,A 6F
Copy Register A (the entry's offset) into Register L.
4947
LD H,42H 26 42
Load Register H with 42H: Register Pair HL = 4200H + the offset, the directory entry.
4949
CP A BF
Compare Register A with itself to set the Z FLAG (success).
494A
RET C9
RETurn with Register Pair HL = the entry, Register A = its offset in the sector and the Z FLAG set.

494BH - Read the FPDE of an Open FCB

Selects the FCB's drive and reads the directory entry of FCB+7. The entry must still belong to the file: it must be an FPDE in use, and its first extent must match the FCB's (unless the FCB has none yet). On exit Register Pair HL points to the entry and the Z FLAG is set, or the NZ FLAG with Register A = the error (2DH BAD FCB DATA).

494B
GOSUB to 476EH to select the drive of the FCB at Index Register IX, (IX+06H).
494E
If the Z FLAG is set (the drive is selected), GOSUB to 4933H to read the directory sector of the FCB's DEC: Register Pair HL = the entry, Register A = its offset in the sector.
4951
RET NZ C0
If the NZ FLAG is set (Register A = the error from the select or the read), RETurn with it.
4952
PUSH HL E5
Save Register Pair HL (the entry) onto the stack.
4953
ADD A,16H C6 16
ADD 16H (22) to Register A (the entry's offset): the offset of its first extent element.
4955
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the entry's first extent element.
4956
LD A,(IX+0EH) DD 7E 0E
Load Register A with the lump of the FCB's first extent from (IX+0EH) (Index Register IX = the FCB), FCB+14.
4959
CP (HL) BE
Compare Register A (the FCB's first lump) against the entry's first lump at Register Pair HL. The Z FLAG is set if they agree.
495A
POP HL E1
Restore Register Pair HL from the stack: the entry. POP does not change the flags.
495B
If the Z FLAG is set (the first extents agree), JUMP to 4960H to check the entry's flags.
495D
INC A 3C
INCrement Register A (the FCB's first lump). The Z FLAG is set if it was FFH, an FCB that has no extent yet.
495E
If the NZ FLAG is set (the FCB has an extent that the entry does not have), JUMP to 4965H to return error 2DH.
4960
LD A,(HL) 7E
Fetch the entry's flag byte (byte 0) at Register Pair HL into Register A.
4961
AND 90H E6 90
AND Register A with 90H, keeping bit 7 (FXDE) and bit 4 (in use).
4963
CP 10H FE 10
Compare Register A against 10H. The Z FLAG is set only for an FPDE in use.
4965
LD A,2DH 3E 2D
Load Register A with error code 2DH (BAD FCB DATA). LD does not change the flags.
4967
RET C9
RETurn: the Z FLAG with Register Pair HL = the FPDE, or the NZ FLAG with Register A = 2DH.

4968H - Compare NEXT with EOF

Loads Register C with NEXT's low byte and Register Pair HL with NEXT's middle and high bytes, and compares NEXT with EOF, highest byte first. The CARRY FLAG is set if NEXT is below EOF and the Z FLAG if they are equal.

4968
LD C,(IX+05H) DD 4E 05
Load Register C with NEXT's low byte from (IX+05H) (Index Register IX = the FCB), FCB+5 (the byte position in the sector).
496B
LD L,(IX+0AH) DD 6E 0A
Load Register L with NEXT's middle byte from (IX+0AH) (Index Register IX = the FCB), FCB+10.
496E
LD H,(IX+0BH) DD 66 0B
Load Register H with NEXT's high byte from (IX+0BH) (Index Register IX = the FCB), FCB+11. Register Pair HL = the sector of the file NEXT is in.
4971
LD A,H 7C
Load Register A with Register H, NEXT's high byte.
4972
CP (IX+0DH) DD BE 0D
Compare Register A (NEXT high) against EOF's high byte at (IX+0DH) (Index Register IX = the FCB), FCB+13. The CARRY FLAG is set if NEXT is lower.
4975
RET NZ C0
If the NZ FLAG is set (the high bytes differ), RETurn: the CARRY FLAG already gives the answer.
4976
LD A,L 7D
Load Register A with Register L, NEXT's middle byte.
4977
CP (IX+0CH) DD BE 0C
Compare Register A (NEXT middle) against EOF's middle byte at (IX+0CH) (Index Register IX = the FCB), FCB+12.
497A
RET NZ C0
If the NZ FLAG is set (the middle bytes differ), RETurn with the CARRY FLAG giving the answer.
497B
LD A,C 79
Load Register A with Register C, NEXT's low byte.
497C
CP (IX+08H) DD BE 08
Compare Register A (NEXT low) against EOF's low byte at (IX+08H) (Index Register IX = the FCB), FCB+8.
497F
RET C9
RETurn: the CARRY FLAG if NEXT is below EOF, the Z FLAG if NEXT equals EOF.

4980H - Run the Rest of a Routine as a DOS Function

Every FCB routine starts with CALL 4980H, Register Pair DE pointing to the FCB. If the FCB is not open, the routine returns at once with error 26H (FILE NOT OPEN). Otherwise the code after the CALL runs as a subroutine with Index Register IX = the FCB and Index Register IY = 4380H, and the Stack Pointer is saved at 49CEH so that any error can leave through 49CDH from any depth. On return Register A and the flags hold the result, Register Pairs BC, DE, HL, AF', IX and IY are as they were on entry, and the return goes to the caller of the routine.

4980
LD A,(DE) 1A
Fetch FCB+0 from the FCB at Register Pair DE into Register A (bit 7 = the file is open).
4981
RLCA 07
Rotate Register A (FCB+0) left: bit 7 (open) goes into the CARRY FLAG.
4982
LD A,26H 3E 26
Load Register A with error code 26H (FILE NOT OPEN). LD does not change the CARRY FLAG.
4984
If the NO CARRY FLAG is set (the FCB is not open), JUMP to 4987H with Register A = 26H.
4986
XOR A AF
The FCB is open: set Register A to 00H, the go-ahead kept in AF' below.
4987
EX AF,AF' 08
Exchange Register Pair AF with the alternate AF': AF' now keeps 00H or 26H, and Register Pair AF holds the caller's AF' (saved at 4992H and restored at the end).
4988
EX (SP),HL E3
Exchange Register Pair HL with the word on top of the stack (the Stack Pointer points to it): Register Pair HL = the return address of the CALL 4980H, the code to run; the stack now holds the caller's HL.
4989
LD (49A6H),HL 22 A6 49
Store Register Pair HL (the address of the code after the CALL 4980H) at 49A6H, the operand of the CALL Z at 49A5H.
498C
POP HL E1
Restore Register Pair HL from the stack: the caller's HL. The top of the stack is now the return address into the caller of the routine.
498D
PUSH IY FD E5
Save Index Register IY (the caller's) onto the stack.
498F
PUSH HL E5
Save Register Pair HL (the caller's) onto the stack.
4990
PUSH DE D5
Save Register Pair DE (the FCB address) onto the stack.
4991
PUSH BC C5
Save Register Pair BC (the caller's) onto the stack.
4992
PUSH AF F5
Save Register Pair AF (the caller's AF', from 4987H) onto the stack.
4993
PUSH DE D5
Save Register Pair DE (the FCB address) onto the stack once more, for the exchange with IX.
4994
EX (SP),IX DD E3
Exchange Index Register IX with the word on top of the stack (the Stack Pointer's target): Index Register IX = the FCB, and the caller's IX is saved there.
4996
PUSH HL E5
Save Register Pair HL (the caller's) onto the stack for a moment.
4997
LD HL,(49CEH) 2A CE 49
Load Register Pair HL with the Stack Pointer saved at 49CEH by an outer DOS function (a DOS function can call another), to be kept on the stack.
499A
EX (SP),HL E3
Exchange Register Pair HL with the word on top of the stack (the Stack Pointer's target): the outer saved Stack Pointer goes onto the stack and Register Pair HL is the caller's HL again.
499B
LD (49CEH),SP ED 73 CE 49
Store the Stack Pointer at 49CEH, the operand of the LD SP at 49CDH: an error exit restores this stack level, where the outer saved Stack Pointer lies.
499F
LD IY,4380H FD 21 80 43
Load Index Register IY with 4380H, the base the DOS functions use for IY+d addressing of the variables around 4380H.
49A3
EX AF,AF' 08
Exchange Register Pair AF with the alternate AF': Register A = 00H (open) or 26H (not open).
49A4
OR A B7
OR Register A with itself. The Z FLAG is set if the FCB is open; the CARRY FLAG is cleared.
49A5
If the Z FLAG is set (the FCB is open), GOSUB to the code after the CALL 4980H (0000H in the file). Self-Modifying Code
The address at 49A6H-49A7H is stored by 4989H. The code runs with Register Pairs BC, DE and HL as the caller passed them and returns its result in Register A and the flags.
49A8
POP HL E1
Restore Register Pair HL from the stack: the outer DOS function's saved Stack Pointer (pushed at 499AH). 49D1H comes here after an error, with the Stack Pointer reset to this level.
49A9
LD (49CEH),HL 22 CE 49
Store Register Pair HL back at 49CEH, so that an error in the outer DOS function still finds its own level.
49AC
EX AF,AF' 08
Exchange Register Pair AF with the alternate AF': the result (Register A and the flags) is kept in AF'.
49AD
POP IX DD E1
Restore Index Register IX from the stack: the caller's IX (saved at 4994H).
49AF
POP AF F1
Restore Register Pair AF from the stack: the caller's AF' (pushed at 4992H).
49B0
POP BC C1
Restore Register Pair BC from the stack: the caller's BC.
49B1
POP DE D1
Restore Register Pair DE from the stack: the FCB address the caller passed.
49B2
POP HL E1
Restore Register Pair HL from the stack: the caller's HL.
49B3
POP IY FD E1
Restore Index Register IY from the stack: the caller's IY.
49B5
EX AF,AF' 08
Exchange Register Pair AF with the alternate AF': Register A and the flags = the result, and AF' = the caller's AF' again.
49B6
RET C9
RETurn to the caller of the routine that did CALL 4980H, with Register A = 00H and the Z FLAG, or the error code with the NZ FLAG.

49B7H - Check the Access Level

The access level (FCB+1 bits 0-2) must be below Register B: 5 for a write (entry 49B7H), 6 for a read (entry 49B9H with Register B = 6). Otherwise the DOS function ends with error 25H (ILLEGAL ACCESS TRIED TO PROTECTED FILE). 49C4H checks NEXT against EOF.

49B7
LD B,05H 06 05
Load Register B with 05H: writing needs an access level below 5 (FULL, KILL, RENAME or WRITE).
49B9
LD A,(IX+01H) DD 7E 01
Fetch FCB+1 from (IX+01H) (Index Register IX = the FCB) into Register A; bits 0-2 are the access level the file was opened with.
49BC
AND 07H E6 07
AND Register A with 07H, keeping the access level (0 FULL, 1 KILL, 2 RENAME, 4 WRITE, 5 READ, 6 EXEC, 7 LOCK).
49BE
CP B B8
Compare Register A (the access level) against Register B (5 or 6). The CARRY FLAG is set if it is lower, so the access is allowed.
49BF
RET C D8
If the CARRY FLAG is set (allowed), RETurn to the read or write routine.
49C0
LD A,25H 3E 25
Load Register A with error code 25H (ILLEGAL ACCESS TRIED TO PROTECTED FILE).
49C2
JUMP to 49CDH to leave the DOS function with Register A = 25H.
49C4
GOSUB to 4968H to compare NEXT with EOF in the FCB at Index Register IX: the CARRY FLAG if NEXT is below EOF, the Z FLAG if equal.
49C7
RET C D8
If the CARRY FLAG is set (NEXT is below EOF), RETurn: the position can be read.
49C8
LD A,1CH 3E 1C
Load Register A with error code 1CH (END OF FILE ENCOUNTERED). LD does not change the flags.
49CA
If the Z FLAG is set (NEXT equals EOF), JUMP to 49CDH to leave with Register A = 1CH.
49CC
INC A 3C
NEXT is past EOF: INCrement Register A to 1DH (PAST END OF FILE) and fall into 49CDH.

49CDH - Leave a DOS Function with an Error

Register A holds the error code. The Stack Pointer saved by 4980H is restored, which throws away everything the function pushed, and the function returns to its caller with the NZ FLAG set. SYS2 and SYS3 jump here too. 49D3H-49DDH serve the overlays that call another overlay and come back.

49CD
LD SP,0000H 31 00 00
Load the Stack Pointer with the value saved by 4980H. Self-Modifying Code
The operand at 49CEH-49CFH is stored by 499BH (and put back by 49A9H); the file has 0000H.
49D0
OR A B7
OR Register A (the error code, not 0) with itself to set the NZ FLAG.
49D1
JUMP to 49A8H to restore the registers and return from the DOS function with Register A = the error code.
49D3
If the NZ FLAG is set, JUMP to 4409H to leave through the DOS error exit with Register A = the error. 49D3H is a return address: SYS1, SYS7, SYS9 and SYS14 push a word holding an RST 28H code (high byte) and a sub-function (low byte), then 49D3H, and jump to a function; when it returns here without an error, the word on the stack names the function to run next.
49D6
XOR A AF
Set Register A to 00H and set the Z FLAG. 49D6H is the return address for callers that do not want the error test (SYS1).
49D7
If the NZ FLAG is set, JUMP to 49CDH to leave the current DOS function with Register A = the error. 49D7H is the return address used inside a DOS function (SYS3 after 4A62H).
49D9
EX (SP),HL E3
Exchange Register Pair HL with the word on top of the stack (the Stack Pointer's target): Register Pair HL = the word pushed by the overlay (RST 28H code and sub-function), and the caller's HL is put in its place.
49DA
LD A,H 7C
Load Register A with Register H, the RST 28H code of the function to run next.
49DB
LD C,L 4D
Load Register C with Register L, its sub-function.
49DC
POP HL E1
Restore Register Pair HL from the stack: the caller's HL. The word is gone from the stack.
49DD
RST 28H EF
RST 28H with Register A = the function code and Register C = the sub-function: call the overlay function through the dispatcher at 4BC2H. Because the dispatcher throws away the RST's return address, CALL 49DDH works as a call of an overlay function that returns to the caller; SYS0 (451FH, 48BFH), SYS6 and SYS9 use it that way.

49DEH - Move a Logical Record

Called at the start of the READ (with the CARRY FLAG set) and WRITE (CARRY FLAG clear) routines. In sector mode (FCB+1 bit 7 clear) it returns at once. In record mode it replaces the rest of the routine: LRL bytes (0 = 256) are moved one by one between the caller's buffer at Register Pair HL and the file, through the byte routine at 4AEDH, and the DOS function returns from here.

49DE
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of FCB+1 at (IX+01H) (Index Register IX = the FCB): record mode. The Z FLAG is set in sector mode. BIT does not change the CARRY FLAG (read or write).
49E2
RET Z C8
If the Z FLAG is set (sector mode), RETurn to the READ or WRITE routine.
49E3
POP DE D1
Restore Register Pair DE from the stack to drop the return address into the READ or WRITE routine: the record loop below returns from the DOS function itself (to 49A8H).
49E4
LD B,(IX+09H) DD 46 09
Load Register B with the logical record length from (IX+09H) (Index Register IX = the FCB), FCB+9 (00H = 256 bytes through the DJNZ).

Record Loop
Register Pair HL = the caller's record buffer, Register B = bytes left, the CARRY FLAG (in Register Pair AF) = read.

49E7
PUSH AF F5
Save Register Pair AF onto the stack: the CARRY FLAG says read (set) or write (clear).
49E8
PUSH HL E5
Save Register Pair HL (the position in the caller's record buffer) onto the stack.
49E9
PUSH BC C5
Save Register Pair BC (Register B = bytes left) onto the stack.
49EA
LD C,(HL) 4E
Load Register C with the byte at Register Pair HL in the caller's buffer, the byte to write (ignored when reading).
49EB
GOSUB to 4AEDH to read a byte from the file into Register A (CARRY FLAG set) or write Register C to it (CARRY FLAG clear).
49EE
If the NZ FLAG is set (an error, Register A = the code), JUMP to 49CDH to leave the DOS function with it.
49F0
LD E,A 5F
Copy Register A (the byte read) into Register E.
49F1
POP BC C1
Restore Register Pair BC from the stack: Register B = bytes left.
49F2
POP HL E1
Restore Register Pair HL from the stack: the position in the caller's buffer.
49F3
POP AF F1
Restore Register Pair AF from the stack: the CARRY FLAG = read or write.
49F4
If the NO CARRY FLAG is set (writing), JUMP to 49F7H: nothing to store.
49F6
LD (HL),E 73
Reading: store Register E (the byte read) in the caller's buffer at Register Pair HL.
49F7
INC HL 23
INCrement Register Pair HL to the next byte of the caller's buffer.
49F8
DECrement Register B (bytes left) and, if it is not 0, LOOP BACK to 49E7H.
49FA
XOR A AF
The record is done: set Register A to 00H and the Z FLAG.
49FB
RET C9
RETurn from the DOS function (to 49A8H) with Register A = 00H, success.

49FCH - READ

4436H comes here (manual 3.19). In sector mode the sector at NEXT is read into the FCB's buffer and NEXT is advanced by 256, also after error 06H (the sector has the directory mark), which is still returned.

49FC
GOSUB to 4980H: the rest runs as a DOS function with Index Register IX = the FCB at Register Pair DE.
49FF
SCF 37
Set the CARRY FLAG: this is a read, for 49DEH.
4A00
GOSUB to 49DEH: in record mode it reads LRL bytes into the buffer at Register Pair HL and returns from the DOS function; in sector mode it returns here.
4A03
GOSUB to 4A19H to read the sector at NEXT into the FCB's buffer. Register A returns the error code, the Z FLAG for success.
4A06
If the Z FLAG is set (read without error), JUMP to 4A0BH to advance NEXT.
4A08
CP 06H FE 06
Compare Register A (the error code) against 06H, the error a sector with the directory mark gives.
4A0A
RET NZ C0
If the NZ FLAG is set (any other error), RETurn with it in Register A; NEXT is not advanced.
4A0B
INC (IX+0AH) DD 34 0A
INCrement NEXT's middle byte at (IX+0AH) (Index Register IX = the FCB), FCB+10: NEXT + 256, the next sector. The Z FLAG is set if it went round to 0.
4A0E
If the NZ FLAG is set (no carry out of the middle byte), JUMP to 4A13H.
4A10
INC (IX+0BH) DD 34 0B
INCrement NEXT's high byte at (IX+0BH) (Index Register IX = the FCB), FCB+11.
4A13
SET 5,(IX+01H) DD CB 01 EE
Set bit 5 of FCB+1 at (IX+01H) (Index Register IX = the FCB): the buffer does not hold the sector at NEXT.
4A17
OR A B7
OR Register A with itself: the Z FLAG for 00H (success), the NZ FLAG for 06H (the directory mark).
4A18
RET C9
RETurn from the DOS function with Register A = 00H or 06H.
4A19
LD B,06H 06 06
Read the sector at NEXT into the FCB's buffer. Load Register B with 06H: reading needs an access level below 6.
4A1B
GOSUB to 49B9H to check the FCB's access level against Register B (6); error 25H leaves the DOS function.
4A1E
GOSUB to 49C4H: NEXT must be below EOF, else errors 1CH or 1DH leave the DOS function.
4A21
LD A,B6H 3E B6
Load Register A with B6H, for 4810H: a sector past the file's last granule gives error 3EH instead of an allocation. 4AA4H enters here.
4A23
GOSUB to 4810H to find the sector at NEXT: Register Pair DE = its number on the diskette, Register Pair HL = the FCB's buffer.
4A26
GOSUB to 4630H to read sector Register Pair DE into the buffer at Register Pair HL. Register A and the flags give the result.
4A29
RES 5,(IX+01H) DD CB 01 AE
Clear bit 5 of FCB+1 at (IX+01H) (Index Register IX = the FCB): the buffer holds the sector at NEXT. RES does not change the flags. 4AA9H calls here.
4A2D
RES 4,(IX+01H) DD CB 01 A6
Clear bit 4 of FCB+1 at (IX+01H) (Index Register IX = the FCB): the buffer has no changes waiting to be written.
4A31
RET C9
RETurn with the read's result in Register A and the flags (or the Z FLAG with Register A = 00H from 4A96H).

4A32H - WRITE

443CH (write with verify, manual 3.21) enters at 4A32H and 4439H (WRITE, manual 3.20) at 4A36H. In sector mode the FCB's buffer is written to the sector at NEXT, NEXT is advanced by 256 when its low byte is 0, and EOF is set to NEXT if NEXT is past EOF or if FCB+1 bit 6 is clear.

4A32
LD A,F6H 3E F6
Write with verify: load Register A with F6H, the opcode of OR n.
4A34
JUMP to 4A38H to store the opcode in Register A.
4A36
LD A,E6H 3E E6
Write: load Register A with E6H, the opcode of AND n.
4A38
LD (4A8BH),A 32 8B 4A
Store Register A (the opcode) at 4A8BH: with OR 90H every write is verified, with AND 90H only those in record mode or with changes from the byte routine.
4A3B
GOSUB to 4980H: the rest runs as a DOS function with Index Register IX = the FCB at Register Pair DE.
4A3E
GOSUB to 49DEH with the CARRY FLAG clear (from 49A4H): in record mode it writes LRL bytes from the buffer at Register Pair HL and returns from the DOS function.
4A41
GOSUB to 4A67H to write the FCB's buffer to the sector at NEXT. 4AB4H jumps here when the byte routine has filled the buffer.
4A44
RET NZ C0
If the NZ FLAG is set (Register A = the error code), RETurn with it.
4A45
LD A,(IX+05H) DD 7E 05
Fetch NEXT's low byte from (IX+05H) (Index Register IX = the FCB), FCB+5, into Register A.
4A48
OR A B7
OR Register A with itself. The Z FLAG is set if NEXT is at the start of a sector.
4A49
If the Z FLAG is set (Register A = 00H), GOSUB to 4A0BH to advance NEXT by 256 and mark the buffer as not holding NEXT.
4A4C
GOSUB to 4968H to compare NEXT with EOF: Register C, Register Pair HL = NEXT; the CARRY FLAG if NEXT is below EOF. 4AB6H jumps here.
4A4F
If the NO CARRY FLAG is set (NEXT is at or past EOF), JUMP to 4A57H to set EOF = NEXT.
4A51
BIT 6,(IX+01H) DD CB 01 76
NEXT is below EOF: test bit 6 of FCB+1 at (IX+01H) (Index Register IX = the FCB), set when EOF may only move forward.
4A55
If the NZ FLAG is set (EOF only moves forward), JUMP to 4A60H and keep the EOF.
4A57
LD (IX+08H),C DD 71 08
Store Register C (NEXT's low byte) at (IX+08H) (Index Register IX = the FCB), FCB+8, EOF's low byte.
4A5A
LD (IX+0CH),L DD 75 0C
Store Register L (NEXT's middle byte) at (IX+0CH) (Index Register IX = the FCB), FCB+12.
4A5D
LD (IX+0DH),H DD 74 0D
Store Register H (NEXT's high byte) at (IX+0DH) (Index Register IX = the FCB), FCB+13. EOF now equals NEXT.
4A60
XOR A AF
Set Register A to 00H and the Z FLAG: success.
4A61
RET C9
RETurn from the DOS function (or to 4A98H's caller) with Register A = 00H.
4A62
BIT 4,(IX+01H) DD CB 01 66
Write the buffer only if it has changes waiting: test bit 4 of FCB+1 at (IX+01H) (Index Register IX = the FCB). Used before the FCB moves to another sector (4B00H, 4B92H).
4A66
RET Z C8
If the Z FLAG is set (no changes waiting), RETurn with the Z FLAG set.
4A67
GOSUB to 480CH to check the access level and find the sector at NEXT, allocating it if needed: Register Pair DE = its number on the diskette, Register Pair HL = the buffer.
4A6A
BIT 5,(IX+02H) DD CB 02 6E
Test bit 5 of FCB+2 at (IX+02H) (Index Register IX = the FCB): set once this FCB has marked the file's FPDE as updated.
4A6E
If the NZ FLAG is set (already marked), JUMP to 4A88H to write the sector.
4A70
BIT 1,(IX+00H) DD CB 00 4E
Test bit 1 of FCB+0 at (IX+00H) (Index Register IX = the FCB): NEXT is a sector of the whole diskette, so there is no directory entry to mark.
4A74
If the NZ FLAG is set (whole-diskette sectors), JUMP to 4A88H.
4A76
PUSH HL E5
Save Register Pair HL (the buffer address) onto the stack.
4A77
GOSUB to 494BH to read the file's FPDE into 4200H: Register Pair HL = the entry, the Z FLAG if it is good. Register Pair DE (the sector) is kept.
4A7A
If the NZ FLAG is set (Register A = the error), JUMP to 4A7FH, where the CALL Z is skipped and the error is returned.
4A7C
INC HL 23
INCrement Register Pair HL to the FPDE's byte 1.
4A7D
SET 5,(HL) CB EE
Set bit 5 of the FPDE's byte 1 at Register Pair HL: the file has been updated (DIR shows it; PROT RUF clears it).
4A7F
If the Z FLAG is set, GOSUB to 491FH to write the directory sector in 4200H back with the directory mark.
4A82
POP HL E1
Restore Register Pair HL from the stack: the buffer address.
4A83
RET NZ C0
If the NZ FLAG is set (Register A = the error from 494BH or 491FH), RETurn with it.
4A84
SET 5,(IX+02H) DD CB 02 EE
Set bit 5 of FCB+2 at (IX+02H) (Index Register IX = the FCB): this FCB has marked the FPDE, so the directory is not written again for each sector.
4A88
LD A,(IX+01H) DD 7E 01
Fetch FCB+1 from (IX+01H) (Index Register IX = the FCB) into Register A. Self-Modifying Code
The VERIFY command (SYS3) replaces these three bytes with NOP / LD A,0FFH to verify every write, or puts them back.
4A8B
AND 90H E6 90
AND Register A (FCB+1) with 90H, keeping bit 7 (record mode) and bit 4 (changes from the byte routine): those writes are verified. Self-Modifying Code
The opcode at 4A8BH is stored at 4A38H: for 443CH it is OR 90H, which always gives a non-zero Register A, so the write is always verified.
4A8D
BIT 0,(IX+00H) DD CB 00 46
Test bit 0 of FCB+0 at (IX+00H) (Index Register IX = the FCB): the NZ FLAG asks for the directory mark on this write.
4A91
GOSUB to 4AB8H to write the buffer at Register Pair HL to sector Register Pair DE (Register A not 0 = verify, the NZ FLAG = directory mark).
4A94
RET NZ C0
If the NZ FLAG is set (Register A = the error), RETurn with it.
4A95
XOR A AF
Set Register A to 00H: success, the sector is written.
4A96
JUMP to 4A2DH to clear FCB+1 bit 4 (no changes waiting) and return with Register A = 00H.

4A98H - Write a Byte to a File

The write half of the byte routine at 4AEDH, entered with the byte in Register C and the Z FLAG set if the FCB's buffer holds the sector at NEXT. The sector is read in first unless NEXT is at EOF on a sector boundary. The byte is stored at NEXT and NEXT is advanced; when the buffer is full it is written, and EOF is brought up to NEXT.

4A98
If the Z FLAG is set (the buffer holds the sector at NEXT), JUMP to 4AACH to store the byte in Register C.
4A9A
PUSH BC C5
Save Register Pair BC (Register C = the byte to write) onto the stack.
4A9B
GOSUB to 480CH to check the access level and find (or allocate) the sector at NEXT: Register Pair DE = its number, Register Pair HL = the buffer.
4A9E
GOSUB to 4968H to compare NEXT with EOF. When they are equal Register A = NEXT's low byte and the Z FLAG is set.
4AA1
If the NZ FLAG is set (NEXT is not at EOF), JUMP to 4AA4H to read the sector before changing it.
4AA3
OR A B7
NEXT is at EOF: OR Register A (NEXT's low byte) with itself. The Z FLAG is set when NEXT is at the start of a sector, which then holds nothing yet.
4AA4
If the NZ FLAG is set, GOSUB to 4A21H to read the sector at NEXT into the buffer (without the access and EOF tests).
4AA7
POP BC C1
Restore Register Pair BC from the stack: Register C = the byte to write.
4AA8
RET NZ C0
If the NZ FLAG is set (Register A = a read error), RETurn with it.
4AA9
GOSUB to 4A29H to clear FCB+1 bits 5 and 4: the buffer holds the sector at NEXT, with no changes yet.
4AAC
GOSUB to 4B0BH: Register Pair HL = the byte's place in the buffer, and NEXT's low byte is counted up. The Z FLAG is set if it went round to 0.
4AAF
LD (HL),C 71
Store Register C (the byte) in the buffer at Register Pair HL.
4AB0
SET 4,(IX+01H) DD CB 01 E6
Set bit 4 of FCB+1 at (IX+01H) (Index Register IX = the FCB): the buffer has changes waiting.
4AB4
If the Z FLAG is set (NEXT's low byte went round: the buffer is full), JUMP to 4A41H to write it, advance NEXT and set EOF.
4AB6
JUMP to 4A4CH to bring EOF up to NEXT if needed.

4AB8H - Write a Sector, Verify and Retry

Register Pair DE = the sector number, Register Pair HL = the buffer. Register A not zero asks for a verify read after the write, and the NZ FLAG asks for the directory mark. When the verify read fails, the write is repeated up to SYSTEM option AW times. On exit the Z FLAG is set or Register A holds the error.

4AB8
LD C,A 4F
Copy Register A (not 0 = verify) into Register C. LD does not change the flags.
4AB9
LD B,03H 06 03
Load Register B with the number of write tries. Self-Modifying Code
The operand at 4ABAH is SYSTEM option AW, stored at reset; the file has 03H.
4ABB
If the NZ FLAG is set (the directory mark is wanted), JUMP to 4ACAH.

Write Loop (Normal Mark)

4ABD
GOSUB to 4640H to write the buffer at Register Pair HL to sector Register Pair DE with the normal data mark.
4AC0
RET NZ C0
If the NZ FLAG is set (Register A = the write error), RETurn with it.
4AC1
LD A,C 79
Load Register A with Register C, the verify flag.
4AC2
OR A B7
OR Register A with itself. The Z FLAG is set if no verify is wanted.
4AC3
If the NZ FLAG is set (verify), GOSUB to 4634H to read sector Register Pair DE back, throwing the data away.
4AC6
RET Z C8
If the Z FLAG is set (no verify, or the verify read was good), RETurn with success.
4AC7
DECrement Register B (the write tries) and, if it is not 0, LOOP BACK to 4ABDH to write again.
4AC9
RET C9
RETurn with the verify error in Register A after the last try failed.

Write Loop (Directory Mark)

4ACA
GOSUB to 463CH to write the buffer at Register Pair HL to sector Register Pair DE with the directory mark.
4ACD
RET NZ C0
If the NZ FLAG is set (Register A = the write error), RETurn with it.
4ACE
LD A,C 79
Load Register A with Register C, the verify flag.
4ACF
OR A B7
OR Register A with itself. The Z FLAG is set if no verify is wanted.
4AD0
RET Z C8
If the Z FLAG is set (no verify), RETurn with success.
4AD1
GOSUB to 4634H to read sector Register Pair DE back.
4AD4
GOSUB to 4903H: a read that returned error 06H (the directory mark was read back) gives the Z FLAG; no error gives 31H, any other error itself.
4AD7
RET Z C8
If the Z FLAG is set (the sector reads back with its directory mark), RETurn with success.
4AD8
DECrement Register B (the write tries) and, if it is not 0, LOOP BACK to 4ACAH to write again.
4ADA
RET C9
RETurn with the error in Register A after the last try failed.

4ADBH - Device I/O Through ROUTE or an FCB

Reached through 4033H when the ROM's dispatcher finds that the type byte of the control block at Register Pair DE does not match the request in Register B (01H input, 02H output). A type byte of C0H marks a device that ROUTE has redirected: the ROUTE list is searched for it. Anything else is taken to be an FCB, and one byte is read from or written to the file (manual 3.38 and 3.39); this is how 0013H and 001BH work with disk files.

4ADB
LD HL,0000H 21 00 00
Load Register Pair HL with the first ROUTE entry. Self-Modifying Code
The operand at 4ADCH-4ADDH is the head of the ROUTE list, stored by 4EB5H (option BA) and by the ROUTE command (SYS14); 0000H for none.
4ADE
LD A,(DE) 1A
Fetch the type byte of the control block at Register Pair DE into Register A.
4ADF
CP C0H FE C0
Compare Register A (the type byte) against C0H, the type of a routed device.
4AE1
If the Z FLAG is set (a routed device), JUMP to 4B40H to search the ROUTE list from Register Pair HL. (Zap 020 changed the offset.)
4AE3
An FCB: GOSUB to 4980H, so the rest runs as a DOS function with Index Register IX = the FCB at Register Pair DE.
4AE6
SET 7,(IX+01H) DD CB 01 FE
Set bit 7 of FCB+1 at (IX+01H) (Index Register IX = the FCB): record mode, so the byte is moved through NEXT.
4AEA
LD A,B 78
Load Register A with Register B, the request (01H input, 02H output).
4AEB
CP 02H FE 02
Compare Register A (the request) against 02H. The CARRY FLAG is set for input.
4AED
BIT 5,(IX+01H) DD CB 01 6E
Test bit 5 of FCB+1 at (IX+01H) (Index Register IX = the FCB). The Z FLAG is set if the buffer holds the sector at NEXT. BIT does not change the CARRY FLAG. 49EBH enters here for each byte of a record.
4AF1
If the NO CARRY FLAG is set (output), JUMP to 4A98H to write Register C.
4AF3
Input: if the NZ FLAG is set (the buffer does not hold the sector), GOSUB to 4A19H to read the sector at NEXT.
4AF6
RET NZ C0
If the NZ FLAG is set (Register A = the read error), RETurn with it.
4AF7
GOSUB to 49C4H: NEXT must be below EOF, else errors 1CH or 1DH leave the DOS function.
4AFA
GOSUB to 4B0BH: Register Pair HL = the byte at NEXT in the buffer, and NEXT's low byte is counted up (the Z FLAG if it went round to 0).
4AFD
If the NZ FLAG is set (still in the same sector), JUMP to 4B08H to fetch the byte.
4AFF
PUSH HL E5
The sector is used up: save Register Pair HL (the byte's address in the buffer) onto the stack.
4B00
GOSUB to 4A62H to write the buffer if it has changes waiting.
4B03
POP HL E1
Restore Register Pair HL from the stack: the byte's address.
4B04
RET NZ C0
If the NZ FLAG is set (Register A = the write error), RETurn with it.
4B05
GOSUB to 4A0BH to advance NEXT by 256 and mark the buffer as not holding the sector at NEXT.
4B08
LD A,(HL) 7E
Fetch the byte at Register Pair HL (the buffer) into Register A, the byte read.
4B09
CP A BF
Compare Register A with itself to set the Z FLAG (success).
4B0A
RET C9
RETurn with Register A = the byte read and the Z FLAG.
4B0B
GOSUB to 4853H: Register Pair HL = the FCB's buffer, Register A = 00H.
4B0E
LD E,(IX+05H) DD 5E 05
Load Register E with NEXT's low byte from (IX+05H) (Index Register IX = the FCB), FCB+5, the byte's position in the sector.
4B11
LD D,A 57
Load Register D with Register A (00H): Register Pair DE = the byte's position.
4B12
ADD HL,DE 19
ADD Register Pair DE (the position) to Register Pair HL (the buffer): Register Pair HL = the byte's place.
4B13
INC (IX+05H) DD 34 05
INCrement NEXT's low byte at (IX+05H) (Index Register IX = the FCB). The Z FLAG is set if it went round to 0, the end of the sector.
4B16
RET C9
RETurn with Register Pair HL = the byte's place in the buffer.

4B17H - Search the ROUTE List

Register Pair HL points to a ROUTE entry, Register Pair DE to the control block the I/O was aimed at, Register B holds the request and Register C the output character. Every entry for this control block gets the request: each is passed to the target device's driver through the ROM at 03D4H (inside the driver entry routine 03C2H, which compares Register A with 02H and jumps to the driver named at IX+1). An output goes to every target; an input returns the first character received. This version is from zap 020.

Entry Loop
Register Pair HL = the ROUTE entry: +0/+1 the control block it serves, +2 the saved type, +3/+4 the link, +5/+6 the target control block.

4B17
LD A,(HL) 7E
Fetch the low byte of the entry's control block address at Register Pair HL (+0) into Register A.
4B18
CP E BB
Compare Register A against Register E, the low byte of the control block in Register Pair DE.
4B19
INC HL 23
INCrement Register Pair HL to the entry's +1, the high byte. INC HL does not change the flags.
4B1A
If the NZ FLAG is set (the low bytes differ), JUMP to 4B1EH.
4B1C
LD A,(HL) 7E
Fetch the high byte at Register Pair HL (+1) into Register A.
4B1D
CP D BA
Compare Register A against Register D, the high byte of the control block. The Z FLAG is set if the entry serves this device.
4B1E
INC HL 23
INCrement Register Pair HL to the entry's +2, the saved type byte.
4B1F
If the NZ FLAG is set (another device's entry), JUMP to 4B3BH to follow the link.
4B21
PUSH HL E5
Save Register Pair HL (the entry's +2) onto the stack.
4B22
PUSH DE D5
Save Register Pair DE (the control block the I/O was aimed at) onto the stack.
4B23
PUSH BC C5
Save Register Pair BC (Register B = the request, Register C = the character) onto the stack.
4B24
LD A,(HL) 7E
Fetch the device's original type byte at Register Pair HL (+2) into Register A.
4B25
AND B A0
AND Register A (the type byte) with Register B (the request): Register A keeps the request bit if the device supports it. The ROM code at 03D4H compares Register A with 02H.
4B26
INC HL 23
INCrement Register Pair HL to the entry's +3.
4B27
INC HL 23
INCrement Register Pair HL to the entry's +4.
4B28
INC HL 23
INCrement Register Pair HL to the entry's +5, the target control block.
4B29
LD E,(HL) 5E
Load Register E with the low byte of the target control block at Register Pair HL (+5).
4B2A
INC HL 23
INCrement Register Pair HL to the entry's +6.
4B2B
LD D,(HL) 56
Load Register D with the high byte at Register Pair HL (+6): Register Pair DE = the target control block.
4B2C
PUSH DE D5
Save Register Pair DE (the target control block) onto the stack.
4B2D
POP IX DD E1
Restore it into Index Register IX: Index Register IX = the target control block, as a driver expects.
4B2F
CALL 03D4H CD D4 03
GOSUB to the ROM at 03D4H, inside the driver entry routine at 03C2H, which runs the target's driver (its address at IX+1) with Register A, Register C and Index Register IX.
4B32
POP BC C1
Restore Register Pair BC from the stack: Register B = the request, Register C = the character.
4B33
POP DE D1
Restore Register Pair DE from the stack: the control block the I/O was aimed at.
4B34
POP HL E1
Restore Register Pair HL from the stack: the entry's +2.
4B35
BIT 0,B CB 40
Test bit 0 of Register B (the request): 1 for input. The Z FLAG is set for output.
4B37
If the Z FLAG is set (output), JUMP to 4B3BH to send the character to the next target too.
4B39
OR A B7
Input: OR Register A (the character from the target's driver) with itself. The NZ FLAG is set if a character was received.
4B3A
RET NZ C0
If the NZ FLAG is set (Register A = a character), RETurn with it.
4B3B
INC HL 23
INCrement Register Pair HL from the entry's +2 to +3, the link to the next entry.
4B3C
LD A,(HL) 7E
Fetch the link's low byte at Register Pair HL into Register A.
4B3D
INC HL 23
INCrement Register Pair HL to the link's high byte (+4).
4B3E
LD H,(HL) 66
Load Register H with the link's high byte at Register Pair HL.
4B3F
LD L,A 6F
Load Register L with Register A, the link's low byte: Register Pair HL = the next entry.
4B40
LD A,H 7C
Load Register A with Register H, the high byte of the entry address in Register Pair HL. 4AE1H enters here with the list head.
4B41
OR L B5
OR Register L into Register A. The Z FLAG is set if Register Pair HL is 0000H, the end of the list.
4B42
If the NZ FLAG is set (another entry), LOOP BACK to 4B17H.
4B44
The end of the list: JUMP to 4CF8H, which returns Register A = 00H with the NZ FLAG for an input, or Register A = Register C for an output.

4B47H - Position an FCB

The positioning vectors of the manual (sections 3.22-3.27) come here. Each works out a new NEXT in Registers H (high), L (middle) and C (low). If the new NEXT is in another sector, the buffer is written first if it has changes waiting and is marked empty. Except for 443FH and 4448H, FCB+1 bit 6 is set, so that later writes do not pull EOF back.

4B47
444EH, position to the byte address in Registers H, L and C: GOSUB to 4980H, so the rest runs as a DOS function with Index Register IX = the FCB at Register Pair DE and Registers H, L, C as the caller passed them.
4B4A
JUMP to 4B80H with the new NEXT in Registers H, L and C.
4B4C
443FH, position to the start of the file: GOSUB to 4980H to run as a DOS function (Register A = 00H when the code runs).
4B4F
LD H,A 67
Load Register H with Register A (00H): the new NEXT's high byte.
4B50
LD L,A 6F
Load Register L with Register A (00H): the new NEXT's middle byte.
4B51
LD C,A 4F
Load Register C with Register A (00H): the new NEXT's low byte. NEXT = 0, the first byte of the file.
4B52
JUMP to 4B90H to write the buffer if needed, mark it empty and store NEXT (FCB+1 bit 6 is not set).
4B54
4448H, position to EOF: GOSUB to 4980H to run as a DOS function with Index Register IX = the FCB.
4B57
LD C,(IX+08H) DD 4E 08
Load Register C with EOF's low byte from (IX+08H) (Index Register IX = the FCB), FCB+8.
4B5A
LD L,(IX+0CH) DD 6E 0C
Load Register L with EOF's middle byte from (IX+0CH) (Index Register IX = the FCB), FCB+12.
4B5D
LD H,(IX+0DH) DD 66 0D
Load Register H with EOF's high byte from (IX+0DH) (Index Register IX = the FCB), FCB+13. Registers H, L, C = the new NEXT.
4B60
JUMP to 4B84H, skipping the SET of FCB+1 bit 6.
4B62
4445H, position back one record: GOSUB to 4980H to run as a DOS function with Index Register IX = the FCB.
4B65
GOSUB to 4968H: Register C = NEXT's low byte and Register Pair HL = NEXT's middle and high bytes.
4B68
XOR A AF
Set Register A to 00H and clear the CARRY FLAG.
4B69
SUB (IX+09H) DD 96 09
SUBtract the LRL at (IX+09H) (Index Register IX = the FCB), FCB+9, from Register A: Register A = 256 minus the LRL (00H for an LRL of 0, meaning 256).
4B6C
ADD A,C 81
ADD Register C (NEXT's low byte) to Register A: the new low byte. The CARRY FLAG is set when NEXT's low byte was at least the LRL, so no borrow from the middle byte is needed (never for an LRL of 256).
4B6D
LD C,A 4F
Store Register A (the new low byte) in Register C.
4B6E
If the CARRY FLAG is set (no borrow), JUMP to 4B80H. (Zap 062 changed the offset so that FCB+1 bit 6 gets set.)
4B70
DEC HL 2B
A borrow: DECrement Register Pair HL, NEXT's middle and high bytes: the previous sector.
4B71
JUMP to 4B80H with Registers H, L, C = the new NEXT. (Also changed by zap 062.)
4B73
4442H, position to the record number in Register Pair BC: GOSUB to 4980H to run as a DOS function.
4B76
LD H,B 60
Load Register H with Register B, the record number's high byte.
4B77
LD L,C 69
Load Register L with Register C: Register Pair HL = the record number.
4B78
LD A,(IX+09H) DD 7E 09
Load Register A with the LRL from (IX+09H) (Index Register IX = the FCB), FCB+9.
4B7B
OR A B7
OR Register A (the LRL) with itself. The Z FLAG is set for an LRL of 0 (256).
4B7C
LD C,A 4F
Copy Register A (the LRL) into Register C. With an LRL of 256 Register C = 00H and Register Pair HL stays the record number, so NEXT = record x 256.
4B7D
If the NZ FLAG is set (an LRL of 1-255), GOSUB to 4C9DH to multiply Register Pair HL (the record) by Register A (the LRL): Registers H, L and C = the byte address.
4B80
SET 6,(IX+01H) DD CB 01 F6
Set bit 6 of FCB+1 at (IX+01H) (Index Register IX = the FCB): after a positioning, EOF only moves forward.
4B84
LD A,H 7C
Load Register A with Register H, the new NEXT's high byte.
4B85
CP (IX+0BH) DD BE 0B
Compare Register A against NEXT's present high byte at (IX+0BH) (Index Register IX = the FCB), FCB+11.
4B88
If the NZ FLAG is set (another sector), JUMP to 4B90H.
4B8A
LD A,L 7D
Load Register A with Register L, the new NEXT's middle byte.
4B8B
CP (IX+0AH) DD BE 0A
Compare Register A against NEXT's present middle byte at (IX+0AH) (Index Register IX = the FCB), FCB+10.
4B8E
If the Z FLAG is set (the same sector), JUMP to 4BA1H to change only the low byte; the buffer stays valid.
4B90
PUSH HL E5
Save Register Pair HL (the new NEXT's middle and high bytes) onto the stack.
4B91
PUSH BC C5
Save Register Pair BC (Register C = the new NEXT's low byte) onto the stack.
4B92
GOSUB to 4A62H to write the buffer if it has changes waiting (FCB+1 bit 4).
4B95
POP BC C1
Restore Register Pair BC from the stack: Register C = the new low byte.
4B96
POP HL E1
Restore Register Pair HL from the stack: the new middle and high bytes.
4B97
RET NZ C0
If the NZ FLAG is set (Register A = the write error), RETurn with it; NEXT is not changed.
4B98
GOSUB to 4A13H to set FCB+1 bit 5: the buffer does not hold the sector at the new NEXT.
4B9B
LD (IX+0AH),L DD 75 0A
Store Register L (the new middle byte) at (IX+0AH) (Index Register IX = the FCB), FCB+10.
4B9E
LD (IX+0BH),H DD 74 0B
Store Register H (the new high byte) at (IX+0BH) (Index Register IX = the FCB), FCB+11.
4BA1
LD (IX+05H),C DD 71 05
Store Register C (the new low byte) at (IX+05H) (Index Register IX = the FCB), FCB+5.
4BA4
XOR A AF
Set Register A to 00H and the Z FLAG: success. 4BA4H is also the driver of the NL device (its control block is 4CFCH): it returns 00H for an input and throws an output away.
4BA5
RET C9
RETurn from the DOS function with Register A = 00H and the Z FLAG (success).

4BA6H - Display or Print a Message

4467H (display, manual 3.33) enters at 4BA6H and 446AH (print, manual 3.34) at 4BBCH. The message at Register Pair HL is sent through the ROM's output routine at 001BH up to and including a 0DH, or up to but not including a 03H. Register Pairs HL and DE are preserved.

4BA6
PUSH DE D5
Display: save Register Pair DE (the caller's) onto the stack.
4BA7
LD DE,401DH 11 1D 40
Point Register Pair DE to 401DH, the display's device control block.
4BAA
PUSH HL E5
Save Register Pair HL (the message address) onto the stack. 4BC0H joins here with Register Pair DE = 4025H.

Character Loop

4BAB
LD A,(HL) 7E
Fetch the message byte at Register Pair HL into Register A.
4BAC
CP 03H FE 03
Compare Register A (the byte) against 03H, the end of message byte that is not sent.
4BAE
If the Z FLAG is set (Register A = 03H), JUMP to 4BB9H to finish.
4BB0
GOSUB to the ROM at 001BH to send the character in Register A to the device whose control block is at Register Pair DE (401DH or 4025H).
4BB3
LD A,(HL) 7E
Fetch the byte at Register Pair HL again into Register A (the ROM routine does not keep Register A).
4BB4
CP 0DH FE 0D
Compare Register A against 0DH (carriage return), which ends a message after being sent.
4BB6
INC HL 23
INCrement Register Pair HL to the next byte of the message. INC HL does not change the flags.
4BB7
If the NZ FLAG is set (Register A was not 0DH), LOOP BACK to 4BABH for the next character.
4BB9
POP HL E1
Restore Register Pair HL from the stack: the message address.
4BBA
POP DE D1
Restore Register Pair DE from the stack: the caller's DE.
4BBB
RET C9
RETurn with Register Pairs HL and DE as they were.
4BBC
PUSH DE D5
Print: save Register Pair DE (the caller's) onto the stack.
4BBD
LD DE,4025H 11 25 40
Point Register Pair DE to 4025H, the printer's device control block.
4BC0
JUMP to 4BAAH to send the message at Register Pair HL to the printer.

4BC2H - RST 28H Dispatcher

RST 28H comes here through 400CH with a function code in Register A. Codes below 20H (function 0) are sent to the BREAK hook at 4312H. Any other code names a system file by its directory slot (bits 0-4) and a function in it (bits 5-7). If that file is not the overlay now in 4D00H-51FFH, its directory entry is read from drive 0, and it is loaded through the FCB at 43CEH; a system file that cannot be found gives error 2EH (SYSTEM PROGRAM NOT FOUND), or a HALT if the missing file is SYS4, the error message module. The overlay is then called at its transfer address with Register Pairs AF, BC, DE and HL as they were at the RST. The return address the RST pushed is thrown away, so the overlay returns to whoever called the routine that executed the RST.

4BC2
INC SP 33
INCrement the Stack Pointer: the first of two steps that drop the return address the RST 28H pushed.
4BC3
INC SP 33
INCrement the Stack Pointer again: the RST's return address is gone, and the top of the stack is the return address of whoever called the routine that did the RST.
4BC4
CP 20H FE 20
Compare Register A (the function code) against 20H. The CARRY FLAG is set for codes 00H-1FH (function 0, used by the ROM's keyboard driver for BREAK).
4BC6
If the CARRY FLAG is set (a code below 20H), JUMP to 4312H, the BREAK key hook, with Register A = the code.
4BC9
PUSH HL E5
Save Register Pair HL (the caller's) onto the stack, to pass it to the overlay.
4BCA
PUSH DE D5
Save Register Pair DE (the caller's) onto the stack.
4BCB
PUSH BC C5
Save Register Pair BC (the caller's, Register C often a sub-function) onto the stack.
4BCC
PUSH AF F5
Save Register Pair AF (Register A = the function code) onto the stack.
4BCD
LD HL,4369H 21 69 43
Point Register Pair HL to 4369H, the DOS flags.
4BD0
SET 6,(HL) CB F6
Set bit 6 of the DOS flags at Register Pair HL (4369H): an overlay function is running, which also stops the key combinations.
4BD2
LD HL,45BEH 21 BE 45
Point Register Pair HL to 45BEH, the first byte of the key combination check.
4BD5
LD (HL),00H 36 00
Store 00H (NOP) at Register Pair HL (45BEH), in case the keyboard driver's RET (stored at 4526H) is still there.
4BD7
EI FB
Enable interrupts. The RST may come from code running with them disabled, such as the interrupt handler's DEBUG entry (45E6H).
4BD8
AND 1FH E6 1F
AND Register A (the function code) with 1FH, keeping bits 0-4: the overlay's directory slot.
4BDA
LD HL,4317H 21 17 43
Point Register Pair HL to 4317H, the directory slot of the overlay now in 4D00H-51FFH.
4BDD
CP (HL) BE
Compare Register A (the slot wanted) against the loaded overlay's slot at Register Pair HL (4317H). The Z FLAG is set if it is already in memory.
4BDE
If the Z FLAG is set (the overlay is loaded), JUMP to 4C19H to call it.
4BE0
LD (HL),A 77
Store Register A (the new slot) at Register Pair HL (4317H), the overlay about to be loaded.
4BE1
AND 07H E6 07
AND Register A (the slot) with 07H, keeping bits 0-2: the directory sector minus 2 that holds the file's entry.
4BE3
LD C,A 4F
Copy Register A (the sector bits) into Register C.
4BE4
XOR A AF
Set Register A to 00H, for NEXT and for the drive number below.
4BE5
LD (43D8H),A 32 D8 43
Store Register A (00H) at 43D8H, NEXT's middle byte (FCB+10) of the load FCB at 43CEH: the load starts at the file's first sector.
4BE8
GOSUB to 4776H to select drive 0 (Register A = 00H): system files are always loaded from drive 0.
4BEB
LD A,(HL) 7E
Fetch the slot at Register Pair HL (4317H) into Register A.
4BEC
SUB C 91
SUBtract Register C (bits 0-2) from Register A, leaving bits 3-4: the file's entry number within the directory sector.
4BED
RLCA 07
Rotate Register A left: bits 3-4 move up (two rotates in all).
4BEE
RLCA 07
Rotate Register A left again: the entry number is now in bits 5-6, where a DEC keeps it.
4BEF
ADD A,C 81
ADD Register C (the sector bits) to Register A: Register A = the DEC of the system file's directory entry.
4BF0
GOSUB to 4936H to read the directory sector of the DEC in Register A: Register Pair HL = the entry, Register A = its offset in the sector.
4BF3
If the NZ FLAG is set (the directory could not be read), JUMP to 4C0EH.
4BF5
BIT 6,(HL) CB 76
Test bit 6 of the entry's byte 0 at Register Pair HL: a system file. The Z FLAG is set if it is not.
4BF7
If the Z FLAG is set (not a system file: the slot holds something else), JUMP to 4C0EH.
4BF9
ADD A,16H C6 16
ADD 16H (22) to Register A (the entry's offset in the sector): the offset of its first extent.
4BFB
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the entry's first extent element.
4BFC
LD E,(HL) 5E
Fetch the first extent's lump byte at Register Pair HL into Register E.
4BFD
INC HL 23
INCrement Register Pair HL to the extent's second byte.
4BFE
LD D,(HL) 56
Fetch the extent's second byte at Register Pair HL into Register D: Register Pair DE = the file's only extent.
4BFF
LD (43DCH),DE ED 53 DC 43
Store Register Pair DE (the extent) at 43DCH-43DDH, FCB+14 of the load FCB; 43DEH (FFH) ends its extent list.
4C03
LD HL,43CEH 21 CE 43
Point Register Pair HL to 43CEH, the load FCB (buffer 4200H, drive 0).
4C06
GOSUB to 4C28H to load the system file through the FCB at Register Pair HL: Register Pair HL returns its transfer address, the Z FLAG for success.
4C09
LD (4C1EH),HL 22 1E 4C
Store Register Pair HL (the transfer address) at 4C1EH, the operand of the CALL at 4C1DH. LD does not change the flags.
4C0C
If the Z FLAG is set (loaded), JUMP to 4C19H to call it.
4C0E
LD A,(4317H) 3A 17 43
The system file could not be loaded: fetch the slot from 4317H into Register A.
4C11
CP 06H FE 06
Compare Register A (the slot) against 06H, SYS4's slot (SYS4 holds the error messages).
4C13
LD A,2EH 3E 2E
Load Register A with error code 2EH (SYSTEM PROGRAM NOT FOUND). LD does not change the flags.
4C15
If the NZ FLAG is set (it was not SYS4), JUMP to 4409H to report error 2EH through SYS4.
4C18
HALT 76
HALT: SYS4 itself cannot be loaded, so no error can be shown. On the Model I the HALT stops the computer until it is reset.
4C19
POP AF F1
Restore Register Pair AF from the stack: Register A = the function code (the overlay uses bits 5-7 as the function).
4C1A
POP BC C1
Restore Register Pair BC from the stack: the caller's BC.
4C1B
POP DE D1
Restore Register Pair DE from the stack: the caller's DE.
4C1C
POP HL E1
Restore Register Pair HL from the stack: the caller's HL.
4C1D
GOSUB to the overlay's transfer address (0000H in the file). Self-Modifying Code
The operand at 4C1EH-4C1FH is stored by 4C09H (4D00H for every overlay but SYS11 and SYS13, 4D0CH; 5200H for SYS18-SYS20). The overlay returns here, or pops this return address and returns elsewhere.
4C20
PUSH HL E5
Save Register Pair HL (the overlay's result) onto the stack. Overlays that end by jumping to 4C20H come here too.
4C21
LD HL,4369H 21 69 43
Point Register Pair HL to 4369H, the DOS flags.
4C24
RES 6,(HL) CB B6
Clear bit 6 of the DOS flags at Register Pair HL (4369H): no overlay function is running.
4C26
POP HL E1
Restore Register Pair HL from the stack: the overlay's result.
4C27
RET C9
RETurn to the caller of the routine that executed the RST 28H, with the overlay's Register Pairs AF, BC, DE and HL.

4C28H - Load a Program File

Loads the load module file of the open FCB at Register Pair HL into memory and returns its transfer address in Register Pair HL with the Z FLAG set. The file is read a sector at a time into 4200H, so the FCB's buffer must be 4200H. Record type 01H is a load block (length, two address bytes, data), 02H is the transfer address (it ends the load), and any other type up to 1FH is skipped. Errors: 22H (LOAD FILE FORMAT ERROR) for a type above 1FH, 24H (TRIED TO LOAD READ ONLY MEMORY) if a loaded byte does not read back, or the read error. Also called by SYS2.

4C28
LD (4C6AH),HL 22 6A 4C
Store Register Pair HL (the FCB address) at 4C6AH, the operand of the LD DE at 4C69H used for each sector read.
4C2B
LD DE,42FFH 11 FF 42
Point Register Pair DE to 42FFH, the byte before the buffer: the first fetch steps Register E to 00H and reads the first sector.

Record Loop

4C2E
GOSUB to 4C65H to fetch the next byte of the file into Register A: the record type.
4C31
LD C,A 4F
Copy Register A (the record type) into Register C.
4C32
LD A,1FH 3E 1F
Load Register A with 1FH, the highest valid record type.
4C34
CP C B9
Compare Register A (1FH) against Register C (the type). The CARRY FLAG is set for a type above 1FH.
4C35
LD A,22H 3E 22
Load Register A with error code 22H (LOAD FILE FORMAT ERROR). LD does not change the flags.
4C37
RET C D8
If the CARRY FLAG is set (a type above 1FH), RETurn with Register A = 22H and the NZ FLAG.
4C38
GOSUB to 4C65H to fetch the record length into Register A (00H = 256).
4C3B
LD B,A 47
Copy Register A (the record length) into Register B, the count of bytes in the record.
4C3C
GOSUB to 4C65H to fetch the record's first byte into Register A (the low byte of an address for types 01H and 02H).
4C3F
LD L,A 6F
Copy Register A (the first byte) into Register L.
4C40
LD H,C 61
Copy Register C (the record type) into Register H: for a skipped record Register Pair HL is then an address in the ROM.
4C41
DEC C 0D
DECrement Register C (the type). The Z FLAG is set for type 01H.
4C42
If the Z FLAG is set (a load block), JUMP to 4C4DH.
4C44
DEC C 0D
DECrement Register C again. The Z FLAG is set for type 02H.
4C45
If the NZ FLAG is set (another type), JUMP to 4C61H to skip the rest of the record. Its bytes are stored at Register Pair HL, an address in the ROM (Register H = the type), where the stores do nothing; the read-back error is ignored because Register C is not 0.
4C47
Transfer address: GOSUB to 4C65H to fetch its high byte into Register A.
4C4A
LD H,A 67
Copy Register A into Register H: Register Pair HL = the transfer address.
4C4B
XOR A AF
Set Register A to 00H and the Z FLAG: the load is complete.
4C4C
RET C9
RETurn with Register Pair HL = the transfer address and the Z FLAG.
4C4D
Load block: GOSUB to 4C65H to fetch the load address's high byte into Register A.
4C50
LD H,A 67
Copy Register A into Register H: Register Pair HL = the load address.
4C51
DEC B 05
DECrement Register B (the record length) for the low address byte.
4C52
DEC B 05
DECrement Register B again for the high address byte: Register B = the number of data bytes.

Data Loop
Register Pair HL = the load address, Register B = bytes left, Register C = 00H for a load block.

4C53
GOSUB to 4C65H to fetch the next data byte into Register A.
4C56
LD (HL),A 77
Store Register A (the data byte) at Register Pair HL, its load address.
4C57
CP (HL) BE
Compare Register A against the byte at Register Pair HL. The Z FLAG is set if it reads back (RAM); the NZ FLAG means ROM or missing memory.
4C58
INC HL 23
INCrement Register Pair HL to the next load address. INC HL does not change the flags.
4C59
If the Z FLAG is set (the byte read back), JUMP to 4C61H.
4C5B
LD A,24H 3E 24
Load Register A with error code 24H (TRIED TO LOAD READ ONLY MEMORY).
4C5D
INC C 0C
INCrement Register C, the first of two steps that test it for 0.
4C5E
DEC C 0D
DECrement Register C back. The Z FLAG is set if Register C is 0: a load block, where the error counts.
4C5F
If the Z FLAG is set (a load block), JUMP to 4CC3H to return Register A = 24H with the NZ FLAG.
4C61
DECrement Register B (bytes left) and, if it is not 0, LOOP BACK to 4C53H.
4C63
JUMP to 4C2EH to read the next record's type byte.
4C65
INC E 1C
Fetch the next byte of the file: INCrement Register E, the low byte of the pointer into the buffer at Register Pair DE. The Z FLAG is set when it wraps to 00H.
4C66
LD A,(DE) 1A
Fetch the byte at Register Pair DE into Register A. LD does not change the flags.
4C67
RET NZ C0
If the NZ FLAG is set (still in the sector), RETurn with the byte in Register A.
4C68
PUSH DE D5
The sector is used up: save Register Pair DE (4200H) onto the stack.
4C69
LD DE,0000H 11 00 00
Point Register Pair DE to the FCB being loaded (0000H in the file). Self-Modifying Code
The operand at 4C6AH is stored by 4C28H.
4C6C
GOSUB to 4436H (READ) to read the next sector of the file into its buffer at 4200H; NEXT advances by 256.
4C6F
POP DE D1
Restore Register Pair DE from the stack: 4200H, the first byte of the new sector.
4C70
If the NZ FLAG is set (Register A = the read error), JUMP to 4C9BH: its POP BC drops this call's return address and its RET returns from 4C28H with the error.
4C72
LD A,(DE) 1A
Fetch the first byte of the new sector at Register Pair DE (4200H) into Register A.
4C73
RET C9
RETurn to the loader with the byte in Register A and the Z FLAG from the read.

4C74H - Sector Number of a Directory Sector

Register A holds a directory sector (0 = GAT). It is stored at 4930H as the sector now in 4200H, and Register Pair DE is loaded with its sector number on the current drive's diskette: (the directory's lump x granules per lump) x 5 + Register A. Register Pair HL is set to 4200H. 4C7CH is the general entry, used by 4850H: Register Pair HL points to a lump byte, Register E holds a granule in the lump and Register A a sector in the granule.

4C74
LD (4930H),A 32 30 49
Store Register A (the directory sector) at 4930H, the operand of 492FH: the directory sector the buffer at 4200H will hold.
4C77
LD E,00H 1E 00
Load Register E with 00H: the directory starts at granule 0 of its lump.
4C79
LD HL,(4399H) 2A 99 43
Load Register Pair HL with the address of the current drive's PDRIVE record from 4399H; its byte 0 is the directory's starting lump.
4C7C
LD C,A 4F
Copy Register A (the sector within the granule) into Register C. 4850H enters here.
4C7D
LD L,(HL) 6E
Load Register L with the lump number at Register Pair HL (the PDRIVE record's byte 0, or an extent's lump byte).
4C7E
LD A,(430FH) 3A 0F 43
Load Register A with the granules per lump of the current drive from 430FH (PDRIVE byte +5).
4C81
GOSUB to 4C92H to multiply Register L (the lump) by Register A (the granules per lump): Register Pair HL = the first granule of the lump, Register A = the high byte (00H).
4C84
LD B,A 47
Copy Register A (00H) into Register B: Register Pair BC = the sector within the granule.
4C85
LD D,A 57
Copy Register A (00H) into Register D: Register Pair DE = the granule within the lump.
4C86
ADD HL,DE 19
ADD Register Pair DE (the granule within the lump) to Register Pair HL: the granule number on the diskette.
4C87
LD A,05H 3E 05
Load Register A with 05H, the sectors per granule.
4C89
GOSUB to 4C94H to multiply Register Pair HL (the granule) by Register A (5): Register Pair HL = its first sector, Register A = the high byte.
4C8C
ADD HL,BC 09
ADD Register Pair BC (the sector within the granule) to Register Pair HL: the sector number on the diskette.
4C8D
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the sector number.
4C8E
LD HL,4200H 21 00 42
Point Register Pair HL to 4200H, the DOS sector buffer, for the read or write that follows.
4C91
RET C9
RETurn with Register Pair DE = the sector number and Register Pair HL = 4200H.

4C92H - Multiply and Divide

4C92H: Register Pair HL = Register L x Register A. 4C94H: Register Pair HL x Register A, with the result in Register A (high byte), Register H and Register L. 4C9DH: Register Pair HL x Register A with the result in Register H (high), Register L and Register C (low), used for record x LRL. 4CB2H divides Register Pair HL by 5 and 4CB4H by Register A: the quotient in Register Pair HL, the remainder in Register A. Used by several overlays.

4C92
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = Register L, the 8-bit number to multiply.
4C94
PUSH BC C5
Save Register Pair BC (the caller's) onto the stack; 4C9DH uses Register C for the low byte of the product.
4C95
GOSUB to 4C9DH to multiply Register Pair HL by Register A: the 24-bit product comes back in Registers H, L and C.
4C98
LD A,H 7C
Load Register A with Register H, the product's high byte.
4C99
LD H,L 65
Load Register H with Register L, the product's middle byte.
4C9A
LD L,C 69
Load Register L with Register C, the product's low byte: Register Pair HL = the low 16 bits.
4C9B
POP BC C1
Restore Register Pair BC from the stack (the caller's). 4C70H jumps here to use this POP to drop the return address of its caller.
4C9C
RET C9
RETurn with Register A = the high byte and Register Pair HL = the low 16 bits of the product.
4C9D
PUSH DE D5
Save Register Pair DE (the caller's) onto the stack.
4C9E
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the number to multiply.
4C9F
LD C,80H 0E 80
Load Register C with 80H: this marker bit is shifted down through Register C and falls into the CARRY FLAG after eight shifts, ending the loop.
4CA1
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, the product's upper 16 bits.

Multiply Loop
Register A = the multiplier (rotated right, back to its value after 8 passes), Register Pair DE = the multiplicand, Registers H, L, C = the product shifted right as it grows.

4CA4
RRCA 0F
Rotate Register A (the multiplier) right: its lowest bit goes into the CARRY FLAG (and to bit 7).
4CA5
If the NO CARRY FLAG is set (that multiplier bit is 0), JUMP to 4CA8H.
4CA7
ADD HL,DE 19
ADD Register Pair DE (the multiplicand) to Register Pair HL (the product's upper part).
4CA8
SRL H CB 3C
Shift Register H right: bit 0 goes into the CARRY FLAG.
4CAA
RR L CB 1D
Rotate Register L right through the CARRY FLAG, taking Register H's bit 0.
4CAC
RR C CB 19
Rotate Register C right through the CARRY FLAG, taking Register L's bit 0; the marker bit in Register C falls out after eight passes.
4CAE
If the NO CARRY FLAG is set (the marker has not come out), LOOP BACK to 4CA4H.
4CB0
POP DE D1
Restore Register Pair DE from the stack (the caller's).
4CB1
RET C9
RETurn with the product in Registers H (high), L and C (low).
4CB2
LD A,05H 3E 05
Divide by 5: load Register A with 05H, the divisor. 4829H calls here to turn a sector of a file into a granule.
4CB4
LD C,A 4F
Copy Register A (the divisor) into Register C; it stays there after the division (4667H uses it).
4CB5
LD B,10H 06 10
Load Register B with 10H (16), one pass per bit of Register Pair HL.
4CB7
XOR A AF
Set Register A to 00H: the remainder starts at 0.

Divide Loop
Register Pair HL = the dividend, becoming the quotient bit by bit; Register A = the remainder; Register C = the divisor.

4CB8
ADD HL,HL 29
ADD Register Pair HL to itself: shift the dividend left; its top bit goes into the CARRY FLAG.
4CB9
RLA 17
Rotate Register A (the remainder) left through the CARRY FLAG, taking the dividend's top bit.
4CBA
If the CARRY FLAG is set (a bit fell out of Register A, so the remainder is above the divisor), JUMP to 4CBFH to subtract.
4CBC
CP C B9
Compare Register A (the remainder) against Register C (the divisor). The CARRY FLAG is set if it is lower.
4CBD
If the CARRY FLAG is set (the remainder is below the divisor), JUMP to 4CC1H: this quotient bit is 0.
4CBF
SUB C 91
SUBtract Register C (the divisor) from Register A (the remainder).
4CC0
INC L 2C
INCrement Register L: set the quotient bit just shifted into Register Pair HL's bit 0.
4CC1
DECrement Register B and, if it is not 0, LOOP BACK to 4CB8H for the next bit.
4CC3
OR A B7
OR Register A (the remainder) with itself to set the flags. 4C5FH jumps here to return Register A = 24H with the NZ FLAG.
4CC4
RET C9
RETurn with Register Pair HL = the quotient, Register A = the remainder (or the error code from 4C5FH).

4CC5H - Compare a Keyword and Step Over Separators

4CC5H compares the 00H-terminated string at Register Pair BC with the text at Register Pair HL: on a match it returns the Z FLAG with Register Pair HL after the text, otherwise the NZ FLAG, Register A = 34H and Register Pair HL unchanged. 4CD5H returns the Z FLAG if Register Pair HL points to 0DH (the end of the command line). 4CD9H steps over a comma or over spaces and returns the NZ and NO CARRY flags; for any other character it returns the CARRY FLAG with Register Pair HL unchanged. Register A is 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR) whenever the Z FLAG is not set.

4CC5
PUSH HL E5
Save Register Pair HL (the text pointer) onto the stack, to go back to it if the keyword does not match.

Compare Loop
Register Pair BC = the keyword, Register Pair HL = the text.

4CC6
LD A,(BC) 0A
Fetch the next keyword character at Register Pair BC into Register A.
4CC7
OR A B7
OR Register A with itself. The Z FLAG is set at the keyword's 00H end.
4CC8
INC BC 03
INCrement Register Pair BC to the next keyword character. INC BC does not change the flags.
4CC9
If the NZ FLAG is set (Register A is a keyword character), JUMP to 4CCEH to compare it.
4CCB
EX (SP),HL E3
The whole keyword matched: exchange Register Pair HL (the text after the keyword) with the saved pointer on the stack (the Stack Pointer's target).
4CCC
POP HL E1
Restore Register Pair HL from the stack: the text after the keyword (the original pointer is dropped).
4CCD
RET C9
RETurn with the Z FLAG set (from 4CC7H) and Register Pair HL after the keyword.
4CCE
CP (HL) BE
Compare Register A (the keyword character) against the text character at Register Pair HL.
4CCF
INC HL 23
INCrement Register Pair HL to the next text character. INC HL does not change the flags.
4CD0
If the Z FLAG is set (the characters are equal), LOOP BACK to 4CC6H.
4CD2
POP HL E1
Different: restore Register Pair HL from the stack, the text pointer as it was on entry.
4CD3
JUMP to 4CE9H to return the NZ FLAG and Register A = 34H.
4CD5
LD A,(HL) 7E
Fetch the character at Register Pair HL (the command line) into Register A.
4CD6
CP 0DH FE 0D
Compare Register A against 0DH, the end of the command line.
4CD8
RET Z C8
If the Z FLAG is set (Register A = 0DH), RETurn with it.
4CD9
LD A,(HL) 7E
Fetch the character at Register Pair HL into Register A. Entry for stepping over a separator.
4CDA
CP 2CH FE 2C
Compare Register A against 2CH (ASCII comma).
4CDC
INC HL 23
INCrement Register Pair HL past the character. INC HL does not change the flags.
4CDD
If the Z FLAG is set (a comma), JUMP to 4CE9H with Register Pair HL after it.
4CDF
CP 20H FE 20
Compare Register A against 20H (ASCII space).
4CE1
DEC HL 2B
DECrement Register Pair HL back to the character. DEC HL does not change the flags.
4CE2
SCF 37
Set the CARRY FLAG, the answer for a character that is neither comma nor space.
4CE3
If the NZ FLAG is set (Register A is not a space), JUMP to 4CEAH with the CARRY FLAG set and Register Pair HL unchanged.

Space Loop

4CE5
INC HL 23
INCrement Register Pair HL to the next character.
4CE6
CP (HL) BE
Compare Register A (20H, a space) against the character at Register Pair HL.
4CE7
If the Z FLAG is set (another space), LOOP BACK to 4CE5H.
4CE9
OR A B7
OR Register A (not 0) with itself: the NZ FLAG and the NO CARRY FLAG.
4CEA
LD A,34H 3E 34
Load Register A with 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR) for the caller to use as an error code.
4CEC
RET C9
RETurn with Register A = 34H and Register Pair HL at the next item.

4CEDH - Delay

Waits Register B x 256 passes of the ROM's delay loop at 0060H (plus the passes in Register C), repeated SYSTEM option BJ times. Used for the motor start and head settle delays, and by SYS5 and SYS6.

4CED
LD D,B 50
Copy Register B (the delay count, high byte) into Register D, to reload it for each pass.
4CEE
LD E,01H 1E 01
Load Register E with the number of passes. Self-Modifying Code
The operand at 4CEFH is SYSTEM option BJ (the CPU speed factor), stored at reset; the file has 01H.
4CF0
LD B,D 42
Load Register B with Register D, the delay count. Register C is as the caller left it.
4CF1
GOSUB to the ROM at 0060H, which counts Register Pair BC down to 0 (14.66 microseconds a count on a standard Model I).
4CF4
DEC E 1D
DECrement Register E, the passes left (option BJ counts down to 0).
4CF5
If the NZ FLAG is set (Register E has not reached 0), LOOP BACK to 4CF0H.
4CF7
RET C9
RETurn after the delay; Register Pair BC = 0000H.
4CF8
BIT 0,B CB 40
The end of the ROUTE list (zap 020), reached from 4B44H with Register A = 00H. Test bit 0 of Register B (the request): 1 for input.
4CFA
RET NZ C0
If the NZ FLAG is set (an input), RETurn with Register A = 00H: no character was received.
4CFB
LD A,C 79
Output: load Register A with Register C, the character sent, as the ROM's drivers return it.
4CFC
RET C9
RETurn with Register A = the character. This byte (C9H) is also byte 0 (the type byte) of the NL device's control block 4CFCH-4CFEH, which ROUTE,NL uses (SYS14's device table and 43B2H).
4CFD-4CFE
DEFW 4BA4H A4 4B
Bytes 1-2 of the NL device's control block: its driver, 4BA4H (XOR A / RET), which returns 00H and throws output away. Put here by zap 020.
4CFF
DEFB 00H 00
4CFFH: the byte after the NL control block, 00H. No instruction in SYS0 uses it; 4D00H starts the reset code.

4D00H - Reset: Memory Size and Clock

BOOT/SYS loads SYS0/SYS and checks that the byte at its transfer address 4D00H is A5H, then jumps to 4D01H. The code from 4D00H to 4FA7H runs once at every reset and is then overwritten by the overlays. It finds the top of memory, restores the clock after a reset while the DOS was active, reads the system data sector and sets the DOS up from the SYSTEM options, shows the banner, asks for the date and time, reads the GAT and runs the AUTO command.

4D00
DEFB A5H A5
4D00H: the byte BOOT/SYS checks before it jumps to 4D01H (BOOT 4246H). A file whose transfer address does not hold A5H gives NO SYS.
4D01
IM 1 ED 56
Set Interrupt Mode 1: interrupts go to the ROM at 0038H and from there through the RST 38H vector at 4012H to 45F2H. BOOT/SYS disabled interrupts at 4203H.
4D03
LD HL,FFFFH 21 FF FF
Point Register Pair HL to FFFFH, the top of the address space, to search downward for the highest RAM byte.

Memory Size Loop

4D06
LD A,(HL) 7E
Fetch the byte at Register Pair HL into Register A.
4D07
CPL 2F
Invert Register A (every bit of the byte flipped), so that the store below changes every bit of a RAM byte.
4D08
LD (HL),A 77
Store Register A (the inverted byte) at Register Pair HL.
4D09
CP (HL) BE
Compare Register A against the byte at Register Pair HL. Only RAM keeps what was stored, giving the Z FLAG.
4D0A
DEC HL 2B
DECrement Register Pair HL to the next lower address. DEC HL does not change the flags.
4D0B
If the NZ FLAG is set (no RAM at that address), LOOP BACK to 4D06H.
4D0D
CPL 2F
RAM was found: invert Register A back to the byte's original value.
4D0E
INC HL 23
INCrement Register Pair HL back to the RAM byte that was found, the top of memory.
4D0F
LD (HL),A 77
Store Register A (the original value) back at Register Pair HL.
4D10
LD (43A9H),HL 22 A9 43
Store Register Pair HL (the top of memory) at 43A9H, the limit HIMEM may not be set above.
4D13
LD (4049H),HL 22 49 40
Store Register Pair HL (the top of memory) at 4049H as HIMEM; 4DC4H may replace it with option AP.
4D16
LD HL,43ABH 21 AB 43
Point Register Pair HL to 43ABH, which holds A5H only if the DOS was running before this reset.
4D19
LD A,A5H 3E A5
Load Register A with A5H, the mark stored at 43ABH by 4F15H.
4D1B
CP (HL) BE
Compare Register A (A5H) against the byte at Register Pair HL (43ABH). The Z FLAG is set after a reset while the DOS was active.
4D1C
If the NZ FLAG is set (a power-on, or a reset after non-disk BASIC), JUMP to 4D27H; the clock and date stay 0.
4D1E
INC HL 23
INCrement Register Pair HL to 43ACH, the copy of the clock and date made every second by 44D1H.
4D1F
LD DE,4041H 11 41 40
Point Register Pair DE to 4041H, the clock (seconds, minutes, hours, then year, day, month).
4D22
LD BC,0006H 01 06 00
Load Register Pair BC with 0006H, the six bytes of time and date.
4D25
LDIR ED B0
Copy Register Pair BC (6) bytes from Register Pair HL (43ACH) to Register Pair DE (4041H): the time and date come back as they were before the reset.

4D27H - Reset: Read the System Data Sector

The boot sector is still in 4200H. Its bytes FDH-FFH describe the system diskette in drive 0, and they are put into drive 0's PDRIVE record so that the DOS can read that diskette. Then sector 2, the system data sector (the third sector of BOOT/SYS), is read into 4200H with the ready-made FCB at 4480H, and the SYSTEM options in it are put where the DOS uses them (see SYSTEM Options in the introduction). Bad values give error 27H (ILLEGAL INITIALIZATION DATA ON SYSTEM DISKETTE).

4D27
LD IY,4380H FD 21 80 43
Load Index Register IY with 4380H, the base for IY+d addressing of the variables 4369H-439FH.
4D2B
LD BC,(42FEH) ED 4B FE 42
Load Register Pair BC from 42FEH-42FFH, the last bytes of the boot sector still in the buffer: Register C = PDRIVE byte +2 and Register B = byte +7 of the system diskette.
4D2F
LD (IY-08H),B FD 70 F8
Store Register B (byte +7, the disk I/O flags) at (IY-08H) (Index Register IY = 4380H, minus 08H), 4378H: byte +7 of drive 0's record.
4D32
LD (IY-0DH),C FD 71 F3
Store Register C (byte +2, the TSR and interface) at (IY-0DH) (Index Register IY = 4380H), 4373H: byte +2 of drive 0's record.
4D35
LD A,(42FDH) 3A FD 42
Fetch byte FDH of the boot sector at 42FDH into Register A: PDRIVE byte +6 (the drive select byte for the sector register).
4D38
LD (IY-09H),A FD 77 F7
Store Register A (byte +6) at (IY-09H) (Index Register IY = 4380H), 4377H: byte +6 of drive 0's record.
4D3B
LD DE,4480H 11 80 44
Point Register Pair DE to 4480H, the DOS FCB, which as loaded addresses sector 2 of drive 0 with buffer 4200H.
4D3E
GOSUB to 4436H (READ) to read the system data sector into 4200H through the FCB at Register Pair DE.
4D41
If the NZ FLAG is set (Register A = the read error), JUMP to 4DD3H to report it through SYS4.
4D44
LD A,(42EFH) 3A EF 42
Fetch byte EFH of the system data sector at 42EFH into Register A.
4D47
CP A5H FE A5
Compare Register A against A5H, the mark of a valid NEWDOS/80 system data sector.
4D49
If the NZ FLAG is set (no A5H), JUMP to 4DD1H for error 27H.
4D4C
LD HL,42F8H 21 F8 42
Point Register Pair HL to 42F8H, bytes F8H-FFH of the sector (the yes/no options AC to BN).
4D4F
LD DE,505BH 11 5B 50
Point Register Pair DE to 505BH, a place in the reset data area where they are kept for 4F23H.
4D52
LD BC,0008H 01 08 00
Load Register Pair BC with 0008H: eight bytes.
4D55
LDIR ED B0
Copy Register Pair BC (8) bytes from Register Pair HL (42F8H) to Register Pair DE (505BH-5062H). The buffer at 4200H is overwritten later by the GAT; 4F23H tests option BD in the copy of byte F9H at 505CH.
4D57
LD HL,(42F0H) 2A F0 42
Load Register Pair HL from 42F0H-42F1H: bytes F0H-F1H, options AA, AB, AG, AI, AR, AS and AT, BC, BE, BK.
4D5A
LD (436CH),HL 22 6C 43
Store Register Pair HL (bytes F0H-F1H) at 436CH-436DH, where the DOS and the overlays test the options.
4D5D
LD HL,(42F2H) 2A F2 42
Load Register Pair HL from 42F2H-42F3H, bytes F2H-F3H of the sector.
4D60
LD (436EH),HL 22 6E 43
Store Register Pair HL (bytes F2H-F3H) at 436EH-436FH.
4D63
LD A,(42A0H) 3A A0 42
Fetch byte A0H at 42A0H into Register A: option AL, the number of drives.
4D66
LD (439FH),A 32 9F 43
Store Register A (option AL) at 439FH, where SYS2, SYS8 and 4DDBH read the number of drives.
4D69
LD (477AH),A 32 7A 47
Store Register A (option AL) at 477AH, the operand of the CP at 4779H, where the drive select routine checks drive numbers.
4D6C
DEC A 3D
DECrement Register A (option AL): 1-4 become 0-3, and 0 becomes FFH.
4D6D
CP 04H FE 04
Compare Register A against 04H. The NO CARRY FLAG is set unless option AL was 1-4.
4D6F
If the NO CARRY FLAG is set (option AL is 0 or above 4), JUMP to 4DD1H for error 27H.
4D71
LD A,(42A1H) 3A A1 42
Fetch byte A1H at 42A1H into Register A: option AW, the number of write-with-verify tries.
4D74
LD (4ABAH),A 32 BA 4A
Store Register A (option AW) at 4ABAH, the operand of the LD B at 4AB9H.
4D77
LD A,(42A2H) 3A A2 42
Fetch byte A2H at 42A2H into Register A: option AN, the default drive of DIR.
4D7A
LD (43A0H),A 32 A0 43
Store Register A (option AN) at 43A0H, read by DIR (SYS8) when no drive is given.
4D7D
LD A,(42A3H) 3A A3 42
Fetch byte A3H at 42A3H into Register A: option AO, the first drive searched for room for a new file.
4D80
LD (43A1H),A 32 A1 43
Store Register A (option AO) at 43A1H, read by SYS2 when it creates a file.
4D83
LD A,(42A6H) 3A A6 42
Fetch byte A6H at 42A6H into Register A: option AM, the number of tries of a disk read or write.
4D86
LD (465AH),A 32 5A 46
Store Register A (option AM) at 465AH, the operand of the LD B at 4659H.
4D89
LD A,(42A9H) 3A A9 42
Fetch byte A9H at 42A9H into Register A: option BJ, the CPU speed factor.
4D8C
LD (43A2H),A 32 A2 43
Store Register A (option BJ) at 43A2H, where the overlays find the CPU speed factor.
4D8F
LD (4CEFH),A 32 EF 4C
Store Register A (option BJ) at 4CEFH, the operand of the LD E at 4CEEH (the passes of the delay routine).
4D92
LD L,06H 2E 06
Load Register L with 06H, the FDC status delay count for a standard CPU (47E3H).
4D94
LD DE,2400H 11 00 24
Load Register Pair DE with 2400H, the index pulse time-out for a standard CPU (47F3H).
4D97
PUSH AF F5
Save Register Pair AF (Register A = option BJ) onto the stack.
4D98
GOSUB to 4C92H to multiply Register L (6) by Register A (option BJ): Register Pair HL = 6 x BJ, Register A = the high byte.
4D9B
OR H B4
OR Register H into Register A (the product's high byte). The NZ FLAG is set if 6 x BJ is above 255.
4D9C
If the NZ FLAG is set (the product does not fit in one byte), JUMP to 4DD1H for error 27H.
4D9E
LD A,L 7D
Load Register A with Register L, the product 6 x BJ (it fits in one byte).
4D9F
LD (47E4H),A 32 E4 47
Store Register A (6 x BJ) at 47E4H, the operand of the LD A at 47E3H (the status delay).
4DA2
POP AF F1
Restore Register Pair AF from the stack: Register A = option BJ.
4DA3
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = 2400H.
4DA4
GOSUB to 4C94H to multiply Register Pair HL (2400H) by Register A (option BJ): Register A = the high byte, Register Pair HL = the low 16 bits.
4DA7
OR A B7
OR Register A (the product's high byte) with itself. The NZ FLAG is set if 2400H x BJ is above FFFFH.
4DA8
If the NZ FLAG is set (too large), JUMP to 4DD1H for error 27H.
4DAA
LD (47F4H),HL 22 F4 47
Store Register Pair HL (2400H x BJ) at 47F4H, the operand of the LD DE at 47F3H (the index pulse time-out).
4DAD
LD A,(42A8H) 3A A8 42
Fetch byte A8H at 42A8H into Register A: option AX, the highest character sent to the printer as it is.
4DB0
LD (4370H),A 32 70 43
Store Register A (option AX) at 4370H, read by J-K-L (SYS3) and the LIST/PRINT commands.
4DB3
LD HL,(4049H) 2A 49 40
Load Register Pair HL with HIMEM from 4049H: the top of memory found at 4D13H.
4DB6
LD DE,(42D0H) ED 5B D0 42
Load Register Pair DE from 42D0H-42D1H: option AP, the HIMEM wanted (0 = leave it).
4DBA
LD A,D 7A
Load Register A with Register D, option AP's high byte.
4DBB
OR E B3
OR Register E (the low byte) into Register A. The Z FLAG is set if option AP is 0.
4DBC
If the Z FLAG is set (option AP = 0), JUMP to 4DC4H to keep the top of memory in Register Pair HL.
4DBE
OR A B7
OR Register A with itself to clear the CARRY FLAG for the SBC.
4DBF
SBC HL,DE ED 52
SUBtract Register Pair DE (option AP) from Register Pair HL (the top of memory). The CARRY FLAG is set if option AP is above the top of memory.
4DC1
If the CARRY FLAG is set (option AP is above the top of memory), JUMP to 4DC4H. Bug
Register Pair HL now holds the top of memory minus option AP (a wrapped value), not the top of memory, and that is what 4DC4H stores as HIMEM.
4DC3
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = option AP.
4DC4
LD (4049H),HL 22 49 40
Store Register Pair HL at 4049H as HIMEM: the top of memory, option AP, or (the bug above) the difference.
4DC7
XOR A AF
Set Register A to 00H: drive 0, the first PDRIVE record.
4DC8
LD DE,4371H 11 71 43
Point Register Pair DE to 4371H, the in-memory PDRIVE table (10 bytes per drive, drives 0-3).
4DCB
LD IX,4200H DD 21 00 42
Load Index Register IX with 4200H, the first PDRIVE record in the system data sector (16 bytes per drive, drives 0-9).
4DCF
JUMP to 4DD7H to check all ten PDRIVE records and copy those of the drives in use.
4DD1
LD A,27H 3E 27
Load Register A with error code 27H (ILLEGAL INITIALIZATION DATA ON SYSTEM DISKETTE).
4DD3
PUSH AF F5
Save Register Pair AF (Register A = the error code) onto the stack for SYS4. 4D41H (a read error) and 4F05H come here with their own code.
4DD4
LD A,46H 3E 46
Load Register A with 46H, the RST 28H code of SYS4 function 2, which sets bit 2 of 436AH (so the SYS1 exit later reports DOS FATAL ERROR) and displays the error.
4DD6
RST 28H EF
RST 28H with Register A = 46H: call SYS4 with the error code on the stack. It does not come back here.

PDRIVE Record Loop
Register A = drive number 0-9, Index Register IX = its record in the sector, Register Pair DE = the next byte of the table at 4371H.

4DD7
LD BC,000AH 01 0A 00
Load Register Pair BC with 000AH, the ten bytes of a record kept in memory.
4DDA
PUSH AF F5
Save Register Pair AF (Register A = the drive number) onto the stack.
4DDB
CP (IY+1FH) FD BE 1F
Compare Register A (the drive number) against option AL at (IY+1FH) (Index Register IY = 4380H), 439FH. The CARRY FLAG is set for a drive that exists.
4DDE
If the NO CARRY FLAG is set (the drive is not counted by option AL), JUMP to 4DE5H: it is checked but not copied.
4DE0
PUSH IX DD E5
Save Index Register IX (the record in the sector) onto the stack.
4DE2
POP HL E1
Restore it into Register Pair HL: Register Pair HL = the record in the sector.
4DE3
LDIR ED B0
Copy Register Pair BC (10) bytes from Register Pair HL (the record) to Register Pair DE (the table at 4371H + 10 x drive); Register Pair DE moves on to the next drive's record, Register Pair BC becomes 0.
4DE5
LD A,(IX+02H) DD 7E 02
Fetch byte +2 of the record from (IX+02H) (Index Register IX = the record in the sector) into Register A.
4DE8
AND 1CH E6 1C
AND Register A with 1CH, keeping bits 2-4: the interface type (TI A-E). The Z FLAG is set if there is none.
4DEA
If the Z FLAG is set (no interface type), JUMP to 4DD1H for error 27H. All ten records must have one.
4DEC
LD C,10H 0E 10
Load Register C with 10H: with Register B = 0, Register Pair BC = 16, the length of a record in the sector.
4DEE
ADD IX,BC DD 09
ADD Register Pair BC (16) to Index Register IX: the next record in the sector.
4DF0
POP AF F1
Restore Register Pair AF from the stack: Register A = the drive number.
4DF1
INC A 3C
INCrement Register A, the drive number, to the next PDRIVE record.
4DF2
CP 0AH FE 0A
Compare Register A against 0AH. The CARRY FLAG is set while drives 0-9 remain.
4DF4
If the CARRY FLAG is set (drives left), LOOP BACK to 4DD7H.

4DF6H - Reset: Set Up the Keyboard, Display and Directory Mark

Changes the resident code according to the SYSTEM options. Register C holds byte F8H of the system data sector, Register B byte F9H, Register E byte F0H (436CH) and Register D byte F1H (436DH).

4DF6
LD A,(42FAH) 3A FA 42
Fetch byte FAH of the system data sector at 42FAH into Register A (bit 7 = option BN).
4DF9
BIT 7,A CB 7F
Test bit 7 of Register A (byte FAH): option BN, write directory sectors with data address mark F8H (FDC command ABH) instead of FAH. The Z FLAG is set for N.
4DFB
If the Z FLAG is set (BN = N), JUMP to 4E02H and keep the FDC command A9H at 463DH.
4DFD
LD A,ABH 3E AB
Load Register A with ABH, the FDC Write Sector command with data address mark F8H.
4DFF
LD (463DH),A 32 3D 46
Store Register A (ABH) at 463DH, the operand of the LD A at 463CH: every directory write now uses mark F8H.
4E02
LD BC,(42F8H) ED 4B F8 42
Load Register Pair BC from 42F8H-42F9H: Register C = byte F8H (options AC, AD, AE, AF, AQ, AJ, AU) and Register B = byte F9H (options AY, AZ, BA, BD, BF, BG, BH).
4E06
LD DE,(436CH) ED 5B 6C 43
Load Register Pair DE from 436CH-436DH: Register E = byte F0H (options AA, AB, AG, AI, AR, AS) and Register D = byte F1H.
4E0A
BIT 6,E CB 73
Test bit 6 of Register E (byte F0H): option AB, RUN-ONLY. The Z FLAG is set for N.
4E0C
If the Z FLAG is set (AB = N), JUMP to 4E16H.
4E0E
SET 2,(IY-17H) FD CB E9 D6
RUN-ONLY: set bit 2 of (IY-17H) (Index Register IY = 4380H), 4369H. The key combination check (45C3H) then ignores D-F-G, 1-2-3 and J-K-L, as if options AD, AE and AF were N.
4E12
RES 6,(IY-13H) FD CB ED B6
Clear bit 6 of (IY-13H) (Index Register IY = 4380H), 436DH: option BC (pause and cancel of chaining) is forced to N.
4E16
BIT 0,C CB 41
Test bit 0 of Register C (byte F8H): option AU, the repeat key. The Z FLAG is set for N.
4E18
If the Z FLAG is set (AU = N), JUMP to 4E28H; the JR at 4538H stays unconditional (no repeat).
4E1A
LD A,20H 3E 20
Load Register A with 20H, the opcode of JR NZ.
4E1C
LD (4538H),A 32 38 45
Store Register A (20H) at 4538H: the keyboard driver now makes repeats when the countdown runs out.
4E1F
LD A,(42A7H) 3A A7 42
Fetch byte A7H at 42A7H into Register A: option AV, the ticks before the first repeat.
4E22
LD (4578H),A 32 78 45
Store Register A (option AV) at 4578H, the operand of the LD A at 4577H (the delay for a new key).
4E25
LD (452FH),A 32 2F 45
Store Register A (option AV) at 452FH, the operand of the LD A at 452EH (the delay after a key is released).
4E28
LD A,(42A5H) 3A A5 42
Fetch byte A5H at 42A5H into Register A: option BI, the cursor character (0 = keep the standard one).
4E2B
OR A B7
OR Register A (option BI) with itself. The Z FLAG is set for 0.
4E2C
If the Z FLAG is set (BI = 0), JUMP to 4E31H and keep 5FH, the standard cursor.
4E2E
LD (4501H),A 32 01 45
Store Register A (option BI) at 4501H, the operand of the LD (HL) at 4500H in the cursor routine.
4E31
BIT 1,C CB 49
Test bit 1 of Register C (byte F8H): option AJ, the NEWDOS/80 keyboard and display drivers. The Z FLAG is set for N.
4E33
If the Z FLAG is set (AJ = N), JUMP to 4E48H: the ROM's drivers stay in the control blocks.
4E35
LD A,(3840H) 3A 40 38
Read keyboard row 6 at 3840H (ENTER, CLEAR, BREAK, up, down, left, right, space) into Register A.
4E38
BIT 3,A CB 5F
Test bit 3 of Register A (keyboard row 6): the up-arrow key. The NZ FLAG is set if it is held.
4E3A
If the NZ FLAG is set (up-arrow held during the reset), JUMP to 4E48H: the drivers are not installed (the manual says AJ = N is forced, for programs that overlay the DOS).
4E3C
LD HL,4516H 21 16 45
Point Register Pair HL to 4516H, SYS0's keyboard driver.
4E3F
LD (4016H),HL 22 16 40
Store Register Pair HL (4516H) at 4016H-4017H, the driver address in the keyboard's device control block.
4E42
LD HL,4505H 21 05 45
Point Register Pair HL to 4505H, SYS0's display driver.
4E45
LD (401EH),HL 22 1E 40
Store Register Pair HL (4505H) at 401EH-401FH, the driver address in the display's device control block.
4E48
LD HL,3C00H 21 00 3C
Point Register Pair HL to 3C00H, the first byte of the screen, to test for the lower case hardware.
4E4B
LD A,61H 3E 61
Load Register A with 61H, a lower case a, which only the lower case hardware can hold.
4E4D
LD (HL),A 77
Store Register A (61H) on the screen at Register Pair HL (3C00H).
4E4E
CP (HL) BE
Compare Register A (61H) against the screen byte at Register Pair HL. Without the lower case modification the screen memory cannot hold 61H, and the NZ FLAG is set.
4E4F
LD (HL),20H 36 20
Store 20H (a space) back on the screen at Register Pair HL (3C00H). LD does not change the flags.
4E51
If the NZ FLAG is set (no lower case hardware), JUMP to 4E6AH: options BF and BG are ignored.
4E53
BIT 2,B CB 50
Test bit 2 of Register B (byte F9H): option BF, the lower case driver (LCDVR). The Z FLAG is set for N.
4E55
If the Z FLAG is set (BF = N), JUMP to 4E61H.
4E57
LD A,4FH 3E 4F
Load Register A with 4FH, the opcode of LD C,A.
4E59
LD (4593H),A 32 93 45
Store Register A (4FH) at 4593H, replacing the RET: the keyboard driver goes on to the letter case handling at 4594H.
4E5C
LD A,38H 3E 38
Load Register A with 38H, the opcode of JR C.
4E5E
LD (4505H),A 32 05 45
Store Register A (38H) at 4505H: the display driver sends only input requests straight to the ROM and stores characters 20H-7FH itself, keeping lower case.
4E61
BIT 1,B CB 48
Test bit 1 of Register B (byte F9H): option BG (LC). The NZ FLAG is set for Y.
4E63
If the NZ FLAG is set (BG = Y), JUMP to 4E6AH and keep the RET at 45B4H (letters keep their flipped case).
4E65
LD A,00H 3E 00
Load Register A with 00H, the opcode of NOP, to replace the RET at 45B4H.
4E67
LD (45B4H),A 32 B4 45
Store Register A (00H) at 45B4H: letters fall into 45B5H and are made upper case.
4E6A
BIT 0,B CB 40
Test bit 0 of Register B (byte F9H): option BH, a blinking cursor. The Z FLAG is set for N.
4E6C
If the Z FLAG is set (BH = N), JUMP to 4E73H.
4E6E
LD A,C8H 3E C8
Load Register A with C8H, the opcode of RET Z.
4E70
LD (4502H),A 32 02 45
Store Register A (C8H) at 4502H in the cursor routine, which then alternates the cursor with the character under it.
4E73
BIT 7,C CB 79
Test bit 7 of Register C (byte F8H): option AC, the keyboard debounce. The NZ FLAG is set for Y.
4E75
If the NZ FLAG is set (AC = Y), JUMP to 4E7CH and keep the debounce test.
4E77
LD A,3EH 3E 3E
Load Register A with 3EH, the opcode of LD A,n.
4E79
LD (457DH),A 32 7D 45
Store Register A (3EH) at 457DH: the JR Z of the debounce test becomes LD A,EEH and the test is skipped.
4E7C
BIT 6,C CB 71
Test bit 6 of Register C (byte F8H): option AD, J-K-L. The Z FLAG is set for N.
4E7E
If the Z FLAG is set (AD = N), JUMP to 4E85H.
4E80
LD A,C0H 3E C0
Load Register A with C0H, the opcode of RET NZ.
4E82
LD (45EEH),A 32 EE 45
Store Register A (C0H) at 45EEH: J-K-L now falls through to the screen print at 45EFH.
4E85
BIT 4,C CB 61
Test bit 4 of Register C (byte F8H): option AF, D-F-G. The Z FLAG is set for N.
4E87
If the Z FLAG is set (AF = N), JUMP to 4E8EH.
4E89
LD A,20H 3E 20
Load Register A with 20H, the opcode of JR NZ.
4E8B
LD (45CCH),A 32 CC 45
Store Register A (20H) at 45CCH: D-F-G now falls through to MINI-DOS at 45CEH.
4E8E
BIT 2,C CB 51
Test bit 2 of Register C (byte F8H): option AQ, the CLEAR key. The Z FLAG is set for N.
4E90
If the Z FLAG is set (AQ = N), JUMP to 4E96H: the CLEAR key stays filtered out.
4E92
XOR A AF
Set Register A to 00H, a value no key can return, for the CLEAR filter.
4E93
LD (4590H),A 32 90 45
Store Register A (00H) at 4590H, the operand of the CP at 458FH: the keyboard driver no longer drops 1FH (CLEAR).
4E96
BIT 5,C CB 69
Test bit 5 of Register C (byte F8H): option AE, 1-2-3. The Z FLAG is set for N.
4E98
If the Z FLAG is set (AE = N), JUMP to 4E9FH.
4E9A
LD A,20H 3E 20
Load Register A with 20H, the opcode of JR NZ.
4E9C
LD (45D8H),A 32 D8 45
Store Register A (20H) at 45D8H: 1-2-3 now falls through to the DEBUG entry at 45DAH.
4E9F
BIT 5,E CB 6B
Test bit 5 of Register E (byte F0H): option AG, BREAK is a key. The Z FLAG is set for N.
4EA1
If the Z FLAG is set (AG = N), JUMP to 4EA7H.
4EA3
SET 4,(IY-17H) FD CB E9 E6
Set bit 4 of (IY-17H) (Index Register IY = 4380H), 4369H, recording option AG = Y. SYS0 itself does not test this bit again.

4EA7H - Reset: Screen, Banner, Date and Time

Clears the screen, routes the display to NL if option BA is Y, shows the banner and, depending on options AY and AZ, asks for the date and time. Then the date and time are displayed, the GAT of drive 0 is read and the AUTO command is run.

4EA7
LD HL,4FA8H 21 A8 4F
Point Register Pair HL to 4FA8H, the message 1CH 1FH 03H (cursor home, clear to the end of the screen).
4EAA
GOSUB to 4467H to display the message at Register Pair HL: the screen is cleared.
4EAD
LD A,(42F9H) 3A F9 42
Fetch byte F9H of the system data sector at 42F9H into Register A.
4EB0
BIT 5,A CB 6F
Test bit 5 of Register A (byte F9H): option BA, ROUTE,DO,NL at reset. The Z FLAG is set for N.
4EB2
If the Z FLAG is set (BA = N), JUMP to 4ECCH.
4EB4
DI F3
Disable interrupts while the display's control block and ROUTE entry 1 are being changed.
4EB5
LD HL,43B2H 21 B2 43
Point Register Pair HL to 43B2H, ROUTE entry 1, whose target is already the NL device (4CFCH).
4EB8
LD (4ADCH),HL 22 DC 4A
Store Register Pair HL (43B2H) at 4ADCH, the operand of 4ADBH: the head of the ROUTE list.
4EBB
LD DE,401DH 11 1D 40
Point Register Pair DE to 401DH, the display's device control block.
4EBE
LD (HL),E 73
Store Register E (1DH) at Register Pair HL, entry +0: the low byte of the device served.
4EBF
INC HL 23
INCrement Register Pair HL to entry +1, the high byte of the device served.
4EC0
LD (HL),D 72
Store Register D (40H) at Register Pair HL, entry +1: the entry serves 401DH, the display.
4EC1
INC HL 23
INCrement Register Pair HL to entry +2, the saved type byte.
4EC2
LD A,(DE) 1A
Fetch the display control block's type byte at Register Pair DE (401DH) into Register A.
4EC3
LD (HL),A 77
Store Register A (the original type) at Register Pair HL, entry +2.
4EC4
INC HL 23
INCrement Register Pair HL to entry +3, the link.
4EC5
LD A,C0H 3E C0
Load Register A with C0H, the type byte of a routed device.
4EC7
LD (DE),A 12
Store Register A (C0H) at Register Pair DE (401DH): the display is now routed, and the ROM's dispatcher sends its I/O to 4033H.
4EC8
XOR A AF
Set Register A to 00H for the link: no further entry for the display.
4EC9
LD (HL),A 77
Store Register A (00H) at Register Pair HL, the link's low byte (entry +3).
4ECA
INC HL 23
INCrement Register Pair HL to entry +4, the link's high byte.
4ECB
LD (HL),A 77
Store Register A (00H) at Register Pair HL, the link's high byte: link 0000H, this is the only entry.
4ECC
EI FB
Enable interrupts again (also reached from 4EB2H when option BA is N).
4ECD
LD HL,4FABH 21 AB 4F
Point Register Pair HL to 4FABH, the banner (NEWDOS/80 in graphics, MODEL I V2.0 and the zap level).
4ED0
GOSUB to 4467H to display the banner at Register Pair HL (lost if the display was routed to NL).
4ED3
LD A,(43ABH) 3A AB 43
Fetch the byte at 43ABH into Register A: A5H if the DOS was active before this reset.
4ED6
CP A5H FE A5
Compare Register A against A5H. The Z FLAG is set after a reset while the DOS was active.
4ED8
LD A,(42F9H) 3A F9 42
Fetch byte F9H of the system data sector at 42F9H into Register A (bit 7 option AY, bit 6 option AZ). LD does not change the flags.
4EDB
If the NZ FLAG is set (a power-on), JUMP to 4EDFH with both options.
4EDD
RES 7,A CB BF
A reset while the DOS was active: clear bit 7 of Register A, so that only option AZ counts.
4EDF
AND C0H E6 C0
AND Register A with C0H, keeping options AY and AZ. After a power-on either one asks for the date and time (the manual says AY alone).
4EE1
If the NZ FLAG is set (Register A shows a Y), GOSUB to 4F3DH to ask for the date and time.
4EE4
LD HL,5089H 21 89 50
Point Register Pair HL to 5089H, the date and time line (spaces filled in below).
4EE7
PUSH HL E5
Save Register Pair HL (5089H) onto the stack, to display the line afterwards.
4EE8
GOSUB to 44C2H to put the date as MM/DD/YY at Register Pair HL (5089H).
4EEB
LD HL,5093H 21 93 50
Point Register Pair HL to 5093H, the time's place in the line.
4EEE
GOSUB to 44A7H to put the time as HH:MM:SS at Register Pair HL (5093H).
4EF1
POP HL E1
Restore Register Pair HL from the stack: 5089H, the line.
4EF2
GOSUB to 4467H to display the date and time line at Register Pair HL.
4EF5
XOR A AF
Set Register A to 00H: directory sector 0, the GAT.
4EF6
LD (4930H),A 32 30 49
Store Register A (00H) at 4930H, the directory sector 48F3H will read.
4EF9
LD HL,4F05H 21 05 4F
Point Register Pair HL to 4F05H, the place to continue after the read.
4EFC
PUSH HL E5
Save Register Pair HL (4F05H) onto the stack as the return address.
4EFD
PUSH DE D5
Save Register Pair DE onto the stack, as 490AH does on entry, for the POP DE at 491DH.
4EFE
PUSH BC C5
Save Register Pair BC onto the stack, for the POP BC at 491CH.
4EFF
LD HL,4200H 21 00 42
Point Register Pair HL to 4200H, the buffer for the read at 4914H.
4F02
JUMP to 4911H to read the boot sector of drive 0 (the current drive), take the directory's lump from its byte 2 into drive 0's PDRIVE record, and read the GAT into 4200H. It returns to 4F05H with the Z FLAG for success.
4F05
If the NZ FLAG is set (Register A = 11H, the GAT could not be read), JUMP to 4DD3H to report the error through SYS4.
4F08
LD DE,4318H 11 18 43
Point Register Pair DE to 4318H, the DOS command buffer.
4F0B
PUSH DE D5
Save Register Pair DE (4318H) onto the stack.
4F0C
PUSH BC C5
Save Register Pair BC onto the stack; the LDIR below uses it as the count.
4F0D
LD HL,42E0H 21 E0 42
Point Register Pair HL to 42E0H, bytes E0H-FFH of the GAT: the AUTO command (0DH alone = none).
4F10
LD BC,0020H 01 20 00
Load Register Pair BC with 0020H: the 32 bytes of the AUTO command field.
4F13
LDIR ED B0
Copy Register Pair BC (32) bytes from Register Pair HL (the GAT's AUTO command) to Register Pair DE (the command buffer at 4318H).
4F15
LD HL,43ABH 21 AB 43
Point Register Pair HL to 43ABH, the mark of an active DOS.
4F18
LD (HL),A5H 36 A5
Store A5H at Register Pair HL (43ABH): the DOS is now active, which the next reset tests.
4F1A
POP BC C1
Restore Register Pair BC from the stack (saved at 4F0CH).
4F1B
POP HL E1
Restore Register Pair HL from the stack: 4318H, the AUTO command in the command buffer.
4F1C
XOR A AF
Set Register A to 00H; it is reloaded before it is used below.
4F1D
BIT 6,(IY-14H) FD CB EC 76
Test bit 6 of (IY-14H) (Index Register IY = 4380H), 436CH: option AB, RUN-ONLY.
4F21
If the NZ FLAG is set (RUN-ONLY), JUMP to 4F37H: the AUTO command is run and ENTER cannot skip it.
4F23
LD A,(505CH) 3A 5C 50
Fetch the copy of byte F9H at 505CH (made at 4D55H) into Register A.
4F26
BIT 3,A CB 5F
Test bit 3 of Register A (byte F9H): option BD, ENTER may skip the AUTO command. The Z FLAG is set for N.
4F28
If the Z FLAG is set (BD = N), JUMP to 4F37H to run the AUTO command.
4F2A
LD A,(3840H) 3A 40 38
Read keyboard row 6 at 3840H into Register A; bit 0 is the ENTER key.
4F2D
RRCA 0F
Rotate Register A right: bit 0 (ENTER) goes into the CARRY FLAG.
4F2E
If the CARRY FLAG is set (ENTER is held), JUMP to 4400H, DOS READY, without the AUTO command.
4F31
LD A,(HL) 7E
Fetch the first character of the AUTO command at Register Pair HL (4318H) into Register A.
4F32
CP 0DH FE 0D
Compare Register A against 0DH. The Z FLAG is set if there is no AUTO command.
4F34
If the Z FLAG is set (no AUTO command), JUMP to 4400H, DOS READY.
4F37
GOSUB to 4467H to display the AUTO command at Register Pair HL (4318H), ended by its 0DH.
4F3A
JUMP to 4405H to execute the command at Register Pair HL (4318H). The reset is over; 4D00H-51DAH may now be overwritten by the overlays.

4F3DH - Ask for the Date and Time

Each question is repeated until the answer is valid. The answer is typed into the command buffer at 4318H through the ROM's line input at 0040H and checked by 4F6FH against the table at 509CH or 50A2H.

Date Question Loop

4F3D
LD HL,5063H 21 63 50
Point Register Pair HL to 5063H, the question DATE? (MM/DD/YY).
4F40
GOSUB to 4F64H to display the question at Register Pair HL and read the answer into 4318H; Register Pair HL returns 4318H.
4F43
LD BC,509CH 01 9C 50
Point Register Pair BC to 509CH, the date limits (month 1-12, day 1-31, year 0-99).
4F46
LD DE,4046H 11 46 40
Point Register Pair DE to 4046H, the month; the day (4045H) and the year (4044H) follow downward.
4F49
LD A,2FH 3E 2F
Load Register A with 2FH (ASCII slash), the separator expected between the values.
4F4B
GOSUB to 4F6FH to check the answer at Register Pair HL and store the three values from Register Pair DE down. The Z FLAG is set if it was valid.
4F4E
If the NZ FLAG is set (an invalid answer), LOOP BACK to 4F3DH to ask again.

Time Question Loop

4F50
LD HL,5076H 21 76 50
Point Register Pair HL to 5076H, the question TIME? (HH:MM:SS).
4F53
GOSUB to 4F64H to display the question at Register Pair HL and read the answer into 4318H.
4F56
LD BC,50A2H 01 A2 50
Point Register Pair BC to 50A2H, the time limits (hours 0-23, minutes 0-59, seconds 0-59).
4F59
LD DE,4043H 11 43 40
Point Register Pair DE to 4043H, the hours; the minutes (4042H) and seconds (4041H) follow downward.
4F5C
LD A,3AH 3E 3A
Load Register A with 3AH (ASCII colon), the separator expected between the values.
4F5E
GOSUB to 4F6FH to check and store the answer. The Z FLAG is set if it was valid.
4F61
If the NZ FLAG is set (an invalid answer), LOOP BACK to 4F50H to ask again.
4F63
RET C9
RETurn to 4EE4H with the date (4044H-4046H) and time (4041H-4043H) set.
4F64
GOSUB to 4467H to display the question at Register Pair HL.
4F67
LD HL,4318H 21 18 43
Point Register Pair HL to 4318H, the command buffer, for the answer.
4F6A
LD B,09H 06 09
Load Register B with 09H, the most characters the answer may have (8 are needed for MM/DD/YY or HH:MM:SS).
4F6C
JUMP to the ROM's line input at 0040H, which reads a line of up to Register B characters into the buffer at Register Pair HL and returns to the caller of 4F64H.

4F6FH - Check and Store a Date or Time

Register Pair HL points to the typed answer, Register Pair DE to the first of three clock bytes (stored downward), Register Pair BC to three pairs of (lowest value, number of values), and Register A holds the separator. Each value must be two digits and within its range. On exit the Z FLAG is set if all three were valid and the line ends after them. Interrupts are off meanwhile, so that the clock does not change while it is being set.

4F6F
LD (4FA0H),A 32 A0 4F
Store Register A (the separator, slash or colon) at 4FA0H, the operand of the CP at 4F9FH.
4F72
DI F3
Disable interrupts, so that the clock routine cannot change the clock bytes while they are stored.
4F73
PUSH BC C5
Save Register Pair BC (the limits table) onto the stack.
4F74
LD B,03H 06 03
Load Register B with 03H, the three values to read.

Value Loop
Register Pair HL = the answer text, Register Pair DE = the clock byte, the stack top = the limits pointer, Register B = values left.

4F76
LD A,(HL) 7E
Fetch the first digit at Register Pair HL into Register A.
4F77
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A, turning a digit into 0-9.
4F79
CP 0AH FE 0A
Compare Register A against 0AH. The CARRY FLAG is set only for a digit.
4F7B
INC HL 23
INCrement Register Pair HL to the second digit. INC HL does not change the flags.
4F7C
If the NO CARRY FLAG is set (not a digit), JUMP to 4FA4H: the answer is invalid.
4F7E
LD C,A 4F
Copy Register A (the tens digit) into Register C.
4F7F
RLCA 07
Rotate Register A left: the tens digit x 2 (the digit is 9 at most, so no bit is lost).
4F80
RLCA 07
Rotate Register A left again: Register A = the tens digit x 4.
4F81
ADD A,C 81
ADD Register C (the digit) to Register A: x 5.
4F82
ADD A,A 87
ADD Register A to itself: Register A = the tens digit x 10.
4F83
LD C,A 4F
Copy Register A (the tens value) into Register C.
4F84
LD A,(HL) 7E
Fetch the second digit at Register Pair HL into Register A.
4F85
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A, turning the second digit into 0-9.
4F87
CP 0AH FE 0A
Compare Register A against 0AH. The CARRY FLAG is set only for a digit.
4F89
INC HL 23
INCrement Register Pair HL past the second digit.
4F8A
If the NO CARRY FLAG is set (not a digit), JUMP to 4FA4H: invalid.
4F8C
ADD A,C 81
ADD Register C (the tens value) to Register A: the two-digit value.
4F8D
LD (DE),A 12
Store Register A (the value) at the clock byte at Register Pair DE. It is stored even if it turns out to be out of range; the question is then asked again.
4F8E
DEC DE 1B
DECrement Register Pair DE to the next clock byte.
4F8F
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer's target): Register Pair HL = the limits pointer, the stack holds the text pointer.
4F90
SUB (HL) 96
SUBtract the lowest allowed value at Register Pair HL from Register A (the value).
4F91
INC HL 23
INCrement Register Pair HL to the number of allowed values.
4F92
CP (HL) BE
Compare Register A (the value minus the lowest) against the number of values at Register Pair HL. The CARRY FLAG is set if it is in range.
4F93
INC HL 23
INCrement Register Pair HL to the next pair of limits.
4F94
If the NO CARRY FLAG is set (out of range), JUMP to 4FA4H with the text pointer on the stack.
4F96
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer's target): Register Pair HL = the text pointer again, the stack holds the limits pointer.
4F97
DECrement Register B (values left) and, if it is not 0, JUMP to 4F9EH to check the separator before the next value.
4F99
POP BC C1
All three values are good: restore Register Pair BC from the stack (the limits pointer, dropped).
4F9A
EI FB
Enable interrupts again: the clock bytes are all stored.
4F9B
JUMP to 4CD5H: it returns the Z FLAG if Register Pair HL points to the 0DH that ends the line, so nothing may follow the third value.
4F9E
LD A,(HL) 7E
Fetch the character at Register Pair HL into Register A: the separator between two values.
4F9F
CP 00H FE 00
Compare Register A against the expected separator. Self-Modifying Code
The operand at 4FA0H is stored by 4F6FH (2FH slash for the date, 3AH colon for the time).
4FA1
INC HL 23
INCrement Register Pair HL past the separator. INC HL does not change the flags.
4FA2
If the Z FLAG is set (the right separator), LOOP BACK to 4F76H for the next value.
4FA4
EI FB
Invalid answer: enable interrupts again (some clock bytes may already be changed).
4FA5
POP AF F1
Restore Register Pair AF from the stack to drop the pointer kept there (the limits pointer, or the text pointer after 4F94H). Register A gets its high byte (50H or 43H), which is not 0.
4FA6
OR A B7
OR Register A (not 0) with itself to set the NZ FLAG.
4FA7
RET C9
RETurn with the NZ FLAG: the caller asks the question again.

4FA8H - Reset Messages (Data)

The messages displayed by the reset code. The banner uses the Model I graphics characters (80H-BFH; 80H is a blank) and space compression codes (C0H-FFH display 0-63 spaces).

4FA8-4FAA
DEFB 1CH, 1FH, 03H 1C 1F 03
The clear screen message displayed first by 4EA7H: 1CH cursor home, 1FH clear to the end of the screen, 03H end of message.
4FAB-4FD5
DEFB BFH, B4H, C1H, BFH, C1H, BEH, 83H, 83H, BDH, C1H, BFH, C2H, BFH, C1H, BFH, 83H, 83H, BDH, C1H, BEH, 83H, 83H, BDH, C1H, BEH, 83H, 83H, 8DH, C3H, B8H, 87H, C1H, BEH, 83H, 83H, BDH, C1H, BEH, 83H, 83H, BDH, C2H, 80H BF B4 C1 BF C1 BE 83 83 BD C1 BF C2 BF C1 BF 83 83 BD C1 BE 83 83 BD C1 BE 83 83 8D C3 B8 87 C1 BE 83 83 BD C1 BE 83 83 BD C2 80
The banner displayed by 4ECDH, line 1: the top of the large NEWDOS/80 drawn in graphics characters (80H-BFH), with C1H-C3H giving 1-3 spaces.
4FD6-4FE6
DEFM "MODEL", 80H, "I", 80H, "V2.0", 80H, 80H, 80H, 80H, 0AH 4D 4F 44 45 4C 80 49 80 56 32 2E 30 80 80 80 80 0A
Beside the graphics on line 1: MODEL I V2.0 (80H is a blank graphics character), then 0AH, a line feed to line 2.
4FE7-5010
DEFB BFH, 82H, ADH, BFH, C1H, BFH, 83H, 83H, B3H, C1H, BFH, 9EH, ADH, BFH, C1H, BFH, C2H, BFH, C1H, BFH, C2H, BFH, C1H, B2H, 83H, 83H, BDH, C1H, A0H, 9EH, 81H, C2H, BEH, 83H, 83H, BDH, C1H, BFH, C2H, BFH, C2H, 80H BF 82 AD BF C1 BF 83 83 B3 C1 BF 9E AD BF C1 BF C2 BF C1 BF C2 BF C1 B2 83 83 BD C1 A0 9E 81 C2 BE 83 83 BD C1 BF C2 BF C2 80
Line 2 of the banner: the middle of the large NEWDOS/80 in graphics characters, with C1H-C2H giving 1-2 spaces.
5011-5021
DEFM "ZAPPED", 80H, "THROUGH", 80H, 80H, 0AH 5A 41 50 50 45 44 80 54 48 52 4F 55 47 48 80 80 0A
Beside the graphics on line 2: ZAPPED THROUGH, then 0AH, a line feed to line 3.
5022-5049
DEFB 83H, C2H, 83H, C1H, 82H, 83H, 83H, 81H, C1H, 83H, C2H, 83H, C1H, 83H, 83H, 83H, 81H, C1H, 82H, 83H, 83H, 81H, C1H, 82H, 83H, 83H, 81H, C1H, 83H, C4H, 82H, 83H, 83H, 81H, C1H, 82H, 83H, 83H, 81H, C3H 83 C2 83 C1 82 83 83 81 C1 83 C2 83 C1 83 83 83 81 C1 82 83 83 81 C1 82 83 83 81 C1 83 C4 82 83 83 81 C1 82 83 83 81 C3
Line 3 of the banner: the bottom of the graphics, ending with C3H (three spaces).
504A-505A
DEFM "90", C1H, "AND", C1H, ",B", C1H, "PATCH ", 0DH 39 30 C1 41 4E 44 C1 2C 42 C1 50 41 54 43 48 20 0D
Beside the graphics on line 3: 90 AND ,B PATCH (C1H = one space), ended by 0DH. With line 2 it reads ZAPPED THROUGH 90 AND ,B PATCH.

505BH - Reset Data

The copy of the system data sector's bytes F8H-FFH, the date and time questions, the date and time line, and the limits used to check the answers.

505B-5062
DEFB 00H x 8 00 x 8
Zeros in the file. Filled at reset with bytes F8H-FFH of the system data sector (the LDIR at 4D55H); 505CH (byte F9H) is read again at 4F23H for option BD.
5063-5075
DEFM "DATE? (MM/DD/YY) ", 03H 44 41 54 45 3F 20 20 28 4D 4D 2F 44 44 2F 59 59 29 20 03
The date question displayed by 4F3DH, ended by 03H so that the answer is typed on the same line.
5076-5088
DEFM "TIME? (HH:MM:SS) ", 03H 54 49 4D 45 3F 20 20 28 48 48 3A 4D 4D 3A 53 53 29 20 03
The time question displayed by 4F50H, ended by 03H so that the answer is typed on the same line.
5089-509B
DEFM "MM/DD/YY HH:MM:SS", 0DH 4D 4D 2F 44 44 2F 59 59 20 20 48 48 3A 4D 4D 3A 53 53 0D
The date and time line: 4EE8H puts the date at 5089H and 4EEEH the time at 5093H, then 4EF2H displays it, ended by 0DH.
509C-509D
DEFB 01H, 0CH 01 0C
Date limits read by 4F90H-4F92H, month: the lowest value 01H and the number of values 0CH (1-12).
509E-509F
DEFB 01H, 1FH 01 1F
Date limits, day: the lowest value 01H and the number of values 1FH (1-31, for every month).
50A0-50A1
DEFB 00H, 64H 00 64
Date limits, year: the lowest value 00H and the number of values 64H (0-99).
50A2-50A3
DEFB 00H, 18H 00 18
Time limits read by 4F90H-4F92H, hours: the lowest value 00H and the number of values 18H (0-23).
50A4-50A5
DEFB 00H, 3CH 00 3C
Time limits, minutes: the lowest value 00H and the number of values 3CH (0-59).
50A6-50A7
DEFB 00H, 3CH 00 3C
Time limits, seconds: the lowest value 00H and the number of values 3CH (0-59).
50A8
DEFB 00H 00
One byte of zero after the time limits. No instruction in SYS0 uses 50A8H.

50A9H - Rest of the File (Data)

The file continues to 51DAH with bytes that nothing refers to. The overlays load over them.

50A9-50E2
DEFB 00H x 58 00 x 58
58 bytes of zeros. No instruction in SYS0 or in the reset code uses 50A9H-50E2H.
50E3
DEFB 03H 03
A single 03H byte among the zeros. No instruction in SYS0 or in the reset code uses 50E3H.
50E4-51DA
DEFB 00H x 247 00 x 247
247 bytes of zeros, never used. 51DAH is the last byte of the file; the overlay area runs on to 51FFH.