Percom DoubleDOS 4.24 for the Model I - SYS0/SYS Disassembled

Page Customization

Introduction/Summary

Percom DoubleDOS 4.24 SYS0/SYS Disassembly (Model I)

SYS0/SYS is the resident part of DoubleDOS (DBLDOS in Percom's manual), the double density disk operating system Percom Data Company supplied with the Percom Doubler for the Model I. The boot sector loads it from cylinder 1, sector 0 on and jumps to its start-up at 4E00H. It stays in memory from 4300H to 4CFFH (with a few bytes at 400CH-405CH) and holds the vector table, the interrupt routine and the clock, the double density disk driver, the file routines and the space allocation, the overlay dispatcher and the program loader. Everything else (DOS READY and the commands, opening and closing files, the error messages, DEBUG) is in the overlays SYS1/SYS to SYS7/SYS, which the dispatcher loads at 4E00H (SYS6/SYS at 5200H, SYS7/SYS at 4D00H) when a request code asks for them.

The file is 3186 bytes: a name record, the copyright record of 169 bytes (MODIFIED FOR DOUBLE DENSITY OPERATION BY JAMES W STUTSMAN - COPYRIGHT (c) 1980 - ALL RIGHTS RESERVED ...), 29 load blocks of 2887 bytes and the transfer address 4E00H. Every loaded byte is on exactly one row below. The name record is 05H 06H 11H S Y S 0 and a space: its first name byte, 11H, is the third byte of the diskette's first sector, which 4B35H reads as the directory block (see Notes). The name record and the copyright record are not loaded and have no rows.

Load Map

AddressesContents
400CH-405CHThe RST 28H and RST 30H vectors, the DOS exits 402DH and 4030H, the device vector 4033H, the interrupt counter, mask and vectors (400CH)
4300H-4314HThe drive tables and system bytes (4300H)
4358H-43FBHCode DoubleDOS added: the error hook, the keyboard driver, the block and sector conversion, the start of a transfer, the overlay entry check (4358H)
4400H-4478HThe vector table, with the Restore routine at 444BH (4400H)
4480H-44FFHThe file specification text, the system FCB, the error and DEBUG entries, the device dispatcher, the text display and print routines; 44EFH-44FFH is the last load block of the file (4480H)
4500H-45FDHThe task table, the interrupt routine, the BREAK vector, the task scheduler and the clock (4500H)
4600H-46FBHThe disk driver: drive select, seek, sector read and write with retries (4600H)
4700H-48DBHThe file routines @POSN, @BKSP, @REW, @PEOF, @READ, @WRITE, @VERF and byte I/O (4700H)
48DCH-4B96HFinding a file's sectors, giving it granules, the directory and GAT routines, multiply and divide (48DCH)
4BA0H-4CFFHThe overlay dispatcher, @RUN, @LOAD and the load module loader, the clock display and trace tasks (4BA2H)
4E00H-4F89HThe start-up and the banner, overwritten by the overlays after it has run (4E00H)

How the Disk Is Addressed

DoubleDOS counts the sectors of a diskette from cylinder 1, sector 0 (cylinder 0 holds only the single density boot sector) in blocks of ten. A block is the unit the directory and the extents name: the routine at 43A5H turns block D and sector E into the linear sector 10 x D + E, then into cylinder 1 + (10 x D + E) / 18 and sector (10 x D + E) mod 18, for the 18 sectors of a double density cylinder. A block holds two granules of five sectors, the unit of space given to files. The directory is block 17 (11H) of a system diskette: sector 0 the GAT, sector 1 the HIT, sectors 2-9 the entries. Its sectors carry the deleted data mark F8H, which a read reports as error 06H; 4B35H treats that as success and, when a directory sector has the ordinary mark, takes the directory block from byte 2 of the diskette's logical sector 0.

How a Sector Is Read or Written

StepWhat the code does
1The entry (46DDH read, 46E6H write, 46EFH write with the deleted data mark, 46F3H read back) passes the command and four parameter bytes to 4671H: the tries, the error code base and the two instruction bytes of the transfer loop at 4698H.
2The drive is selected with its own head position (4600H): the controller's track register is saved and loaded per drive in 4300H-4303H, and a drive whose motor was off gets a delay of about a second.
3The sector and cylinder go to the controller (43A5H) and a Seek 1BH is issued when the head is elsewhere (4647H).
4With the interrupts off, the command is issued (43C9H) and the bytes are moved by polling DATA REQUEST three times for each test of BUSY (4692H).
5An error is tried again: LOST DATA at once, other errors after a Restore on a ready drive (444BH), at most three more times on a drive that is not ready (4C9BH). The error code is the base plus the number of the lowest error bit (46C8H).

Differences Between the Versions

The load blocks of SYS0/SYS are the same in DoubleDOS 4.20, 4.23 and 4.24 except for the version digit of the banner at 4F15H (30H, 33H, 34H). The name record differs: 4.20 has 05H 06H S Y S 0 and two spaces; 4.23 and 4.24 have 05H 06H 11H S Y S 0 and a space. That is the change of Percom's memo DPM-0003 (record 1, offset 2 of SYS0/SYS: 11H, then SYS0), for programs that read the directory: they take its block from byte 2 of the diskette's first sector, and 4.20 gave them 53H.

Notes

The step rate: the operands at 444CH (Restore 0BH) and 4657H (Seek 1BH) are the bytes Percom's STEPnn/PAT patch files change (records 3 and 5, offset 15): 08H/18H STEP06, 09H/19H STEP12, 0AH/1AH STEP20, 0BH/1BH STEP30. The diskette carries the STEP30 values, stepping rate 3, which the manual lists as the standard 30 ms (it calls the system diskette's rate 40 ms in another place).

The test at 45E3H-45EDH compares Register B with 4DH when the overlay last called runs at 4Dxx (SYS7/SYS). Register B holds the tries left of the transfer there, never more than 0AH, so the store that would mark the overlay as no longer in memory never runs.

Code no longer used: 4611H-4618H, 46D3H-46DCH, 47D5H-47D9H, 480AH-480DH and 4CA5H-4CA8H are bytes left in the code that nothing reaches; 4E32H-4E75H in the start-up is passed over by the jump at 4E2FH and would overwrite the DoubleDOS code at 4358H-43FBH if it ran.

The routine at 4B35H reads byte 2 of logical sector 0 again each time it meets a directory sector with the ordinary data mark; if that byte also names a block without the deleted data mark, it does not stop.

The error code of a write is the base 09H minus one plus the number of the lowest status bit (46C8H). For NOT READY, bit 7, that is 10H, the code whose message in SYS4/SYS is ILLEGAL LOGICAL FILE NUMBER, the code SYS0/SYS also gives a bad directory record (4B31H). A read of a drive that is not ready gives 08H, DEVICE NOT AVAILABLE.

Variables

SYS0/SYS's Own Bytes

Address
Size
Contents
4040H
1 byte
Interrupt Counter
Incremented on every 25 ms interrupt (4577H); its low three bits choose task slot 0-7.
404BH
1 byte
Interrupt Latch Copy
37E0H as read at the last interrupt (4520H).
404CH
1 byte
Interrupt Mask
Bits 7 (clock) and 6 (disk controller) set by the start-up.
404DH-405CH
16 bytes
Interrupt Vectors
One word for each latch bit 0-7; 4059H = 45F7H, 405BH = 4560H, the rest 4537H (RET).
4300H-4303H
4 bytes
Head Position of Drives 0-3
The track register of each drive, swapped by 4600H.
4304H-4307H
4 bytes
Directory Block of Drives 0-3
11H; changed by 4B51H from byte 2 of logical sector 0.
4308H
1 byte
Drive in Use
4309H
1 byte
Select Bit of the Drive in Use
Stored by 4621H, used by 445EH.
430AH-430BH
2 bytes
FCB of the Last File Call
Stored by 489BH.
430CH-430DH
2 bytes
Return Address of the Last File Call
Stored by 4898H; SYS4/SYS reads it.
430EH
1 byte
Request Code of the Overlay Last Loaded
02H at load (no overlay); compared by its low four bits (4BAAH).
430FH
1 byte
DEBUG Flag
01H after the start-up; bit 7 makes @RUN enter DEBUG (4C0EH).
4358H-435EH
7 bytes
Error Hook
OR A, JP M,(435AH), JP (435DH); only never run code of BASIC/CMD (5444H) would set the addresses and point @ERROR here.
44A0H-44AFH
16 bytes
System FCB
The FCB through which the dispatcher loads the overlays from drive 0, buffer 4200H.
4500H-4517H
24 bytes
Task Table
Twelve slots, each the address of a task header; 45A3H is the empty header.
45AFH-45B1H
3 bytes
Clock Task Header
Routine 45B2H and a count of runs; slot 7.
4CA9H-4CABH
3 bytes
Clock Display Task Header
Routine 4CACH and a count of runs; installed by SYS6/SYS.
4CD9H-4CDAH
2 bytes
Trace Task Header
Routine 4CDBH; installed by SYS1/SYS.

Operands Changed by the Code

Address
Size
Contents
439AH
1 byte
Last Key
The character the keyboard driver returned last (439BH).
43CEH
1 byte
Disk Command
88H, A8H or A9H, stored by 4671H.
444CH, 4657H
1 byte each
Step Rate Bytes
The Restore and Seek commands, changed by the STEPnn/PAT patches.
45A6H-45A7H
2 bytes
Slot of the Running Task
Stored by 457FH.
4645H
1 byte
SET n,A
Second byte of the bit mask instruction (4640H).
4698H-4699H
2 bytes
Transfer Instructions
From the parameters of 4671H (4681H).
46C9H
1 byte
Error Code Base
01H read, 09H write (467AH).
485EH
1 byte
Read Back Switch
00H @WRITE, 01H @VERF and full buffers in byte mode.
499AH, 49AAH, 49AEH
1 byte each
Place in the Extent, Sector in the Granule, Blocks After the Extent
The adds of 4999H, 49A9H and 49ADH.
4ABEH
1 byte
Directory Record to Write Back
Stored by 49BDH.
4B68H
1 byte
BIT n,B
Second byte of the bit test (4B64H).
4BFCH-4BFDH
2 bytes
Overlay Transfer Address
Stored by 4BE8H.
4C00H
1 byte
Saved BREAK Flag
Stored by 4BF1H around an overlay call.
4C8DH-4C8EH
2 bytes
FCB of the Loader
Stored by 4C39H.

The FCB

Offset
Size
Contents
+00H
1 byte
Open
Bit 7 set when the file is open (4892H).
+01H
1 byte
Flags
Bits 0-2 the access level (reading needs below 6, writing below 5, loading below 7); bit 4 the buffer has been changed; bit 5 the buffer must be read; bit 6 positioned; bit 7 byte mode.
+03H-+04H
2 bytes
Buffer Address
+05H
1 byte
Byte Offset in the Buffer
+06H
1 byte
Drive
+07H
1 byte
Directory Record
Bits 7-5 the entry in the sector, bits 4-0 the entry sector (4B1EH).
+08H
1 byte
End of File Offset
+09H
1 byte
Record Length
00H for 256.
+0AH-+0BH
2 bytes
Sector
The next sector (sector mode) or the sector of the position (byte mode).
+0CH-+0DH
2 bytes
End of File Sector
+0EH-+1FH
18 bytes
Extents
Five extents: the block and granule byte of the first at +0EH-+0FH, then for each later one the count of granules before it, its block and its granule byte (48DCH).

Error Codes Returned by SYS0/SYS

The messages in capitals are those SYS4/SYS shows for each code (it uses the low six bits; bit 6 has no effect in 4.24).

CodeMeaning and message (where set)
03H-08HRead, by status bit 2-7: LOST DATA DURING READ, PARITY ERROR DURING READ, DATA RECORD NOT FOUND DURING READ, ATTEMPTED TO READ LOCKED/DELETED DATA RECORD, ATTEMPTED TO READ SYSTEM DATA RECORD, DEVICE NOT AVAILABLE (46C8H)
0BH-10HWrite, by status bit 2-7: LOST DATA DURING WRITE, PARITY ERROR DURING WRITE, DATA RECORD NOT FOUND DURING WRITE, WRITE FAULT ON DISK DRIVE, WRITE PROTECTED DISKETTE, and for NOT READY 10H, ILLEGAL LOGICAL FILE NUMBER (a bug, 46CDH)
10HBad directory record: ILLEGAL LOGICAL FILE NUMBER (4B31H)
11H, 12HDIRECTORY READ ERROR, DIRECTORY WRITE ERROR (4AD1H, 4AEBH)
14H, 15HGAT READ ERROR, GAT WRITE ERROR (4B00H, 4B19H)
1BHDISK SPACE FULL (4A85H)
1CH, 1DHEND OF FILE ENCOUNTERED; past the end of file, RECORD NUMBER OUT OF RANGE (48D4H, 48D7H)
1DHAlso the end of the extent search at 44A0H (43F9H)
25HILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE (4817H, 4847H, 4C33H)
26HFILE NOT OPEN (48AFH)
58HOverlay missing: 18H with bit 6, FILE NOT IN DIRECTORY (43E6H)
5FH, 62H-64H@LOAD and the loader, with bit 6 set: PROGRAM NOT FOUND (4C25H), LOAD FILE FORMAT ERROR, MEMORY FAULT, ATTEMPTED TO LOAD READ ONLY MEMORY (4C5EH-4C87H)

Memory and Hardware Outside SYS0/SYS

Address
Size
Contents
4012H-4014H
3 bytes
RST 38H Vector
JP 4518H, stored by the start-up.
4016H-4017H
2 bytes
Keyboard Driver Address
4378H, stored by the start-up.
4036H-403CH
7 bytes
Keyboard Row Images
The ROM's, used by the driver at 4378H.
4041H-4043H
3 bytes
Seconds, Minutes, Hours
Counted by the clock task.
4044H-4046H
3 bytes
Date
Written by 4CD2H from 4046H down.
4047H-4048H
2 bytes
Lowest Free Address
5200H (4E09H).
4049H-404AH
2 bytes
Top of Memory
Found by the start-up (4E1DH).
4315H
1 byte
BREAK Flag
Not 00H: BREAK goes to the vector at 4316H-4317H (454FH).
4318H-4357H
64 bytes
Command Line
The AUTO command is copied here (4EE2H); SYS1/SYS takes up to 63 characters and a carriage return here.
4200H-42FFH
256 bytes
Sector Buffer
Directory sectors and the overlays' sectors.
4D00H-4DFFH
256 bytes
GAT Buffer
4AF0H, 4B03H.
37E0H
1 byte
Interrupt Latch
Bit 7 clock, bit 6 disk controller.
37E1H
1 byte
Drive Select Latch
37ECH-37EFH
4 bytes
Controller
Command and status, track, sector, data.
3840H, 38C0H
1 byte each
Keyboard Rows
BREAK (3840H bit 2); the keys tested by the start-up (38C0H).
3C2EH, 3C35H
4 and 8 bytes
Screen
Where the trace and clock display tasks write.

Outside Routines

AddressUse
0033HROM: Display a Character
44D5H, 4EB2H.
003BHROM: Print a Character
44E5H.
002BHROM: Scan the Keyboard
4EBAH.
03FAHROM: Decode a Key
4392H.
SYS1/SYS-SYS7/SYSThe Overlays
Called through RST 28H with the request codes of the vector table.

Disassembly

400CH - The Restart Vectors and the DOS Exits in the 4000H Area

SYS0/SYS loads a few bytes into the communication area that the ROM set up at 4000H-40FFH. The ROM's restarts RST 28H and RST 30H jump to 400CH and 400FH; programs leave through 402DH and 4030H; the ROM's device routine reaches DoubleDOS through 4033H.

400C
RST 28H vector: jump to 4BA2H, the overlay dispatcher. The ROM's RST 28H at 0028H jumps to 400CH; Register A then holds the request code that names the overlay and the job.
400F
RST 30H vector: jump to 44B4H, which calls SYS5/SYS (request code 87H), the DEBUG overlay. The ROM's RST 30H at 0030H jumps to 400FH, and 4C12H jumps here after a program is loaded when DEBUG is on.
4012-402C
DEFS 27
Not in the file: 4012H-402CH, the RST 38H vector at 4012H (which the start-up sets to JP 4518H), the keyboard, display and printer device control blocks at 4015H-402CH set up by the ROM.
402D
Jump to 4400H, DOS READY. A program ends with JP 402DH to give control back to DoubleDOS, which loads SYS1/SYS and shows DOS READY (BASIC/CMD, COPY/CMD, DOUBLE/CMD and SYS6/SYS all leave here).
4030
LD A,A3H 3E A3
Load Register A with A3H, the request code of the abnormal exit at 4030H: SYS1/SYS (low four bits 3), job A3H. A program jumps to 4030H after an error to return to DoubleDOS. While DEBUG is on, SYS1/SYS makes 4030H-4032H CALL 400FH, the entry of DEBUG (SYS1/SYS 517AH-517EH).
4032
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code A3H in Register A; SYS1/SYS does not return here.
4033
Jump to 44BBH, the device dispatcher. The ROM's device routine at 03C2H jumps to 4033H (03D1H) for a device control block it does not handle itself; Register Pair DE points at the block.
403E-403F
DEFB 21H,01H 21 01
Two bytes of the 4000H area that SYS0/SYS loads with 21H and 01H; no instruction of SYS0/SYS reads or writes 403EH or 403FH.
4040
DEFB 00H 00
The interrupt counter at 4040H: 00H at load, incremented by every 25 ms clock interrupt at 4577H, its low three bits choose which of the task slots 0-7 runs. SYS2/SYS reads it (50ABH).
4041-404A
DEFS 10
Not in the file: the clock at 4041H-4043H, the date at 4044H-4046H, the lowest free address at 4047H and the top of memory at 4049H, set at run time.
404B
DEFB 00H 00
The interrupt latch copy at 404BH: the interrupt routine stores the latch 37E0H here on each interrupt (4520H) before it tests the bits.
404C
DEFB 00H 00
The interrupt mask at 404CH: 00H at load; the start-up clears it (4E80H) and then sets bit 7 (the 25 ms clock, 4E94H) and bit 6 (the disk controller, 4E9DH). The routine at 4518H serves only the latch bits set here.
404D-4058
DEFW 4537H x 6 37 45 37 45 37 45 37 45 37 45 37 45
The vectors of interrupt latch bits 0-5 at 404DH-4058H, two bytes each, all 4537H: a RET, so these interrupts are ignored. The routine at 4538H jumps through the vector of each latch bit that is set and enabled.
4059-405A
DEFW 4537H 37 45
The vector of interrupt latch bit 6, the disk controller, at 4059H: 4537H at load; the start-up stores 45F7H here (4E99H), the routine that reads the status register to clear the interrupt.
405B-405C
DEFW 4537H 37 45
The vector of interrupt latch bit 7, the 25 ms clock, at 405BH: 4537H at load; the start-up stores 4560H here (4E90H), the task scheduler of 4560H-458DH.

4300H - Drive Tables and System Bytes

The load block 4300H-4314H. The bytes 4315H-4357H (the BREAK flag and vector, the command line buffer at 4318H) are not in the file.

4300-4303
DEFB 11H,11H,11H,11H 11 11 11 11
The track register of drives 0-3 at 4300H-4303H, one byte each, 11H at load. Before it selects another drive, 4604H-460DH stores the controller's track register 37EDH in the byte of the drive that was in use and 4619H-461AH loads the new drive's byte into 37EDH, so that each drive keeps its own head position.
4304-4307
DEFB 11H,11H,11H,11H 11 11 11 11
The directory block of drives 0-3 at 4304H-4307H, 11H (block 17, cylinder 10, sector 8 on) at load. 4B55H takes the byte of drive Register C; when a directory read finds an ordinary data mark, 4B47H-4B51H puts byte 2 of the drive's logical sector 0 here and reads again.
4308
DEFB 00H 00
The drive in use at 4308H, 00H at load: 4604H-4608H swaps the new drive number from Register C in and uses the old one to save the track register.
4309
DEFB 01H 01
The select bit of the drive in use at 4309H (01H, drive 0): stored by 4621H, written to the drive select latch 37E1H by 4461H while a Restore runs to keep the motor turning.
430A-430B
DEFW 0000H 00 00
The FCB address of the last file call at 430AH-430BH, stored by 489BH from Register Pair DE. SYS4/SYS (4E7DH) and DOUBLE/CMD read it.
430C-430D
DEFW 0000H 00 00
The return address of the last file call at 430CH-430DH, stored by 4898H: the address after the CALL in the program that called @READ, @WRITE or another file routine. SYS4/SYS reads it (4F0CH).
430E
DEFB 02H 02
The request code of the overlay last loaded at 430EH, 02H at load: its low four bits name no overlay, so the first RST 28H loads one. The dispatcher compares the low four bits (4BAAH-4BAEH) and stores each new code (4BB1H); 45EDH can clear it.
430F
DEFB 00H 00
The DEBUG flag at 430FH, 00H at load and 01H after the start-up (4EA1H). When bit 7 is set, @RUN enters DEBUG before the program (4C0EH-4C12H). SYS1/SYS sets and clears bit 7 (DEBUG on, SYS1/SYS 516BH and 5184H) and bit 4 (SYS6/SYS in memory at 5200H, SYS1/SYS 4E9BH), BASIC/CMD clears bit 4, and SYS1/SYS and SYS6/SYS test bit 5, which no file sets.
4310-4311
DEFB 00H,00H 00 00
Two bytes of 00H at 4310H-4311H; no instruction of SYS0/SYS reads or writes them.
4312
Jump to 4BA0H, which clears Register A and returns. The dispatcher at 4BA5H jumps here for a request code with bit 7 clear, which asks for no overlay.

4358H - The Error Hook

Three instructions meant as an error handler for BASIC/CMD: code at BASIC/CMD 5444H-5447H would point the @ERROR vector at 4409H to 4358H and store its own addresses at 435AH and 435DH, but that code (CMD with a DOS command) is never run, so nothing sets this hook and it is never reached.

4358
OR A B7
Set the flags from Register A, the error code passed to @ERROR at 4409H: the S FLAG is set when bit 7 of the error code is set.
4359
If the M FLAG is set (bit 7 of the error code is set), jump to the address at 435AH, 0000H at load, which BASIC/CMD stores from Register Pair HL (5441H). SYS1/SYS tests bit 5 of the opcode byte 4359H (4E23H).
435C
Jump to the address at 435DH, 0000H at load, which BASIC/CMD stores (54A8H): the handler of an error code with bit 7 clear.

435FH - Step to the Next Sector

Entered from 47CFH and 4868H when the byte offset at FCB+05H has wrapped to 00H: the buffer is used up, the sector number goes up by one and the next sector must be read before its first byte is used.

435F
SET 5,(IX+01H) DD CB 01 EE
Set bit 5 of the FCB flags at +01H through Index Register IX: the sector buffer must be read before its next byte is used (47BFH tests the bit).
4363
Jump to 4823H to add one to the record number at FCB+0AH-+0BH and return with Register A 00H and the Z FLAG set.

4366H - Read the Sector of the Next Byte

Called from 47C5H when a file read byte by byte needs a new sector in its buffer. 480EH reads the sector and adds one to the sector number at FCB+0AH-+0BH; 436AH-4373H take the one away again, so that in byte mode FCB+0AH-+0BH is the sector in the buffer.

4366
Call 480EH to read the sector of FCB+0AH-+0BH into the file's buffer. The Z FLAG returns set when the sector was read.
4369
RET NZ C0
If the NZ FLAG is set (the read failed), return with the error code in Register A.
436A
LD A,(IX+0AH) DD 7E 0A
Load Register A with the low byte of the sector number at FCB+0AH through Index Register IX, before it is lowered again.
436D
DEC (IX+0AH) DD 35 0A
Decrement the low byte of the sector number at FCB+0AH through Index Register IX, taking back the increment of 4823H.
4370
OR A B7
Set the flags from Register A, the low byte as it was before the decrement: the Z FLAG is set when it was 00H and has wrapped to FFH.
4371
If the NZ FLAG is set (no borrow from the low byte), jump to 4376H.
4373
DEC (IX+0BH) DD 35 0B
Decrement the high byte of the sector number at FCB+0BH through Index Register IX for the borrow from the low byte at +0AH.
4376
XOR A AF
Clear Register A to 00H and set the Z FLAG: no error.
4377
RET C9
Return with Register A 00H and the Z FLAG set.

4378H - The Keyboard Driver

The start-up stores 4378H at 4016H, the driver address of the keyboard device control block (4E29H-4E2CH), unless keys of bits 0 and 3 of 38C0H are held. The scan at 4378H-438DH is the ROM's own scan of 03E3H-03F8H; the key is decoded by the ROM at 03FAH, and 4397H-43A4H add a check that a key reported twice is still down.

4378
LD HL,4036H 21 36 40
Load Register Pair HL with 4036H, the ROM's image of the keyboard rows 0-6 at 4036H-403CH, one byte a row.
437B
LD BC,3801H 01 01 38
Load Register Pair BC with 3801H, the address of keyboard row 0. Register C is the row bit, shifted left for each row.
437E
LD D,00H 16 00
Load Register D with 00H, the row counter that the ROM's decode at 03FAH uses.
4380
LD A,(BC) 0A
Load Register A with the keys of the row at Register Pair BC.
4381
LD E,A 5F
Copy the keys of the row from Register A into Register E.
4382
XOR (HL) AE
Exclusive OR Register A with the image of the row at Register Pair HL: the bits that changed since the last scan are set.
4383
LD (HL),E 73
Store Register E, the keys down now, in the image of the row at Register Pair HL.
4384
AND E A3
AND Register A, the changed bits, with Register E, the keys down: the bits of keys newly pressed stay set.
4385
If the NZ FLAG is set (a key of this row was just pressed), jump to 4390H to decode it.
4387
INC D 14
Increment Register D, the row counter, for the next row.
4388
INC L 2C
Increment Register L to the image byte of the next row in Register Pair HL.
4389
RLC C CB 01
Rotate Register C, the row bit of Register Pair BC, left to the address bit of the next row.
438B
If the P FLAG is set (Register C has not reached 80H, row 7), jump back to 4380H for the next row. Rows 0-6 are scanned.
438E
Jump to 4397H with Register A 00H: no key was pressed.
4390
PUSH BC C5
Save Register Pair BC, the address of the row, on the stack.
4391
PUSH AF F5
Save Register Pair AF on the stack: Register A, the bits of the keys just pressed in this row.
4392
Call the ROM's keyboard decode at 03FAH with Register A the new key bits and Register D the row: Register A returns the character, or 00H.
4395
POP DE D1
Restore the saved Register Pair AF into Register Pair DE: Register D is now the bits of the keys just pressed in the row.
4396
POP BC C1
Restore Register Pair BC, the address of the row, from the stack.
4397
OR A B7
Set the flags from Register A, the character: the Z FLAG is set when there is none.
4398
RET Z C8
If the Z FLAG is set (no character), return with Register A 00H.
4399
CP 00H FE 00
Compare Register A, the character, with the operand at 439AH, the character returned the last time (00H at load).
439B
LD (439AH),A 32 9A 43
Store Register A, the character, in the operand byte at 439AH of the compare at 4399H, the character for the next call.
439E
RET NZ C0
If the NZ FLAG is set (a different character from the last one), return with it in Register A.
439F
LD E,A 5F
Copy the character from Register A into Register E: the same key has been reported twice.
43A0
LD A,(BC) 0A
Load Register A with the keys of the row at Register Pair BC again.
43A1
AND D A2
AND Register A with Register D, the bits of the key decoded: the Z FLAG is set when the key has been let go.
43A2
RET Z C8
If the Z FLAG is set (the key is no longer down), return with Register A 00H: a bounce of the key is not taken as a second press.
43A3
LD A,E 7B
Copy the character from Register E back into Register A.
43A4
RET C9
Return with the character in Register A and the NZ FLAG set.

43A5H - Convert a Block and Sector to Cylinder and Sector

DoubleDOS numbers the sectors of a diskette in blocks of ten from cylinder 1, sector 0 on. Called from 4651H with Register D the block, Register E the sector in it and Register A the cylinder in the track register: the sector goes to the sector register 37EEH and the cylinder to the data register 37EFH, and the Z FLAG returns set when the head is already on that cylinder.

43A5
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF': Register A, the controller's track register read at 464DH, and the flags are kept there.
43A6
PUSH BC C5
Save Register Pair BC on the stack for the return at 43C8H.
43A7
PUSH DE D5
Save Register Pair DE, the block in Register D and the sector in Register E, on the stack.
43A8
PUSH HL E5
Save Register Pair HL on the stack; the conversion uses it for the product and the quotient.
43A9
LD L,D 6A
Copy the block number from Register D into Register L.
43AA
LD H,00H 26 00
Load Register H with 00H: Register Pair HL is the block number.
43AC
LD A,0AH 3E 0A
Load Register A with 0AH, ten sectors a block, the multiplier for 4B6AH.
43AE
PUSH DE D5
Save Register Pair DE on the stack across the multiplication.
43AF
Call 4B6AH to multiply Register Pair HL by Register A: the product is returned with its low byte in Register A and its high bytes in Register Pair HL.
43B2
POP DE D1
Restore Register Pair DE, the block in Register D and the sector in Register E, from the stack.
43B3
LD H,L 65
Copy Register L into Register H, the high byte of the product (block x 10).
43B4
LD L,A 6F
Copy Register A into Register L, the low byte: Register Pair HL is the block times ten.
43B5
LD D,00H 16 00
Load Register D with 00H: Register Pair DE is the sector in the block.
43B7
ADD HL,DE 19
Add Register Pair DE to Register Pair HL: Register Pair HL is the linear sector number counted from cylinder 1, sector 0.
43B8
LD A,12H 3E 12
Load Register A with 12H, the 18 sectors of a double density cylinder, the divisor for 4B84H.
43BA
Call 4B84H to divide Register Pair HL by Register A: the quotient (the cylinder counted from 1) comes back in Register Pair HL and the remainder (the sector) in Register A.
43BD
LD H,L 65
Copy Register L, the quotient, into Register H.
43BE
LD L,A 6F
Copy Register A, the remainder, into Register L: Register L is the sector and Register H the cylinder minus 1.
43BF
INC H 24
Increment Register H to the cylinder: cylinder 0 holds only the single density boot sector, so the blocks start on cylinder 1.
43C0
LD (37EEH),HL 22 EE 37
Store Register Pair HL at 37EEH: Register L (the sector) in the sector register 37EEH and Register H (the cylinder) in the data register 37EFH, the target of a Seek.
43C3
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF' again: Register A is the track register read at 464DH.
43C4
CP H BC
Compare Register A, the cylinder the head is on, with Register H, the cylinder of the sector: the Z FLAG is set when no seek is needed.
43C5
POP HL E1
Restore Register Pair HL, saved at 43A8H, from the stack.
43C6
POP DE D1
Restore Register Pair DE, the block and sector saved at 43A7H, from the stack.
43C7
POP BC C1
Restore Register Pair BC, saved at 43A6H, from the stack.
43C8
RET C9
Return to 4654H with the Z FLAG set when the head is on the right cylinder.

43C9H - Issue the Read or Write Command

Reached by the jump at 45F0H with the command at 43CEH (stored by 4671H) and the buffer address on the stack. The interrupts are turned off for the transfer.

43C9
LD HL,37ECH 21 EC 37
Load Register Pair HL with 37ECH, the controller's command and status register.
43CC
DI F3
Turn the interrupts off: the transfer loop must take every byte in time.
43CD
LD (HL),00H 36 00
Store the command through Register Pair HL into 37ECH. The operand at 43CEH is set by 4671H: 88H Read Sector, A8H Write Sector, A9H Write Sector with the deleted data mark F8H.
43CF
LD DE,37EFH 11 EF 37
Load Register Pair DE with 37EFH, the controller's data register.
43D2
POP BC C1
Load Register Pair BC with the buffer address from the top of the stack (pushed from Register Pair HL at 468EH).
43D3
PUSH BC C5
Put Register Pair BC, the buffer address, back on the stack for 46B3H-46B5H.
43D4
LD A,(43CEH) 3A CE 43
Load Register A with the command from 43CEH, the operand of 43CDH, for the test at 44EFH.
43D7
Jump to 44EFH, which goes on to the read loop at 4692H or the write loop.
43DA-43DC
DEFB 00H,00H,00H 00 00 00
Three bytes of 00H at 43DAH-43DCH between the routines; no instruction reads or runs them.

43DDH - Check the Overlay's Directory Entry

Called from 4BD4H with Register Pair HL at the directory entry the overlay dispatcher has read and Register B its directory record.

43DD
LD A,L 7D
Copy Register L, the low byte of the entry address in Register Pair HL, into Register A.
43DE
ADD A,16H C6 16
Add 16H to Register A: Register A is the low byte of the entry's first extent at +16H, which 4BD7H uses.
43E0
BIT 4,(HL) CB 66
Test bit 4 of the attribute byte of the entry at Register Pair HL: the bit is set in every directory entry in use.
43E2
RET NZ C0
If the NZ FLAG is set (the entry is in use), return with the low byte of the extent in Register A.
43E3
LD A,B 78
Copy Register B, the directory record of the overlay, into Register A.
43E4
CP 06H FE 06
Compare Register A with 06H, the directory record of SYS4/SYS, the overlay that shows error messages.
43E6
LD A,58H 3E 58
Load Register A with 58H, the error code for a missing overlay: 18H with bit 6 set, which SYS4/SYS shows it as FILE NOT IN DIRECTORY; LD does not change the flags of 43E4H.
43E8
If the NZ FLAG is set (the missing overlay is not SYS4/SYS), jump to @ERROR at 4409H with error 58H in Register A.
43EB
HALT 76
HALT: SYS4/SYS, the overlay that would show the error, is itself missing, so the computer stops.

43ECH - Stop the Extent Search at 44A0H

Entered by the jump at 4912H with Register Pair HL at the next extent of the FCB being searched: when Register Pair HL has reached 44A0H the search ends with error 1DH, else it goes on at 48F9H. 44A0H is the end of the extents of an FCB at 4480H, the FCB that SYS1/SYS passes to @RUN for a program (SYS1/SYS 4E52H, 4E81H).

43EC
PUSH AF F5
Save Register Pair AF, the count of extents left in Register A, on the stack.
43ED
LD A,H 7C
Copy Register H, the high byte of the extent address in Register Pair HL, into Register A.
43EE
SUB 44H D6 44
Subtract 44H from Register A: Register A is 00H when Register H is 44H.
43F0
If the NZ FLAG is set (Register Pair HL is not 44A0H), jump to 48F9H to test the next extent.
43F3
LD A,L 7D
Copy Register L, the low byte of the extent address, into Register A.
43F4
SUB A0H D6 A0
Subtract A0H from Register A: Register A is 00H when Register L is A0H.
43F6
If the NZ FLAG is set, jump back to 43F0H, which goes on to 48F9H, since Register A is not 00H.
43F8
POP BC C1
Restore the saved Register Pair AF into Register Pair BC, taking it off the stack: Register Pair HL is 44A0H.
43F9
OR 1DH F6 1D
OR Register A (00H) with 1DH: Register A is 1DH, the error code of the extent search, and the NZ FLAG is set.
43FB
RET C9
Return with error 1DH in Register A and the NZ FLAG set.
43FC-43FF
DEFS 4
Not in the file: four bytes between the DoubleDOS code ending at 43FBH and the vector table at 4400H.

4400H - The Vector Table

The fixed entry points of DoubleDOS at 4400H-4478H. Each overlay entry is two instructions, LD A,nn and RST 28H, that pass a request code to the dispatcher at 4BA2H: the low four bits name the overlay (3 SYS1/SYS, 4 SYS2/SYS, 5 SYS3/SYS, 6 SYS4/SYS, 7 SYS5/SYS) and the code is handed to it. The bytes between the entries (4403H-4404H, 4408H, 440CH, 441FH, 4423H, 4427H, 442BH, 442FH, 4466H) are not in the file.

4400
LD A,93H 3E 93
DOS READY: load Register A with 93H, the request code of SYS1/SYS's command level, which shows DOS READY and takes the next command. 402DH, the start-up and every program's exit come here.
4402
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code 93H in Register A; it does not return.
4403-4404
DEFS 2
Not in the file: the two bytes after the RST 28H of 4402H, never reached because the dispatcher does not return there.
4405
LD A,B3H 3E B3
Load Register A with B3H, the request code of SYS1/SYS that runs the command line at Register Pair HL. The start-up's AUTO command (4EEAH) and BASIC/CMD (54C0H) jump to 4405H.
4407
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code B3H in Register A.
4408
DEFS 1
Not in the file: the byte after the RST 28H of 4407H, never reached.
4409
@ERROR: jump to 44B0H, which hands the error code in Register A to SYS4/SYS. SYS0/SYS jumps here on every error it cannot return to its caller; code of BASIC/CMD that is never run (5444H) would change the operand at 440AH to 4358H.
440C
DEFS 1
Not in the file: the byte after the jump of 4409H-440BH, never reached.
440D
DEBUG: jump to 44B4H, which calls SYS5/SYS, the DEBUG overlay, with Register Pair AF on the stack.
4410
Add a task: jump to 4596H, which puts the task header at Register Pair DE in slot Register A (0-11) of the task table 4500H-4517H.
4413
Remove a task: jump to 4593H, which puts the empty header 45A3H in slot Register A.
4416
Jump to 45A5H: a task routine calls 4416H to make the address after its CALL the routine of its task header, so the next run of the task starts there.
4419
Jump to 458EH: a task routine calls 4419H to take its own task out of the task table.
441C
LD A,C3H 3E C3
Parse a file specification: load Register A with C3H, the request code of SYS1/SYS (4F56H there) that copies the file specification at Register Pair HL into the buffer at Register Pair DE. BASIC/CMD, COPY/CMD and SYS6/SYS call 441CH.
441E
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code C3H in Register A.
441F
DEFS 1
Not in the file: the byte after the RST 28H of 441EH, never reached.
4420
LD A,A4H 3E A4
Open or make a file: load Register A with A4H, the request code of SYS2/SYS (4ED8H there) that opens the file of the FCB at Register Pair DE, or makes it when no drive has it and returns the C FLAG set. BASIC/CMD, COPY/CMD and SYS6/SYS call 4420H.
4422
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code A4H in Register A.
4423
DEFS 1
Not in the file: the byte after the RST 28H of 4422H, never reached.
4424
LD A,94H 3E 94
Open a file: load Register A with 94H, the request code of SYS2/SYS (4E12H there) that opens the file of the FCB at Register Pair DE with Register Pair HL the buffer and Register B the record length; @LOAD calls it with 4200H and 00H (4C16H-4C1BH).
4426
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code 94H in Register A.
4427
DEFS 1
Not in the file: the byte after the RST 28H of 4426H, never reached.
4428
LD A,95H 3E 95
Close a file: load Register A with 95H, the request code of SYS3/SYS (4E0DH there) that writes the end of file of the open FCB at Register Pair DE, gives back the granules beyond it and leaves the specification text in the FCB. BASIC/CMD, COPY/CMD and SYS6/SYS call 4428H.
442A
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code 95H in Register A.
442B
DEFS 1
Not in the file: the byte after the RST 28H of 442AH, never reached.
442C
LD A,A5H 3E A5
Kill a file: load Register A with A5H, the request code of SYS3/SYS (4F72H there) that frees the granules, the directory entries and the hash index table places of the open FCB at Register Pair DE. BASIC/CMD and SYS6/SYS call 442CH.
442E
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code A5H in Register A.
442F
DEFS 1
Not in the file: the byte after the RST 28H of 442EH, never reached.
4430
@LOAD: jump to 4C16H, which opens the file of the FCB at Register Pair DE and loads it, returning its transfer address in Register Pair HL.
4433
@RUN: jump to 4C06H, which loads the file of the FCB at Register Pair DE and jumps to its transfer address.
4436
@READ: jump to 476DH, which reads the next record of the file of the FCB at Register Pair DE (a sector into the buffer, or a logical record to Register Pair HL).
4439
@WRITE: jump to 478BH, which writes the next record of the file of the FCB at Register Pair DE.
443C
@VERF: jump to 47A8H, which writes the next record and reads the sector back to check it.
443F
@REW: jump to 4756H, which sets the file of the FCB at Register Pair DE back to its first record.
4442
@POSN: jump to 4700H, which sets the file of the FCB at Register Pair DE to record Register Pair BC.
4445
@BKSP: jump to 4737H, which sets the file of the FCB at Register Pair DE back one record.
4448
@PEOF: jump to 475FH, which sets the file of the FCB at Register Pair DE to its end.

444BH - Restore the Head of the Drive in Use

Called through the jump at 4C9CH from the retry code of 46C2H when a sector read or write has failed on a ready drive: the head goes back to cylinder 0 and the next try seeks again. The routine sits in the space after the vector at 4448H.

444B
LD A,0BH 3E 0B
Load Register A with 0BH, the Restore command with head load and stepping rate 3. Its operand at 444CH is the first of the two step rate bytes the STEPnn/PAT patches change (record 3, offset 15 of SYS0/SYS): 08H with STEP06/PAT, 09H STEP12, 0AH STEP20, 0BH STEP30, the value shipped.
444D
PUSH AF F5
Save Register Pair AF, the Restore command in Register A, on the stack while the drive is selected.
444E
Call 4600H to select drive Register C, keeping each drive's own track register value, and turn its motor on.
4451
POP AF F1
Restore Register Pair AF from the stack: Register A is the Restore command 0BH again.
4452
Call 4658H to wait until the controller is not busy and then store the command in Register A into the command register 37ECH.
4455
Call 45F3H to wait a moment and read the status register 37ECH into Register A.
4458
AND 81H E6 81
AND Register A, the status, with 81H to keep bit 7 (NOT READY) and bit 0 (BUSY).
445A
DEC A 3D
Decrement Register A: it is 00H, with the Z FLAG set, only when the status was 01H, busy on a ready drive.
445B
If the NZ FLAG is set (the Restore is over, or the drive is not ready), jump to 4669H to wait for the controller to finish and return.
445E
LD A,(4309H) 3A 09 43
Load Register A with the select bit of the drive in use from 4309H.
4461
LD (37E1H),A 32 E1 37
Store Register A in the drive select latch at 37E1H: selecting the drive again keeps its motor turning while the head steps back.
4464
Jump back to 4455H to read the status again while the Restore steps the head.
4466
DEFS 1
Not in the file: the byte after the jump of 4464H-4465H, never reached.

4467H - Display, Print and the Time and Date Texts

Four more entries of the vector table.

4467
Jump to 44CFH, which displays the text at Register Pair HL up to a 03H (not shown) or a 0DH (shown) through the ROM at 0033H.
446A
Jump to 44DFH, which sends the text at Register Pair HL to the printer up to a 03H or a 0DH through the ROM at 003BH.
446D
Jump to 4CB7H, which writes the time from 4041H-4043H as HH:MM:SS (eight characters) at Register Pair HL.
4470
Jump to 4CD2H, which writes the date from 4044H-4046H as three two digit numbers with a slash between them at Register Pair HL. DOUBLE/CMD calls 4470H.
4473
LD A,D3H 3E D3
Add a default extension: load Register A with D3H, the request code of SYS1/SYS (4FC0H there) that adds the three characters at Register Pair HL to the file specification at Register Pair DE when it has no extension. SYS6/SYS calls 4473H.
4475
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code D3H in Register A.
4476
LD A,E3H 3E E3
Parse a parameter list: load Register A with E3H, the request code of SYS1/SYS (507DH there) that reads the list in parentheses at Register Pair HL with the parameter table at Register Pair DE. SYS6/SYS calls 4476H.
4478
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code E3H in Register A.

4480H - The File Specification Template and the System FCB

A text whose 32 bytes SYS1/SYS uses as the buffer of a command's name and as the FCB of a program (4E52H there), and the FCB through which the overlay dispatcher loads the overlays.

4480-449F
DEFM "NAMENAME/EXT.PASSWORD:N " 4E 41 4D 45 4E 41 4D 45 2F 45 58 54 2E 50 41 53 53 57 4F 52 44 3A 4E 20 20 20 20 20 20 20 20 20
The 32 characters NAMENAME/EXT.PASSWORD:N and nine spaces at 4480H-449FH: the form of a file specification (an eight character name, a three character extension, a password and a drive number). SYS1/SYS parses a command's name over it and passes 4480H to @RUN as the FCB of the program (SYS1/SYS 4E52H, 4E81H).
44A0
DEFB 80H 80
FCB+00H of the system FCB at 44A0H-44AFH, 80H: bit 7 set marks the FCB as open, the test of 4892H-4894H. The dispatcher passes Register Pair DE = 44A0H to the loader (4BDFH).
44A1
DEFB 00H 00
FCB+01H, the flags, 00H: bit 7 clear, so @READ reads whole sectors (4774H); the dispatcher clears the byte for each overlay (4BC5H).
44A2
DEFB 00H 00
FCB+02H of the system FCB, 00H; no instruction of SYS0/SYS uses it for this FCB.
44A3-44A4
DEFW 4200H 00 42
FCB+03H-+04H, the buffer address: 4200H, so each sector of an overlay is read into 4200H-42FFH (the loader takes its bytes from there, 4C96H).
44A5
DEFB 00H 00
FCB+05H, the offset of the next byte in the buffer, 00H.
44A6
DEFB 00H 00
FCB+06H, the drive: 00H, the overlays are always read from drive 0.
44A7
DEFB 00H 00
FCB+07H, the directory record of the file: the dispatcher stores the overlay's record here (4BC1H).
44A8
DEFB 00H 00
FCB+08H, the byte offset of the end of file in its last sector, 00H.
44A9
DEFB 00H 00
FCB+09H, the logical record length: 00H, records of 256 bytes, whole sectors.
44AA-44AB
DEFW 0000H 00 00
FCB+0AH-+0BH, the next sector of the file: the dispatcher sets it to 0000H for each overlay (4BCAH).
44AC-44AD
DEFW FFFFH FF FF
FCB+0CH-+0DH, the end of file sector: FFFFH, so the reads of an overlay never meet an end of file (48B9H-48D2H).
44AE-44AF
DEFW 0000H 00 00
FCB+0EH-+0FH, the first extent: the block and granule byte of the overlay, copied from its directory entry (4BDCH).

44B0H - Hand an Error to SYS4/SYS

Reached by the jump at 4409H with the error code in Register A.

44B0
PUSH AF F5
Save Register Pair AF, the error code in Register A, on the stack, where SYS4/SYS finds it.
44B1
LD A,86H 3E 86
Load Register A with 86H, the request code of SYS4/SYS, the error message overlay.
44B3
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code 86H in Register A.

44B4H - Enter DEBUG

Reached by the jumps at 400FH (RST 30H) and 440DH.

44B4
PUSH AF F5
Save Register Pair AF on the stack, where SYS5/SYS, the DEBUG overlay, finds it.
44B5
LD A,87H 3E 87
Load Register A with 87H, the request code of SYS5/SYS, the DEBUG overlay.
44B7
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code 87H in Register A.

44B8H - The Device Dispatcher

Entered at 44BBH by the jump at 4033H with Index Register IX at a device control block (the ROM's device routine at 03C2H sets it). A block of type 10H is a link to another block; a type above 10H is an open FCB, served as a device by 47AEH; any other type goes to the driver at +01H-+02H.

44B8
PUSH HL E5
Save Register Pair HL, the address of the next device control block, on the stack.
44B9
POP IX DD E1
Load Index Register IX from the stack: Index Register IX points at the device control block the link named.
44BB
LD L,(IX+01H) DD 6E 01
Load Register L with the low byte of the driver address (or link) at +01H through Index Register IX.
44BE
LD H,(IX+02H) DD 66 02
Load Register H with the high byte of the driver address (or link) at +02H through Index Register IX.
44C1
LD A,(IX+00H) DD 7E 00
Load Register A with the type byte at +00H of the device control block through Index Register IX.
44C4
CP 10H FE 10
Compare Register A, the type, with 10H, the type of a link.
44C6
If the Z FLAG is set (a link), jump back to 44B8H to follow it to the block at Register Pair HL.
44C8
If the NC FLAG is set (a type above 10H: an open FCB), jump to 47AEH to read or write a byte of the file.
44CB
LD A,B 78
Copy Register B, the ROM's request (01H input, 02H output, 04H control), into Register A.
44CC
CP 02H FE 02
Compare Register A, the request, with 02H: the driver receives the flags of the request (Z FLAG output, C FLAG input) as the ROM sets them.
44CE
JP (HL) E9
Jump to the driver at Register Pair HL, the address taken from +01H-+02H of the block.

44CFH - Display a Text

Called through 4467H with Register Pair HL at the text.

44CF
PUSH HL E5
Save Register Pair HL, the address of the text, on the stack.
44D0
LD A,(HL) 7E
Load Register A with the next character of the text at Register Pair HL.
44D1
CP 03H FE 03
Compare Register A with 03H, the end of text mark that is not displayed.
44D3
If the Z FLAG is set (03H), jump to 44DDH to return.
44D5
Call the ROM's display routine at 0033H to show the character in Register A.
44D8
INC HL 23
Increment Register Pair HL to the next character of the text.
44D9
CP 0DH FE 0D
Compare Register A, the character just displayed, with 0DH, the carriage return that ends a line of text.
44DB
If the NZ FLAG is set (not 0DH), jump back to 44D0H for the next character.
44DD
POP HL E1
Restore Register Pair HL, the address of the text, from the stack.
44DE
RET C9
Return to the caller with Register Pair HL at the start of the text.

44DFH - Print a Text

Called through 446AH with Register Pair HL at the text.

44DF
PUSH HL E5
Save Register Pair HL, the address of the text, on the stack.
44E0
LD A,(HL) 7E
Load Register A with the next character of the text at Register Pair HL.
44E1
CP 03H FE 03
Compare Register A with 03H, the end of text mark that is not printed.
44E3
If the Z FLAG is set (03H), jump to 44EDH to return.
44E5
Call the ROM's printer routine at 003BH to print the character in Register A.
44E8
INC HL 23
Increment Register Pair HL to the next character of the text.
44E9
CP 0DH FE 0D
Compare Register A, the character just printed, with 0DH, the carriage return that ends a line of text.
44EB
If the NZ FLAG is set (not 0DH), jump back to 44E0H for the next character.
44ED
POP HL E1
Restore Register Pair HL, the address of the text, from the stack.
44EE
RET C9
Return to the caller with Register Pair HL at the start of the text.

44EFH - Start the Transfer Loop

Reached by the jump at 43D7H with Register A the command, Register Pair HL at 37ECH, Register Pair DE at 37EFH and Register Pair BC the buffer. These 17 bytes are the last load block of SYS0/SYS in the file, after the blocks of the start-up at 4E00H; nothing runs before the whole file is loaded, so the order has no effect.

44EF
CP 88H FE 88
Compare Register A, the command, with 88H, Read Sector (the read and the read back check of 46DDH and 46F3H).
44F1
If the Z FLAG is set (Read Sector), jump to 4692H, the wait for the first byte of the read.
44F4
LD A,(HL) 7E
Load Register A with the status register at Register Pair HL (37ECH): a write is waiting for its first DATA REQUEST.
44F5
AND 03H E6 03
AND Register A with 03H to keep bit 1 (DATA REQUEST) and bit 0 (BUSY).
44F7
If the PO FLAG is set (parity odd: exactly one of the two bits is set), jump back to 44F4H to wait. The loop ends when DATA REQUEST and BUSY are both set (the first byte is wanted) or both clear (the command has ended).
44FA
LD A,(BC) 0A
Load Register A with the first byte to write from the buffer at Register Pair BC.
44FB
INC BC 03
Increment Register Pair BC to the next byte of the buffer.
44FC
Jump to 4698H, the transfer loop, which writes the byte in Register A to the data register at Register Pair DE (37EFH).
44FF
DEFB 00H 00
A byte of 00H at 44FFH that ends the last load block; no instruction reads or runs it.

4500H - The Task Table

Twelve slots of two bytes, each the address of a task header: a word, the address of the task's routine, followed by the task's own bytes. The scheduler at 4560H runs the tasks of slots 8-11 on every 25 ms clock interrupt and one of the slots 0-7 in turn, each every eighth interrupt (200 ms). An empty slot holds 45A3H, a header whose routine is the RET at 45A2H.

4500-4517
DEFW 45A3H x 12 A3 45 A3 45 A3 45 A3 45 A3 45 A3 45 A3 45 A3 45 A3 45 A3 45 A3 45 A3 45
Slots 0-11 at 4500H-4517H, all 45A3H, the empty header, at load. The start-up puts the clock task header 45AFH in slot 7 (4EA4H-4EA9H); 4596H, reached through 4410H, fills a slot and 4593H empties it.

4518H - The Interrupt Routine

The start-up stores JP 4518H at 4012H (4E81H-4E8AH), where the ROM's RST 38H, the Z80's interrupt mode 1 entry, jumps. Every bit of the interrupt latch 37E0H that is also set in the mask at 404CH is served through its vector at 404DH-405CH (bit 0 first); then the BREAK key is checked.

4518
PUSH HL E5
Save Register Pair HL of the interrupted program on the stack.
4519
PUSH AF F5
Save Register Pair AF of the interrupted program on the stack.
451A
LD A,(37E0H) 3A E0 37
Load Register A with the interrupt latch at 37E0H: bit 7 the 25 ms clock, bit 6 the disk controller. Reading the latch clears the clock interrupt.
451D
LD HL,404BH 21 4B 40
Load Register Pair HL with 404BH, the copy of the latch, followed by the mask at 404CH and the vectors.
4520
LD (HL),A 77
Store Register A, the latch, at 404BH through Register Pair HL.
4521
INC L 2C
Increment Register L: Register Pair HL points at the interrupt mask at 404CH.
4522
AND (HL) A6
AND Register A, the latch, with the mask at Register Pair HL (404CH): only the enabled interrupts stay set.
4523
If the Z FLAG is set (no enabled interrupt is waiting), jump to 452DH to check the BREAK key.
4525
INC L 2C
Increment Register L to the low byte of the next vector in Register Pair HL (404DH for latch bit 0).
4526
RRA 1F
Rotate Register A right through the carry: the C FLAG is the latch bit of this vector.
4527
If the C FLAG is set (the interrupt of this bit is waiting), jump to 4538H to call its vector.
4529
INC L 2C
Increment Register L past the high byte of the vector in Register Pair HL.
452A
OR A B7
Set the flags from Register A, the latch bits not yet tested.
452B
If the NZ FLAG is set (more bits are waiting), jump back to 4525H for the next vector.
452D
LD A,(3840H) 3A 40 38
Load Register A with keyboard row 6 at 3840H, which holds the BREAK key in bit 2.
4530
AND 04H E6 04
AND Register A with 04H to keep bit 2, the BREAK key.
4532
If the NZ FLAG is set (BREAK is held), jump to 454FH to take the BREAK vector.
4534
POP AF F1
Restore Register Pair AF of the interrupted program from the stack.
4535
POP HL E1
Restore Register Pair HL of the interrupted program from the stack.
4536
EI FB
Turn the interrupts back on; they take effect after the RET.
4537
RET C9
Return to the interrupted program. Every unused interrupt vector of 404DH-405CH points at this RET.

4538H - Call the Vector of an Interrupt

Entered from 4527H with Register Pair HL at the low byte of the vector and Register A the latch bits not yet tested.

4538
PUSH AF F5
Save Register Pair AF, the latch bits not yet tested, on the stack.
4539
PUSH BC C5
Save Register Pair BC on the stack for the vector routine.
453A
PUSH DE D5
Save Register Pair DE on the stack for the vector routine.
453B
PUSH HL E5
Save Register Pair HL, the address of the vector, on the stack.
453C
PUSH IX DD E5
Save Index Register IX on the stack: the task scheduler loads it with a task header.
453E
LD DE,4547H 11 47 45
Load Register Pair DE with 4547H, the address the vector routine returns to.
4541
PUSH DE D5
Push Register Pair DE (4547H) on the stack as the return address of the vector routine.
4542
LD E,(HL) 5E
Load Register E with the low byte of the vector at Register Pair HL.
4543
INC L 2C
Increment Register L to the high byte of the vector in Register Pair HL.
4544
LD D,(HL) 56
Load Register D with the high byte of the vector at Register Pair HL.
4545
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is the vector routine's address.
4546
JP (HL) E9
Jump to the vector routine at Register Pair HL; it returns to 4547H.
4547
POP IX DD E1
Restore Index Register IX from the stack after the vector routine.
4549
POP HL E1
Restore Register Pair HL, the address of the vector, from the stack.
454A
POP DE D1
Restore Register Pair DE from the stack after the vector routine.
454B
POP BC C1
Restore Register Pair BC from the stack after the vector routine.
454C
POP AF F1
Restore Register Pair AF, the latch bits not yet tested in Register A, from the stack.
454D
Jump back to 4529H to step past this vector and test the next bit.

454FH - Take the BREAK Vector

Entered from 4532H when BREAK is held. When the BREAK flag at 4315H is set (a program has armed it), the flag is cleared and the interrupt returns to the address at 4316H-4317H instead of the interrupted program.

454F
LD HL,4315H 21 15 43
Load Register Pair HL with 4315H, the BREAK flag, followed by the BREAK vector at 4316H-4317H.
4552
XOR A AF
Clear Register A to 00H for the test of the flag. SYS4/SYS jumps here (4F70H).
4553
CP (HL) BE
Compare Register A (00H) with the BREAK flag at Register Pair HL (4315H).
4554
If the Z FLAG is set (the flag is 00H, BREAK is not armed), jump back to 4534H to return to the interrupted program.
4556
LD (HL),A 77
Store Register A (00H) in the BREAK flag at Register Pair HL (4315H): the key is taken once.
4557
INC L 2C
Increment Register L: Register Pair HL points at the BREAK vector at 4316H.
4558
LD A,(HL) 7E
Load Register A with the low byte of the BREAK vector at Register Pair HL (4316H).
4559
INC L 2C
Increment Register L to the high byte of the BREAK vector (4317H).
455A
LD H,(HL) 66
Load Register H with the high byte of the BREAK vector at Register Pair HL.
455B
LD L,A 6F
Copy the low byte from Register A into Register L: Register Pair HL is the BREAK vector.
455C
POP AF F1
Restore Register Pair AF of the interrupted program from the stack.
455D
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer: the BREAK vector replaces the saved Register Pair HL and Register Pair HL is the interrupted program's own again.
455E
EI FB
Turn the interrupts back on; they take effect after the RET.
455F
RET C9
Return to the BREAK vector; the address in the interrupted program is still on the stack beneath it.

4560H - The Task Scheduler

The vector of latch bit 7, the 25 ms clock (405BH, stored by 4E90H). Slots 8-11 run on every interrupt; then the counter at 4040H chooses one of slots 0-7.

4560
LD A,08H 3E 08
Load Register A with 08H, task slot 8, the first of the four slots run on every interrupt.
4562
Call 457BH to run the task of slot Register A (8).
4565
LD A,09H 3E 09
Load Register A with 09H, task slot 9, run on every 25 ms interrupt.
4567
Call 457BH to run the task of slot Register A (9).
456A
LD A,0AH 3E 0A
Load Register A with 0AH, task slot 10, run on every 25 ms interrupt.
456C
Call 457BH to run the task of slot Register A (10).
456F
LD A,0BH 3E 0B
Load Register A with 0BH, task slot 11, the last of the slots run on every interrupt.
4571
Call 457BH to run the task of slot Register A (11).
4574
LD HL,4040H 21 40 40
Load Register Pair HL with 4040H, the interrupt counter.
4577
INC (HL) 34
Increment the interrupt counter at Register Pair HL (4040H).
4578
LD A,(HL) 7E
Load Register A with the interrupt counter from Register Pair HL (4040H).
4579
AND 07H E6 07
AND Register A with 07H: one of the slots 0-7, in turn on each interrupt; the routine goes on into 457BH and the task's RET returns to 4547H.
457B
RLCA 07
Rotate Register A left: the slot number times two, the offset of the slot in the task table.
457C
LD L,A 6F
Copy the offset from Register A into Register L.
457D
LD H,45H 26 45
Load Register H with 45H: Register Pair HL is the slot at 4500H plus the offset.
457F
LD (45A6H),HL 22 A6 45
Store Register Pair HL, the slot of the running task, in the operand at 45A6H, where 4416H and 4419H find it.
4582
LD E,(HL) 5E
Load Register E with the low byte of the task header address from the slot at Register Pair HL.
4583
INC L 2C
Increment Register L to the high byte of the slot in Register Pair HL.
4584
LD D,(HL) 56
Load Register D with the high byte of the task header address from the slot at Register Pair HL: Register Pair DE is the header.
4585
PUSH DE D5
Push Register Pair DE, the task header address, on the stack.
4586
POP IX DD E1
Load Index Register IX from the stack: the task routine finds its own bytes through Index Register IX.
4588
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is the task header.
4589
LD E,(HL) 5E
Load Register E with the low byte of the routine address at the start of the header at Register Pair HL.
458A
INC HL 23
Increment Register Pair HL to the high byte of the routine address.
458B
LD D,(HL) 56
Load Register D with the high byte of the routine address from the header at Register Pair HL: Register Pair DE is the routine.
458C
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is the task routine.
458D
JP (HL) E9
Jump to the task routine at Register Pair HL; it returns to the caller of 457BH.

458EH - Remove the Running Task

Reached by the jump at 4419H from a task routine.

458E
POP DE D1
Take the return address of the call to 4419H off the stack into Register Pair DE: the RET at 45A2H then returns straight to the scheduler.
458F
LD A,(45A6H) 3A A6 45
Load Register A with the low byte of the running task's slot address from 45A6H (stored by 457FH): the slot number times two.
4592
RRCA 0F
Rotate Register A right: the slot number of the running task.
4593
LD DE,45A3H 11 A3 45
Load Register Pair DE with 45A3H, the empty task header. 4413H jumps here to empty slot Register A.
4596
CP 0CH FE 0C
Compare Register A, the slot, with 0CH. 4410H jumps here to put the header at Register Pair DE in slot Register A.
4598
RET NC D0
If the NC FLAG is set (slot 12 or higher, outside the table), return without a change.
4599
RLCA 07
Rotate Register A left: the slot number times two, the offset in the task table.
459A
LD L,A 6F
Copy the offset from Register A into Register L.
459B
LD H,45H 26 45
Load Register H with 45H: Register Pair HL is the slot at 4500H plus the offset.
459D
DI F3
Turn the interrupts off while the two bytes of the slot change.
459E
LD (HL),E 73
Store Register E, the low byte of the header address, through Register Pair HL.
459F
INC L 2C
Increment Register L to the high byte in Register Pair HL.
45A0
LD (HL),D 72
Store Register D, the high byte of the header address, through Register Pair HL.
45A1
EI FB
Turn the interrupts back on; they take effect after the RET.
45A2
RET C9
Return. The empty task header 45A3H names this RET as its routine.
45A3-45A4
DEFW 45A2H A2 45
The empty task header at 45A3H: a routine address of 45A2H, the RET above. 4593H puts it in a slot.

45A5H - Continue the Running Task After the Call

Reached by the jump at 4416H from a task routine: the address after its CALL 4416H becomes the routine address of its header.

45A5
LD HL,0000H 21 00 00
Load Register Pair HL with the slot of the running task: the operand at 45A6H (0000H in the file) is stored by 457FH.
45A8
LD E,(HL) 5E
Load Register E with the low byte of the task header address from the slot at Register Pair HL.
45A9
INC HL 23
Increment Register Pair HL to the high byte of the slot.
45AA
LD D,(HL) 56
Load Register D with the high byte of the task header address from the slot at Register Pair HL: Register Pair DE is the header.
45AB
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is the task header.
45AC
POP DE D1
Take the return address of the call to 4416H off the stack into Register Pair DE: the address in the task routine after the CALL.
45AD
Jump to 459DH to store Register Pair DE as the routine address at the start of the header at Register Pair HL; the RET at 45A2H then returns to the scheduler.

45AFH - The Clock Task

Its header is in slot 7 (4EA4H-4EA9H), so the routine runs every 200 ms; it counts the seconds, minutes and hours at 4041H-4043H every fifth run.

45AF-45B0
DEFW 45B2H B2 45
The clock task header at 45AFH: the routine address 45B2H.
45B1
DEFB 05H 05
The clock task's count of runs at 45B1H (header +02H): 05H, five runs of 200 ms to a second.
45B2
DEC (IX+02H) DD 35 02
Decrement the count of runs at header +02H through Index Register IX (45B1H).
45B5
RET NZ C0
If the NZ FLAG is set (the second is not over), return.
45B6
LD (IX+02H),05H DD 36 02 05
Store 05H in the count at header +02H through Index Register IX (45B1H) for the next second.
45BA
LD B,03H 06 03
Load Register B with 03H: the seconds, the minutes and the hours.
45BC
LD HL,4041H 21 41 40
Load Register Pair HL with 4041H, the seconds, followed by the minutes at 4042H and the hours at 4043H.
45BF
LD DE,45CCH 11 CC 45
Load Register Pair DE with 45CCH, the limits 60, 60 and 24.
45C2
INC (HL) 34
Increment the count at Register Pair HL (the seconds first).
45C3
LD A,(DE) 1A
Load Register A with the limit of this count at Register Pair DE.
45C4
SUB (HL) 96
Subtract the count at Register Pair HL from Register A, the limit: 00H when the count has reached it.
45C5
RET NZ C0
If the NZ FLAG is set (the count is below its limit), return.
45C6
LD (HL),A 77
Store Register A (00H) in the count at Register Pair HL: it starts again from 0.
45C7
INC L 2C
Increment Register L to the next count (minutes, then hours) in Register Pair HL.
45C8
INC E 1C
Increment Register E to the next limit in Register Pair DE.
45C9
Decrement Register B and loop back to 45C2H to carry into the next count.
45CB
RET C9
Return after the hours have passed 23 and gone back to 0; the date at 4044H-4046H is not changed.
45CC-45CE
DEFB 3CH,3CH,18H 3C 3C 18
The limits of the clock at 45CCH-45CEH: 3CH (60 seconds), 3CH (60 minutes), 18H (24 hours).

45CFH - Write a Directory Sector and Read It Back

Writes the buffer at Register Pair HL to sector Register E of block Register D on drive Register C with the deleted data mark F8H, the mark of the directory sectors, and reads it back. The Z FLAG returns set when all went well. SYS2/SYS, SYS3/SYS and SYS6/SYS call it.

45CF
Call 46EFH to write the sector with the deleted data mark (Write Sector A9H). The Z FLAG returns set when the write succeeded.
45D2
RET NZ C0
If the NZ FLAG is set (the write failed), return with the error code in Register A.
45D3
Call 46F3H to read the sector back without storing its bytes; it ends with error 06H when the sector carries the deleted data mark.
45D6
CP 06H FE 06
Compare Register A, the result of the read back, with 06H: the Z FLAG is set when the sector was read and has the directory's data mark.
45D8
RET C9
Return with the Z FLAG set when the directory sector was written and read back.

45D9H - Check a File Sector After It Is Written

Called from 4860H with the flags of the verify switch (485EH): the NZ FLAG asks for the check.

45D9
If the NZ FLAG is set (the write came through @VERF, or a logical record write), jump to 45E0H to read the sector back.
45DB
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of the FCB flags at +01H through Index Register IX: the bit is set when the file is read and written by logical records.
45DF
RET Z C8
If the Z FLAG is set (whole sector writes), return with Register A 00H without a read back.
45E0
Jump to 46F3H to read the sector back without storing its bytes; it returns the error code, 00H when the read succeeded.

45E3H - Test the Overlay Area Before a Transfer

Reached by the jump at 468FH after the seek, with Register B the tries left and the buffer address in Register Pair HL.

45E3
LD A,(4BFDH) 3A FD 4B
Load Register A with the high byte of the overlay transfer address at 4BFDH, the operand of the CALL at 4BFBH (stored by 4BE8H).
45E6
CP 4DH FE 4D
Compare Register A with 4DH, the page of SYS7/SYS, which loads and runs at 4D00H.
45E8
If the NZ FLAG is set (the overlay last called does not run at 4Dxx), jump to 45F0H.
45EA
SUB B 90
Subtract Register B from Register A (4DH). Register B holds the tries left of the transfer here (0AH or 05H at the most), so Register A never becomes 00H and the NZ FLAG is always set.
45EB
If the NZ FLAG is set, jump to 45F0H; the jump is always taken.
45ED
LD (430EH),A 32 0E 43
Store Register A (00H) in the overlay request code at 430EH, which would make the next RST 28H read the overlay again. The test at 45EAH never lets this store run.
45F0
Jump to 43C9H to issue the command and transfer the sector.

45F3H - Wait and Read the Status

Called from 4455H and 4669H; 45F7H is also the vector of the disk controller's interrupt (4059H, stored by 4E99H), where reading the status ends the interrupt request.

45F3
PUSH HL E5
Save Register Pair HL on the stack: with the next three instructions a short delay before the status is read.
45F4
POP HL E1
Restore Register Pair HL from the stack, part of the delay before the status is read.
45F5
PUSH HL E5
Save Register Pair HL on the stack again, part of the delay before the status is read.
45F6
POP HL E1
Restore Register Pair HL from the stack, the end of the delay before the status is read.
45F7
LD A,(37ECH) 3A EC 37
Load Register A with the status register at 37ECH. Reading it clears the controller's interrupt request.
45FA
RET C9
Return with the controller's status in Register A.
45FB-45FD
DEFB 1FH,1EH,1FH 1F 1E 1F
Three bytes 1FH, 1EH and 1FH (31, 30, 31) at 45FBH-45FDH, the end of the load block 4500H-45FDH; no instruction reads them.

4600H - Select a Drive

Called with Register C the drive number. Each drive keeps its own head position in 4300H-4303H, because the controller has one track register for all drives. A drive whose motor was off is given time to come up to speed.

4600
Call 4669H to wait until the controller is not busy.
4603
PUSH HL E5
Save Register Pair HL on the stack; the routine uses it to reach 4300H-4308H.
4604
LD HL,4308H 21 08 43
Load Register Pair HL with 4308H, the drive in use.
4607
LD A,(HL) 7E
Load Register A with the drive in use from 4308H through Register Pair HL.
4608
LD (HL),C 71
Store Register C, the new drive, at 4308H through Register Pair HL.
4609
LD L,A 6F
Copy the old drive number from Register A into Register L: Register Pair HL is its byte in 4300H-4303H.
460A
LD A,(37EDH) 3A ED 37
Load Register A with the controller's track register 37EDH, the head position of the old drive.
460D
LD (HL),A 77
Store Register A, the old drive's head position, at Register Pair HL.
460E
LD L,C 69
Copy the new drive number from Register C into Register L: Register Pair HL is its byte in 4300H-4303H.
460F
Jump to 4619H, passing over eight bytes that are no longer used.
4611-4618
DEFB 69H,46H,3AH,EDH,37H,77H,79H,6FH 69 46 3A ED 37 77 79 6F
Eight bytes at 4611H-4618H that the jump at 460FH passes over and nothing else reaches: as instructions LD L,C, LD B,(HL), LD A,(37EDH), LD (HL),A, LD A,C, LD L,A.
4619
LD A,(HL) 7E
Load Register A with the new drive's head position from Register Pair HL.
461A
LD (37EDH),A 32 ED 37
Store Register A in the controller's track register at 37EDH.
461D
LD A,C 79
Copy the drive number from Register C into Register A.
461E
Call 4639H to turn the drive number in Register A into its select bit (01H, 02H, 04H or 08H).
4621
LD (4309H),A 32 09 43
Store Register A, the select bit, at 4309H for 445EH.
4624
LD L,A 6F
Copy the select bit from Register A into Register L.
4625
LD A,(37ECH) 3A EC 37
Load Register A with the status register 37ECH, read before the drive is selected.
4628
RLCA 07
Rotate Register A left: the C FLAG is bit 7, NOT READY.
4629
LD A,L 7D
Copy the select bit from Register L into Register A; LD does not change the C FLAG.
462A
LD (37E1H),A 32 E1 37
Store Register A, the select bit, in the drive select latch at 37E1H: the drive is selected and its motor turns.
462D
If the NC FLAG is set (the drive was ready), jump to 4637H.
462F
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, the count of a delay of 65536 loops (about a second) while the motor comes up to speed.
4632
DEC HL 2B
Decrement Register Pair HL, the count of the motor start delay.
4633
LD A,H 7C
Copy Register H, the high byte of the delay count, into Register A.
4634
OR L B5
OR Register A with Register L: the Z FLAG is set when the delay count in Register Pair HL is 0000H.
4635
If the NZ FLAG is set, jump back to 4632H to go on with the delay.
4637
POP HL E1
Restore Register Pair HL, saved at 4603H, from the stack.
4638
RET C9
Return with drive Register C selected and its head position in the track register.

4639H - Make a Bit Mask

Returns in Register A a byte with only bit n set, n being the low three bits of Register A: the routine writes the instruction SET n,A at 4644H. 461EH uses it for a drive's select bit, 4A9DH for a granule's bit in the GAT.

4639
AND 07H E6 07
AND Register A with 07H to keep the bit number 0-7.
463B
RLCA 07
Rotate Register A left: the bit number moves toward bits 5-3, where the SET instruction holds it.
463C
RLCA 07
Rotate Register A left a second time toward the bit field of the SET instruction.
463D
RLCA 07
Rotate Register A left a third time: Register A is the bit number times 8.
463E
OR C7H F6 C7
OR Register A with C7H: Register A is the second byte of SET n,A (C7H plus 8 times n).
4640
LD (4645H),A 32 45 46
Store Register A at 4645H, the second byte of the SET instruction at 4644H.
4643
XOR A AF
Clear Register A to 00H, the byte in which the SET at 4644H sets one bit.
4644
SET 0,A CB C7
Set bit n of Register A: the second byte of this instruction (C7H, SET 0,A, at load) is stored by 4640H.
4646
RET C9
Return with the bit mask in Register A: only bit n is set.

4647H - Select the Drive and Seek the Cylinder

Called with Register C the drive, Register D the block and Register E the sector in the block. The sector and cylinder go to the controller (43A5H) and a Seek is issued when the head is on another cylinder. 4652H holds the second step rate byte.

4647
Call 4600H to select drive Register C with its own head position.
464A
Call 4669H to wait until the controller is not busy.
464D
LD A,(37EDH) 3A ED 37
Load Register A with the track register 37EDH, the cylinder the head is on.
4650
CP D BA
Compare Register A with Register D; 43A5H keeps Register A and sets the flags again for its own result.
4651
Call 43A5H to set the sector and cylinder registers for block Register D, sector Register E; the Z FLAG returns set when the head is on that cylinder. COPY/CMD reads the operand at 4652H.
4654
NOP 00
No operation: a byte left by the change to the call of 43A5H.
4655
RET Z C8
If the Z FLAG is set (the head is on the cylinder), return.
4656
LD A,1BH 3E 1B
Load Register A with 1BH, the Seek command with head load, no verify and stepping rate 3. Its operand at 4657H is the second step rate byte of the STEPnn/PAT patches (record 5, offset 15): 18H STEP06, 19H STEP12, 1AH STEP20, 1BH STEP30, the value shipped.

4658H - Issue a Command

Waits until the controller is not busy and stores the command in Register A in its command register.

4658
PUSH AF F5
Save Register Pair AF, the command in Register A, on the stack.
4659
Call 4669H to wait until the controller is not busy.
465C
POP AF F1
Restore Register Pair AF from the stack: Register A is the command again.
465D
LD (37ECH),A 32 EC 37
Store Register A, the command, in the controller's command register 37ECH.
4660
RET C9
Return to the caller; the controller carries the command out on its own.

4661H - Wait Until the Controller Is Not Busy

Entered at 4669H. While the controller is busy the status is read again; a busy controller on a drive that is not ready is stopped with Force Interrupt.

4661
RLCA 07
Rotate Register A, the status, left: the C FLAG is bit 7, NOT READY.
4662
If the NC FLAG is set (the drive is ready), jump to 4669H to read the status again.
4664
LD A,D0H 3E D0
Load Register A with D0H, Force Interrupt with no condition.
4666
LD (37ECH),A 32 EC 37
Store Register A (D0H) in the command register 37ECH: the command that cannot finish is ended.
4669
Call 45F3H to wait a moment and read the status register 37ECH into Register A.
466C
BIT 0,A CB 47
Test bit 0 of Register A, the status: BUSY, set while a command runs.
466E
RET Z C8
If the Z FLAG is set (the controller is not busy), return with the status in Register A.
466F
Jump back to 4661H to check NOT READY and read again.

4671H - Read or Write a Sector

Called with Register A the command, followed by four parameter bytes after the CALL: the number of tries, the error code base, and the two instruction bytes of the transfer loop at 4698H. Register C is the drive, Register D the block, Register E the sector and Register Pair HL the buffer. The routine returns to the caller of the entry (46DDH, 46E6H, 46EFH, 46F3H) with Register Pair BC as it was, Register A the error code and the Z FLAG set when there was none.

4671
LD (43CEH),A 32 CE 43
Store Register A, the command, at 43CEH, the operand of the command store at 43CDH.
4674
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer: Register Pair HL points at the parameter bytes after the CALL and the buffer address takes their place on the stack.
4675
PUSH BC C5
Save Register Pair BC, the caller's, on the stack.
4676
LD B,(HL) 46
Load Register B with the first parameter, the number of tries, from Register Pair HL.
4677
INC HL 23
Increment Register Pair HL to the second parameter.
4678
LD A,(HL) 7E
Load Register A with the second parameter, the error code base, from Register Pair HL.
4679
INC HL 23
Increment Register Pair HL to the third parameter.
467A
LD (46C9H),A 32 C9 46
Store Register A, the error code base, at 46C9H, the operand of LD B,nn at 46C8H.
467D
LD A,(HL) 7E
Load Register A with the third parameter, the first instruction byte of the transfer, from Register Pair HL.
467E
INC HL 23
Increment Register Pair HL to the fourth parameter.
467F
LD H,(HL) 66
Load Register H with the fourth parameter, the second instruction byte of the transfer, from Register Pair HL.
4680
LD L,A 6F
Copy the first instruction byte from Register A into Register L.
4681
LD (4698H),HL 22 98 46
Store Register Pair HL, the two instruction bytes, at 4698H-4699H in the transfer loop.
4684
POP HL E1
Take the caller's Register Pair BC off the stack into Register Pair HL.
4685
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer: Register Pair HL is the buffer address again and the caller's Register Pair BC is left on the stack in place of the return address, which is dropped.
4686
Call 4647H to select drive Register C and seek the cylinder of block Register D, sector Register E. Each try starts here (46C6H).
4689
Call 4455H to wait until the Seek is over, selecting the drive again meanwhile.
468C
PUSH BC C5
Save Register Pair BC, the tries in Register B and the drive in Register C, on the stack.
468D
PUSH DE D5
Save Register Pair DE, the block and sector, on the stack.
468E
PUSH HL E5
Save Register Pair HL, the buffer address, on the stack; 43D2H takes it from there.
468F
Jump to 45E3H, which goes on to issue the command at 43C9H.

4692H - The Transfer Loop

Reached from 44F1H for Read Sector and from 44FCH, with the first byte in Register A, for a write. Register Pair HL is 37ECH, Register Pair DE 37EFH and Register Pair BC the buffer; the interrupts are off.

4692
LD A,(HL) 7E
Load Register A with the status register at Register Pair HL (37ECH): the read is waiting for its first byte.
4693
AND 03H E6 03
AND Register A with 03H to keep bit 1 (DATA REQUEST) and bit 0 (BUSY).
4695
If the PO FLAG is set (exactly one of the two bits is set), jump back to 4692H to wait. The loop ends when both are set (the first byte has come) or both are clear (the command has ended).
4698
NOP 00
The first of two instruction bytes stored by 4681H from the parameters of the call: 1AH 02H for a read (LD A,(DE) and LD (BC),A: the byte goes from the data register at Register Pair DE to the buffer at Register Pair BC), 12H 0AH for a write (LD (DE),A and LD A,(BC)), 1AH 00H for the read back (LD A,(DE) and a NOP). The file holds 00H 00H, two NOPs.
4699
NOP 00
The second instruction byte stored by 4681H (00H, NOP, in the file): LD (BC),A for a read, LD A,(BC) for a write, NOP for the read back, each through Register Pair BC.
469A
INC BC 03
Increment Register Pair BC, the buffer pointer, to the next byte.
469B
BIT 1,(HL) CB 4E
Test bit 1 of the status register at Register Pair HL (37ECH), DATA REQUEST.
469D
If the NZ FLAG is set (the next byte is ready), jump back to 4698H to move it.
469F
BIT 1,(HL) CB 4E
Test bit 1 of the status register at Register Pair HL (37ECH), DATA REQUEST, a second time.
46A1
If the NZ FLAG is set (the next byte is ready), jump back to 4698H to move it.
46A3
BIT 1,(HL) CB 4E
Test bit 1 of the status register at Register Pair HL (37ECH), DATA REQUEST, a third time.
46A5
If the NZ FLAG is set (the next byte is ready), jump back to 4698H to move it.
46A7
BIT 0,(HL) CB 46
Test bit 0 of the status register at Register Pair HL (37ECH), BUSY.
46A9
If the NZ FLAG is set (the command is still running), jump back to 469BH to wait for the next DATA REQUEST.
46AB
NOP 00
No operation: one of three bytes of 00H at 46ABH-46ADH before the status is taken.
46AC
NOP 00
No operation: the second of the three bytes of 00H before the status is taken.
46AD
NOP 00
No operation: the third of the three bytes of 00H before the status is taken.
46AE
LD A,(HL) 7E
Load Register A with the final status of the command from the status register at Register Pair HL (37ECH).
46AF
LD (HL),D0H 36 D0
Store D0H through Register Pair HL into the command register at 37ECH: Force Interrupt with no condition, which leaves the controller idle.
46B1
AND FCH E6 FC
AND Register A, the status, with FCH to drop bit 1 (DATA REQUEST) and bit 0 (BUSY): the Z FLAG is set when the command ended without an error bit.
46B3
POP HL E1
Restore Register Pair HL, the buffer address, from the stack.
46B4
POP DE D1
Restore Register Pair DE, the block and sector, from the stack.
46B5
POP BC C1
Restore Register Pair BC, the tries in Register B and the drive in Register C, from the stack.
46B6
If the Z FLAG is set (no error), jump to 46D0H to return with Register A 00H.
46B8
CP 20H FE 20
Compare Register A, the error bits, with 20H, bit 5 alone: for a read the RECORD TYPE bit (the sector has the deleted data mark F8H), for a write the WRITE FAULT bit.
46BA
If the Z FLAG is set (bit 5 alone), jump to 46C8H to return its error code at once: another try would give the same result.
46BC
BIT 2,A CB 57
Test bit 2 of Register A, the error bits: LOST DATA, a byte not taken in time.
46BE
If the NZ FLAG is set (a byte was missed), jump to 46C6H to try again without a Restore.
46C0
EI FB
Turn the interrupts back on before the Restore.
46C1
PUSH AF F5
Save Register Pair AF, the error bits in Register A, on the stack.
46C2
Call 4C9BH: on a ready drive the head is restored to cylinder 0 (444BH); on a drive that is not ready the tries left in Register B are cut to three at the most.
46C5
POP AF F1
Restore Register Pair AF, the error bits in Register A, from the stack.
46C6
Decrement Register B, the tries left, and jump back to 4686H for another try until none are left.
46C8
LD B,00H 06 00
Load Register B with the error code base: its operand at 46C9H is stored by 467AH (01H for a read, 09H for a write).
46CA
DEC B 05
Decrement Register B: the base minus one, counted up again for each bit below the error bit.
46CB
INC B 04
Increment Register B for the next bit of the status.
46CC
RRCA 0F
Rotate Register A right: the C FLAG is the bit just shifted out.
46CD
If the NC FLAG is set (the bit is clear), jump back to 46CBH. Register B ends as the base minus one plus the number of the lowest error bit counted from 1: a read gives 03H LOST DATA DURING READ (status bit 2), 04H PARITY ERROR DURING READ (bit 3, CRC), 05H DATA RECORD NOT FOUND DURING READ (bit 4), 06H ATTEMPTED TO READ LOCKED/DELETED DATA RECORD (bit 5), 07H ATTEMPTED TO READ SYSTEM DATA RECORD (bit 6), 08H DEVICE NOT AVAILABLE (bit 7, NOT READY); a write gives 0BH LOST DATA DURING WRITE, 0CH PARITY ERROR DURING WRITE, 0DH DATA RECORD NOT FOUND DURING WRITE, 0EH WRITE FAULT ON DISK DRIVE, 0FH WRITE PROTECTED DISKETTE and, for NOT READY, 10H, whose message in SYS4/SYS is ILLEGAL LOGICAL FILE NUMBER (a bug: the read side gives 08H).
46CF
LD A,B 78
Copy the error code from Register B into Register A; the NZ FLAG is still set from the INC B at 46CBH.
46D0
EI FB
Turn the interrupts back on: they were off from 43CCH on.
46D1
POP BC C1
Restore the caller's Register Pair BC from the stack (left there by 4685H).
46D2
RET C9
Return to the caller of 46DDH, 46E6H, 46EFH or 46F3H with the error code in Register A (00H and the Z FLAG set on success).
46D3-46DC
DEFB 00H,CBH,08H,38H,03H,3CH,18H,F9H,C1H,C9H 00 CB 08 38 03 3C 18 F9 C1 C9
Ten bytes at 46D3H-46DCH that no instruction reaches: a NOP, then a loop (RRC B, JR C, INC A, JR) and POP BC, RET.

46DDH - Read a Sector

Reads sector Register E of block Register D on drive Register C into the buffer at Register Pair HL, ten tries. Error codes 03H-08H (46CDH).

46DD
LD A,88H 3E 88
Load Register A with 88H, the Read Sector command.
46DF
Call 4671H with the four parameter bytes that follow; it returns to the caller of 46DDH.
46E2-46E5
DEFB 0AH,01H,1AH,02H 0A 01 1A 02
The parameters of the read: 0AH tries, error code base 01H, and the transfer instructions 1AH 02H (LD A,(DE), LD (BC),A).

46E6H - Write a Sector

Writes the buffer at Register Pair HL to sector Register E of block Register D on drive Register C with the ordinary data mark FBH (Write Sector A8H), five tries. Error codes 0BH-10H. 46EFH writes with the deleted data mark F8H instead.

46E6
LD A,A8H 3E A8
Load Register A with A8H, Write Sector with the data mark FBH.
46E8
Call 4671H with the four parameter bytes that follow; it returns to the caller of 46E6H or 46EFH.
46EB-46EE
DEFB 05H,09H,12H,0AH 05 09 12 0A
The parameters of the write: 05H tries, error code base 09H, and the transfer instructions 12H 0AH (LD (DE),A, LD A,(BC)).
46EF
LD A,A9H 3E A9
Load Register A with A9H, Write Sector with the deleted data mark F8H, the mark of the directory sectors.
46F1
Jump back to 46E8H to call 4671H with the parameters of the write.

46F3H - Read a Sector Back

Reads sector Register E of block Register D on drive Register C without storing its bytes, to check that it can be read, five tries. A directory sector returns error 06H, the deleted data mark.

46F3
LD A,88H 3E 88
Load Register A with 88H, the Read Sector command.
46F5
Call 4671H with the four parameter bytes that follow; it returns to the caller of 46F3H.
46F8-46FB
DEFB 05H,01H,1AH,00H 05 01 1A 00
The parameters of the read back: 05H tries, error code base 01H, and the transfer instructions 1AH 00H (LD A,(DE), NOP: the byte is read and dropped).

4700H - @POSN: Position to a Record

Reached through 4442H with Register Pair DE the FCB and Register Pair BC the record number. In byte mode (FCB+01H bit 7 set) the record is multiplied by the record length at FCB+09H to give the sector and the byte offset; else the record is the sector. 4717H is the common end of @POSN, @BKSP, @REW and @PEOF. The FCB is laid out as follows: +00H bit 7 open; +01H flags (bits 0-2 the access level, bit 4 the buffer has been changed, bit 5 the buffer must be read, bit 6 positioned, bit 7 byte mode); +03H-+04H the buffer; +05H the byte offset; +06H the drive; +07H the directory record; +08H the end of file offset; +09H the record length; +0AH-+0BH the sector; +0CH-+0DH the end of file sector; +0EH-+1FH the extents.

4700
Call 4892H, the common start of the file routines: it checks that the FCB at Register Pair DE is open, loads Index Register IX with it and arranges the return through 48B3H, with Register A 00H.
4703
SET 6,(IX+01H) DD CB 01 F6
Set bit 6 of the FCB flags at +01H through Index Register IX: the file has been positioned, so a write before the end of file does not move the end of file (4870H).
4707
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of the FCB flags at +01H through Index Register IX: byte mode.
470B
If the Z FLAG is set (whole sectors), jump to 4717H with Register Pair BC the sector and Register A 00H the offset.
470D
LD H,B 60
Copy Register B, the high byte of the record number, into Register H.
470E
LD L,C 69
Copy Register C, the low byte of the record number, into Register L: Register Pair HL is the record number.
470F
LD A,(IX+09H) DD 7E 09
Load Register A with the record length at FCB+09H through Index Register IX (00H for 256).
4712
Call 4B6AH to multiply Register Pair HL by Register A: the low byte of the product, the byte offset, comes back in Register A and the sector in Register Pair HL.
4715
LD B,H 44
Copy Register H, the high byte of the sector, into Register B.
4716
LD C,L 4D
Copy Register L, the low byte of the sector, into Register C: Register Pair BC is the sector.
4717
LD (IX+05H),A DD 77 05
Store Register A, the new byte offset, at FCB+05H through Index Register IX.
471A
PUSH BC C5
Save Register Pair BC, the new sector, on the stack.
471B
Call 4878H, which writes the buffer back when it has been changed in byte mode. The Z FLAG returns set when all went well.
471E
POP BC C1
Restore Register Pair BC, the new sector, from the stack.
471F
RET NZ C0
If the NZ FLAG is set (the buffer could not be written), return with the error code in Register A.
4720
LD (IX+0AH),C DD 71 0A
Store Register C, the low byte of the new sector, at FCB+0AH through Index Register IX.
4723
LD (IX+0BH),B DD 70 0B
Store Register B, the high byte of the new sector, at FCB+0BH through Index Register IX.
4726
SET 5,(IX+01H) DD CB 01 EE
Set bit 5 of the FCB flags at +01H through Index Register IX: the buffer must be read before its bytes are used.
472A
Call 48B9H to compare the new position with the end of file: Register A returns 1CH at the end of file, 1DH past it, else 00H.
472D
RET NZ C0
If the NZ FLAG is set (at or past the end of file), return with error 1CH or 1DH in Register A.
472E
Call 48DCH to find the block and sector of the new position on the disk (Register D and Register E, drive Register C).
4731
RET NZ C0
If the NZ FLAG is set (the sector could not be found or given space), return with the error code in Register A.
4732
Call 4647H to select the drive and seek the cylinder of block Register D, sector Register E, ready for the next read or write.
4735
XOR A AF
Clear Register A to 00H and set the Z FLAG: the file is positioned.
4736
RET C9
Return with Register A 00H and the Z FLAG set, through 48B3H.

4737H - @BKSP: Back One Record

Reached through 4445H with Register Pair DE the FCB.

4737
Call 4892H, the common start of the file routines, which loads Index Register IX with the FCB at Register Pair DE and sets Register A to 00H.
473A
LD C,(IX+0AH) DD 4E 0A
Load Register C with the low byte of the sector at FCB+0AH through Index Register IX.
473D
LD B,(IX+0BH) DD 46 0B
Load Register B with the high byte of the sector at FCB+0BH through Index Register IX: Register Pair BC is the sector.
4740
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of the FCB flags at +01H through Index Register IX: byte mode.
4744
If the Z FLAG is set (whole sectors), jump to 4753H to take one from the sector, with Register A 00H the offset.
4746
LD A,(IX+09H) DD 7E 09
Load Register A with the record length at FCB+09H through Index Register IX.
4749
OR A B7
Set the flags from Register A, the record length: the Z FLAG is set for 00H, records of 256 bytes.
474A
If the Z FLAG is set (records of 256 bytes), jump to 4753H to step back one sector with Register A 00H.
474C
NEG ED 44
Negate Register A: minus the record length, to be added to the offset.
474E
ADD A,(IX+05H) DD 86 05
Add the byte offset at FCB+05H through Index Register IX to Register A: the offset minus the record length. The C FLAG is set when the record starts in the same sector.
4751
If the C FLAG is set (no borrow), jump to 4717H with Register A the new offset in the same sector, Register Pair BC.
4753
DEC BC 0B
Decrement Register Pair BC to the sector before; Register A is the offset in it.
4754
Jump to 4717H to position to sector Register Pair BC, offset Register A.

4756H - @REW: Back to the First Record

Reached through 443FH with Register Pair DE the FCB.

4756
Call 4892H, the common start of the file routines, which loads Index Register IX with the FCB at Register Pair DE.
4759
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H, the first sector of the file.
475C
XOR A AF
Clear Register A to 00H, the offset of the first byte.
475D
Jump to 4717H to position to sector Register Pair BC (0000H), offset Register A (00H).

475FH - @PEOF: Position to the End of File

Reached through 4448H with Register Pair DE the FCB. The routine returns error 1CH, the end of file, from 472AH.

475F
Call 4892H, the common start of the file routines, which loads Index Register IX with the FCB at Register Pair DE.
4762
LD C,(IX+0CH) DD 4E 0C
Load Register C with the low byte of the end of file sector at FCB+0CH through Index Register IX.
4765
LD B,(IX+0DH) DD 46 0D
Load Register B with the high byte of the end of file sector at FCB+0DH through Index Register IX.
4768
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file offset at FCB+08H through Index Register IX.
476B
Jump to 4717H to position to sector Register Pair BC, offset Register A: the end of the file.

476DH - @READ: Read a Record

Reached through 4436H with Register Pair DE the FCB. In sector mode the next sector is read into the file's buffer; in byte mode a record of FCB+09H bytes (00H: 256) is taken byte by byte and stored at Register Pair HL.

476D
Call 4892H, the common start of the file routines, which loads Index Register IX with the FCB at Register Pair DE.
4770
Call 4878H, which writes the buffer back first when it has been changed in byte mode.
4773
RET NZ C0
If the NZ FLAG is set (the buffer could not be written), return with the error code in Register A.
4774
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of the FCB flags at +01H through Index Register IX: byte mode.
4778
If the Z FLAG is set (whole sectors), jump to 480EH to read the next sector into the buffer.
477B
LD B,(IX+09H) DD 46 09
Load Register B with the record length at FCB+09H through Index Register IX, the count of bytes (00H: 256).
477E
PUSH HL E5
Save Register Pair HL, the address for the next byte of the record, on the stack.
477F
PUSH BC C5
Save Register Pair BC, the bytes left in Register B, on the stack.
4780
Call 47BBH to take the next byte of the file into Register A.
4783
POP BC C1
Restore Register Pair BC, the bytes left, from the stack.
4784
POP HL E1
Restore Register Pair HL, the address for the byte, from the stack.
4785
RET NZ C0
If the NZ FLAG is set (an error or the end of file), return with the error code in Register A.
4786
LD (HL),A 77
Store Register A, the byte, at Register Pair HL in the caller's record.
4787
INC HL 23
Increment Register Pair HL to the next byte of the record.
4788
Decrement Register B, the bytes left, and loop back to 477EH for the next byte.
478A
RET C9
Return with the record stored and Register A 00H.

478BH - @WRITE: Write a Record

Reached through 4439H with Register Pair DE the FCB, and from 47ACH for @VERF with Register A 01H. Register A is stored at 485EH, the switch for reading each sector back after it is written.

478B
Call 4892H, the common start of the file routines, which loads Index Register IX with the FCB at Register Pair DE and sets Register A to 00H. SYS6/SYS reads 478BH.
478E
LD (485EH),A 32 5E 48
Store Register A at 485EH, the operand of LD A,nn at 485DH: 00H no read back (@WRITE), 01H read back (@VERF).
4791
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of the FCB flags at +01H through Index Register IX: byte mode.
4795
If the Z FLAG is set (whole sectors), jump to 483EH to write the buffer as the next sector.
4798
LD B,(IX+09H) DD 46 09
Load Register B with the record length at FCB+09H through Index Register IX, the count of bytes (00H: 256).
479B
LD A,(HL) 7E
Load Register A with the next byte of the caller's record at Register Pair HL.
479C
INC HL 23
Increment Register Pair HL to the byte after it.
479D
PUSH HL E5
Save Register Pair HL, the address of the next byte of the record, on the stack.
479E
PUSH BC C5
Save Register Pair BC, the bytes left in Register B, on the stack.
479F
Call 47DAH to put the byte in Register A into the file.
47A2
POP BC C1
Restore Register Pair BC, the bytes left, from the stack.
47A3
POP HL E1
Restore Register Pair HL, the address of the next byte, from the stack.
47A4
RET NZ C0
If the NZ FLAG is set (an error), return with the error code in Register A.
47A5
Decrement Register B, the bytes left, and loop back to 479BH for the next byte.
47A7
RET C9
Return with the record written and Register A 00H.

47A8H - @VERF: Write a Record and Read It Back

Reached through 443CH with Register Pair DE the FCB.

47A8
Call 4892H, the common start of the file routines, which sets Register A to 00H. SYS6/SYS reads 47A8H.
47AB
INC A 3C
Increment Register A to 01H, the switch for the read back.
47AC
Jump to 478EH to store the switch and write the record.

47AEH - A File Used as a Device

Reached from 44C8H when a device control block is an open FCB (type above 10H). Register B is the ROM's request: 01H takes a byte from the file into Register A, 02H (and 04H) puts the byte in Register C into the file.

47AE
Call 4892H, the common start of the file routines, which loads Index Register IX with the FCB at Register Pair DE.
47B1
SET 7,(IX+01H) DD CB 01 FE
Set bit 7 of the FCB flags at +01H through Index Register IX: the file is read and written byte by byte from now on.
47B5
LD A,B 78
Copy Register B, the request, into Register A.
47B6
CP 02H FE 02
Compare Register A, the request, with 02H: the C FLAG is set for 01H, input.
47B8
LD A,C 79
Copy Register C, the byte to put, into Register A; LD does not change the flags.
47B9
If the NC FLAG is set (output), jump to 47DAH to put the byte in Register A into the file.

47BBH - Take the Next Byte of a File

Called from 4780H and entered from 47AEH. Register A returns the byte with the Z FLAG set, or an error code with the NZ FLAG set.

47BB
Call 48B9H to compare the position with the end of file: Register A returns 1CH at the end of file, 1DH past it.
47BE
RET NZ C0
If the NZ FLAG is set (no byte is left), return with error 1CH or 1DH in Register A.
47BF
BIT 5,(IX+01H) DD CB 01 6E
Test bit 5 of the FCB flags at +01H through Index Register IX: the buffer must be read.
47C3
If the Z FLAG is set (the buffer holds the sector), jump to 47C9H.
47C5
Call 4366H to read the sector of the position into the buffer.
47C8
RET NZ C0
If the NZ FLAG is set (the read failed), return with the error code in Register A.
47C9
Call 4883H: Register Pair DE returns the address of the byte in the buffer and Register C the offset.
47CC
INC (IX+05H) DD 34 05
Increment the byte offset at FCB+05H through Index Register IX; the Z FLAG is set when it wraps to 00H.
47CF
If the Z FLAG is set (the last byte of the buffer), call 435FH to step the sector number on and mark the buffer to be read.
47D2
XOR A AF
Clear Register A to 00H and set the Z FLAG: no error.
47D3
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE in the buffer; the Z FLAG of 47D2H stays set.
47D4
RET C9
Return with the byte in Register A and the Z FLAG set.
47D5-47D9
DEFB CBH,01H,EEH,F1H,C9H CB 01 EE F1 C9
Five bytes at 47D5H-47D9H that nothing reaches: the end of an instruction SET 5,(IX+01H) (DD CB 01 EE without its DD), then POP AF and RET. The instruction survives at 435FH, where DoubleDOS moved it.

47DAH - Put a Byte into a File

Called from 479FH and entered from 47B9H with the byte in Register A. When the buffer is full it is written as the sector; the end of file is moved to the new position.

47DA
PUSH AF F5
Save Register Pair AF, the byte in Register A, on the stack.
47DB
BIT 5,(IX+01H) DD CB 01 6E
Test bit 5 of the FCB flags at +01H through Index Register IX: the buffer must be read first.
47DF
If the Z FLAG is set (the buffer holds the sector), jump to 47E9H.
47E1
Call 482DH to find the sector of the position and read it into the buffer, so that the bytes around the new one are kept.
47E4
If the Z FLAG is set (the sector was read), jump to 47E9H.
47E6
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer, the saved byte, ready to drop it.
47E7
POP HL E1
Restore Register Pair HL from the stack: the saved byte is dropped and Register Pair HL is as it was.
47E8
RET C9
Return with the error code of the read in Register A.
47E9
Call 4883H: Register Pair DE returns the address of the byte in the buffer and Register C the offset.
47EC
POP AF F1
Restore Register Pair AF from the stack: Register A is the byte to put.
47ED
LD (DE),A 12
Store Register A, the byte, at Register Pair DE in the buffer.
47EE
INC DE 13
Increment Register Pair DE past the byte just stored in the buffer.
47EF
SET 4,(IX+01H) DD CB 01 E6
Set bit 4 of the FCB flags at +01H through Index Register IX: the buffer has been changed.
47F3
INC (IX+05H) DD 34 05
Increment the byte offset at FCB+05H through Index Register IX; the Z FLAG is set when it wraps to 00H.
47F6
If the NZ FLAG is set (the buffer is not yet full), jump to 486BH to move the end of file when the byte lies beyond it.
47F8
LD A,01H 3E 01
Load Register A with 01H: a full buffer is always read back after it is written.
47FA
LD (485EH),A 32 5E 48
Store Register A (01H) at 485EH, the switch for the read back.
47FD
Jump to 483EH to write the buffer as the sector.

47FFH - Set the End of File to the Position

Entered from 486EH and 4874H with Register Pair HL the sector and Register C the offset (from 48B9H).

47FF
LD (IX+08H),C DD 71 08
Store Register C, the byte offset, at FCB+08H through Index Register IX: the end of file offset.
4802
LD (IX+0CH),L DD 75 0C
Store Register L, the low byte of the sector, at FCB+0CH through Index Register IX.
4805
LD (IX+0DH),H DD 74 0D
Store Register H, the high byte of the sector, at FCB+0DH through Index Register IX: the end of file sector.
4808
XOR A AF
Clear Register A to 00H and set the Z FLAG: no error.
4809
RET C9
Return with Register A 00H and the Z FLAG set.
480A-480D
DEFB 01H,EEH,18H,30H 01 EE 18 30
Four bytes at 480AH-480DH that nothing reaches: the end of another SET 5,(IX+01H) (01H EEH) and JR 483EH (18H 30H), left from the code DoubleDOS replaced.

480EH - Read the Next Sector

Reached from 4778H for @READ in sector mode and called from 4366H. The sector of FCB+0AH-+0BH is read into the buffer and the sector number goes up by one.

480E
LD A,(IX+01H) DD 7E 01
Load Register A with the FCB flags at +01H through Index Register IX.
4811
AND 07H E6 07
AND Register A with 07H to keep the access level, bits 0-2.
4813
CP 06H FE 06
Compare Register A, the access level, with 06H.
4815
If the C FLAG is set (an access level below 6), jump to 481BH: reading is allowed.
4817
LD A,25H 3E 25
Load Register A with 25H, the error code for an access the level does not allow, which SYS4/SYS shows it as ILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE.
4819
OR A B7
Set the flags from Register A (25H): the NZ FLAG is set.
481A
RET C9
Return with error 25H in Register A and the NZ FLAG set.
481B
Call 48B9H to compare the position with the end of file.
481E
RET NZ C0
If the NZ FLAG is set (at or past the end of file), return with error 1CH or 1DH in Register A.
481F
Call 482DH to find the sector on the disk and read it into the buffer.
4822
RET NZ C0
If the NZ FLAG is set (the read failed), return with the error code in Register A.
4823
INC (IX+0AH) DD 34 0A
Increment the low byte of the sector number at FCB+0AH through Index Register IX. 4363H jumps here.
4826
If the NZ FLAG is set (no carry), jump to 482BH.
4828
INC (IX+0BH) DD 34 0B
Increment the high byte of the sector number at FCB+0BH through Index Register IX for the carry.
482B
XOR A AF
Clear Register A to 00H and set the Z FLAG: no error.
482C
RET C9
Return with Register A 00H and the Z FLAG set.

482DH - Find the Sector and Read It into the Buffer

Called from 47E1H and 481FH.

482D
Call 48DCH to find the block in Register D and the sector in Register E of the position, on drive Register C.
4830
RET NZ C0
If the NZ FLAG is set (no space could be found), return with the error code in Register A.
4831
RES 5,(IX+01H) DD CB 01 AE
Reset bit 5 of the FCB flags at +01H through Index Register IX: the buffer will hold the sector.
4835
LD L,(IX+03H) DD 6E 03
Load Register L with the low byte of the buffer address at FCB+03H through Index Register IX.
4838
LD H,(IX+04H) DD 66 04
Load Register H with the high byte of the buffer address at FCB+04H through Index Register IX.
483B
Jump to 46DDH to read the sector into the buffer at Register Pair HL; it returns to the caller of 482DH.

483EH - Write the Buffer as the Sector

Reached from 4795H, 47FDH and 487FH.

483E
LD A,(IX+01H) DD 7E 01
Load Register A with the FCB flags at +01H through Index Register IX.
4841
AND 07H E6 07
AND Register A with 07H to keep the access level, bits 0-2.
4843
CP 05H FE 05
Compare Register A, the access level, with 05H.
4845
If the C FLAG is set (an access level below 5), jump to 484BH: writing is allowed.
4847
LD A,25H 3E 25
Load Register A with 25H, the error code for an access the level does not allow, which SYS4/SYS shows it as ILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE.
4849
OR A B7
Set the flags from Register A (25H): the NZ FLAG is set.
484A
RET C9
Return with error 25H in Register A and the NZ FLAG set.
484B
Call 48DCH to find (or give space to) the block in Register D and the sector in Register E of the position.
484E
RET NZ C0
If the NZ FLAG is set (the disk is full or the directory could not be read), return with the error code in Register A.
484F
LD L,(IX+03H) DD 6E 03
Load Register L with the low byte of the buffer address at FCB+03H through Index Register IX.
4852
LD H,(IX+04H) DD 66 04
Load Register H with the high byte of the buffer address at FCB+04H through Index Register IX.
4855
Call 46E6H to write the buffer at Register Pair HL to the sector.
4858
RET NZ C0
If the NZ FLAG is set (the write failed), return with the error code in Register A.
4859
RES 4,(IX+01H) DD CB 01 A6
Reset bit 4 of the FCB flags at +01H through Index Register IX: the buffer is the same as the sector.
485D
LD A,00H 3E 00
Load Register A with the read back switch: the operand at 485EH is stored by 478EH and 47FAH (00H in the file).
485F
OR A B7
Set the flags from Register A, the switch: the NZ FLAG asks for the read back.
4860
Call 45D9H, which reads the sector back when the switch or byte mode asks for it.
4863
RET NZ C0
If the NZ FLAG is set (the read back failed), return with the error code in Register A.
4864
LD A,(IX+05H) DD 7E 05
Load Register A with the byte offset at FCB+05H through Index Register IX.
4867
OR A B7
Set the flags from Register A, the offset: the Z FLAG is set when the whole sector has been used.
4868
If the Z FLAG is set, call 435FH to step the sector number on and mark the buffer to be read.
486B
Call 48B9H to compare the position with the end of file: Register Pair HL returns the sector and Register C the offset.
486E
If the NZ FLAG is set (at or past the end of file), jump to 47FFH to make the position the new end of file.
4870
BIT 6,(IX+01H) DD CB 01 76
Test bit 6 of the FCB flags at +01H through Index Register IX: the file has been positioned.
4874
If the Z FLAG is set (not positioned), jump to 47FFH: a write moves the end of file to the position.
4876
Jump to 4808H to return with Register A 00H: the end of file is kept.

4878H - Write the Buffer Back When Changed

Called from 471BH and 4770H: in byte mode a changed buffer is written before the position moves.

4878
LD A,(IX+01H) DD 7E 01
Load Register A with the FCB flags at +01H through Index Register IX. SYS3/SYS calls 4878H (4E10H).
487B
AND 90H E6 90
AND Register A with 90H to keep bit 7 (byte mode) and bit 4 (the buffer has been changed).
487D
CP 90H FE 90
Compare Register A with 90H: the Z FLAG is set when both bits are set.
487F
If the Z FLAG is set (a changed buffer in byte mode), jump to 483EH to write it.
4881
XOR A AF
Clear Register A to 00H and set the Z FLAG: nothing to write.
4882
RET C9
Return with Register A 00H and the Z FLAG set.

4883H - The Address of the Byte in the Buffer

Returns Register Pair DE as the buffer address at FCB+03H-+04H plus the byte offset, and Register C the offset.

4883
LD A,(IX+05H) DD 7E 05
Load Register A with the byte offset at FCB+05H through Index Register IX.
4886
LD C,A 4F
Copy the offset from Register A into Register C.
4887
ADD A,(IX+03H) DD 86 03
Add the low byte of the buffer address at FCB+03H through Index Register IX to Register A.
488A
LD E,A 5F
Copy the low byte of the sum from Register A into Register E.
488B
LD A,(IX+04H) DD 7E 04
Load Register A with the high byte of the buffer address at FCB+04H through Index Register IX.
488E
ADC A,00H CE 00
Add the carry of 4887H to Register A, the high byte of the buffer address.
4890
LD D,A 57
Copy the high byte from Register A into Register D: Register Pair DE is the address of the byte.
4891
RET C9
Return with Register Pair DE the address of the byte and Register C the offset.

4892H - The Common Start of the File Routines

Called as the first instruction of every file routine. It checks that the FCB at Register Pair DE is open, keeps the FCB address and the caller's return address at 430AH and 430CH, saves Index Register IX, Register Pairs HL, DE and BC, loads Index Register IX with the FCB and goes on with the rest of the routine, which returns through 48B3H. SYS2/SYS and SYS3/SYS call it, SYS2/SYS at 4896H.

4892
LD A,(DE) 1A
Load Register A with FCB+00H at Register Pair DE.
4893
RLCA 07
Rotate Register A left: the C FLAG is bit 7, set when the FCB is open.
4894
If the NC FLAG is set (the FCB is not open), jump to 48AEH to return error 26H.
4896
POP AF F1
Take the return address into the file routine off the stack into Register Pair AF; it is pushed again at 48ABH.
4897
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer: Register Pair HL is the return address into the program that called the file routine.
4898
LD (430CH),HL 22 0C 43
Store Register Pair HL, the program's return address, at 430CH.
489B
LD (430AH),DE ED 53 0A 43
Store Register Pair DE, the FCB address, at 430AH.
489F
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer again: the program's return address is back on the stack and Register Pair HL is the caller's own.
48A0
PUSH DE D5
Push Register Pair DE, the FCB address, on the stack.
48A1
EX (SP),IX DD E3
Exchange Index Register IX with the top of the stack at the Stack Pointer: Index Register IX is the FCB and the caller's Index Register IX is saved.
48A3
PUSH HL E5
Save Register Pair HL on the stack, restored by 48B5H.
48A4
PUSH DE D5
Save Register Pair DE, the FCB address, on the stack.
48A5
PUSH BC C5
Save Register Pair BC on the stack, restored by 48B3H.
48A6
PUSH HL E5
Push Register Pair HL again: it is replaced by 48B3H at 48AAH.
48A7
LD HL,48B3H 21 B3 48
Load Register Pair HL with 48B3H, the address the file routine returns to.
48AA
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer: 48B3H is the return address of the file routine and Register Pair HL is the caller's own again.
48AB
PUSH AF F5
Push Register Pair AF, the return address into the file routine taken off at 4896H.
48AC
XOR A AF
Clear Register A to 00H; the file routines start with Register A 00H.
48AD
RET C9
Return into the file routine at the address just pushed.
48AE
POP AF F1
Take the return address into the file routine off the stack into Register Pair AF: the routine is not run.
48AF
LD A,26H 3E 26
Load Register A with 26H, the error code for a file that is not open, which SYS4/SYS shows it as FILE NOT OPEN.
48B1
OR A B7
Set the flags from Register A (26H): the NZ FLAG is set.
48B2
RET C9
Return to the program with error 26H in Register A and the NZ FLAG set.
48B3
POP BC C1
Restore Register Pair BC from the stack: the file routine has returned here.
48B4
POP DE D1
Restore Register Pair DE, the FCB address, from the stack.
48B5
POP HL E1
Restore Register Pair HL from the stack, saved at 48A3H.
48B6
POP IX DD E1
Restore Index Register IX, the caller's, from the stack.
48B8
RET C9
Return to the program with the result of the file routine in Register A and the flags.

48B9H - Compare the Position with the End of File

Returns Register Pair HL the sector at FCB+0AH-+0BH and Register C the offset at FCB+05H, with Register A 00H and the Z FLAG set before the end of file, 1CH at the end of file and 1DH past it, both with the NZ FLAG set.

48B9
LD L,(IX+0AH) DD 6E 0A
Load Register L with the low byte of the sector at FCB+0AH through Index Register IX.
48BC
LD H,(IX+0BH) DD 66 0B
Load Register H with the high byte of the sector at FCB+0BH through Index Register IX.
48BF
LD C,(IX+05H) DD 4E 05
Load Register C with the byte offset at FCB+05H through Index Register IX.
48C2
LD A,H 7C
Copy Register H, the high byte of the sector, into Register A.
48C3
CP (IX+0DH) DD BE 0D
Compare Register A with the high byte of the end of file sector at FCB+0DH through Index Register IX.
48C6
If the NZ FLAG is set (the high bytes differ), jump to 48D7H with the C FLAG telling which is greater.
48C8
LD A,L 7D
Copy Register L, the low byte of the sector, into Register A.
48C9
CP (IX+0CH) DD BE 0C
Compare Register A with the low byte of the end of file sector at FCB+0CH through Index Register IX.
48CC
If the NZ FLAG is set (the low bytes differ), jump to 48D7H.
48CE
LD A,C 79
Copy Register C, the offset, into Register A.
48CF
SUB (IX+08H) DD 96 08
Subtract the end of file offset at FCB+08H through Index Register IX from Register A.
48D2
If the NZ FLAG is set (the offsets differ), jump to 48D7H.
48D4
OR 1CH F6 1C
OR Register A (00H) with 1CH: Register A is 1CH, the end of file, and the NZ FLAG is set.
48D6
RET C9
Return with error 1CH in Register A: the position is the end of file.
48D7
LD A,1DH 3E 1D
Load Register A with 1DH, the error code for a position past the end of file, which SYS4/SYS shows it as RECORD NUMBER OUT OF RANGE; LD does not change the C FLAG.
48D9
RET NC D0
If the NC FLAG is set (the position is past the end of file), return with error 1DH and the NZ FLAG set from the compare.
48DA
XOR A AF
Clear Register A to 00H and set the Z FLAG: the position is before the end of file.
48DB
RET C9
Return with Register A 00H and the Z FLAG set.

48DCH - Find the Sector of the Position on the Disk

Called with Index Register IX the FCB. The sector number at FCB+0AH-+0BH is divided into granules of five sectors; the granule is looked for in the five extents kept in the FCB at +0EH-+1FH, then in the directory entry, and the file is given new granules when it has none there. Each extent of the FCB is four bytes: the count of granules before it (two bytes, 0 for the first extent, which has none), the block and the granule byte (bits 7-5 the first granule in the block, bits 4-0 the count of granules minus 1). Returns Register D the block, Register E the sector in it and Register C the drive.

48DC
LD L,(IX+0AH) DD 6E 0A
Load Register L with the low byte of the sector number at FCB+0AH through Index Register IX.
48DF
LD H,(IX+0BH) DD 66 0B
Load Register H with the high byte of the sector number at FCB+0BH through Index Register IX.
48E2
LD A,05H 3E 05
Load Register A with 05H, the five sectors of a granule, the divisor for 4B84H.
48E4
Call 4B84H to divide Register Pair HL by Register A: Register Pair HL returns the granule of the file and Register A the sector in the granule.
48E7
LD (49AAH),A 32 AA 49
Store Register A, the sector in the granule, at 49AAH, the operand of ADD A,nn at 49A9H.
48EA
PUSH IX DD E5
Push Index Register IX, the FCB address, on the stack.
48EC
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer: Register Pair HL is the FCB address and the granule is on the stack.
48ED
LD BC,000FH 01 0F 00
Load Register Pair BC with 000FH, the offset of the first extent's granule byte in the FCB.
48F0
ADD HL,BC 09
Add Register Pair BC to Register Pair HL: Register Pair HL is FCB+0FH.
48F1
POP BC C1
Take the granule off the stack into Register Pair BC: the granule looked for.
48F2
LD A,05H 3E 05
Load Register A with 05H, the five extents of the FCB.
48F4
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H: the first extent has no granules before it.
48F7
PUSH AF F5
Save Register Pair AF, the extents left in Register A, on the stack.
48F8
DEC HL 2B
Decrement Register Pair HL to FCB+0EH, the block of the first extent.
48F9
LD A,(HL) 7E
Load Register A with the block of the extent at Register Pair HL. 43F0H jumps here for the later extents.
48FA
INC HL 23
Increment Register Pair HL to the granule byte of the extent.
48FB
INC A 3C
Increment Register A: the Z FLAG is set when the block was FFH, an extent not in use.
48FC
If the Z FLAG is set (an unused extent), jump to 4909H for the next one.
48FE
PUSH HL E5
Save Register Pair HL, the address of the granule byte, on the stack.
48FF
LD H,D 62
Copy Register D, the high byte of the granules before the extent, into Register H.
4900
LD L,E 6B
Copy Register E, the low byte, into Register L: Register Pair HL is the first granule of the extent.
4901
XOR A AF
Clear Register A to 00H and the C FLAG for the subtraction.
4902
SBC HL,BC ED 42
Subtract Register Pair BC, the granule looked for, from Register Pair HL, the extent's first granule.
4904
If the C FLAG is set (the granule lies at or after the start of the extent), jump to 4915H to see whether it lies inside it.
4906
POP HL E1
Restore Register Pair HL, the address of the granule byte, from the stack.
4907
If the Z FLAG is set (the granule is the first of the extent), jump to 496AH with Register A 00H, the granule's place in the extent.
4909
INC HL 23
Increment Register Pair HL to the count of granules that follows the extent, the first granule of the next one.
490A
POP AF F1
Restore Register Pair AF, the extents left in Register A, from the stack.
490B
DEC A 3D
Decrement Register A, the count of FCB extents still to search.
490C
If the Z FLAG is set (all five extents have been searched), jump to 4928H to look in the directory entry.
490E
LD E,(HL) 5E
Load Register E with the low byte of the count of granules before the next extent from Register Pair HL.
490F
INC HL 23
Increment Register Pair HL to the high byte of the count.
4910
LD D,(HL) 56
Load Register D with the high byte of the count from Register Pair HL: Register Pair DE is the first granule of the next extent.
4911
INC HL 23
Increment Register Pair HL to the block of the next extent.
4912
Jump to 43ECH, which saves the extents left and goes on at 48F9H unless Register Pair HL has reached 44A0H.
4915
INC H 24
Increment Register H: the Z FLAG is set when Register H was FFH, the granule less than 256 granules after the extent's start.
4916
LD A,L 7D
Copy Register L, the low byte of the difference (the extent's start minus the granule), into Register A.
4917
POP HL E1
Restore Register Pair HL, the address of the granule byte, from the stack.
4918
If the NZ FLAG is set (the granule is far beyond this extent), jump to 4909H for the next one.
491A
PUSH DE D5
Save Register Pair DE, the extent's first granule, on the stack.
491B
LD E,A 5F
Copy the difference from Register A into Register E.
491C
LD A,(HL) 7E
Load Register A with the granule byte of the extent at Register Pair HL.
491D
AND 1FH E6 1F
AND Register A with 1FH to keep the count of granules in the extent minus 1.
491F
ADD A,E 83
Add Register E, the difference (negative), to Register A: the C FLAG is set when the granule lies inside the extent.
4920
LD A,E 7B
Copy the difference from Register E back into Register A; LD does not change the C FLAG.
4921
POP DE D1
Restore Register Pair DE, the extent's first granule, from the stack.
4922
If the NC FLAG is set (the granule lies beyond this extent), jump to 4909H for the next one.
4924
NEG ED 44
Negate Register A: the granule's place in the extent, counted from 0.
4926
Jump to 496AH with the place in Register A and Register Pair HL at the extent's granule byte.

4928H - Look in the Directory Entry

Reached when none of the five extents in the FCB holds the granule. 49B5H finds it in the directory entry (giving the file new granules when needed); the extent found is then put in the FCB as its second extent, the others moving up and the fifth dropped, unless it is there already.

4928
Call 49B5H to find granule Register Pair BC in the extents of the directory entry: Register Pair HL returns the extent (Register L the block, Register H the granule byte) and Register Pair DE the granules before it.
492B
RET NZ C0
If the NZ FLAG is set (an error), return with the error code in Register A.
492C
PUSH HL E5
Save Register Pair HL, the extent, on the stack.
492D
LD H,B 60
Copy Register B, the high byte of the granule looked for, into Register H.
492E
LD L,C 69
Copy Register C, the low byte, into Register L: Register Pair HL is the granule.
492F
XOR A AF
Clear Register A to 00H and the C FLAG for the subtraction.
4930
SBC HL,DE ED 52
Subtract Register Pair DE, the granules before the extent, from Register Pair HL: the granule's place in the extent.
4932
LD A,L 7D
Copy the place in the extent, Register L, into Register A for the store at 4933H.
4933
LD (499AH),A 32 9A 49
Store Register A, the place in the extent, at 499AH, the operand of ADD A,nn at 4999H.
4936
POP HL E1
Restore Register Pair HL, the extent, from the stack.
4937
PUSH DE D5
Save Register Pair DE, the granules before the extent, on the stack.
4938
PUSH IX DD E5
Push Index Register IX, the FCB address, on the stack.
493A
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer: Register Pair HL is the FCB address and the extent is on the stack.
493B
LD DE,000EH 11 0E 00
Load Register Pair DE with 000EH, the offset of the first extent's block in the FCB.
493E
ADD HL,DE 19
Add Register Pair DE to Register Pair HL: Register Pair HL is FCB+0EH.
493F
POP DE D1
Take the extent off the stack into Register Pair DE: Register E the block, Register D the granule byte.
4940
LD B,05H 06 05
Load Register B with 05H, the five extents of the FCB.
4942
LD A,(HL) 7E
Load Register A with the block of the FCB's extent at Register Pair HL.
4943
INC HL 23
Increment Register Pair HL to the granule byte of the FCB's extent.
4944
CP E BB
Compare Register A with Register E, the block of the extent found.
4945
If the NZ FLAG is set (another block), jump to 494DH for the next extent of the FCB.
4947
LD A,(HL) 7E
Load Register A with the granule byte of the FCB's extent at Register Pair HL.
4948
XOR D AA
Exclusive OR Register A with Register D, the granule byte of the extent found.
4949
AND E0H E6 E0
AND Register A with E0H to keep the difference in bits 7-5, the first granule.
494B
If the Z FLAG is set (the same extent), jump to 4965H to store its granule byte, whose count may have grown.
494D
DEC B 05
Decrement Register B, the count of FCB extents still to compare.
494E
If the Z FLAG is set (the extent is not in the FCB), jump to 4955H to put it in as the second extent.
4950
INC HL 23
Increment Register Pair HL to the low byte of the count before the next extent.
4951
INC HL 23
Increment Register Pair HL to the high byte of the count.
4952
INC HL 23
Increment Register Pair HL to the block of the next extent.
4953
Jump back to 4942H to compare the next extent of the FCB.
4955
PUSH DE D5
Save Register Pair DE, the extent found, on the stack.
4956
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE is FCB+1FH, the granule byte of the fifth extent.
4957
LD HL,FFFCH 21 FC FF
Load Register Pair HL with FFFCH, minus 4, to step back one extent of four bytes.
495A
ADD HL,DE 19
Add Register Pair DE to Register Pair HL: Register Pair HL is FCB+1BH, the granule byte of the fourth extent.
495B
LD BC,000CH 01 0C 00
Load Register Pair BC with 000CH, the twelve bytes of the second, third and fourth extents.
495E
LDDR ED B8
Move twelve bytes from Register Pair HL to Register Pair DE downward, counted in Register Pair BC: the second to fourth extents become the third to fifth and the fifth is dropped.
4960
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is FCB+13H, the granule byte of the second extent.
4961
POP BC C1
Take the extent found off the stack into Register Pair BC: Register C the block, Register B the granule byte.
4962
POP DE D1
Restore Register Pair DE, the granules before the extent, from the stack.
4963
Jump to 498AH to store the extent as the second extent of the FCB.
4965
LD (HL),D 72
Store Register D, the granule byte of the extent found, at Register Pair HL in the FCB's extent.
4966
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is the extent (Register L the block, Register H the granule byte).
4967
POP AF F1
Take the granules before the extent off the stack into Register Pair AF; they are not needed.
4968
Jump to 4993H to work out the block and the sector.

496AH - Bring the Extent Forward

Entered from 4907H and 4926H with Register A the granule's place in the extent and Register Pair HL at the extent's granule byte in the FCB. The third, fourth or fifth extent is moved to the second place, so that the extents used last are found first.

496A
LD (499AH),A 32 9A 49
Store Register A, the place in the extent, at 499AH, the operand of ADD A,nn at 4999H.
496D
LD B,(HL) 46
Load Register B with the granule byte of the extent at Register Pair HL.
496E
DEC HL 2B
Decrement Register Pair HL to the block of the extent.
496F
LD C,(HL) 4E
Load Register C with the block of the extent at Register Pair HL.
4970
INC HL 23
Increment Register Pair HL to the granule byte again.
4971
POP AF F1
Restore Register Pair AF, the extents left in Register A (5 for the first extent, 1 for the fifth), from the stack.
4972
CPL 2F
Complement Register A, the extents left, for the test at 4973H.
4973
ADD A,04H C6 04
Add 04H to Register A: the C FLAG is set for the third, fourth and fifth extents, and Register A is 00H, 01H or 02H.
4975
If the NC FLAG is set (the first or second extent), jump to 4991H: it stays where it is.
4977
INC A 3C
Increment Register A: 1, 2 or 3 extents to move.
4978
RLCA 07
Rotate Register A left: twice the number of extents.
4979
RLCA 07
Rotate Register A left again: the number of bytes to move, four for each extent.
497A
PUSH DE D5
Save Register Pair DE, the granules before the extent, on the stack.
497B
LD D,H 54
Copy Register H into Register D, the high byte of the destination of the move.
497C
LD E,L 5D
Copy Register L into Register E: Register Pair DE is the address of the extent's granule byte.
497D
DEC HL 2B
Decrement Register Pair HL, the first of four steps back to the extent before.
497E
DEC HL 2B
Decrement Register Pair HL, the second step back.
497F
DEC HL 2B
Decrement Register Pair HL, the third step back.
4980
DEC HL 2B
Decrement Register Pair HL, the fourth step: Register Pair HL is the granule byte of the extent before.
4981
PUSH BC C5
Save Register Pair BC, the extent (Register C the block, Register B the granule byte), on the stack.
4982
LD C,A 4F
Copy the count of bytes to move from Register A into Register C.
4983
LD B,00H 06 00
Load Register B with 00H: Register Pair BC is the count of bytes to move.
4985
LDDR ED B8
Move the bytes from Register Pair HL to Register Pair DE downward, counted in Register Pair BC: the extents from the second on move up one place.
4987
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is FCB+13H, the granule byte of the second extent.
4988
POP BC C1
Restore Register Pair BC, the extent, from the stack.
4989
POP DE D1
Restore Register Pair DE, the granules before the extent, from the stack.
498A
LD (HL),B 70
Store Register B, the granule byte, at Register Pair HL. 4963H jumps here.
498B
DEC HL 2B
Decrement Register Pair HL to the block of the extent.
498C
LD (HL),C 71
Store Register C, the block, at Register Pair HL.
498D
DEC HL 2B
Decrement Register Pair HL to the high byte of the count before the extent.
498E
LD (HL),D 72
Store Register D, the high byte of the granules before the extent, at Register Pair HL.
498F
DEC HL 2B
Decrement Register Pair HL to the low byte of the count.
4990
LD (HL),E 73
Store Register E, the low byte of the granules before the extent, at Register Pair HL.
4991
LD H,B 60
Copy Register B, the granule byte, into Register H.
4992
LD L,C 69
Copy Register C, the block, into Register L: Register Pair HL is the extent.

4993H - Work Out the Block and the Sector

Entered with Register Pair HL the extent (Register L the block, Register H the granule byte), the granule's place in the extent at 499AH and the sector in the granule at 49AAH. A block holds two granules of five sectors.

4993
LD A,H 7C
Copy the granule byte from Register H into Register A.
4994
RLCA 07
Rotate Register A left, the first of three turns that bring bits 7-5 to bits 2-0.
4995
RLCA 07
Rotate Register A left, the second of the three turns of the granule byte.
4996
RLCA 07
Rotate Register A left, the third turn: bits 2-0 are the first granule of the extent in its block.
4997
AND 07H E6 07
AND Register A with 07H to keep the first granule.
4999
ADD A,00H C6 00
Add the granule's place in the extent to Register A: the operand at 499AH is stored by 4933H or 496AH. Register A is the granule counted from the extent's block.
499B
LD E,A 5F
Copy the granule count from Register A into Register E.
499C
AND FEH E6 FE
AND Register A with FEH to drop the granule in the block, bit 0.
499E
RRCA 0F
Rotate Register A right: the number of blocks after the extent's block.
499F
LD (49AEH),A 32 AE 49
Store Register A, the number of blocks, at 49AEH, the operand of ADD A,nn at 49ADH.
49A2
LD A,E 7B
Copy the granule count from Register E into Register A.
49A3
AND 01H E6 01
AND Register A with 01H: the granule in its block, 0 or 1.
49A5
LD E,A 5F
Copy the granule in the block from Register A into Register E.
49A6
RLCA 07
Rotate Register A left: twice the granule in the block, on the way to five times.
49A7
RLCA 07
Rotate Register A left again: four times the granule.
49A8
ADD A,E 83
Add Register E to Register A: five times the granule, the first sector of the granule in the block (0 or 5).
49A9
ADD A,00H C6 00
Add the sector in the granule to Register A: the operand at 49AAH is stored by 48E7H.
49AB
LD E,A 5F
Copy the sector in the block from Register A into Register E.
49AC
LD A,L 7D
Copy the extent's block from Register L into Register A.
49AD
ADD A,00H C6 00
Add the number of blocks after it to Register A: the operand at 49AEH is stored by 499FH.
49AF
LD D,A 57
Copy the block from Register A into Register D.
49B0
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at FCB+06H through Index Register IX.
49B3
XOR A AF
Clear Register A to 00H and set the Z FLAG: the sector has been found.
49B4
RET C9
Return with Register D the block, Register E the sector and Register C the drive.

49B5H - Find a Granule in the Directory Entry

Called with Register Pair BC the granule of the file. The directory entry of the file (record FCB+07H) is read into 4200H and its extents at +16H-+1FH are counted; an extent byte FEH is followed by the record of another entry of the same file, FFH ends the list and makes 4A00H give the file new granules. Returns Register Pair HL the extent and Register Pair DE the granules before it.

49B5
PUSH BC C5
Save Register Pair BC, the granule looked for, on the stack.
49B6
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H; it becomes the count of granules before the extent in Register Pair HL.
49B9
LD B,(IX+07H) DD 46 07
Load Register B with the directory record of the file at FCB+07H through Index Register IX.
49BC
LD A,B 78
Copy the directory record from Register B into Register A.
49BD
LD (4ABEH),A 32 BE 4A
Store Register A, the record, at 4ABEH, the operand of LD B,nn at 4ABDH, so that 4AB6H writes this entry back.
49C0
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at FCB+06H through Index Register IX.
49C3
Call 4AC1H to read the directory sector of record Register B into 4200H: Register Pair HL returns the address of the entry.
49C6
LD BC,0016H 01 16 00
Load Register Pair BC with 0016H, the offset of the extents in a directory entry.
49C9
ADD HL,BC 09
Add Register Pair BC to Register Pair HL: Register Pair HL is the first extent of the entry.
49CA
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE is the extent and Register Pair HL the count of granules (0000H).
49CB
POP BC C1
Restore Register Pair BC, the granule looked for, from the stack.
49CC
RET NZ C0
If the NZ FLAG is set (the directory could not be read), return with the error code in Register A.
49CD
LD A,(DE) 1A
Load Register A with the block of the extent at Register Pair DE.
49CE
CP FEH FE FE
Compare Register A with FEH: the C FLAG is clear for FEH (a link to another entry) and FFH (the end).
49D0
If the NC FLAG is set (FEH or FFH), jump to 49F1H.
49D2
INC DE 13
Increment Register Pair DE to the granule byte of the extent.
49D3
LD A,(DE) 1A
Load Register A with the granule byte at Register Pair DE.
49D4
PUSH HL E5
Save Register Pair HL, the granules before this extent, on the stack.
49D5
AND 1FH E6 1F
AND Register A with 1FH to keep the count of granules minus 1.
49D7
INC A 3C
Increment Register A: the granules in the extent.
49D8
ADD A,L 85
Add Register L, the low byte of the count, to Register A.
49D9
LD L,A 6F
Copy the sum from Register A into Register L.
49DA
If the NC FLAG is set (no carry), jump to 49DDH.
49DC
INC H 24
Increment Register H for the carry: Register Pair HL is the granules up to the end of the extent.
49DD
PUSH HL E5
Save Register Pair HL, the granules up to the end of the extent, on the stack.
49DE
DEC HL 2B
Decrement Register Pair HL: the last granule of the extent.
49DF
XOR A AF
Clear Register A to 00H and the C FLAG for the subtraction.
49E0
SBC HL,BC ED 42
Subtract Register Pair BC, the granule looked for, from Register Pair HL: the NC FLAG is set when the granule lies in this extent.
49E2
POP HL E1
Restore Register Pair HL, the granules up to the end of the extent, from the stack.
49E3
If the NC FLAG is set (the granule is in this extent), jump to 49E9H.
49E5
INC DE 13
Increment Register Pair DE to the next extent of the entry.
49E6
POP AF F1
Take the granules before the extent off the stack into Register Pair AF; the new count is in Register Pair HL.
49E7
Jump back to 49CDH for the next extent of the directory entry.
49E9
POP HL E1
Restore Register Pair HL, the granules before the extent, from the stack.
49EA
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE is the granules before the extent and Register Pair HL the extent's granule byte.
49EB
LD A,(HL) 7E
Load Register A with the granule byte at Register Pair HL.
49EC
DEC HL 2B
Decrement Register Pair HL to the block of the extent.
49ED
LD L,(HL) 6E
Load Register L with the block at Register Pair HL.
49EE
LD H,A 67
Copy the granule byte from Register A into Register H: Register Pair HL is the extent.
49EF
XOR A AF
Clear Register A to 00H and set the Z FLAG: the granule has been found.
49F0
RET C9
Return with Register Pair HL the extent and Register Pair DE the granules before it.
49F1
PUSH BC C5
Save Register Pair BC, the granule looked for, on the stack.
49F2
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is the address of the FEH or FFH byte and Register Pair DE the granules so far.
49F3
If the NZ FLAG is set (FFH, the end of the extents), jump to 49F9H to give the file more granules.
49F5
INC HL 23
Increment Register Pair HL to the byte after FEH, the directory record of the next entry of the file.
49F6
LD B,(HL) 46
Load Register B with the next entry's directory record at Register Pair HL.
49F7
Jump back to 49BCH to read that entry and go on counting.
49F9
Call 4A00H to give the file the granules up to the one looked for.
49FC
POP BC C1
Restore Register Pair BC, the granule looked for, from the stack.
49FD
RET NZ C0
If the NZ FLAG is set (the disk is full or a sector could not be read or written), return with the error code in Register A.
49FE
Jump back to 49B5H to find the granule in the extended entry.

4A00H - Give the File New Granules

Called from 49F9H with Register Pair BC the granule wanted, Register Pair DE the granules the file has and Register Pair HL at the FFH that ends the extents in the directory entry at 4200H. The GAT is read into 4D00H; a granule following the last extent is added to it when free, else a new extent is begun at the first free granule from the GAT byte 4D00H plus four times the low three bits of the directory record. The GAT and the entry are written back at the end.

4A00
PUSH BC C5
Save Register Pair BC, the granule wanted, on the stack.
4A01
LD B,(IX+07H) DD 46 07
Load Register B with the directory record at FCB+07H through Index Register IX.
4A04
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at FCB+06H through Index Register IX.
4A07
Call 4AF0H to read the GAT of drive Register C into 4D00H.
4A0A
POP BC C1
Restore Register Pair BC, the granule wanted, from the stack.
4A0B
RET NZ C0
If the NZ FLAG is set (the GAT could not be read), return with error 14H in Register A.
4A0C
PUSH HL E5
Save Register Pair HL, the address of the FFH in the entry, on the stack.
4A0D
LD H,B 60
Copy Register B, the high byte of the granule wanted, into Register H.
4A0E
LD L,C 69
Copy Register C, the low byte, into Register L: Register Pair HL is the granule wanted.
4A0F
XOR A AF
Clear Register A to 00H and the C FLAG for the subtraction.
4A10
SBC HL,DE ED 52
Subtract Register Pair DE, the granules the file has, from Register Pair HL.
4A12
LD B,H 44
Copy Register H into Register B, the high byte of the difference.
4A13
LD C,L 4D
Copy Register L into Register C: Register Pair BC is the granule wanted minus the granules there are.
4A14
INC BC 03
Increment Register Pair BC: the number of granules to add.
4A15
POP DE D1
Take the address of the FFH in the entry off the stack into Register Pair DE.
4A16
INC DE 13
Increment Register Pair DE to the granule byte of the free extent place.
4A17
NOP 00
No operation: a byte of 00H left in the code.
4A18
LD A,(IX+07H) DD 7E 07
Load Register A with the directory record at FCB+07H through Index Register IX.
4A1B
AND 07H E6 07
AND Register A with 07H to keep its low three bits.
4A1D
RLCA 07
Rotate Register A left: twice the low three bits of the directory record.
4A1E
RLCA 07
Rotate Register A left again: four times the bits.
4A1F
LD L,A 6F
Copy Register A, four times the low bits of the record, into Register L.
4A20
LD H,4DH 26 4D
Load Register H with 4DH: Register Pair HL is the GAT byte (of the GAT at 4D00H) where the search for a free granule begins.
4A22
PUSH BC C5
Save Register Pair BC, the granules to add, on the stack.
4A23
LD A,E 7B
Copy Register E, the low byte of the free extent place in Register Pair DE, into Register A.
4A24
AND 1EH E6 1E
AND Register A with 1EH to keep the offset of the extent place in the entry.
4A26
CP 16H FE 16
Compare Register A with 16H, the first extent place.
4A28
If the Z FLAG is set (the entry has no extent yet), jump to 4A6EH to search the GAT.
4A2A
DEC E 1D
Decrement Register E: Register Pair DE steps back toward the extent before.
4A2B
DEC E 1D
Decrement Register E again: Register Pair DE is the granule byte of the last extent.
4A2C
LD A,(DE) 1A
Load Register A with the granule byte of the last extent at Register Pair DE. 4AB2H jumps back here for each granule added.
4A2D
AND 1FH E6 1F
AND Register A with 1FH to keep the count of granules minus 1.
4A2F
INC A 3C
Increment Register A: the granules in the extent.
4A30
LD C,A 4F
Copy the granules in the extent from Register A into Register C.
4A31
CP 20H FE 20
Compare Register A with 20H, the 32 granules an extent can hold.
4A33
If the Z FLAG is set (the extent is full), jump to 4A54H to begin a new one.
4A35
LD A,(DE) 1A
Load Register A with the granule byte of the extent at Register Pair DE.
4A36
AND E0H E6 E0
AND Register A with E0H to keep bits 7-5, the first granule.
4A38
RLCA 07
Rotate Register A left, the first of three turns that bring bits 7-5 to bits 2-0.
4A39
RLCA 07
Rotate Register A left, the second of the three turns of the granule byte.
4A3A
RLCA 07
Rotate Register A left, the third turn: Register A is the first granule of the extent.
4A3B
ADD A,C 81
Add Register C, the granules in the extent, to Register A: the granule after the extent, counted from its block.
4A3C
LD B,A 47
Copy the granule after the extent from Register A into Register B.
4A3D
SRL B CB 38
Shift Register B right: the number of blocks after the extent's block.
4A3F
AND 01H E6 01
AND Register A with 01H: the granule in its block.
4A41
LD C,A 4F
Copy the granule in the block from Register A into Register C.
4A42
DEC DE 1B
Decrement Register Pair DE to the block of the extent.
4A43
LD A,(DE) 1A
Load Register A with the block of the extent at Register Pair DE.
4A44
INC DE 13
Increment Register Pair DE to the granule byte again.
4A45
ADD A,B 80
Add Register B, the blocks after it, to Register A: the block of the granule after the extent.
4A46
LD L,A 6F
Copy the block from Register A into Register L.
4A47
LD H,4DH 26 4D
Load Register H with 4DH: Register Pair HL is the GAT byte of that block.
4A49
CP C0H FE C0
Compare Register A, the block, with C0H, the end of the GAT bytes.
4A4B
If the NC FLAG is set (beyond the GAT), jump to 4A54H to begin a new extent.
4A4D
LD A,C 79
Copy the granule in the block from Register C into Register A.
4A4E
LD B,(HL) 46
Load Register B with the GAT byte at Register Pair HL.
4A4F
Call 4B5DH to test the granule's bit, number Register A, of Register B: the Z FLAG is set when the granule is free.
4A52
If the Z FLAG is set (the granule after the extent is free), jump to 4A9CH to add it to the extent.
4A54
INC E 1C
Increment Register E: Register Pair DE steps forward toward the free extent place.
4A55
INC E 1C
Increment Register E again: Register Pair DE is the granule byte of the free extent place.
4A56
LD A,E 7B
Copy Register E, the low byte of the extent place address, into Register A.
4A57
AND 1EH E6 1E
AND Register A with 1EH to keep the offset of the extent place in the entry.
4A59
CP 1EH FE 1E
Compare Register A with 1EH, the last extent place.
4A5B
If the NZ FLAG is set (not the last place), jump to 4A6EH to begin the new extent there.
4A5D
Call 4AB6H to write the GAT and the directory entry back.
4A60
POP BC C1
Restore Register Pair BC, the granules to add, from the stack.
4A61
RET NZ C0
If the NZ FLAG is set (a write failed), return with the error code in Register A.
4A62
PUSH BC C5
Save Register Pair BC, the granules to add, on the stack again.
4A63
Call 4A6BH, which calls SYS2/SYS with request code B4H to give the file another directory entry.
4A66
POP BC C1
Restore Register Pair BC, the granules to add, from the stack.
4A67
RET NZ C0
If the NZ FLAG is set (no entry could be made), return with the error code in Register A.
4A68
Jump to 49B5H to count the extents again with Register Pair BC; it returns to 49FCH, which looks for the granule wanted once more.
4A6B
LD A,B4H 3E B4
Load Register A with B4H, the request code of SYS2/SYS that gives a file another directory entry.
4A6D
RST 28H EF
Call the overlay dispatcher through RST 28H (400CH, 4BA2H) with the request code B4H in Register A; SYS2/SYS returns to the caller of 4A6BH.
4A6E
LD B,02H 06 02
Load Register B with 02H: the GAT is searched from the starting byte to its end and once more from 4D00H.
4A70
LD A,L 7D
Copy Register L, the GAT byte in Register Pair HL, into Register A.
4A71
CP C0H FE C0
Compare Register A with C0H, the end of the GAT bytes.
4A73
If the NC FLAG is set (the end of the GAT), jump to 4A7CH to start again at 4D00H.
4A75
LD A,(HL) 7E
Load Register A with the GAT byte at Register Pair HL.
4A76
INC A 3C
Increment Register A: the Z FLAG is set when the byte was FFH, a block with no free granule.
4A77
If the NZ FLAG is set (a free granule in this block), jump to 4A89H.
4A79
INC L 2C
Increment Register L to the next GAT byte, the next block, in Register Pair HL.
4A7A
Jump back to 4A70H to test the next GAT byte for a free granule.
4A7C
LD L,00H 2E 00
Load Register L with 00H: Register Pair HL is 4D00H, the first GAT byte.
4A7E
Decrement Register B and jump back to 4A70H for the second pass.
4A80
POP BC C1
Restore Register Pair BC, the granules to add, from the stack.
4A81
Call 4AB6H to write the GAT and the directory entry back with the granules already added.
4A84
RET NZ C0
If the NZ FLAG is set (a write failed), return with the error code in Register A.
4A85
LD A,1BH 3E 1B
Load Register A with 1BH, the error code for a full disk, which SYS4/SYS shows it as DISK SPACE FULL.
4A87
OR A B7
Set the flags from Register A (1BH): the NZ FLAG is set.
4A88
RET C9
Return with error 1BH in Register A: no free granule is left on the diskette.
4A89
LD A,FFH 3E FF
Load Register A with FFH for the granule byte of the new extent; 4AA9H-4AACH add one to it.
4A8B
LD (DE),A 12
Store Register A (FFH) in the granule byte of the new extent place at Register Pair DE.
4A8C
LD C,00H 0E 00
Load Register C with 00H, the first granule of the block.
4A8E
LD B,(HL) 46
Load Register B with the GAT byte at Register Pair HL.
4A8F
LD A,C 79
Copy the granule number from Register C into Register A.
4A90
Call 4B5DH to test the granule's bit, number Register A, of Register B: the Z FLAG is set when it is free.
4A93
If the Z FLAG is set (the granule is free), jump to 4A9CH to take it.
4A95
LD A,(DE) 1A
Load Register A with the granule byte of the new extent at Register Pair DE.
4A96
ADD A,20H C6 20
Add 20H to Register A: one more in bits 7-5, the first granule.
4A98
LD (DE),A 12
Store Register A in the granule byte at Register Pair DE.
4A99
INC C 0C
Increment Register C to the next granule of the block.
4A9A
Jump back to 4A8FH to test the bit of the next granule of the block.
4A9C
LD A,C 79
Copy the granule number from Register C into Register A.
4A9D
Call 4639H to turn the granule number in Register A into its bit in Register A.
4AA0
OR (HL) B6
OR Register A, the bit, with the GAT byte at Register Pair HL.
4AA1
LD (HL),A 77
Store Register A at Register Pair HL: the granule is marked as used in the GAT.
4AA2
DEC E 1D
Decrement Register E: Register Pair DE is the block byte of the extent.
4AA3
LD A,(DE) 1A
Load Register A with the block byte at Register Pair DE.
4AA4
INC A 3C
Increment Register A: the Z FLAG is set when it was FFH, a new extent.
4AA5
If the NZ FLAG is set (the extent has its block), jump to 4AA9H.
4AA7
LD A,L 7D
Copy Register L, the GAT byte of the block (its number), into Register A.
4AA8
LD (DE),A 12
Store Register A, the block, in the block byte of the new extent at Register Pair DE.
4AA9
INC E 1C
Increment Register E: Register Pair DE is the granule byte of the extent.
4AAA
LD A,(DE) 1A
Load Register A with the granule byte at Register Pair DE.
4AAB
INC A 3C
Increment Register A: one more granule in the extent (FFH becomes 00H, one granule from granule 0; 1FH becomes 20H, one granule from granule 1).
4AAC
LD (DE),A 12
Store Register A in the granule byte of the extent at Register Pair DE.
4AAD
POP BC C1
Restore Register Pair BC, the granules to add, from the stack.
4AAE
DEC BC 0B
Decrement Register Pair BC, one fewer granule to add.
4AAF
PUSH BC C5
Save Register Pair BC, the granules still to add, on the stack again.
4AB0
LD A,B 78
Copy Register B, the high byte of the granules still to add, into Register A.
4AB1
OR C B1
OR Register A with Register C: the Z FLAG is set when Register Pair BC is 0000H.
4AB2
If the NZ FLAG is set (more granules to add), jump back to 4A2CH to add the next to the extent at Register Pair DE.
4AB5
POP BC C1
Restore Register Pair BC, the granules to add (now 0000H), from the stack.
4AB6
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at FCB+06H through Index Register IX.
4AB9
Call 4B03H to write the GAT at 4D00H back to drive Register C.
4ABC
RET NZ C0
If the NZ FLAG is set (the GAT could not be written), return with error 15H in Register A.
4ABD
LD B,00H 06 00
Load Register B with the directory record: the operand at 4ABEH is stored by 49BDH.
4ABF
Jump to 4AD6H to write the directory sector at 4200H back; it returns to the caller of 4AB6H.

4AC1H - Read a Directory Record

Reads the directory sector of record Register B of drive Register C into 4200H. Returns Register Pair HL the address of the entry, or error 11H. SYS2/SYS calls it.

4AC1
PUSH BC C5
Save Register Pair BC, the record and the drive, on the stack.
4AC2
PUSH DE D5
Save Register Pair DE on the stack; 4B1EH loads the block and sector into it.
4AC3
Call 4B1EH to find the block (Register D), the sector (Register E) and the entry's address in 4200H (Register Pair HL) of record Register B.
4AC6
If the NZ FLAG is set (no such record), jump to 4AD1H to return error 11H.
4AC8
PUSH HL E5
Save Register Pair HL, the address of the entry, on the stack.
4AC9
LD L,00H 2E 00
Load Register L with 00H: Register Pair HL is 4200H, the start of the sector buffer.
4ACB
Call 4B35H to read the directory sector into 4200H.
4ACE
POP HL E1
Restore Register Pair HL, the address of the entry, from the stack.
4ACF
If the Z FLAG is set (the sector was read), jump to 4AD3H to return.
4AD1
LD A,11H 3E 11
Load Register A with 11H, the error code for a directory read error.
4AD3
POP DE D1
Restore Register Pair DE, saved at 4AC2H, from the stack.
4AD4
POP BC C1
Restore Register Pair BC, the record and the drive, from the stack.
4AD5
RET C9
Return with Register Pair HL the entry and the Z FLAG set, or error 11H.

4AD6H - Write a Directory Record

Writes the directory sector at 4200H back as the sector of record Register B of drive Register C, with the deleted data mark, and reads it back. Returns error 12H if it fails. SYS2/SYS, SYS3/SYS and SYS6/SYS call it.

4AD6
PUSH BC C5
Save Register Pair BC, the record and the drive, on the stack.
4AD7
PUSH DE D5
Save Register Pair DE on the stack; 4B1EH loads the block and sector into it.
4AD8
Call 4B1EH to find the block (Register D) and the sector (Register E) of record Register B.
4ADB
If the NZ FLAG is set (no such record), jump to 4AEDH to return error 10H.
4ADD
LD L,00H 2E 00
Load Register L with 00H: Register Pair HL is 4200H, the sector to write.
4ADF
Call 46EFH to write the sector at Register Pair HL with the deleted data mark F8H.
4AE2
If the NZ FLAG is set (the write failed), jump to 4AEBH to return error 12H.
4AE4
Call 46F3H to read the sector back without storing its bytes.
4AE7
CP 06H FE 06
Compare Register A with 06H: the Z FLAG is set when the sector was read with the deleted data mark.
4AE9
If the Z FLAG is set (the sector is good), jump to 4AEDH to return.
4AEB
LD A,12H 3E 12
Load Register A with 12H, the error code for a directory write error.
4AED
POP DE D1
Restore Register Pair DE, saved at 4AD7H, from the stack.
4AEE
POP BC C1
Restore Register Pair BC, the record and the drive, from the stack.
4AEF
RET C9
Return with the Z FLAG set, or the error code in Register A.

4AF0H - Read the GAT

Reads sector 0 of the directory block of drive Register C, the GAT, into 4D00H. Returns error 14H if it fails. SYS3/SYS and SYS6/SYS call it.

4AF0
PUSH DE D5
Save Register Pair DE on the stack; the block and sector of the GAT go into it.
4AF1
PUSH HL E5
Save Register Pair HL on the stack; it is loaded with the GAT buffer 4D00H.
4AF2
Call 4B55H to load Register D with the directory block of drive Register C.
4AF5
LD E,00H 1E 00
Load Register E with 00H, sector 0 of the directory block: the GAT.
4AF7
LD HL,4D00H 21 00 4D
Load Register Pair HL with 4D00H, the buffer for the GAT.
4AFA
Call 4B35H to read the directory sector D, E into 4D00H.
4AFD
POP HL E1
Restore Register Pair HL, saved at 4AF1H, from the stack.
4AFE
POP DE D1
Restore Register Pair DE, saved at 4AF0H, from the stack.
4AFF
RET Z C8
If the Z FLAG is set (the GAT was read), return.
4B00
LD A,14H 3E 14
Load Register A with 14H, the error code for a GAT read error.
4B02
RET C9
Return with error 14H in Register A and the NZ FLAG set from 4B35H.

4B03H - Write the GAT

Writes the GAT at 4D00H back as sector 0 of the directory block of drive Register C and reads it back. Returns error 15H if it fails. SYS3/SYS and SYS6/SYS call it.

4B03
PUSH DE D5
Save Register Pair DE on the stack; the block and sector of the GAT go into it.
4B04
PUSH HL E5
Save Register Pair HL on the stack; it is loaded with the GAT buffer 4D00H.
4B05
Call 4B55H to load Register D with the directory block of drive Register C.
4B08
LD E,00H 1E 00
Load Register E with 00H, sector 0 of the directory block: the GAT.
4B0A
LD HL,4D00H 21 00 4D
Load Register Pair HL with 4D00H, the GAT to write.
4B0D
Call 46EFH to write the sector at Register Pair HL with the deleted data mark F8H.
4B10
If the NZ FLAG is set (the write failed), jump to 4B19H to return error 15H.
4B12
Call 46F3H to read the sector back without storing its bytes.
4B15
CP 06H FE 06
Compare Register A with 06H: the Z FLAG is set when the sector was read with the deleted data mark.
4B17
If the Z FLAG is set (the GAT is good), jump to 4B1BH to return.
4B19
LD A,15H 3E 15
Load Register A with 15H, the error code for a GAT write error.
4B1B
POP HL E1
Restore Register Pair HL, saved at 4B04H, from the stack.
4B1C
POP DE D1
Restore Register Pair DE, saved at 4B03H, from the stack.
4B1D
RET C9
Return with the Z FLAG set, or error 15H in Register A.

4B1EH - Find the Sector of a Directory Record

Register B is the directory record: bits 7-5 the entry in the sector (eight entries of 32 bytes), bits 4-0 the entry sector (0-7, sectors 2-9 of the directory block, after the GAT and the HIT). Returns Register D the block, Register E the sector and Register Pair HL the entry's address in 4200H, or error 10H for a sector above 7.

4B1E
Call 4B55H to load Register D with the directory block of drive Register C.
4B21
LD A,B 78
Copy the directory record from Register B into Register A.
4B22
AND E0H E6 E0
AND Register A with E0H to keep bits 7-5: the entry times 32, its offset in the sector.
4B24
LD L,A 6F
Copy the offset from Register A into Register L.
4B25
LD H,42H 26 42
Load Register H with 42H: Register Pair HL is the entry's address in the buffer at 4200H.
4B27
XOR B A8
Exclusive OR Register A with Register B: Register A is bits 4-0 of the record, the entry sector.
4B28
CP 08H FE 08
Compare Register A with 08H: the eight entry sectors are 0-7.
4B2A
If the NC FLAG is set (8 or more), jump to 4B31H to return error 10H.
4B2C
ADD A,02H C6 02
Add 02H to Register A, past the GAT (sector 0) and the HIT (sector 1).
4B2E
LD E,A 5F
Copy the sector of the directory block from Register A into Register E.
4B2F
XOR A AF
Clear Register A to 00H and set the Z FLAG: the record is valid.
4B30
RET C9
Return with Register D the block, Register E the sector and Register Pair HL the entry.
4B31
LD A,10H 3E 10
Load Register A with 10H, the error code for a bad directory record, which SYS4/SYS shows it as ILLEGAL LOGICAL FILE NUMBER.
4B33
OR A B7
Set the flags from Register A (10H): the NZ FLAG is set.
4B34
RET C9
Return with error 10H in Register A: the directory record is not valid.

4B35H - Read a Directory Sector

Reads sector Register E of block Register D on drive Register C into the buffer at Register Pair HL and expects the deleted data mark of the directory. A sector with the ordinary mark means the directory is elsewhere on this diskette: the directory block is taken from byte 2 of logical sector 0 (the first sector of cylinder 1), kept at 4304H plus the drive, and the read is made again. Returns Register A 00H and the Z FLAG set, or the error code. SYS2/SYS, SYS3/SYS and SYS6/SYS call it, and the start-up reads the GAT with it (4ECBH).

4B35
Call 46DDH to read the sector into the buffer at Register Pair HL.
4B38
SUB 06H D6 06
Subtract 06H from Register A: the Z FLAG is set when the read ended with error 06H, the deleted data mark.
4B3A
RET Z C8
If the Z FLAG is set (a directory sector), return with Register A 00H.
4B3B
ADD A,06H C6 06
Add 06H to Register A again: the read's own result.
4B3D
RET NZ C0
If the NZ FLAG is set (another error), return with the error code in Register A.
4B3E
PUSH DE D5
Save Register Pair DE, the block and sector, on the stack.
4B3F
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H: block 0, sector 0, the first sector of SYS0/SYS on a system diskette.
4B42
Call 46DDH to read logical sector 0 into the buffer at Register Pair HL.
4B45
POP DE D1
Restore Register Pair DE, the block and sector, from the stack.
4B46
RET NZ C0
If the NZ FLAG is set (the read failed), return with the error code in Register A.
4B47
PUSH HL E5
Save Register Pair HL, the buffer address, on the stack.
4B48
INC HL 23
Increment Register Pair HL to byte 1 of the sector.
4B49
INC HL 23
Increment Register Pair HL to byte 2 of the sector.
4B4A
LD D,(HL) 56
Load Register D with byte 2 of logical sector 0 at Register Pair HL: the directory block of the diskette. On a system diskette this is the third byte of SYS0/SYS, 11H (Percom memo DPM-0003 corrected it from the 53H of DoubleDOS 4.20).
4B4B
LD A,04H 3E 04
Load Register A with 04H, the offset of the directory blocks in 4300H.
4B4D
ADD A,C 81
Add Register C, the drive, to Register A: the offset of the drive's byte.
4B4E
LD L,A 6F
Copy Register A, the low byte of the drive's byte address, into Register L.
4B4F
LD H,43H 26 43
Load Register H with 43H: Register Pair HL is 4304H plus the drive.
4B51
LD (HL),D 72
Store Register D, the directory block, at Register Pair HL for the drive.
4B52
POP HL E1
Restore Register Pair HL, the buffer address, from the stack.
4B53
Jump back to 4B35H to read the sector of the directory block now in Register D.

4B55H - The Directory Block of a Drive

Loads Register D with the directory block of drive Register C from 4304H-4307H. SYS2/SYS, SYS3/SYS and SYS6/SYS use it.

4B55
LD A,04H 3E 04
Load Register A with 04H, the offset of the directory blocks in 4300H.
4B57
ADD A,C 81
Add Register C, the drive, to Register A: the offset of the drive's byte.
4B58
LD L,A 6F
Copy Register A, the low byte of the drive's byte address, into Register L.
4B59
LD H,43H 26 43
Load Register H with 43H: Register Pair HL is 4304H plus the drive.
4B5B
LD D,(HL) 56
Load Register D with the directory block of the drive at Register Pair HL.
4B5C
RET C9
Return with the directory block in Register D.

4B5DH - Test a Bit

Tests bit n of Register B, n being the low three bits of Register A: the routine writes the instruction BIT n,B at 4B67H. The Z FLAG returns set when the bit is clear (in the GAT: the granule is free).

4B5D
AND 07H E6 07
AND Register A with 07H to keep the bit number 0-7.
4B5F
RLCA 07
Rotate Register A left, the first of three turns that bring the bit number to bits 5-3.
4B60
RLCA 07
Rotate Register A left, the second of the three turns of the bit number.
4B61
RLCA 07
Rotate Register A left, the third turn: Register A is the bit number times 8.
4B62
OR 40H F6 40
OR Register A with 40H: Register A is the second byte of BIT n,B (40H plus 8 times n).
4B64
LD (4B68H),A 32 68 4B
Store Register A at 4B68H, the second byte of the BIT instruction at 4B67H.
4B67
BIT 0,B CB 40
Test bit n of Register B: the second byte of this instruction (40H, BIT 0,B, in the file) is stored by 4B64H.
4B69
RET C9
Return with the Z FLAG set when the bit is clear.

4B6AH - Multiply

Multiplies Register Pair HL by Register A. Returns the 24 bit product with its low byte in Register A and its upper 16 bits in Register Pair HL; Register Pair DE returns the multiplicand. DOUBLE/CMD calls it.

4B6A
PUSH BC C5
Save Register Pair BC on the stack; the multiplication counts in Register B.
4B6B
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE is the multiplicand.
4B6C
LD C,A 4F
Copy the multiplier from Register A into Register C.
4B6D
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, the product.
4B70
LD A,L 7D
Copy Register L (00H) into Register A, the top byte of the 24 bit product.
4B71
LD B,08H 06 08
Load Register B with 08H, the eight bits of the multiplier.
4B73
ADD HL,HL 29
Add Register Pair HL to itself: the product moves one bit left.
4B74
RLA 17
Rotate Register A left through the carry: the bit shifted out of Register Pair HL goes into the top byte.
4B75
RLC C CB 01
Rotate Register C, the multiplier, left: the C FLAG is its next bit.
4B77
If the NC FLAG is set (the bit is 0), jump to 4B7CH.
4B79
ADD HL,DE 19
Add Register Pair DE, the multiplicand, to Register Pair HL.
4B7A
ADC A,00H CE 00
Add the carry to Register A, the top byte of the product, with ADC 00H.
4B7C
Decrement Register B and loop back to 4B73H for the next bit of the multiplier.
4B7E
LD C,A 4F
Copy Register A, the top byte of the product, into Register C.
4B7F
LD A,L 7D
Copy Register L, the low byte of the product, into Register A.
4B80
LD L,H 6C
Copy Register H, the middle byte, into Register L.
4B81
LD H,C 61
Copy Register C, the top byte, into Register H: Register Pair HL is the upper 16 bits of the product.
4B82
POP BC C1
Restore Register Pair BC, saved at 4B6AH, from the stack.
4B83
RET C9
Return with the product in Register A (low byte) and Register Pair HL.

4B84H - Divide

Divides Register Pair HL by Register A. Returns the quotient in Register Pair HL and the remainder in Register A. DOUBLE/CMD and SYS3/SYS call it.

4B84
PUSH DE D5
Save Register Pair DE on the stack; the division keeps its divisor and count there.
4B85
LD D,A 57
Copy the divisor from Register A into Register D.
4B86
LD E,10H 1E 10
Load Register E with 10H, the sixteen bits of the dividend.
4B88
XOR A AF
Clear Register A to 00H, the remainder, before the sixteen steps.
4B89
ADD HL,HL 29
Add Register Pair HL to itself: the dividend moves one bit left and bit 0 is free for the quotient bit.
4B8A
RLA 17
Rotate Register A, the remainder, left through the carry: it takes the bit shifted out of Register Pair HL.
4B8B
If the C FLAG is set (the remainder passed 255), jump to 4B90H to subtract the divisor.
4B8D
CP D BA
Compare Register A, the remainder, with Register D, the divisor.
4B8E
If the C FLAG is set (the remainder is less than the divisor), jump to 4B92H: the quotient bit is 0.
4B90
SUB D 92
Subtract Register D, the divisor, from Register A, the remainder.
4B91
INC L 2C
Increment Register L: the quotient bit shifted into Register Pair HL is 1.
4B92
DEC E 1D
Decrement Register E, the count of dividend bits left.
4B93
If the NZ FLAG is set (bits are left), jump back to 4B89H.
4B95
POP DE D1
Restore Register Pair DE, saved at 4B84H, from the stack.
4B96
RET C9
Return with the quotient in Register Pair HL and the remainder in Register A.
4B97-4B9F
DEFS 9
Not in the file: nine bytes between the divide routine ending at 4B96H and 4BA0H.

4BA0H - Return with Register A 00H

Reached by the jump at 4312H.

4BA0
XOR A AF
Clear Register A to 00H and set the Z FLAG: a request code with bit 7 clear asks for nothing.
4BA1
RET C9
Return to the caller of the vector entry with Register A 00H and the Z FLAG set.

4BA2H - The Overlay Dispatcher

Reached by RST 28H through 400CH with Register A a request code. Bit 7 clear: nothing is done. Else the low four bits n name the overlay: directory record n (n below 8) or n plus 18H, read from drive 0 (records 03H-07H, SYS1/SYS to SYS5/SYS, are the first entry of entry sectors 3-7; records 20H and 21H, SYS6/SYS and SYS7/SYS, the second entry of entry sectors 0 and 1). The overlay is loaded through the system FCB at 44A0H unless the same low four bits were asked for last, then called at its transfer address with the request code in Register A. The return address of the RST is dropped, so the overlay returns to the caller of the vector entry.

4BA2
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer: Register Pair HL is the return address of the RST 28H and the caller's Register Pair HL is on the stack.
4BA3
POP HL E1
Restore the caller's Register Pair HL from the stack; the return address of the RST is dropped.
4BA4
OR A B7
Set the flags from Register A, the request code: the P FLAG is set when bit 7 is clear.
4BA5
If the P FLAG is set (bit 7 clear), jump to 4312H, which returns with Register A 00H.
4BA8
PUSH HL E5
Save Register Pair HL, the caller's, on the stack.
4BA9
LD H,A 67
Copy the request code from Register A into Register H.
4BAA
LD A,(430EH) 3A 0E 43
Load Register A with the request code of the overlay last loaded from 430EH.
4BAD
XOR H AC
Exclusive OR Register A with Register H, the new request code: bits 3-0 are 0000 when both name the same overlay.
4BAE
AND 0FH E6 0F
AND Register A with 0FH to keep the difference of the low four bits.
4BB0
LD A,H 7C
Copy the new request code from Register H into Register A; LD does not change the Z FLAG.
4BB1
LD (430EH),A 32 0E 43
Store Register A, the new request code, at 430EH.
4BB4
If the Z FLAG is set (the overlay is already in memory), jump to 4BEDH to call it.
4BB6
PUSH DE D5
Save Register Pair DE on the stack while the overlay is loaded.
4BB7
PUSH BC C5
Save Register Pair BC on the stack while the overlay is loaded.
4BB8
AND 0FH E6 0F
AND Register A, the request code, with 0FH to keep the overlay number n.
4BBA
CP 08H FE 08
Compare Register A, the overlay number, with 08H.
4BBC
If the C FLAG is set (n below 8), jump to 4BC0H: the directory record is n.
4BBE
ADD A,18H C6 18
Add 18H to Register A: overlays 8 and 9 are directory records 20H and 21H.
4BC0
LD B,A 47
Copy the directory record from Register A into Register B.
4BC1
LD (44A7H),A 32 A7 44
Store Register A, the directory record, at 44A7H, FCB+07H of the system FCB.
4BC4
XOR A AF
Clear Register A to 00H and the C FLAG for the subtraction at 4BC8H.
4BC5
LD (44A1H),A 32 A1 44
Store Register A (00H) at 44A1H, the flags of the system FCB: sector mode, access level 0.
4BC8
SBC HL,HL ED 62
Subtract Register Pair HL and the carry from Register Pair HL: Register Pair HL is 0000H.
4BCA
LD (44AAH),HL 22 AA 44
Store Register Pair HL (0000H) at 44AAH-44ABH, the sector of the system FCB: the overlay is read from its first sector.
4BCD
LD C,A 4F
Copy Register A (00H) into Register C: drive 0.
4BCE
Call 4AC1H to read the directory record Register B of drive 0 into 4200H: Register Pair HL returns the entry.
4BD1
If the NZ FLAG is set (the directory could not be read), jump to @ERROR at 4409H with the error code in Register A.
4BD4
Call 43DDH to check that the entry is in use (error 58H, or HALT for SYS4/SYS): Register A returns the low byte of the entry's first extent.
4BD7
LD L,A 6F
Copy the low byte of the extent's address from Register A into Register L: Register Pair HL is the first extent of the entry.
4BD8
LD A,(HL) 7E
Load Register A with the block of the first extent at Register Pair HL.
4BD9
INC L 2C
Increment Register L to the granule byte of the extent.
4BDA
LD H,(HL) 66
Load Register H with the granule byte at Register Pair HL.
4BDB
LD L,A 6F
Copy the block from Register A into Register L: Register Pair HL is the extent.
4BDC
LD (44AEH),HL 22 AE 44
Store Register Pair HL, the extent, at 44AEH-44AFH, the first extent of the system FCB.
4BDF
LD DE,44A0H 11 A0 44
Load Register Pair DE with 44A0H, the system FCB.
4BE2
Call 4C39H to load the overlay through the FCB at Register Pair DE: Register Pair HL returns its transfer address.
4BE5
If the NZ FLAG is set (the overlay could not be loaded), jump to @ERROR at 4409H with the error code in Register A.
4BE8
LD (4BFCH),HL 22 FC 4B
Store Register Pair HL, the overlay's transfer address, at 4BFCH, the operand of the CALL at 4BFBH.
4BEB
POP BC C1
Restore Register Pair BC, saved at 4BB7H, from the stack.
4BEC
POP DE D1
Restore Register Pair DE, saved at 4BB6H, from the stack.
4BED
POP HL E1
Restore Register Pair HL, the caller's, from the stack.
4BEE
LD A,(4315H) 3A 15 43
Load Register A with the BREAK flag at 4315H.
4BF1
LD (4C00H),A 32 00 4C
Store Register A, the BREAK flag, at 4C00H, the operand of LD A,nn at 4BFFH, to be put back after the overlay.
4BF4
XOR A AF
Clear Register A to 00H for the BREAK flag at 4315H.
4BF5
LD (4315H),A 32 15 43
Store Register A (00H) in the BREAK flag at 4315H: BREAK is not taken while an overlay runs.
4BF8
LD A,(430EH) 3A 0E 43
Load Register A with the request code from 430EH, which the overlay reads to choose its job.
4BFB
Call the overlay at its transfer address: the operand at 4BFCH is stored by 4BE8H (0000H in the file).
4BFE
PUSH AF F5
Save Register Pair AF, the overlay's result, on the stack.
4BFF
LD A,00H 3E 00
Load Register A with the BREAK flag as it was before the overlay: the operand at 4C00H is stored by 4BF1H.
4C01
LD (4315H),A 32 15 43
Store Register A in the BREAK flag at 4315H again.
4C04
POP AF F1
Restore Register Pair AF, the overlay's result, from the stack.
4C05
RET C9
Return to the caller of the vector entry with the overlay's result in Register A and the flags.

4C06H - @RUN: Load and Run a Program

Reached through 4433H with Register Pair DE the FCB of the program file.

4C06
PUSH HL E5
Save Register Pair HL on the stack; its place is taken by the transfer address at 4C0DH.
4C07
Call 4430H, @LOAD, to load the program: Register Pair HL returns its transfer address.
4C0A
If the NZ FLAG is set (the program could not be loaded), jump to @ERROR at 4409H with the error code in Register A.
4C0D
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack at the Stack Pointer: the transfer address is on the stack and Register Pair HL is the caller's again.
4C0E
LD A,(430FH) 3A 0F 43
Load Register A with the DEBUG flag at 430FH.
4C11
OR A B7
Set the flags from Register A, the DEBUG flag: the M FLAG is set when bit 7 is set.
4C12
If the M FLAG is set (DEBUG is on), jump to 400FH to enter DEBUG with the transfer address on the stack.
4C15
RET C9
Return to the transfer address on the stack: the program runs.

4C16H - @LOAD: Load a Program

Reached through 4430H with Register Pair DE the FCB of the program file. The file is opened with records of 256 bytes and the buffer 4200H; a file opened with an access level of 7 is refused, and bit 2 of the access level is cleared so that a file of level 4-6 can be read for loading. Returns the transfer address in Register Pair HL.

4C16
LD B,00H 06 00
Load Register B with 00H, the record length for the open: 256 bytes.
4C18
LD HL,4200H 21 00 42
Load Register Pair HL with 4200H, the buffer for the open.
4C1B
Call 4424H to open the file of the FCB at Register Pair DE through SYS2/SYS.
4C1E
If the Z FLAG is set (the file is open), jump to 4C29H.
4C20
SET 6,A CB F7
Set bit 6 of Register A, the error code returned by the open.
4C22
CP 58H FE 58
Compare Register A with 58H, error 18H with bit 6 set.
4C24
RET NZ C0
If the NZ FLAG is set (another error), return with the error code and bit 6 in Register A.
4C25
LD A,5FH 3E 5F
Load Register A with 5FH, error 1FH with bit 6 set, in place of 58H: SYS4/SYS shows 1FH as PROGRAM NOT FOUND.
4C27
OR A B7
Set the flags from Register A (5FH): the NZ FLAG is set.
4C28
RET C9
Return with error 5FH in Register A: the program file was not found.
4C29
LD H,D 62
Copy Register D, the high byte of the FCB address, into Register H.
4C2A
LD L,E 6B
Copy Register E, the low byte, into Register L: Register Pair HL is the FCB.
4C2B
INC HL 23
Increment Register Pair HL to FCB+01H, the flags.
4C2C
LD A,(HL) 7E
Load Register A with the flags at Register Pair HL.
4C2D
AND 07H E6 07
AND Register A with 07H to keep the access level, bits 0-2.
4C2F
CP 07H FE 07
Compare Register A, the access level, with 07H.
4C31
If the C FLAG is set (below 7), jump to 4C37H.
4C33
LD A,25H 3E 25
Load Register A with 25H, the error code for an access the level does not allow, which SYS4/SYS shows it as ILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE.
4C35
OR A B7
Set the flags from Register A (25H): the NZ FLAG is set.
4C36
RET C9
Return with error 25H in Register A: the file may not be loaded.
4C37
RES 2,(HL) CB 96
Reset bit 2 of the flags at Register Pair HL: an access level of 4, 5 or 6 becomes 0, 1 or 2, so that 480EH lets the file be read.

4C39H - Load a Load Module

Called from 4BE2H for an overlay and entered from 4C37H for a program, with Register Pair DE the FCB, whose buffer must be 4200H. Each record is a type byte, a length byte and the record: type 01H a load block (two address bytes and length minus 2 data bytes, a length of 02H giving 256), type 02H the transfer address, any other type below 20H passed over. Every byte stored is read back. Returns the transfer address in Register Pair HL, or with bit 6 set in Register A: 22H (a type of 20H or more), 23H (a byte reads back differently twice), 24H (a byte does not stay), or the error of @READ.

4C39
LD (4C8DH),DE ED 53 8D 4C
Store Register Pair DE, the FCB, at 4C8DH, the operand of LD DE,nnnn at 4C8CH.
4C3D
PUSH DE D5
Save Register Pair DE, the FCB, on the stack.
4C3E
LD E,FFH 1E FF
Load Register E with FFH, the offset in the buffer before its first byte, so that the first fetch reads a sector.
4C40
Call 4C89H to fetch the next byte of the file into Register A: the record type.
4C43
CP 20H FE 20
Compare Register A, the record type, with 20H, the first type not allowed.
4C45
If the NC FLAG is set (20H or more), jump to 4C5EH to return error 22H.
4C47
LD H,A 67
Copy the record type from Register A into Register H.
4C48
Call 4C89H to fetch the length byte of the record into Register A.
4C4B
LD B,A 47
Copy the length from Register A into Register B.
4C4C
Call 4C89H to fetch the next byte, the low byte of the address (or the first byte of another record), into Register A.
4C4F
LD L,A 6F
Copy the byte from Register A into Register L.
4C50
DEC H 25
Decrement Register H, the type: the Z FLAG is set for type 01H, a load block.
4C51
If the Z FLAG is set (a load block), jump to 4C6CH.
4C53
DEC H 25
Decrement Register H again: the Z FLAG is set for type 02H, the transfer address.
4C54
If the NZ FLAG is set (another record), jump to 4C68H to pass over the rest of it.
4C56
Call 4C89H to fetch the high byte of the transfer address into Register A.
4C59
LD H,A 67
Copy the high byte from Register A into Register H: Register Pair HL is the transfer address.
4C5A
DEC B 05
Decrement Register B, the length of the record; it is not used further.
4C5B
XOR A AF
Clear Register A to 00H and set the Z FLAG: the module has been loaded.
4C5C
Jump to 4C62H to return with the transfer address in Register Pair HL.
4C5E
LD A,22H 3E 22
Load Register A with 22H, the error code for a record type of 20H or more, which SYS4/SYS shows it as LOAD FILE FORMAT ERROR.
4C60
OR 40H F6 40
Set bit 6 of Register A, the error code, with OR 40H. 4C84H, 4C87H and 4C93H jump here.
4C62
POP DE D1
Restore Register Pair DE, the FCB, from the stack.
4C63
RET C9
Return with the transfer address in Register Pair HL and the Z FLAG set, or the error code in Register A.
4C64
INC E 1C
Increment Register E, the offset in the buffer, past a byte of the record passed over.
4C65
If the Z FLAG is set (the buffer is used up), call 4C8CH to read the next sector.
4C68
Decrement Register B, the bytes of the record left, and loop back to 4C64H until the record is passed over.
4C6A
Jump back to 4C40H for the next record after the one passed over.
4C6C
Call 4C89H to fetch the high byte of the load address into Register A.
4C6F
LD H,A 67
Copy the high byte from Register A into Register H: Register Pair HL is the load address.
4C70
DEC B 05
Decrement Register B, the length, for the low address byte.
4C71
DEC B 05
Decrement Register B again for the high address byte: Register B is the count of data bytes (00H for 256).
4C72
INC E 1C
Increment Register E, the offset in the buffer, to the next data byte.
4C73
If the Z FLAG is set (the buffer is used up), call 4C8CH to read the next sector.
4C76
LD A,(DE) 1A
Load Register A with the data byte at Register Pair DE in the buffer.
4C77
LD (HL),A 77
Store Register A, the data byte, at the load address in Register Pair HL.
4C78
CP (HL) BE
Compare Register A with the byte at Register Pair HL: the Z FLAG is set when the byte has stayed in memory.
4C79
If the NZ FLAG is set (the byte did not stay), jump to 4C80H.
4C7B
INC HL 23
Increment Register Pair HL to the next load address.
4C7C
Decrement Register B, the data bytes left, and loop back to 4C72H for the next byte.
4C7E
Jump back to 4C40H for the next record after the load block.
4C80
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL again.
4C81
CP (HL) BE
Compare Register A with the byte at Register Pair HL a third time: the Z FLAG is set when two reads agree.
4C82
LD A,24H 3E 24
Load Register A with 24H, the error code for a byte that does not stay in memory (no RAM or a write protected area), which SYS4/SYS shows it as ATTEMPTED TO LOAD READ ONLY MEMORY.
4C84
If the Z FLAG is set (the reads agree), jump to 4C60H to return error 24H with bit 6 set.
4C86
DEC A 3D
Decrement Register A to 23H, the error code for a byte that reads back differently each time.
4C87
Jump to 4C60H to return error 23H with bit 6 set, which SYS4/SYS shows it as MEMORY FAULT.

4C89H - Fetch the Next Byte of the Load Module

Returns the next byte of the file in Register A; Register E is the offset in the buffer 4200H-42FFH. When the buffer is used up the next sector is read through @READ. On an error the routine returns straight from the loader, taking its return address and the saved FCB off the stack.

4C89
INC E 1C
Increment Register E, the offset in the buffer; the Z FLAG is set when it wraps to 00H.
4C8A
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE in the buffer.
4C8B
RET NZ C0
If the NZ FLAG is set (the buffer still had this byte), return with it in Register A.
4C8C
LD DE,0000H 11 00 00
Load Register Pair DE with the FCB: the operand at 4C8DH (0000H in the file) is stored by 4C39H.
4C8F
Call 4436H, @READ, to read the next sector of the file into the buffer.
4C92
POP DE D1
Take the return address into the loader off the stack into Register Pair DE.
4C93
If the NZ FLAG is set (the read failed), jump to 4C60H: the error code gets bit 6 and the loader returns to its caller.
4C95
PUSH DE D5
Push Register Pair DE, the return address into the loader, back on the stack.
4C96
LD DE,4200H 11 00 42
Load Register Pair DE with 4200H, the first byte of the buffer: Register E is 00H.
4C99
LD A,(DE) 1A
Load Register A with the first byte of the sector at Register Pair DE.
4C9A
RET C9
Return with the first byte of the new sector in Register A.

4C9BH - Restore or Cut the Tries

Called from 46C2H after a failed transfer with Register A the error bits and Register B the tries left.

4C9B
RLCA 07
Rotate Register A, the error bits, left: the C FLAG is bit 7, NOT READY.
4C9C
If the NC FLAG is set (the drive is ready), jump to 444BH to restore the head to cylinder 0; it returns to 46C5H.
4C9F
LD A,03H 3E 03
Load Register A with 03H, the most tries left for a drive that is not ready.
4CA1
CP B B8
Compare Register A (03H) with Register B, the tries left.
4CA2
RET NC D0
If the NC FLAG is set (three tries or fewer are left), return.
4CA3
LD B,A 47
Copy Register A (03H) into Register B: only three more tries.
4CA4
RET C9
Return with Register B the tries left, three at the most.
4CA5-4CA8
DEFB 4DH,0AH,C1H,C9H 4D 0A C1 C9
Four bytes at 4CA5H-4CA8H that nothing reaches: LD C,L, LD A,(BC), POP BC and RET.

4CA9H - The Clock Display Task

A task header for the table at 4500H; SYS6/SYS puts its address in a slot (52C8H). Every fifth run the time is shown as HH:MM:SS at 3C35H, the right end of the top line of the screen.

4CA9-4CAA
DEFW 4CACH AC 4C
The clock display task header at 4CA9H: the routine address 4CACH.
4CAB
DEFB 05H 05
The task's count of runs at 4CABH (header +02H): 05H.
4CAC
DEC (IX+02H) DD 35 02
Decrement the count of runs at header +02H through Index Register IX (4CABH).
4CAF
RET NZ C0
If the NZ FLAG is set (not the fifth run), return.
4CB0
LD (IX+02H),05H DD 36 02 05
Store 05H in the count at header +02H through Index Register IX (4CABH) again.
4CB4
LD HL,3C35H 21 35 3C
Load Register Pair HL with 3C35H, the screen position of the time; the routine goes on into 4CB7H.

4CB7H - Write the Time or the Date as Text

Entered at 4CB7H (through 446DH) for the time and at 4CD2H (through 4470H) for the date, with Register Pair HL where the eight characters go. Three bytes are taken from the highest address down and written as two decimal digits each, with a colon (time) or a slash (date) between them.

4CB7
LD DE,4043H 11 43 40
Load Register Pair DE with 4043H, the hours, followed downward by the minutes at 4042H and the seconds at 4041H.
4CBA
LD C,3AH 0E 3A
Load Register C with 3AH, the colon between the numbers of the time.
4CBC
LD B,03H 06 03
Load Register B with 03H, the three numbers. 4CD7H jumps here for the date.
4CBE
LD A,(DE) 1A
Load Register A with the number at Register Pair DE.
4CBF
DEC DE 1B
Decrement Register Pair DE to the next number.
4CC0
LD (HL),2FH 36 2F
Store 2FH, the character before 0, at Register Pair HL: the tens digit is counted up from it.
4CC2
INC (HL) 34
Increment the tens digit at Register Pair HL.
4CC3
SUB 0AH D6 0A
Subtract 0AH from Register A, the number, for each ten counted.
4CC5
If the NC FLAG is set (no borrow), jump back to 4CC2H to count another ten.
4CC7
ADD A,3AH C6 3A
Add 3AH to Register A: the units, minus ten, plus 30H plus ten, the character of the units digit.
4CC9
INC HL 23
Increment Register Pair HL to the place of the units digit.
4CCA
LD (HL),A 77
Store Register A, the units digit, at Register Pair HL.
4CCB
INC HL 23
Increment Register Pair HL to the place after the number.
4CCC
DEC B 05
Decrement Register B, the count of numbers left to write.
4CCD
RET Z C8
If the Z FLAG is set (all three are written), return.
4CCE
LD (HL),C 71
Store Register C, the colon or the slash, at Register Pair HL.
4CCF
INC HL 23
Increment Register Pair HL to the place of the next number.
4CD0
Jump back to 4CBEH for the next number of the time or date.
4CD2
LD DE,4046H 11 46 40
Load Register Pair DE with 4046H, the first date byte, followed downward by 4045H and 4044H.
4CD5
LD C,2FH 0E 2F
Load Register C with 2FH, the slash between the numbers of the date.
4CD7
Jump to 4CBCH to write the three numbers of the date.

4CD9H - The Trace Task

A task header; SYS1/SYS puts its address in a slot (5194H). The routine shows the address the interrupted program was at as four hexadecimal digits at 3C2EH on the top line of the screen. Run from slots 8-11, through the CALL of 457BH, it finds that address 12H bytes above the Stack Pointer: the interrupt's own push, Register Pairs HL and AF (4518H), the five pushes of 4538H-453CH, the return address 4547H and the return address of the CALL.

4CD9-4CDA
DEFW 4CDBH DB 4C
The trace task header at 4CD9H: the routine address 4CDBH.
4CDB
LD HL,0012H 21 12 00
Load Register Pair HL with 0012H, the distance of the interrupted program's address above the Stack Pointer.
4CDE
ADD HL,SP 39
Add the Stack Pointer to Register Pair HL: Register Pair HL points at the interrupted program's address on the stack.
4CDF
LD E,(HL) 5E
Load Register E with the low byte of the interrupted program's address at Register Pair HL.
4CE0
INC HL 23
Increment Register Pair HL to the high byte of the interrupted address.
4CE1
LD D,(HL) 56
Load Register D with the high byte at Register Pair HL: Register Pair DE is the interrupted program's address.
4CE2
LD HL,3C2EH 21 2E 3C
Load Register Pair HL with 3C2EH, the screen position of the address.
4CE5
LD A,D 7A
Copy Register D, the high byte of the address, into Register A.
4CE6
Call 4CEAH to write Register A as two hexadecimal digits at Register Pair HL.
4CE9
LD A,E 7B
Copy Register E, the low byte of the address, into Register A; the routine goes on into 4CEAH to write it.
4CEA
PUSH AF F5
Save Register Pair AF, the byte in Register A, on the stack.
4CEB
RRA 1F
Rotate Register A right, the first of four turns that bring the high four bits down.
4CEC
RRA 1F
Rotate Register A right, the second of the four turns.
4CED
RRA 1F
Rotate Register A right, the third of the four turns.
4CEE
RRA 1F
Rotate Register A right, the fourth turn: the high four bits are in bits 3-0.
4CEF
Call 4CF3H to write the high digit of the byte at Register Pair HL.
4CF2
POP AF F1
Restore Register Pair AF, the byte, from the stack; the routine goes on into 4CF3H for the low digit.
4CF3
AND 0FH E6 0F
AND Register A with 0FH to keep the digit 0-15.
4CF5
ADD A,30H C6 30
Add 30H to Register A: the digit becomes its character from 0 on.
4CF7
CP 3AH FE 3A
Compare Register A with 3AH, the character after 9.
4CF9
If the C FLAG is set (a digit 0-9), jump to 4CFDH to store it.
4CFB
ADD A,07H C6 07
Add 07H to Register A: the letters A-F follow.
4CFD
LD (HL),A 77
Store Register A, the digit, at Register Pair HL.
4CFE
INC HL 23
Increment Register Pair HL to the next place on the screen.
4CFF
RET C9
Return after writing the digit and stepping Register Pair HL on.

4E00H - The Start-up

The transfer address of SYS0/SYS, reached from the boot sector at 424BH with the interrupts off. It is run once: SYS1/SYS and the other overlays later load over 4E00H. The start-up finds the top of memory, installs the keyboard driver, the interrupt routine, its vectors and the clock task, shows the banner and runs the AUTO command stored in the GAT unless ENTER is held.

4E00
DI F3
Turn the interrupts off; they come on again at 45A1H, when the clock task is put in the task table.
4E01
IM 1 ED 56
Set interrupt mode 1: an interrupt calls 0038H, the ROM's RST 38H, which jumps to 4012H.
4E03
LD SP,41FCH 31 FC 41
Load the Stack Pointer with 41FCH, the same stack as the boot sector's.
4E06
LD HL,5200H 21 00 52
Load Register Pair HL with 5200H, the lowest address free for programs, above the overlay area.
4E09
LD (4047H),HL 22 47 40
Store Register Pair HL (5200H) at 4047H, the lowest address free for programs.
4E0C
LD HL,FFFFH 21 FF FF
Load Register Pair HL with FFFFH, the highest address the memory test tries first.
4E0F
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL.
4E10
LD B,A 47
Copy the byte from Register A into Register B to put it back after the test.
4E11
CPL 2F
Complement Register A, the byte under test, to see whether it can change.
4E12
LD (HL),A 77
Store Register A, the complemented byte, at Register Pair HL.
4E13
CP (HL) BE
Compare Register A with the byte at Register Pair HL: the Z FLAG is set when the complement has stayed, so there is memory at this address.
4E14
LD (HL),B 70
Store Register B, the old byte, back at Register Pair HL.
4E15
If the Z FLAG is set (memory was found), jump to 4E1DH.
4E17
LD A,H 7C
Copy Register H, the high byte of the address, into Register A.
4E18
SUB 04H D6 04
Subtract 04H from Register A: the address 1024 bytes lower.
4E1A
LD H,A 67
Copy Register A into Register H: Register Pair HL is 0400H lower, the low byte still FFH.
4E1B
Jump back to 4E0FH to test the byte at the lower address.
4E1D
LD (4049H),HL 22 49 40
Store Register Pair HL, the top of memory (7FFFH, BFFFH or FFFFH for 16K, 32K or 48K), at 4049H. BASIC/CMD, COPY/CMD and DOUBLE/CMD read it.
4E20
LD A,(38C0H) 3A C0 38
Load Register A with keyboard rows 6 and 7 together at 38C0H.
4E23
AND 09H E6 09
AND Register A with 09H to keep bit 0 (ENTER of row 6, SHIFT of row 7) and bit 3 (the up arrow of row 6).
4E25
CP 09H FE 09
Compare Register A with 09H: the Z FLAG is set when both bits are held.
4E27
If the Z FLAG is set (both are held), jump to 4E2FH: the ROM's keyboard driver is kept.
4E29
LD HL,4378H 21 78 43
Load Register Pair HL with 4378H, DoubleDOS's keyboard driver.
4E2C
LD (4016H),HL 22 16 40
Store Register Pair HL (4378H) at 4016H, the driver address of the keyboard device control block at 4015H.
4E2F
Jump to 4E76H, passing over the code at 4E32H-4E75H.

4E32H - Code That Is Never Run

The jump at 4E2FH passes over these 68 bytes and nothing else reaches them. As instructions they store Register Pair HL and words from 4023H, 4026H and 402BH into 43BAH-43CBH, clear 43CCH-43FFH, and copy the three ROM device control blocks at 4015H-402CH to 4358H with eight bytes of 00H and sixteen of FFH after each. Run, they would overwrite the DoubleDOS code at 4358H-43FBH.

4E32
LD (43BAH),HL 22 BA 43
Store Register Pair HL at 43BAH (never run: the jump at 4E2FH passes over it).
4E35
LD (43C6H),HL 22 C6 43
Store Register Pair HL at 43C6H (never run: the jump at 4E2FH passes over it).
4E38
LD HL,(4023H) 2A 23 40
Load Register Pair HL with the word at 4023H, in the ROM's display device control block (never run).
4E3B
LD (43C4H),HL 22 C4 43
Store Register Pair HL at 43C4H (never run: the jump at 4E2FH passes over it).
4E3E
LD HL,(4026H) 2A 26 40
Load Register Pair HL with the word at 4026H, the printer device control block's driver address (never run).
4E41
LD (43BCH),HL 22 BC 43
Store Register Pair HL at 43BCH (never run: the jump at 4E2FH passes over it).
4E44
LD (43CAH),HL 22 CA 43
Store Register Pair HL at 43CAH (never run: the jump at 4E2FH passes over it).
4E47
LD HL,(402BH) 2A 2B 40
Load Register Pair HL with the word at 402BH, in the printer device control block (never run).
4E4A
LD (43C8H),HL 22 C8 43
Store Register Pair HL at 43C8H (never run: the jump at 4E2FH passes over it).
4E4D
LD HL,43CCH 21 CC 43
Load Register Pair HL with 43CCH, the first byte to clear (never run).
4E50
LD (HL),00H 36 00
Store 00H at Register Pair HL (never run: the jump at 4E2FH passes over it).
4E52
INC L 2C
Increment Register L to the next byte in Register Pair HL (never run).
4E53
If the NZ FLAG is set (Register L has not wrapped past 43FFH), jump back to 4E50H (never run).
4E55
LD A,03H 3E 03
Load Register A with 03H, the three device control blocks to copy (never run).
4E57
LD HL,4015H 21 15 40
Load Register Pair HL with 4015H, the keyboard device control block, the first to copy (never run).
4E5A
LD DE,4358H 11 58 43
Load Register Pair DE with 4358H, where the copies would go (never run).
4E5D
PUSH AF F5
Save Register Pair AF, the blocks left in Register A, on the stack (never run).
4E5E
LD BC,0008H 01 08 00
Load Register Pair BC with 0008H, the eight bytes of a device control block (never run).
4E61
LDIR ED B0
Copy eight bytes from Register Pair HL to Register Pair DE, counted in Register Pair BC (never run).
4E63
XOR A AF
Clear Register A to 00H for the eight bytes of 00H (never run).
4E64
LD B,08H 06 08
Load Register B with 08H, the count of the bytes of 00H (never run).
4E66
LD (DE),A 12
Store Register A (00H) at Register Pair DE (never run: the jump at 4E2FH passes over it).
4E67
INC DE 13
Increment Register Pair DE to the next byte (never run: the jump at 4E2FH passes over it).
4E68
Decrement Register B and loop back to 4E66H for the next byte of 00H (never run).
4E6A
LD A,FFH 3E FF
Load Register A with FFH for the sixteen bytes of FFH (never run).
4E6C
LD B,10H 06 10
Load Register B with 10H, the count of the bytes of FFH (never run).
4E6E
LD (DE),A 12
Store Register A (FFH) at Register Pair DE (never run: the jump at 4E2FH passes over it).
4E6F
INC DE 13
Increment Register Pair DE to the next byte (never run: the jump at 4E2FH passes over it).
4E70
Decrement Register B and loop back to 4E6EH for the next byte of FFH (never run).
4E72
POP AF F1
Restore Register Pair AF, the blocks left in Register A, from the stack (never run).
4E73
DEC A 3D
Decrement Register A, the blocks left (never run: the jump at 4E2FH passes over it).
4E74
If the NZ FLAG is set (blocks are left), jump back to 4E5DH for the next block (never run).

4E76H - Install the Interrupts and the Clock

Reached by the jump at 4E2FH.

4E76
LD A,(37ECH) 3A EC 37
Load Register A with the status register 37ECH: reading it clears any interrupt request of the controller.
4E79
XOR A AF
Clear Register A to 00H for the BREAK flag and the interrupt mask.
4E7A
LD (4315H),A 32 15 43
Store Register A (00H) in the BREAK flag at 4315H: BREAK is not armed.
4E7D
LD HL,404CH 21 4C 40
Load Register Pair HL with 404CH, the interrupt mask.
4E80
LD (HL),A 77
Store Register A (00H) in the interrupt mask at Register Pair HL (404CH): no interrupt is served yet.
4E81
LD A,C3H 3E C3
Load Register A with C3H, the opcode of JP nnnn.
4E83
LD DE,4518H 11 18 45
Load Register Pair DE with 4518H, the interrupt routine.
4E86
LD (4013H),DE ED 53 13 40
Store Register Pair DE (4518H) at 4013H, the operand of the jump at 4012H.
4E8A
LD (4012H),A 32 12 40
Store Register A (C3H) at 4012H: the RST 38H vector is now JP 4518H.
4E8D
LD DE,4560H 11 60 45
Load Register Pair DE with 4560H, the task scheduler.
4E90
LD (405BH),DE ED 53 5B 40
Store Register Pair DE (4560H) at 405BH, the vector of latch bit 7, the 25 ms clock.
4E94
SET 7,(HL) CB FE
Set bit 7 of the interrupt mask at Register Pair HL (404CH): the clock interrupt is served.
4E96
LD DE,45F7H 11 F7 45
Load Register Pair DE with 45F7H, the routine that reads the controller's status.
4E99
LD (4059H),DE ED 53 59 40
Store Register Pair DE (45F7H) at 4059H, the vector of latch bit 6, the disk controller.
4E9D
SET 6,(HL) CB F6
Set bit 6 of the interrupt mask at Register Pair HL (404CH): the controller's interrupt is served.
4E9F
LD A,01H 3E 01
Load Register A with 01H for the DEBUG flag at 430FH.
4EA1
LD (430FH),A 32 0F 43
Store Register A (01H) at 430FH, the DEBUG flag; bit 7 is clear, so DEBUG is off.
4EA4
LD DE,45AFH 11 AF 45
Load Register Pair DE with 45AFH, the clock task header.
4EA7
LD A,07H 3E 07
Load Register A with 07H, task slot 7, run every 200 ms.
4EA9
Call 4410H to put the clock task in slot 7; its EI at 45A1H turns the interrupts on.
4EAC
LD HL,4EEDH 21 ED 4E
Load Register Pair HL with 4EEDH, the banner.
4EAF
LD A,(HL) 7E
Load Register A with the next character of the banner at Register Pair HL.
4EB0
NOP 00
No operation: the first of two bytes of 00H in the display loop.
4EB1
NOP 00
No operation: the second of two bytes of 00H in the display loop.
4EB2
Call the ROM's display routine at 0033H to show the character in Register A; the 03H at the end is passed to it too.
4EB5
INC HL 23
Increment Register Pair HL to the next character of the banner.
4EB6
CP 03H FE 03
Compare Register A, the character just shown, with 03H, the end of the banner.
4EB8
If the NZ FLAG is set (not the end), jump back to 4EAFH for the next character.
4EBA
Call the ROM's keyboard scan at 002BH: Register A returns the key held, or 00H.
4EBD
CP 0DH FE 0D
Compare Register A, the key, with 0DH, ENTER.
4EBF
If the Z FLAG is set (ENTER is held), jump to 4400H, DOS READY, without the AUTO command.
4EC2
LD C,00H 0E 00
Load Register C with 00H, drive 0, the system diskette.
4EC4
LD D,11H 16 11
Load Register D with 11H, block 17, the directory of a DoubleDOS system diskette.
4EC6
LD E,00H 1E 00
Load Register E with 00H, sector 0 of the block, the GAT.
4EC8
LD HL,4200H 21 00 42
Load Register Pair HL with 4200H, the buffer for the GAT.
4ECB
Call 4B35H to read the GAT of drive 0 into 4200H.
4ECE
If the NZ FLAG is set (the GAT could not be read), jump to @ERROR at 4409H with the error code in Register A.
4ED1
LD A,(42E0H) 3A E0 42
Load Register A with GAT byte E0H at 42E0H, the first character of the AUTO command.
4ED4
CP 0DH FE 0D
Compare Register A with 0DH: an AUTO command that is only a carriage return is empty.
4ED6
If the Z FLAG is set (no AUTO command), jump to 4400H, DOS READY.
4ED9
LD HL,42E0H 21 E0 42
Load Register Pair HL with 42E0H, the AUTO command in the GAT (bytes E0H-FFH).
4EDC
LD DE,4318H 11 18 43
Load Register Pair DE with 4318H, the command line buffer.
4EDF
LD BC,0020H 01 20 00
Load Register Pair BC with 0020H, the 32 bytes of the command.
4EE2
LDIR ED B0
Copy the 32 bytes from Register Pair HL to Register Pair DE, counted in Register Pair BC.
4EE4
LD HL,4318H 21 18 43
Load Register Pair HL with 4318H, the command line.
4EE7
Call 4467H to display the command line at Register Pair HL up to its carriage return.
4EEA
Jump to 4405H to run the command line at Register Pair HL through SYS1/SYS.

4EEDH - The Banner

Shown by 4EACH-4EB8H when the system starts: four lines ended by 0DH and the end mark 03H. The version digit at 4F15H is the only byte of the load blocks that tells 4.20, 4.23 and 4.24 apart.

4EED-4F14
DEFM "DBLDOS - DISK OPERATING SYSTEM - VER 4.2" 44 42 4C 44 4F 53 20 2D 20 44 49 53 4B 20 4F 50 45 52 41 54 49 4E 47 20 53 59 53 54 45 4D 20 2D 20 56 45 52 20 34 2E 32
The first line of the banner, DBLDOS - DISK OPERATING SYSTEM - VER 4.2, up to the last digit of the version.
4F15
DEFM "4" 34
The last digit of the version at 4F15H: 34H (4) in DoubleDOS 4.24, 33H (3) in 4.23 and 30H (0) in 4.20.
4F16
DEFB 0DH 0D
The carriage return that ends the first line of the banner.
4F17-4F43
DEFM "ORIGINAL DOS COPYRIGHTED BY TANDY CORPORATION" 4F 52 49 47 49 4E 41 4C 20 44 4F 53 20 43 4F 50 59 52 49 47 48 54 45 44 20 42 59 20 54 41 4E 44 59 20 43 4F 52 50 4F 52 41 54 49 4F 4E
The second line of the banner, ORIGINAL DOS COPYRIGHTED BY TANDY CORPORATION.
4F44
DEFB 0DH 0D
The carriage return that ends the second line of the banner.
4F45-4F6C
DEFM "DOUBLE DENSITY ADAPTATION COPYRIGHT 1980" 44 4F 55 42 4C 45 20 44 45 4E 53 49 54 59 20 41 44 41 50 54 41 54 49 4F 4E 20 43 4F 50 59 52 49 47 48 54 20 31 39 38 30
The third line of the banner, DOUBLE DENSITY ADAPTATION COPYRIGHT 1980.
4F6D
DEFB 0DH 0D
The carriage return that ends the third line of the banner.
4F6E-4F87
DEFM "BY PERCOM DATA CO. INC. " 42 59 20 50 45 52 43 4F 4D 20 44 41 54 41 20 43 4F 2E 20 49 4E 43 2E 20 20 20
The fourth line of the banner, BY PERCOM DATA CO. INC. and three spaces.
4F88
DEFB 0DH 0D
The carriage return that ends the fourth line of the banner.
4F89
DEFB 03H 03
The end mark 03H of the banner: the loop at 4EAFH-4EB8H stops after it.