400CH - Restart Vectors and the ROM Device Control Blocks
The Model III ROM sends RST 28H, RST 30H and RST 38H to 400CH, 400FH and 4012H, and its character I/O to the device control blocks at 4015H, 401DH and 4025H. SYS0/SYS loads a jump into each of the three restart vectors and into EXIT@, ABORT@ and 4033H; the control blocks, the keyboard row images and the ROM's interrupt vectors between them stay as the ROM set them, apart from what the start-up stores.
400C
JUMP to 498EH, the overlay request handler. The ROM's RST 28H comes here: every system entry point that lives in an overlay (4400H, 4405H, 4424H and the others) loads Register A with a request code and executes RST 28H, and 498EH loads the overlay and runs the routine.
400F
JUMP to 440DH, DEBUG@. The ROM's RST 30H comes here, so an RST 30H placed in a program enters the DEBUG monitor through the system entry point at 440DH.
4012
JUMP to 45FEH, the interrupt handler. The ROM's RST 38H comes here: in interrupt mode 1 (selected by the start-up at 4E01H) every maskable interrupt (the real time clock 30 times a second, the cassette, the I/O bus and the RS-232 interface) is an RST 38H.
4015-401C
DEFS 8
The keyboard (@KI) device control block, in the ROM's RAM and not loaded by SYS0/SYS. The first entry of the DCB table (44A6H) points here. DCB+01H-02H (4016H-4017H) holds the driver address: the start-up stores 4DCAH there at 4E9FH unless SHIFT and the up arrow (1BH) are held at boot. The start-up also stores two bytes of BOOT/SYS sector 2 into this block: the caps switch (5215H) at 4019H (4E89H) and the cursor blink switch (5213H) at 401CH (4E7DH).
401D-4024
DEFS 8
The video display (@DO) device control block, in the ROM's RAM and not loaded by SYS0/SYS. The second entry of the DCB table (44B1H) points here. The start-up stores the cursor character of BOOT/SYS sector 2 (5214H) at 4023H (4E83H).
4025-402C
DEFS 8
The printer (@PR) device control block, in the ROM's RAM and not loaded by SYS0/SYS. The third entry of the DCB table (44BCH) points here.
402D
JUMP to 4400H. EXIT@, the normal return of a program to DOSPLUS: 4400H requests the command interpreter (request code 03H, SYS1/SYS). The start-up pushes 402DH as the return address of whatever it runs (4E06H-4E09H), so a program ending with RET returns to DOSPLUS.
4030
JUMP to 4400H. ABORT@, the return to DOSPLUS after an error: it too goes to the command interpreter through 4400H. SYS0/SYS jumps here after displaying System error (4A4FH).
4033
JUMP to 455EH, the character I/O routine. The ROM's device routine at 0674H jumps to 4033H (from 0687H) when bit 7 of the type byte of the control block Register Pair DE points to is set and the type lacks the bits Register B asks for (01H input, 02H output, 04H control); 455EH then serves file control blocks, FORCE, JOIN and NIL.
4036-403C
DEFS 7
The keyboard row images, in the ROM's RAM: one byte for each of the keyboard rows 3801H-3840H. The start-up clears the seven bytes (4E44H-4E4BH).
403D-403F
DEFS 3
The vector of the I/O bus interrupt (bit 3 of port E0H), in the ROM's RAM: the interrupt handler jumps here at 4619H.
4040-4042
DEFS 3
The vector of the RS-232 error interrupt (bit 6 of port E0H), in the ROM's RAM: the interrupt handler jumps here at 4625H.
4043-4045
DEFS 3
The vector of bit 7 of port E0H, in the ROM's RAM: the interrupt handler jumps here at 4629H.
4046-4048
DEFS 3
The real time clock vector (bit 2 of port E0H): the start-up stores C3H at 4046H (4E4FH) and 4657H at 4047H-4048H (4E55H-4E58H), JP 4657H, the clock task. The interrupt handler jumps here at 4615H.
4049-404B
DEFS 3
The NMI vector: the ROM's NMI routine (0066H, then 3039H) jumps here from 351CH when bit 5 of port E4H is set. The start-up stores C3H at 4049H (4E52H) and 4842H at 404AH-404BH (4E5BH-4E5EH), JP 4842H, the end of a sector transfer.
4206H - Bytes of the ROM's RAM that SYS0/SYS Uses
Not in the file. 4206H and 4209H are the RS-232 interrupt vectors the interrupt handler jumps to; the start-up fills the others: 4210H is the ROM's copy of port ECH, TIME$ and DATE$ are at 4217H and 421AH, and the command buffer INPBUF$ is at 4225H.
4206-4208
DEFS 3
The vector of the RS-232 transmitter interrupt (bit 4 of port E0H), in the ROM's RAM: the interrupt handler jumps here at 461DH.
4209-420B
DEFS 3
The vector of the RS-232 receiver interrupt (bit 5 of port E0H), in the ROM's RAM: the interrupt handler jumps here at 4621H.
4210
DEFS 1
The image of port ECH, the miscellaneous control latch: the start-up sets its bit 4, which enables the external I/O bus, and writes the byte to port ECH (4E27H-4E2DH).
4214
DEFS 1
A byte of the ROM's RAM that the start-up clears (4E3EH). No other instruction of SYS0/SYS refers to it.
4217-4219
DEFS 3
TIME$, the system time: seconds (4217H), minutes (4218H) and hours (4219H). GTTIME@ (446DH) goes to the ROM's 3036H; the start-up stores the time typed at boot through Index Register IX = 4217H (4F49H-4F55H).
421A-421C
DEFS 3
DATE$, the system date: year (421AH, the last two digits: the start-up keeps the remainder of the year typed divided by 100), day (421BH) and month (421CH). GTDATE@ (4470H) goes to the ROM's 3033H; the start-up fills it from the saved date at 42BBH (4ED6H-4EE7H) or from the date typed at boot (4F0BH-4F1DH).
4225-4264
DEFS 64
INPBUF$, the 64 byte command buffer: the start-up puts a 0DH at 4225H (4E2FH-4E37H) and copies the automatic command of the diskette into it (4F94H-4F9EH) before running it through 4405H.
428DH - FILPTR@ and RAMDIR@
Two system entry points that the Model III keeps below the variables, at the addresses the manual gives (T/30, T/31): each loads its request code into Register A and executes RST 28H.
428D
LD A,75H 3E 75
FILPTR@: load Register A with 75H, the request code of routine 5 of SYS8/SYS.
428F
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 75H: SYS8/SYS is loaded at 4E00H unless it is resident and its routine 5 is run. The handler drops the address the RST pushes, so the bytes after it are not run.
4290
LD A,76H 3E 76
RAMDIR@, the directory of a drive in memory: load Register A with 76H, the request code of routine 6 of SYS8/SYS.
4292
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 76H: routine 6 of SYS8/SYS.
4293H - System Variables at 4293H-42BDH
The tick count, the drive select state, the NMI mask value, the system flags SFLAG1$, the last error code, the overlay request state and the overlay bytes OVLYL$ and OVLYH$ (4293H-429EH are in the file); then the overlay table addresses, the command buffer pointer, the top of memory, LOW$, DODCB$, BREAK$ and the saved date, which the start-up and the other routines fill.
4293
DEFB 00H 00
The tick count of the real time clock: the clock task increments it on every tick (466DH-4670H) and uses its two low bits to pick one of the four slow interrupt slots.
4294
DEFB 00H 00
The physical drive used last: 4870H compares the drive of each access with it (4877H-4878H); when they differ it stores the new drive (4880H) and loads the drive's head position into the track register (4881H-4884H).
4295
DEFB 81H 81
The drive select value for port F4H: 48A5H builds it from the physical drive number (bits 0-3), the density (bit 7) and write precompensation (bit 5) at 48BBH, and DSEEK sets bit 4 for side 1 (478DH). 489FH writes it to port F4H, and the sector transfer adds bit 6, the wait states (4815H-4819H). 81H in the file: drive 0, double density.
4296
DEFB 00H 00
The NMI mask value: the sector transfer sets its bit 7 and writes it to port E4H before a command (481DH-4822H), and writes it back unchanged when the command ends (4843H-4846H). SYS9/SYS (its 547DH) and SYS14/SYS (its 5677H) load the address 4296H.
4297
DEFB 00H 00
SFLAG1$, the system flags: bit 0 the BREAK key disable (tested by the request code 01H at 4997H), bit 1 the run access flag (set by RUN@ at 4A63H, cleared at 4A6AH, tested at 4C16H), bit 2 DEBUG (tested by RUN@ at 4A6FH), bit 3 the verify after write switch (4C6AH), bit 5 an active DO file (4DCDH, cleared at 4DE4H). The manual gives bit 6 as the DO block allocated flag; SYS0/SYS does not test bit 6.
4298
DEFB 00H 00
00H. No instruction of SYS0/SYS refers to 4298H, and no other system file of this diskette refers to it.
4299
DEFB 00H 00
The last error code: SYS5/SYS stores the number of each error it posts here (its 4E38H) and SYS12/SYS reads it (its 53B6H). SYS0/SYS does not use it.
429A
DEFB 00H 00
The low byte of a word the overlay request handler saves on the stack (499FH-49A2H) and puts back when the requested routine returns (49E8H), so a request made inside an overlay leaves 429AH-429BH as they were. SYS5/SYS stores Register Pair HL into the word (its 4E49H).
429B
DEFB 00H 00
The high byte of the word at 429AH and the DEBUG on BREAK switch: when it is not 00H and the BREAK key is down, the interrupt handler clears it and enters DEBUG@ (4644H-4652H). The overlay request handler clears it during each request (49ABH-49AEH), RUN@ sets it from the access level of the program it runs (4A85H) and the start-up clears it (4E41H). SYS1/SYS (its 4E3AH) stores into it.
429C
DEFB FFH FF
The request code of the last overlay request, stored by the handler at 49B1H: bits 7-4 the overlay (the system number less 1), bits 3-0 the routine in it, read at 49D3H. When an overlay cannot be loaded, 4A3EH tests its bit 7 to choose the overlay byte to set to FFH. FFH in the file.
429D
DEFB FFH FF
OVLYL$, the low overlay resident at 4E00H: the high four bits of its request codes, the system number less 1 (00H SYS1/SYS up to 70H SYS8/SYS). The handler compares the new request with it at 49C0H and stores it at 49C1H; FFH, none, so the first request loads one. 4D5CH reads it. SYS16/SYS saves and restores 429DH-429EH as a word (its 5720H, 5772H).
429E
DEFB FFH FF
OVLYH$, the high overlay resident at 5200H: the high four bits of its request codes (80H SYS9/SYS up to F0H SYS16/SYS), compared and stored like 429DH for requests with bit 7 set (49BAH). FFH, none. SYS1/SYS stores into it (its 4ECAH).
429F-42A0
DEFS 2
The address of the resident low overlay's routine table: the transfer address the loader returns in Register Pair HL, stored at 49C9H-49CCH after a load and read at 49CFH-49D2H when the overlay is already in memory. The handler takes the routine's address from the table (49D3H-49E2H).
42A1-42A2
DEFS 2
The address of the resident high overlay's routine table, kept like 429FH for requests with bit 7 set (49BBH).
42A3-42A4
DEFS 2
The command buffer pointer: the start-up stores 4225H here (4E31H-4E34H). SYS1/SYS (its 4E40H) and SYS12/SYS (its 5278H) read it.
42A5-42A6
DEFS 2
The top of memory: the highest address the start-up's memory test finds, stored at 4E1BH. SYS16/SYS reads it (its 5557H).
42A7-42A8
DEFS 2
LOW$, the lowest address free for programs: the start-up stores 5200H here (4E21H-4E24H); RUN@ passes it to a program in Register Pair BC (4A73H). SYS16/SYS reads it (its 553FH).
42A9-42AA
DEFS 2
DODCB$, the address of the DO file's 32 byte file control block and 256 byte buffer in high memory. The keyboard driver reads its next character from this file control block when bit 5 of SFLAG1$ is set (4DD7H); SYS13/SYS stores it (its 525DH).
42AB-42AC
DEFS 2
No instruction of SYS0/SYS refers to 42ABH-42ACH.
42AD-42AF
DEFS 3
BREAK$, the BREAK key vector: the start-up stores C9H, a RET, at 42ADH (4E38H-4E3AH). The request code 01H jumps to it when bit 0 of SFLAG1$ is clear (4999H); a program may install a jump to its own routine here. SYS1/SYS stores into 42ADH (its 4E2BH).
42B0-42BA
DEFS 11
A work area of SYS7/SYS, which loads the addresses 42B0H, 42B1H and 42B8H (its 4EE3H, 4EE7H, 4EFFH). SYS0/SYS does not use it.
42BB-42BD
DEFS 3
The saved date, year, day and month like DATE$: the start-up copies it to 421AH-421CH when its year byte is 01H-63H (4ED6H-4EE7H) and copies a date typed at boot back here (4F20H-4F29H). SYS12/SYS uses it (its 528CH).
42BEH - The Interrupt Slots, and the System File Control Block
42BEH-42CDH is the table of the eight interrupt slots (0-3 slow, 4-7 fast), each the address of a task block; SET@ and RESET@ change them and the clock task at 4657H runs them. 42CEH-42EDH is the 32 byte file control block the overlay loader opens each /SYS file in (49EDH-4A37H), with its buffer at 4300H; its first 16 bytes are in the file, the rest of its segment list is not.
42BE-42BF
DEFW 469CH 9C 46
Slot 0, a slow slot (every fourth tick): the empty task block 469CH.
42C0-42C1
DEFW 469CH 9C 46
Slot 1, a slow slot: the empty task block 469CH.
42C2-42C3
DEFW 469CH 9C 46
Slot 2, a slow slot: the empty task block 469CH.
42C4-42C5
DEFW 469CH 9C 46
Slot 3, a slow slot: the empty task block 469CH.
42C6-42C7
DEFW 469CH 9C 46
Slot 4, a fast slot (every tick): the empty task block 469CH.
42C8-42C9
DEFW 469CH 9C 46
Slot 5, a fast slot: the empty task block 469CH.
42CA-42CB
DEFW 469CH 9C 46
Slot 6, a fast slot: the empty task block 469CH.
42CC-42CD
DEFW 469CH 9C 46
Slot 7, a fast slot: the empty task block 469CH in the file; the start-up puts the ROM's clock task block 469FH here (4E61H-4E66H).
42CE
DEFB 80H 80
The system file control block, FCB+00H: 80H, the type byte of an open file.
42CF
DEFB 00H 00
FCB+01H, the file flags: the overlay loader clears them at 4A16H, so the access code (bits 0-2) is 0, full access, and the file is read sector by sector (bit 7 clear).
42D0
DEFB 00H 00
FCB+02H, the second flag byte (bit 7 non-shrinkable, bit 6 modified): 00H.
42D1-42D2
DEFW 4300H 00 43
FCB+03H-04H, the address of the file's 256 byte buffer: 4300H, where READ@ puts each sector of the /SYS file being loaded.
42D3
DEFB 00H 00
FCB+05H, the offset of the next byte in the buffer: 00H.
42D4
DEFB 00H 00
FCB+06H, the drive: 00H, the /SYS files are read from drive 0.
42D5
DEFB 00H 00
FCB+07H, the logical file number, the position of the /SYS file's directory entry: the overlay loader stores it at 4A12H for each overlay it loads.
42D6
DEFB 00H 00
FCB+08H, the end of file byte (the bytes used in the last sector): 00H.
42D7
DEFB 00H 00
FCB+09H, the logical record length: 00H, 256 bytes.
42D8-42D9
DEFW 0000H 00 00
FCB+0AH-0BH, the next record number: the overlay loader clears 42D8H at 4A19H so each /SYS file is read from its first sector.
42DA-42DB
DEFW FFFFH FF FF
FCB+0CH-0DH, the ending record number: FFFFH, so the end of file test never stops a /SYS file being loaded.
42DC-42DD
DEFW 0000H 00 00
FCB+0EH-0FH, the first segment descriptor (cylinder, then starting granule and granule count): the overlay loader copies the first descriptor of the /SYS file's directory entry here (4A2DH-4A32H).
42DE-42ED
DEFS 16
FCB+10H-1FH, the rest of the segment list: a two byte count of the granules before each next segment and four more segment descriptors, which the record locator at 4D07H walks (4D1CH-4D43H).
4400H - The System Entry Points
The documented entry points of DOSPLUS, 4400H-44A5H. Each routine that lives in SYS0/SYS is a JP to it; each routine that lives in an overlay is LD A,request code followed by RST 28H, which goes through 400CH to the overlay request handler at 498EH. The high four bits of a request code are the system number less 1 (03H SYS1/SYS, 13H SYS2/SYS ... 73H SYS8/SYS) and the low four bits pick the routine from the overlay's routine table (2 is its first entry). The RST 28H pushes the address after it, which the handler discards, so the routine returns to the caller of the entry point. Blocks of the file skip the bytes between the entries (4403H-4404H, 4408H, 4411H-4412H, 441FH, 4423H, 4427H, 442BH, 442FH, 445AH-4466H): SYS0/SYS does not load them. 4411H-4412H, after the RST 28H of DEBUG@, is HMEM$.
4400
LD A,03H 3E 03
CMD@, the return to the DOSPLUS command level (EXIT@ and ABORT@ at 402DH and 4030H jump here): load Register A with 03H, the request code of routine 3 of SYS1/SYS, the command interpreter.
4402
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 03H: SYS1/SYS is loaded at 4E00H unless it is resident and its routine 3 is run.
4403-4404
DEFS 2
Not in the file and never run: the RST 28H before it does not return here, since the overlay request handler drops the address the RST pushes (498EH-498FH). The bytes are whatever memory held.
4405
LD A,05H 3E 05
CMNDI@, execute a command line: load Register A with 05H, the request code of routine 5 of SYS1/SYS. The start-up comes here with Register Pair HL pointing to the automatic command in the command buffer (4FA8H).
4407
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 05H: routine 5 of SYS1/SYS runs the command line.
4408
DEFS 1
Not in the file and never run: the RST 28H before it does not return here, since the overlay request handler drops the address the RST pushes (498EH-498FH). The byte is whatever memory held.
4409
PUSH AF F5
ERROR@, post an error: save Register Pair AF to the top of the stack, so Register A, the error code the caller brings, is kept for the overlay while Register A is loaded with the request code.
440A
LD A,43H 3E 43
Load Register A with 43H, the request code of routine 3 of SYS5/SYS, the error routine.
440C
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 43H: SYS5/SYS is loaded and its routine 3 takes the error code from the stack.
440D
PUSH AF F5
DEBUG@: save Register Pair AF to the top of the stack, so the Register A and the flags of the interrupted program are kept for the monitor while Register A carries the request code. RST 30H (400FH), the BREAK key when 429BH is set (464CH), RUN@ (4A82H) and the start-up's D key (4F8CH) come here.
440E
LD A,53H 3E 53
Load Register A with 53H, the request code of routine 3 of SYS6/SYS, the DEBUG monitor.
4410
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 53H: SYS6/SYS is loaded and its routine 3 runs the monitor.
4411-4412
DEFS 2
HMEM$, the highest address free for programs, in the two bytes the RST 28H of DEBUG@ never returns to: the start-up stores the top of memory it finds here (4E1EH); RUN@ passes it to a program in Register Pair DE (4A77H). SYS10/SYS, SYS11/SYS, SYS13/SYS and SYS15/SYS read and lower it when they take memory.
4413
SET@, insert a task into the interrupt chain: JUMP to 468BH with Register A = the slot number (0-7) and Register Pair DE = the task block. The start-up calls it at 4E66H.
4416
RESET@, remove the task of a slot from the interrupt chain: JUMP to 4688H with Register A = the slot number.
4419
LD A,74H 3E 74
CAT@, the catalog of a drive: load Register A with 74H, the request code of routine 4 of SYS8/SYS.
441B
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 74H: routine 4 of SYS8/SYS.
441C
LD A,06H 3E 06
FSPEC@, move a file specification into a file control block: load Register A with 06H, the request code of routine 6 of SYS1/SYS.
441E
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 06H: routine 6 of SYS1/SYS checks the file specification and copies it.
441F
DEFS 1
Not in the file and never run: the RST 28H before it does not return here, since the overlay request handler drops the address the RST pushes (498EH-498FH). The byte is whatever memory held.
4420
LD A,14H 3E 14
INIT@, open a file and create it when it does not exist: load Register A with 14H, the request code of routine 4 of SYS2/SYS.
4422
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 14H: routine 4 of SYS2/SYS.
4423
DEFS 1
Not in the file and never run: the RST 28H before it does not return here, since the overlay request handler drops the address the RST pushes (498EH-498FH). The byte is whatever memory held.
4424
LD A,13H 3E 13
OPEN@, open an existing file: load Register A with 13H, the request code of routine 3 of SYS2/SYS. LOAD@ uses it at 4A8EH.
4426
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 13H: routine 3 of SYS2/SYS opens the file whose file control block Register Pair DE points to.
4427
DEFS 1
Not in the file and never run: the RST 28H before it does not return here, since the overlay request handler drops the address the RST pushes (498EH-498FH). The byte is whatever memory held.
4428
LD A,23H 3E 23
CLOSE@, close a file: load Register A with 23H, the request code of routine 3 of SYS3/SYS.
442A
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 23H: routine 3 of SYS3/SYS.
442B
DEFS 1
Not in the file and never run: the RST 28H before it does not return here, since the overlay request handler drops the address the RST pushes (498EH-498FH). The byte is whatever memory held.
442C
LD A,24H 3E 24
KILL@, delete a file: load Register A with 24H, the request code of routine 4 of SYS3/SYS.
442E
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 24H: routine 4 of SYS3/SYS.
442F
DEFS 1
Not in the file and never run: the RST 28H before it does not return here, since the overlay request handler drops the address the RST pushes (498EH-498FH). The byte is whatever memory held.
4430
LOAD@, load a program file: JUMP to 4A89H, which opens the file of the file control block at Register Pair DE and loads it, returning its transfer address in Register Pair HL. RUN@ calls it at 4A66H.
4433
RUN@, load a program file and run it: JUMP to 4A5FH.
4436
READ@, read the next record of an open file: JUMP to 4B61H. The loader reads each sector of a program file through it (4ADCH).
4439
WRITE@, write the next record of an open file: JUMP to 4B7CH.
443C
VER@, write with verification: JUMP to 4B7CH, the same routine as WRITE@; the read after write check depends on bit 3 of SFLAG1$ (4297H) for both.
443F
REW@, rewind a file to its first record: JUMP to 4B30H.
4442
POSN@, position a file at the record in Register Pair BC: JUMP to 4AF2H.
4445
BKSP@, back a file up one record: JUMP to 4B45H.
4448
PEOF@, position a file at its end: JUMP to 4B37H.
444B
FEXT@, add a default extension to a file specification: JUMP to 4473H, the request of routine 7 of SYS1/SYS.
444E
MULT@, multiply Register Pair HL by Register A: JUMP to 4961H.
4451
DIVD@, divide Register Pair HL by Register A, the quotient in Register Pair HL and the remainder in Register A: JUMP to 497BH.
4454
PARAM@, scan a parameter field: JUMP to 4476H, the request of routine 8 of SYS1/SYS.
4457
CKEOF@, test a file for its end: JUMP to 4CC2H. The keyboard driver uses it for a DO file (4DDFH).
445A-4466
DEFS 13
Not in the file: no entry point of the Model III uses 445AH-4466H, and no instruction of SYS0/SYS refers to them. The bytes are whatever memory held.
4467
DSPLY@, display the text at Register Pair HL up to a 03H or 0DH: JUMP to 45BDH.
446A
PRINT@, print the text at Register Pair HL up to a 03H or 0DH: JUMP to 45B9H.
446D
GTTIME@, the time as HH:MM:SS at Register Pair HL: JUMP to 3036H, the ROM's time routine, which works from TIME$ at 4217H.
4470
GTDATE@, the date as MM/DD/YY at Register Pair HL: JUMP to 3033H, the ROM's date routine, which works from DATE$ at 421AH.
4473
LD A,07H 3E 07
The request of FEXT@ (444BH): load Register A with 07H, the request code of routine 7 of SYS1/SYS.
4475
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 07H: routine 7 of SYS1/SYS.
4476
LD A,08H 3E 08
The request of PARAM@ (4454H): load Register A with 08H, the request code of routine 8 of SYS1/SYS.
4478
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 08H: routine 8 of SYS1/SYS.
4479
LD A,63H 3E 63
EVAL@: load Register A with 63H, the request code of routine 3 of SYS7/SYS.
447B
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 63H: routine 3 of SYS7/SYS.
447C
LD A,64H 3E 64
WILD@: load Register A with 64H, the request code of routine 4 of SYS7/SYS.
447E
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 64H: routine 4 of SYS7/SYS.
447F
LD A,65H 3E 65
LOCDEV@, find a device by name: load Register A with 65H, the request code of routine 5 of SYS7/SYS.
4481
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 65H: routine 5 of SYS7/SYS.
4482
LD A,73H 3E 73
SORT@: load Register A with 73H, the request code of routine 3 of SYS8/SYS.
4484
RST 28H EF
RST 28H to 400CH and the overlay request handler at 498EH, with Register A = 73H: routine 3 of SYS8/SYS.
4485
JUMP to 45A2H, the routine that calls the code after a CALL 45A2H with Register Pairs BC, DE, HL and Index Registers IX and IY saved.
4488
DISKIO%, a disk function on drive Register C: JUMP to 46A4H. SYS0/SYS calls it at 4938H, 4C34H, 4C63H, 4C73H and 4F61H.
448B
JUMP to 4CE9H, the file control block wrapper entered after its check: the routine after the CALL runs with Index Register IX = the file control block and its registers restored when it returns.
448E
JUMP to 4CE5H, the file control block check: an open file control block at Register Pair DE (bit 7 of FCB+00H) goes on into 4CE9H; any other returns error 26H.
4491
JUMP to 493EH, the 8 bit multiply: Register A = Register A times Register E.
4494
JUMP to 494DH, the 8 bit divide: Register A = Register E divided by Register A, Register E = the remainder.
4497
JUMP to 4C7CH, which writes the buffer of the file at Index Register IX through 4C4AH when bits 7 and 4 of its FCB+01H are both set, and otherwise returns Register A = 00H.
449A
JUMP to 4916H, read the directory sector of logical file number Register B on drive Register C into 4300H.
449D
JUMP to 491FH, write the directory sector of logical file number Register B on drive Register C from 4300H.
44A0
LOCDCB%, the DCB address of device Register A: JUMP to 45ECH.
44A3
LOCDCT%, the drive control table of drive Register C: JUMP to 45D4H. The start-up calls it at 4E6BH and 4EABH.
44A6H - The DCB Table (DCBTBL)
Six 11 byte entries, one for each character device: +00H the DCB address (FFFFH none), +02H the filter table address, +04H the linking DCB of a JOIN, +06H the driver address and +08H the DCB type saved during a FORCE or JOIN, +09H the two character device name. LOCDCB% (44A0H, 45ECH) returns the DCB address of a device from its number. @RS, @U1 and @U2 have no DCB of their own: their entries point to the NIL control block at 4508H.
44A6-44B0
DEFW 4015H / DEFW FFFFH x 3 / DEFB FFH / DEFM "KI" 15 40 FF FF FF FF FF FF FF 4B 49
Device 0, @KI the keyboard: DCB at 4015H, no filter table, no linking DCB, no saved driver (FFFFH each), saved type FFH, name KI.
44B1-44BB
DEFW 401DH / DEFW FFFFH x 3 / DEFB FFH / DEFM "DO" 1D 40 FF FF FF FF FF FF FF 44 4F
Device 1, @DO the video display: DCB at 401DH, no filter table, no linking DCB, no saved driver, saved type FFH, name DO.
44BC-44C6
DEFW 4025H / DEFW FFFFH x 3 / DEFB FFH / DEFM "PR" 25 40 FF FF FF FF FF FF FF 50 52
Device 2, @PR the printer: DCB at 4025H, no filter table, no linking DCB, no saved driver, saved type FFH, name PR.
44C7-44D1
DEFW 4508H / DEFW FFFFH x 3 / DEFB 08H / DEFM "RS" 08 45 FF FF FF FF FF FF 08 52 53
Device 3, @RS the RS-232 interface: the NIL control block at 4508H until a driver is assigned, no filter table, no linking DCB, no saved driver, saved type 08H (NIL), name RS.
44D2-44DC
DEFW 4508H / DEFW FFFFH x 3 / DEFB 08H / DEFM "U1" 08 45 FF FF FF FF FF FF 08 55 31
Device 4, @U1 the first user device: the NIL control block at 4508H, no filter table, no linking DCB, no saved driver, saved type 08H, name U1.
44DD-44E7
DEFW 4508H / DEFW FFFFH x 3 / DEFB 08H / DEFM "U2" 08 45 FF FF FF FF FF FF 08 55 32
Device 5, @U2 the second user device: the NIL control block at 4508H, no filter table, no linking DCB, no saved driver, saved type 08H, name U2.
44E8H - The Drive Table (DCTTBL)
Eight 4 byte entries, one for each drive: +00H the address of the drive's drive control table (DCT), +02H the two character drive name. LOCDCT% (44A3H, 45D4H) loads Index Register IY from the entry of drive Register C. Drives 0-3 have their tables at 450BH-455AH; drives 4-7 point to the NIL control block at 4508H.
44E8-44EB
DEFW 450BH / DEFM "0 " 0B 45 30 20
Drive 0: its drive control table is at 450BH; name 0 and a blank.
44EC-44EF
DEFW 451FH / DEFM "1 " 1F 45 31 20
Drive 1: its drive control table is at 451FH; name 1 and a blank.
44F0-44F3
DEFW 4533H / DEFM "2 " 33 45 32 20
Drive 2: its drive control table is at 4533H; name 2 and a blank.
44F4-44F7
DEFW 4547H / DEFM "3 " 47 45 33 20
Drive 3: its drive control table is at 4547H; name 3 and a blank.
44F8-44FB
DEFW 4508H / DEFM "4 " 08 45 34 20
Drive 4: no drive control table of its own, the NIL control block at 4508H; name 4 and a blank.
44FC-44FF
DEFW 4508H / DEFM "5 " 08 45 35 20
Drive 5: no drive control table of its own, the NIL control block at 4508H; name 5 and a blank.
4500-4503
DEFW 4508H / DEFM "6 " 08 45 36 20
Drive 6: no drive control table of its own, the NIL control block at 4508H; name 6 and a blank.
4504-4507
DEFW 4508H / DEFM "7 " 08 45 37 20
Drive 7: no drive control table of its own, the NIL control block at 4508H; name 7 and a blank.
4508H - The NIL Control Block
The control block of every device and drive that has none: type 08H, NIL, and no driver.
4508
DEFB 08H 08
The type byte of the NIL control block: 08H, bit 3 NIL. The character I/O routine returns at once for a NIL device (4586H-458CH) and DISKIO% returns error 08H for a NIL drive (46ACH-46B4H).
4509-450A
DEFW FFFFH FF FF
The driver address of the NIL control block: FFFFH, no driver. Neither routine jumps to it, since both test bit 3 of 4508H first.
450BH - The Drive Control Tables of Drives 0-3
Four 20 byte drive control tables (DCTs), at 450BH, 451FH, 4533H and 4547H, the ones DCTTBL (44E8H) points to. Bytes +00H-0AH describe the drive and stay as CONFIG sets them; bytes +0BH-13H describe the diskette: +0BH-11H are set again from the table at 48FAH when the density changes or the drive is logged (4707H-470FH, 4718H, 48D1H-48F9H), and the start-up copies drive 0's +0BH-13H from sector 2 of BOOT/SYS (4EA6H-4EB9H) and stores the step rate code of 5216H into +04H of all four (4E69H-4E78H). The file holds the values of a one sided, eighteen sector double density diskette of 40 cylinders; drive 0's head position and directory cylinder are 11H, the other drives' 14H.
450B
DEFB 40H 40
DCT+00H of drive 0, the type byte: 40H, an active drive (bit 3 clear, not NIL). DISKIO% tests bit 3 at 46ACH.
450C-450D
DEFW 46BEH BE 46
DCT+01H-02H of drive 0, the driver address: 46BEH, the floppy disk driver of SYS0/SYS. DISKIO% jumps to it at 46B5H-46BDH.
450E
DEFB 10H 10
DCT+03H of drive 0, the drive flags: 10H, bit 4 set, a delay after the motor starts (tested at 4886H); bit 6 clear, not write protected (47EBH, 4746H); bit 2 clear, no double step (479CH); bit 0 clear, no log pending (46F5H).
450F
DEFB 03H 03
DCT+04H of drive 0, the step rate code: 03H, ORed into the restore (4762H) and seek (47ACH) commands. The start-up replaces it with the default step rate of 5216H.
4510
DEFB 00H 00
DCT+05H of drive 0, the head offset of a partitioned volume: 00H, none. SYS0/SYS does not read it.
4511-4512
DEFW 0000H 00 00
DCT+06H-07H of drive 0, the cylinder offset of a partitioned volume: 0000H, none. SYS0/SYS does not read it.
4513
DEFB 00H 00
DCT+08H of drive 0, the sector offset, the number of the first sector of a track: 00H. SYS0/SYS does not read it.
4514
DEFB 11H 11
DCT+09H of drive 0, the cylinder the head is over: 11H in the file. A restore sets it to 00H (475EH), a seek to the new cylinder (47B5H), and it goes to the track register when the drive is selected (4881H-4884H).
4515
DEFB 00H 00
DCT+0AH of drive 0, the physical drive number: 00H, from which 48A5H builds the drive select value; 4878H compares it with the drive used last.
4516
DEFB C0H C0
DCT+0BH of drive 0, the diskette flags: C0H, bit 7 set (double density, read at 48B2H and 48D4H, switched at 4707H) and bit 6 set (a protected directory).
4517
DEFB 01H 01
DCT+0CH of drive 0, the surface count: 01H, one sided. The geometry routine reads it at 48DCH.
4518
DEFB 12H 12
DCT+0DH of drive 0, the sectors per track: 12H, eighteen. A sector number at or above it is on side 1 (4788H-478FH).
4519
DEFB 12H 12
DCT+0EH of drive 0, the directory length in sectors: 12H, eighteen. The overlay loader works out the /SYS file positions from it (49FFH, 4A09H).
451A
DEFB 06H 06
DCT+0FH of drive 0, the sectors per granule: 06H. The record locator divides by it (4D13H) and multiplies back (4DBAH).
451B
DEFB 03H 03
DCT+10H of drive 0, the granules per cylinder: 03H. The record locator divides by it (4DB2H).
451C
DEFB 12H 12
DCT+11H of drive 0, the sectors per cylinder: 12H, eighteen. SYS0/SYS sets it from the geometry table but does not read it.
451D
DEFB 11H 11
DCT+12H of drive 0, the directory cylinder: 11H, cylinder 17. The directory routines read it at 46FDH and 47D2H; logging stores the one read from the diskette (472AH).
451E
DEFB 28H 28
DCT+13H of drive 0, the cylinder count: 28H, 40 cylinders. SYS0/SYS does not read it.
451F
DEFB 40H 40
DCT+00H of drive 1, the type byte: 40H, an active drive (bit 3 clear, not NIL). DISKIO% tests bit 3 at 46ACH.
4520-4521
DEFW 46BEH BE 46
DCT+01H-02H of drive 1, the driver address: 46BEH, the floppy disk driver of SYS0/SYS. DISKIO% jumps to it at 46B5H-46BDH.
4522
DEFB 10H 10
DCT+03H of drive 1, the drive flags: 10H, bit 4 set, a delay after the motor starts (tested at 4886H); bit 6 clear, not write protected (47EBH, 4746H); bit 2 clear, no double step (479CH); bit 0 clear, no log pending (46F5H).
4523
DEFB 03H 03
DCT+04H of drive 1, the step rate code: 03H, ORed into the restore (4762H) and seek (47ACH) commands. The start-up replaces it with the default step rate of 5216H.
4524
DEFB 00H 00
DCT+05H of drive 1, the head offset of a partitioned volume: 00H, none. SYS0/SYS does not read it.
4525-4526
DEFW 0000H 00 00
DCT+06H-07H of drive 1, the cylinder offset of a partitioned volume: 0000H, none. SYS0/SYS does not read it.
4527
DEFB 00H 00
DCT+08H of drive 1, the sector offset, the number of the first sector of a track: 00H. SYS0/SYS does not read it.
4528
DEFB 14H 14
DCT+09H of drive 1, the cylinder the head is over: 14H in the file. A restore sets it to 00H (475EH), a seek to the new cylinder (47B5H), and it goes to the track register when the drive is selected (4881H-4884H).
4529
DEFB 01H 01
DCT+0AH of drive 1, the physical drive number: 01H, from which 48A5H builds the drive select value; 4878H compares it with the drive used last.
452A
DEFB C0H C0
DCT+0BH of drive 1, the diskette flags: C0H, bit 7 set (double density, read at 48B2H and 48D4H, switched at 4707H) and bit 6 set (a protected directory).
452B
DEFB 01H 01
DCT+0CH of drive 1, the surface count: 01H, one sided. The geometry routine reads it at 48DCH.
452C
DEFB 12H 12
DCT+0DH of drive 1, the sectors per track: 12H, eighteen. A sector number at or above it is on side 1 (4788H-478FH).
452D
DEFB 12H 12
DCT+0EH of drive 1, the directory length in sectors: 12H, eighteen. The overlay loader works out the /SYS file positions from it (49FFH, 4A09H).
452E
DEFB 06H 06
DCT+0FH of drive 1, the sectors per granule: 06H. The record locator divides by it (4D13H) and multiplies back (4DBAH).
452F
DEFB 03H 03
DCT+10H of drive 1, the granules per cylinder: 03H. The record locator divides by it (4DB2H).
4530
DEFB 12H 12
DCT+11H of drive 1, the sectors per cylinder: 12H, eighteen. SYS0/SYS sets it from the geometry table but does not read it.
4531
DEFB 14H 14
DCT+12H of drive 1, the directory cylinder: 14H, cylinder 20. The directory routines read it at 46FDH and 47D2H; logging stores the one read from the diskette (472AH).
4532
DEFB 28H 28
DCT+13H of drive 1, the cylinder count: 28H, 40 cylinders. SYS0/SYS does not read it.
4533
DEFB 40H 40
DCT+00H of drive 2, the type byte: 40H, an active drive (bit 3 clear, not NIL). DISKIO% tests bit 3 at 46ACH.
4534-4535
DEFW 46BEH BE 46
DCT+01H-02H of drive 2, the driver address: 46BEH, the floppy disk driver of SYS0/SYS. DISKIO% jumps to it at 46B5H-46BDH.
4536
DEFB 10H 10
DCT+03H of drive 2, the drive flags: 10H, bit 4 set, a delay after the motor starts (tested at 4886H); bit 6 clear, not write protected (47EBH, 4746H); bit 2 clear, no double step (479CH); bit 0 clear, no log pending (46F5H).
4537
DEFB 03H 03
DCT+04H of drive 2, the step rate code: 03H, ORed into the restore (4762H) and seek (47ACH) commands. The start-up replaces it with the default step rate of 5216H.
4538
DEFB 00H 00
DCT+05H of drive 2, the head offset of a partitioned volume: 00H, none. SYS0/SYS does not read it.
4539-453A
DEFW 0000H 00 00
DCT+06H-07H of drive 2, the cylinder offset of a partitioned volume: 0000H, none. SYS0/SYS does not read it.
453B
DEFB 00H 00
DCT+08H of drive 2, the sector offset, the number of the first sector of a track: 00H. SYS0/SYS does not read it.
453C
DEFB 14H 14
DCT+09H of drive 2, the cylinder the head is over: 14H in the file. A restore sets it to 00H (475EH), a seek to the new cylinder (47B5H), and it goes to the track register when the drive is selected (4881H-4884H).
453D
DEFB 02H 02
DCT+0AH of drive 2, the physical drive number: 02H, from which 48A5H builds the drive select value; 4878H compares it with the drive used last.
453E
DEFB C0H C0
DCT+0BH of drive 2, the diskette flags: C0H, bit 7 set (double density, read at 48B2H and 48D4H, switched at 4707H) and bit 6 set (a protected directory).
453F
DEFB 01H 01
DCT+0CH of drive 2, the surface count: 01H, one sided. The geometry routine reads it at 48DCH.
4540
DEFB 12H 12
DCT+0DH of drive 2, the sectors per track: 12H, eighteen. A sector number at or above it is on side 1 (4788H-478FH).
4541
DEFB 12H 12
DCT+0EH of drive 2, the directory length in sectors: 12H, eighteen. The overlay loader works out the /SYS file positions from it (49FFH, 4A09H).
4542
DEFB 06H 06
DCT+0FH of drive 2, the sectors per granule: 06H. The record locator divides by it (4D13H) and multiplies back (4DBAH).
4543
DEFB 03H 03
DCT+10H of drive 2, the granules per cylinder: 03H. The record locator divides by it (4DB2H).
4544
DEFB 12H 12
DCT+11H of drive 2, the sectors per cylinder: 12H, eighteen. SYS0/SYS sets it from the geometry table but does not read it.
4545
DEFB 14H 14
DCT+12H of drive 2, the directory cylinder: 14H, cylinder 20. The directory routines read it at 46FDH and 47D2H; logging stores the one read from the diskette (472AH).
4546
DEFB 28H 28
DCT+13H of drive 2, the cylinder count: 28H, 40 cylinders. SYS0/SYS does not read it.
4547
DEFB 40H 40
DCT+00H of drive 3, the type byte: 40H, an active drive (bit 3 clear, not NIL). DISKIO% tests bit 3 at 46ACH.
4548-4549
DEFW 46BEH BE 46
DCT+01H-02H of drive 3, the driver address: 46BEH, the floppy disk driver of SYS0/SYS. DISKIO% jumps to it at 46B5H-46BDH.
454A
DEFB 10H 10
DCT+03H of drive 3, the drive flags: 10H, bit 4 set, a delay after the motor starts (tested at 4886H); bit 6 clear, not write protected (47EBH, 4746H); bit 2 clear, no double step (479CH); bit 0 clear, no log pending (46F5H).
454B
DEFB 03H 03
DCT+04H of drive 3, the step rate code: 03H, ORed into the restore (4762H) and seek (47ACH) commands. The start-up replaces it with the default step rate of 5216H.
454C
DEFB 00H 00
DCT+05H of drive 3, the head offset of a partitioned volume: 00H, none. SYS0/SYS does not read it.
454D-454E
DEFW 0000H 00 00
DCT+06H-07H of drive 3, the cylinder offset of a partitioned volume: 0000H, none. SYS0/SYS does not read it.
454F
DEFB 00H 00
DCT+08H of drive 3, the sector offset, the number of the first sector of a track: 00H. SYS0/SYS does not read it.
4550
DEFB 14H 14
DCT+09H of drive 3, the cylinder the head is over: 14H in the file. A restore sets it to 00H (475EH), a seek to the new cylinder (47B5H), and it goes to the track register when the drive is selected (4881H-4884H).
4551
DEFB 03H 03
DCT+0AH of drive 3, the physical drive number: 03H, from which 48A5H builds the drive select value; 4878H compares it with the drive used last.
4552
DEFB C0H C0
DCT+0BH of drive 3, the diskette flags: C0H, bit 7 set (double density, read at 48B2H and 48D4H, switched at 4707H) and bit 6 set (a protected directory).
4553
DEFB 01H 01
DCT+0CH of drive 3, the surface count: 01H, one sided. The geometry routine reads it at 48DCH.
4554
DEFB 12H 12
DCT+0DH of drive 3, the sectors per track: 12H, eighteen. A sector number at or above it is on side 1 (4788H-478FH).
4555
DEFB 12H 12
DCT+0EH of drive 3, the directory length in sectors: 12H, eighteen. The overlay loader works out the /SYS file positions from it (49FFH, 4A09H).
4556
DEFB 06H 06
DCT+0FH of drive 3, the sectors per granule: 06H. The record locator divides by it (4D13H) and multiplies back (4DBAH).
4557
DEFB 03H 03
DCT+10H of drive 3, the granules per cylinder: 03H. The record locator divides by it (4DB2H).
4558
DEFB 12H 12
DCT+11H of drive 3, the sectors per cylinder: 12H, eighteen. SYS0/SYS sets it from the geometry table but does not read it.
4559
DEFB 14H 14
DCT+12H of drive 3, the directory cylinder: 14H, cylinder 20. The directory routines read it at 46FDH and 47D2H; logging stores the one read from the diskette (472AH).
455A
DEFB 28H 28
DCT+13H of drive 3, the cylinder count: 28H, 40 cylinders. SYS0/SYS does not read it.
455BH - Character I/O: Files, FORCE, JOIN and NIL
4033H comes to 455EH from the ROM's device routine at 0674H: its 0687H jumps to 4033H when bit 7 of the control block's type byte is set and the type lacks the bits Register B asks for (01H input, 02H output, 04H control). On entry Index Register IX and Register Pair DE point to the control block, Register C holds the character to output and the ROM has stacked Register Pairs BC, HL, the old IX and DE and its return to 0694H. A file control block (type 80H) goes to the file routine at 4B97H; a FORCEd device is replaced by the device it is forced to; a JOINed device runs its own driver and then the linked device's; a NIL device returns at once.
455B
PUSH HL E5
FORCE: save Register Pair HL, which holds the DCB+01H-02H word of a FORCEd device (the DCB it is forced to), to the top of the stack.
455C
POP IX DD E1
Restore Index Register IX from the top of the stack: Index Register IX now points to the DCB the device is forced to, and the character I/O starts again with that device at 455EH.
455E
LD A,(IX+00H) DD 7E 00
Load Register A with the type byte of the control block at Index Register IX+00H (on entry from 4033H, Register A held the type AND Register B).
4561
CP 80H FE 80
Compare Register A against 80H, the type byte of an open file control block.
4563
If the Z FLAG is set (the control block is a file: 80H), JUMP to 4B97H to read or write the character Register C from or to the file.
4566
LD L,(IX+01H) DD 6E 01
Load Register L with the low byte of the driver address from Index Register IX+01H.
4569
LD H,(IX+02H) DD 66 02
Load Register H with the high byte from Index Register IX+02H: Register Pair HL = DCB+01H-02H, the driver address, or the DCB of a FORCE, or the DCB table entry of a JOIN.
456C
BIT 4,A CB 67
Test bit 4 of Register A, the FORCE flag of the type byte.
456E
If the NZ FLAG is set (the device is FORCEd), JUMP back to 455BH to go on with the DCB Register Pair HL points to.
4570
BIT 5,A CB 6F
Test bit 5 of Register A, the JOIN flag of the type byte at Index Register IX+00H.
4572
If the Z FLAG is set (not JOINed), JUMP to 4584H; Register Pair HL is the device's own driver.
4574
PUSH BC C5
JOIN: save Register Pair BC (Register B the I/O type, Register C the character) to the top of the stack for the second device.
4575
LD E,(HL) 5E
Load Register E with the byte Register Pair HL points to: with a JOIN, Register Pair HL points to ENTRY+04H of the device's DCB table entry, the linking DCB address.
4576
INC HL 23
INCrement Register Pair HL by 1 to the high byte of the linking DCB address.
4577
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the DCB of the device this one is JOINed to.
4578
INC HL 23
INCrement Register Pair HL by 1 to ENTRY+06H, the driver address saved by the JOIN.
4579
PUSH DE D5
Save Register Pair DE (the linking DCB) to the top of the stack, for 4591H.
457A
LD E,(HL) 5E
Load Register E with the low byte of the saved driver address from Register Pair HL.
457B
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
457C
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the device's own driver.
457D
INC HL 23
INCrement Register Pair HL by 1 to ENTRY+08H, the type byte saved by the JOIN.
457E
LD A,(HL) 7E
Load Register A with the saved type byte from Register Pair HL, the device's own type, to test below in place of the JOIN type.
457F
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the device's own driver.
4580
LD DE,4591H 11 91 45
Load Register Pair DE with 4591H, where the driver is to return so the linked device is served next.
4583
PUSH DE D5
Save Register Pair DE (4591H) to the top of the stack as the driver's return address.
4584
AND B A0
AND Register A (the type byte) with Register B (the I/O type asked for: 01H, 02H or 04H). The Z FLAG is set when the device does not do that kind of I/O.
4585
RET Z C8
If the Z FLAG is set, RETurn to the caller: the driver cannot do the I/O asked for.
4586
LD A,(IX+00H) DD 7E 00
Load Register A with the type byte at Index Register IX+00H again.
4589
CPL 2F
Complement Register A, so a set NIL bit (bit 3) becomes 0.
458A
AND 08H E6 08
AND Register A with 08H to keep the inverted NIL bit. The Z FLAG is set when the device is NIL.
458C
RET Z C8
If the Z FLAG is set (a NIL device), RETurn to the caller with nothing done.
458D
LD A,B 78
Load Register A with Register B, the I/O type.
458E
CP 02H FE 02
Compare Register A against 02H, setting the flags the drivers expect: the C FLAG for input (01H), the Z FLAG for output (02H), neither for control (04H).
4590
JP (HL) E9
JUMP to the driver at Register Pair HL, with Register C the character, Index Register IX the DCB and the flags of 458EH.
4591
POP IX DD E1
A JOINed device's driver returns here (4580H): restore Index Register IX from the top of the stack, the linking DCB pushed at 4579H.
4593
POP BC C1
Restore Register Pair BC from the top of the stack: Register B the I/O type and Register C the character, as they were for the first device.
4594
PUSH AF F5
Save Register Pair AF (the driver's result: Register A a character read, and its flags) to the top of the stack.
4595
LD A,B 78
Load Register A with Register B, the I/O type.
4596
CP 02H FE 02
Compare Register A against 02H. The C FLAG is set for input.
4598
If the C FLAG is set (Register B was 01H, an input), JUMP to 459DH.
459A
POP AF F1
Output or control: restore Register Pair AF from the top of the stack (the first device's result is not kept).
459B
JUMP to 455EH to do the same output or control with the linked device at Index Register IX.
459D
POP AF F1
Input: restore Register Pair AF from the top of the stack, the result of the first device.
459E
OR A B7
OR Register A with itself to test the character read. The Z FLAG is set when the first device had no character.
459F
RET NZ C0
If the NZ FLAG is set (the first device gave a character), RETurn with it in Register A.
45A0
JUMP to 455EH to ask the linked device at Index Register IX for a character instead.
45A2H - Call a Routine With the Registers Saved
Called with the address of a routine on the stack under the return address: CALL 45A2H followed by the routine to wrap, which runs with Register Pairs BC, DE, HL and Index Registers IX and IY saved around it, and returns to the caller of the caller with Register Pair AF as the routine left it. 4485H is a jump to it; DISKIO% (46A4H), DSPLY@ and PRINT@ (45BFH), the logging routine (4715H) and the geometry routine (48D1H) use it.
45A2
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: Register Pair HL = the return address, which is the address of the code after the CALL 45A2H, and the old Register Pair HL goes to the stack.
45A3
LD (45AFH),HL 22 AF 45
Store Register Pair HL into the operand of the CALL at 45AEH (45AFH-45B0H), so 45AEH calls the code after the caller's CALL 45A2H.
45A6
POP HL E1
Restore Register Pair HL from the top of the stack, the value it had at the CALL.
45A7
PUSH BC C5
Save Register Pair BC to the top of the stack.
45A8
PUSH DE D5
Save Register Pair DE to the top of the stack.
45A9
PUSH HL E5
Save Register Pair HL to the top of the stack.
45AA
PUSH IX DD E5
Save Index Register IX to the top of the stack.
45AC
PUSH IY FD E5
Save Index Register IY to the top of the stack.
45AE
GOSUB to the routine whose address 45A3H stored into this operand (0000H in the file), with all registers as the caller left them.
45B1
POP IY FD E1
Restore Index Register IY from the top of the stack.
45B3
POP IX DD E1
Restore Index Register IX from the top of the stack.
45B5
POP HL E1
Restore Register Pair HL from the top of the stack.
45B6
POP DE D1
Restore Register Pair DE from the top of the stack.
45B7
POP BC C1
Restore Register Pair BC from the top of the stack.
45B8
RET C9
RETurn to the caller of the routine that called 45A2H, with Register Pair AF as the wrapped routine left it.
45B9H - PRINT@ and DSPLY@
PRINT@ (446AH) and DSPLY@ (4467H): send the text at Register Pair HL, up to and including a 0DH or up to a 03H, to the printer (device 2) or the display (device 1) through the ROM's output routine, so a FORCE or JOIN of the device applies.
45B9
LD A,02H 3E 02
PRINT@: load Register A with 02H, the device number of @PR.
45BB
JUMP to 45BFH with Register A = 02H, the printer, to share the text loop.
45BD
LD A,01H 3E 01
DSPLY@: load Register A with 01H, the device number of @DO.
45BF
GOSUB to 45A2H, which calls 45C2H with the registers saved and, when the text is out, returns to the caller of DSPLY@ or PRINT@ with them restored.
45C2
GOSUB to 45ECH (LOCDCB%) to load Register Pair DE with the DCB address of device Register A.
45C5
LD A,(HL) 7E
Load Register A with the next character of the text at Register Pair HL.
45C6
CP 03H FE 03
Compare Register A against 03H, the end of text character that leaves the cursor where it is.
45C8
RET Z C8
If the Z FLAG is set (03H), RETurn: the 03H is not output.
45C9
PUSH AF F5
Save Register Pair AF (Register A the character) to the top of the stack.
45CA
GOSUB to the ROM's output routine at 001BH, which sends Register A to the control block at Register Pair DE.
45CD
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the character just output.
45CE
INC HL 23
INCrement Register Pair HL by 1 to the next character.
45CF
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return.
45D1
If the NZ FLAG is set (not a carriage return), JUMP back to 45C5H for the next character.
45D3
RET C9
RETurn: the 0DH has been output and ends the text.
45D4H - LOCDCT% and LOCDCB%
LOCDCT% (44A3H): Index Register IY = the drive control table address of drive Register C, from DCTTBL at 44E8H. LOCDCB% (44A0H): Register Pair DE = the DCB address of device Register A, from the DCB table at 44A6H.
45D4
PUSH DE D5
LOCDCT%: save Register Pair DE to the top of the stack.
45D5
LD IY,44E8H FD 21 E8 44
Point Index Register IY to 44E8H, the start of DCTTBL.
45D9
LD A,C 79
Load Register A with Register C, the drive number.
45DA
ADD A,A 87
Double Register A: Register A = the drive number times 2.
45DB
ADD A,A 87
Double Register A again: Register A = the drive times 4, the offset of its 4 byte entry.
45DC
LD E,A 5F
Load Register E with Register A, the offset of the entry in DCTTBL.
45DD
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the offset.
45DF
ADD IY,DE FD 19
ADD Register Pair DE to Index Register IY: Index Register IY points to the drive's DCTTBL entry.
45E1
LD E,(IY+00H) FD 5E 00
Load Register E with the low byte of the DCT address from Index Register IY+00H.
45E4
LD D,(IY+01H) FD 56 01
Load Register D with the high byte from Index Register IY+01H: Register Pair DE = the drive's drive control table.
45E7
PUSH DE D5
Save Register Pair DE (the DCT address) to the top of the stack, to move it into Index Register IY.
45E8
POP IY FD E1
Restore Index Register IY from the top of the stack: Index Register IY = the drive control table of drive Register C.
45EA
POP DE D1
Restore Register Pair DE from the top of the stack, its value at the call.
45EB
RET C9
RETurn with Index Register IY pointing to the drive control table.
45EC
PUSH HL E5
LOCDCB%: save Register Pair HL to the top of the stack.
45ED
LD HL,44A6H 21 A6 44
Point Register Pair HL to 44A6H, the start of the DCB table.
45F0
LD E,0BH 1E 0B
Load Register E with 0BH, the length of a DCB table entry.
45F2
GOSUB to 493EH to multiply Register A (the device number) by Register E: Register A = the offset of the device's entry.
45F5
LD E,A 5F
Load Register E with Register A, the offset of the entry in the DCB table.
45F6
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the offset.
45F8
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL points to the device's DCB table entry.
45F9
LD E,(HL) 5E
Load Register E with the low byte of the DCB address from Register Pair HL.
45FA
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
45FB
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the DCB address of the device, FFFFH when it has none.
45FC
POP HL E1
Restore Register Pair HL from the top of the stack.
45FD
RET C9
RETurn with Register Pair DE = the DCB address.
45FEH - The Interrupt Handler
RST 38H (4012H) comes here for every maskable interrupt. The handler reads the interrupt status at port E0H and serves the first source whose bit is 0, taking the bits from bit 0 up: bits 0 and 1 (the cassette edges) go straight to the ROM's routines at 3365H and 3369H; for bits 2-7 the handler saves the registers and jumps to the RAM vector of the source (4046H, 403DH, 4206H, 4209H, 4040H, 4043H) with 462DH as its return address. Only one source is served per interrupt. On the way out it checks the BREAK key: when BREAK and the key of bit 1 of keyboard row 3880H are down and the DEBUG on BREAK switch at 429BH is set, the interrupted program continues in DEBUG@.
45FE
PUSH AF F5
Save Register Pair AF to the top of the stack, as the interrupted program had it.
45FF
IN A,(E0H) DB E0
Read port E0H, the maskable interrupt status, into Register A. The handler takes a 0 bit as the source to serve: each JP NC below runs a source's routine when its bit is clear.
4601
RRA 1F
Rotate Register A right through the carry: bit 0 of the status (the cassette rising edge) goes to the C FLAG.
4602
If the NC FLAG is set (bit 0 clear), JUMP to 3365H, the ROM's cassette rising edge routine, with Register Pair AF of the interrupted program still on the stack.
4605
RRA 1F
Rotate Register A right through the carry: bit 1 of the status (the cassette falling edge) goes to the C FLAG.
4606
If the NC FLAG is set (bit 1 clear), JUMP to 3369H, the ROM's cassette falling edge routine, with Register Pair AF of the interrupted program still on the stack.
4609
PUSH BC C5
Save Register Pair BC to the top of the stack, for the vector routine to use freely.
460A
PUSH DE D5
Save Register Pair DE to the top of the stack.
460B
PUSH HL E5
Save Register Pair HL to the top of the stack.
460C
PUSH IX DD E5
Save Index Register IX to the top of the stack.
460E
PUSH IY FD E5
Save Index Register IY to the top of the stack.
4610
LD HL,462DH 21 2D 46
Point Register Pair HL to 462DH, where the registers are restored.
4613
PUSH HL E5
Save Register Pair HL (462DH) to the top of the stack as the return address of the vector routine.
4614
RRA 1F
Rotate Register A right through the carry: bit 2 of the status (the real time clock) goes to the C FLAG.
4615
If the NC FLAG is set (bit 2 clear), JUMP to 4046H, the real time clock vector, where the start-up puts a JP to 4657H (4E4DH-4E58H).
4618
RRA 1F
Rotate Register A right through the carry: bit 3 of the status (the I/O bus) goes to the C FLAG.
4619
If the NC FLAG is set (bit 3 clear), JUMP to 403DH, the I/O bus interrupt vector in the ROM's RAM.
461C
RRA 1F
Rotate Register A right through the carry: bit 4 of the status (the RS-232 transmitter) goes to the C FLAG.
461D
If the NC FLAG is set (bit 4 clear), JUMP to 4206H, the RS-232 transmitter interrupt vector in the ROM's RAM.
4620
RRA 1F
Rotate Register A right through the carry: bit 5 of the status (the RS-232 receiver) goes to the C FLAG.
4621
If the NC FLAG is set (bit 5 clear), JUMP to 4209H, the RS-232 receiver interrupt vector in the ROM's RAM.
4624
RRA 1F
Rotate Register A right through the carry: bit 6 of the status (the RS-232 error) goes to the C FLAG.
4625
If the NC FLAG is set (bit 6 clear), JUMP to 4040H, the RS-232 error interrupt vector in the ROM's RAM.
4628
RRA 1F
Rotate Register A right through the carry: bit 7 of the status goes to the C FLAG.
4629
If the NC FLAG is set (bit 7 clear), JUMP to 4043H, the interrupt vector of bit 7 in the ROM's RAM.
462C
RET C9
No bit is clear: RETurn to 462DH, the address pushed at 4613H, with nothing served.
462D
POP IY FD E1
Every vector routine returns here: restore Index Register IY from the top of the stack.
462F
POP IX DD E1
Restore Index Register IX from the top of the stack.
4631
POP HL E1
Restore Register Pair HL from the top of the stack.
4632
POP DE D1
Restore Register Pair DE from the top of the stack.
4633
POP BC C1
Restore Register Pair BC from the top of the stack.
4634
POP AF F1
Restore Register Pair AF from the top of the stack: every register is now as the interrupted program had it.
4635
PUSH HL E5
Save Register Pair HL to the top of the stack again, for the BREAK test.
4636
PUSH AF F5
Save Register Pair AF to the top of the stack again.
4637
LD HL,3840H 21 40 38
Point Register Pair HL to 3840H, keyboard row 6 (ENTER, CLEAR, BREAK, the arrows and the space bar).
463A
BIT 2,(HL) CB 56
Test bit 2 of the keyboard row at Register Pair HL (3840H), the BREAK key. The Z FLAG is set when it is up.
463C
If the Z FLAG is set (BREAK up), JUMP to 4653H to return to the interrupted program.
463E
LD L,80H 2E 80
Load Register L with 80H: Register Pair HL = 3880H, keyboard row 7, the SHIFT keys.
4640
BIT 1,(HL) CB 4E
Test bit 1 of the keyboard row at Register Pair HL (3880H). The Z FLAG is set when that key is up.
4642
If the Z FLAG is set (the key of bit 1 is up), JUMP to 4653H to return to the interrupted program.
4644
LD HL,429BH 21 9B 42
Point Register Pair HL to 429BH, the DEBUG on BREAK switch.
4647
XOR A AF
Set Register A to 00H by XORing it with itself.
4648
CP (HL) BE
Compare Register A (00H) against the switch at Register Pair HL (429BH).
4649
If the Z FLAG is set (the switch is 00H), JUMP to 4653H: BREAK does not enter DEBUG.
464B
LD (HL),A 77
Store Register A (00H) to the switch at Register Pair HL (429BH): the switch is used once.
464C
LD HL,440DH 21 0D 44
Load Register Pair HL with 440DH, the DEBUG@ entry point.
464F
POP AF F1
Restore Register Pair AF from the top of the stack, as the interrupted program had it.
4650
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: the stack holds 440DH over the interrupted program's address, and Register Pair HL is the program's again.
4651
EI FB
Enable interrupts, which the RST 38H left disabled.
4652
RET C9
RETurn to 440DH: DEBUG@ starts with every register as the interrupted program left it and the program's address on the stack.
4653
POP AF F1
Restore Register Pair AF from the top of the stack.
4654
POP HL E1
Restore Register Pair HL from the top of the stack.
4655
EI FB
Enable interrupts, which the RST 38H left disabled.
4656
RET C9
RETurn to the interrupted program with its registers as they were.
4657H - The Clock Task and the Interrupt Slots
The real time clock routine: the start-up puts JP 4657H at 4046H, the vector of bit 2 of port E0H. On every tick it reads port ECH and runs the tasks of the fast slots 4-7, then counts the tick at 4293H and runs one of the slow slots 0-3 in turn (each slow slot every fourth tick). A slot of the table at 42BEH holds the address of a task block; the block's first word is the task's address, and the task runs with Index Register IX pointing to its block.
4657
IN A,(ECH) DB EC
Read port ECH into Register A, the real time clock's acknowledge: the read clears the clock interrupt. Register A is not used.
4659
LD A,04H 3E 04
Load Register A with 04H, fast slot 4, which runs on every tick.
465B
GOSUB to 4674H to run the task of slot Register A (4).
465E
LD A,05H 3E 05
Load Register A with 05H, fast slot 5, which runs on every tick.
4660
GOSUB to 4674H to run the task of slot Register A (5).
4663
LD A,06H 3E 06
Load Register A with 06H, fast slot 6, which runs on every tick.
4665
GOSUB to 4674H to run the task of slot Register A (6).
4668
LD A,07H 3E 07
Load Register A with 07H, fast slot 7, which runs on every tick; the start-up puts the ROM's clock task block 469FH into it (4E61H-4E66H).
466A
GOSUB to 4674H to run the task of slot Register A (7).
466D
LD HL,4293H 21 93 42
Point Register Pair HL to 4293H, the tick count.
4670
INC (HL) 34
INCrement the tick count at Register Pair HL (4293H) by 1.
4671
LD A,(HL) 7E
Load Register A with the tick count at Register Pair HL (4293H).
4672
AND 03H E6 03
AND Register A with 03H: Register A = the slow slot whose turn it is (0-3); the code falls into 4674H to run it.
4674
ADD A,A 87
Run the task of slot Register A: double Register A, the offset of the slot's word.
4675
LD L,A 6F
Load Register L with Register A, the offset of the slot in the slot table.
4676
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = the offset.
4678
LD BC,42BEH 01 BE 42
Load Register Pair BC with 42BEH, the slot table.
467B
ADD HL,BC 09
ADD Register Pair BC to Register Pair HL: Register Pair HL points to the slot.
467C
LD E,(HL) 5E
Load Register E with the low byte of the task block address from Register Pair HL.
467D
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
467E
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the task block.
467F
PUSH DE D5
Save Register Pair DE (the task block) to the top of the stack.
4680
POP IX DD E1
Restore Index Register IX from the top of the stack: Index Register IX = the task block, as the task expects.
4682
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the task block.
4683
LD E,(HL) 5E
Load Register E with the low byte of the task address, the first word of the block at Register Pair HL.
4684
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
4685
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the task.
4686
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the task.
4687
JP (HL) E9
JUMP to the task at Register Pair HL; its RET returns to the caller of 4674H.
4688H - RESET@ and SET@
RESET@ (4416H): put the empty task block 469CH into slot Register A. SET@ (4413H): put the task block at Register Pair DE into slot Register A (0-7). The two task blocks of SYS0/SYS follow: the empty block, and the block of the ROM's clock task, which the start-up installs in slot 7.
4688
LD DE,469CH 11 9C 46
RESET@: load Register Pair DE with 469CH, the empty task block, and go on into SET@.
468B
CP 08H FE 08
SET@: compare Register A (the slot) against 08H, the number of slots.
468D
RET NC D0
If the NC FLAG is set (slot 8 or more), RETurn with nothing changed.
468E
ADD A,A 87
Double Register A, the offset of the slot's word.
468F
LD L,A 6F
Load Register L with Register A, the offset of the slot in the slot table.
4690
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = the offset.
4692
LD BC,42BEH 01 BE 42
Load Register Pair BC with 42BEH, the slot table.
4695
ADD HL,BC 09
ADD Register Pair BC to Register Pair HL: Register Pair HL points to the slot.
4696
DI F3
Disable interrupts, so the clock task cannot run the slot while its two bytes are changed.
4697
LD (HL),E 73
Store Register E, the low byte of the task block, to the slot at Register Pair HL.
4698
INC HL 23
INCrement Register Pair HL by 1 to the high byte of the slot.
4699
LD (HL),D 72
Store Register D, the high byte of the task block, to the slot at Register Pair HL.
469A
EI FB
Enable interrupts again: the slot holds the new task block.
469B
RET C9
RETurn to the caller of SET@ or RESET@ with the slot changed.
469C-469D
DEFW 469EH 9E 46
The empty task block: its task address is 469EH, a RET. Every slot of the table at 42BEH holds it in the file, and RESET@ puts it back.
469E
RET C9
RETurn at once: the task of the empty block, which does nothing.
469F-46A0
DEFW 46A1H A1 46
The task block of the ROM's clock task: its task address is 46A1H. The start-up puts it into slot 7 through SET@ (4E61H-4E66H).
46A1
JUMP to 3529H, the ROM's real time clock routine, run on every tick from slot 7; the manual gives slot 7 to the ROM's interrupt tasks.
46A4H - DISKIO%
DISKIO% (4488H): Register A = the function (0-9), Register C = the drive, Register D = the cylinder, Register E = the sector, Register Pair HL = the 256 byte buffer. The registers other than Register Pair AF come back as they were; Register A returns 00H with the Z FLAG set, or an error code with the NZ FLAG set. A NIL drive returns error 08H; any other goes to the driver at DCT+01H-02H.
46A4
GOSUB to 45A2H, which calls 46A7H with Register Pairs BC, DE, HL and Index Registers IX and IY saved, and returns to the caller of DISKIO% when the driver is done.
46A7
PUSH AF F5
Save Register Pair AF (Register A the function) to the top of the stack.
46A8
GOSUB to 45D4H (LOCDCT%) to point Index Register IY to the drive control table of drive Register C.
46AB
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the function.
46AC
BIT 3,(IY+00H) FD CB 00 5E
Test bit 3, the NIL flag, of the type byte at Index Register IY+00H.
46B0
If the Z FLAG is set (the drive is not NIL), JUMP to 46B5H.
46B2
LD A,08H 3E 08
Load Register A with 08H, the error code for a drive that is not available; the NZ FLAG from 46ACH stays set.
46B4
RET C9
RETurn with Register A = 08H and the NZ FLAG set.
46B5
PUSH HL E5
Save Register Pair HL (the buffer) to the top of the stack.
46B6
LD L,(IY+01H) FD 6E 01
Load Register L with the low byte of the driver address from Index Register IY+01H.
46B9
LD H,(IY+02H) FD 66 02
Load Register H with the high byte from Index Register IY+02H: Register Pair HL = the drive's driver.
46BC
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: the driver address goes to the stack and Register Pair HL is the buffer again.
46BD
RET C9
RETurn, which jumps to the driver (46BEH for drives 0-3) with Register A the function and Index Register IY the drive control table.
46BEH - The Floppy Disk Driver: Function Dispatch
The driver of the drive control tables at 450BH-455AH. Register A (the function, 0-9) picks the routine from the table at 46CEH; the routine is entered with Register Pair HL the buffer again and Index Register IY the drive control table.
46BE
PUSH HL E5
Save Register Pair HL (the buffer) to the top of the stack.
46BF
LD HL,46CEH 21 CE 46
Point Register Pair HL to 46CEH, the table of the ten function routines.
46C2
ADD A,A 87
Double Register A, the function: Register A = the offset of its word in the table.
46C3
ADD A,L 85
ADD Register L (CEH, the low byte of 46CEH) to Register A.
46C4
LD L,A 6F
Load Register L with Register A, the low byte of the table entry's address.
46C5
If the NC FLAG is set (no carry from the low byte), JUMP to 46C8H.
46C7
INC H 24
INCrement Register H by 1, the carry into the high byte of the entry's address.
46C8
LD A,(HL) 7E
Load Register A with the low byte of the routine's address from the table entry at Register Pair HL.
46C9
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
46CA
LD H,(HL) 66
Load Register H with the high byte of the routine's address from Register Pair HL.
46CB
LD L,A 6F
Load Register L with Register A: Register Pair HL = the function's routine.
46CC
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: the routine goes to the stack, the buffer back into Register Pair HL.
46CD
RET C9
RETurn, which jumps to the function's routine.
46CE-46CF
DEFW 4733H 33 47
Function 0, DCHECK, test the drive for a diskette and write protection: 4733H.
46D0-46D1
DEFW 475BH 5B 47
Function 1, DHOME, restore the head to cylinder 0: 475BH.
46D2-46D3
DEFW 477FH 7F 47
Function 2, DSEEK, seek cylinder Register D and set up sector Register E: 477FH.
46D4-46D5
DEFW 47BDH BD 47
Function 3, DREAD, read a sector with five tries: 47BDH.
46D6-46D7
DEFW 47C4H C4 47
Function 4, DVERF, read a sector back with one try: 47C4H.
46D8-46D9
DEFW 47CBH CB 47
Function 5, DWRITE, write a sector with the normal data address mark: 47CBH.
46DA-46DB
DEFW 46E2H E2 46
Function 6, SREAD, read a sector of the directory cylinder: 46E2H.
46DC-46DD
DEFW 47D2H D2 47
Function 7, SWRITE, write a sector of the directory cylinder: 47D2H.
46DE-46DF
DEFW 47D5H D5 47
Function 8, DWRITA, write a sector with the deleted data address mark the directory uses: 47D5H.
46E0-46E1
DEFW 47DCH DC 47
Function 9, DFORMT, write a whole track from the buffer: 47DCH.
46E2H - SREAD, Reading the Directory Cylinder, and Logging a Diskette
SREAD reads sector Register E of the directory cylinder (DCT+12H). The directory is written with the deleted data address mark, so the controller reports the record type (error code 06H) for a good directory read; SREAD turns that into 00H. When the first read fails the drive is logged again and the read repeated; a second failure is error 11H. Logging (4715H) restores the head, reads cylinder 0 sector 0 (in either density) and takes the directory cylinder from its byte 2.
46E2
GOSUB to 46F5H to log the diskette when its log flag is set and read sector Register E of the directory cylinder. Register A returns 06H when the directory mark was read.
46E5
SUB 06H D6 06
SUBtract 06H from Register A. The Z FLAG is set when the directory mark was read: Register A = 00H, no error.
46E7
RET Z C8
If the Z FLAG is set, RETurn with Register A = 00H, success.
46E8
SET 0,(IY+03H) FD CB 03 C6
Set bit 0 of the drive flags at Index Register IY+03H, the log flag: the diskette is logged before the second try.
46EC
GOSUB to 46F5H to log the diskette and read the directory sector again.
46EF
SUB 06H D6 06
SUBtract 06H from Register A. The Z FLAG is set when the directory mark was read this time.
46F1
RET Z C8
If the Z FLAG is set, RETurn with Register A = 00H, success.
46F2
LD A,11H 3E 11
Load Register A with 11H, the error code for a directory read error; the NZ FLAG from 46EFH stays set.
46F4
RET C9
RETurn with Register A = 11H and the NZ FLAG set.
46F5
BIT 0,(IY+03H) FD CB 03 46
Test bit 0 of the drive flags at Index Register IY+03H, the log flag.
46F9
If the NZ FLAG is set (the diskette is to be logged), GOSUB to 4715H to log it.
46FC
RET NZ C0
If the NZ FLAG is set (the logging failed), RETurn with its error code in Register A.
46FD
LD D,(IY+12H) FD 56 12
Load Register D with the directory cylinder from Index Register IY+12H.
4700
GOSUB to 47C4H (DVERF) to read cylinder Register D, sector Register E into the buffer at Register Pair HL, one try.
4703
RET Z C8
If the Z FLAG is set (the sector was read with a normal data address mark), RETurn with Register A = 00H.
4704
CP 06H FE 06
Compare Register A, the error code, against 06H, the record type error the deleted data mark gives.
4706
RET Z C8
If the Z FLAG is set (the directory mark was read), RETurn with Register A = 06H.
4707
LD A,(IY+0BH) FD 7E 0B
Any other error: load Register A with the diskette flags at Index Register IY+0BH.
470A
XOR 80H EE 80
XOR Register A with 80H to switch bit 7, the density.
470C
LD (IY+0BH),A FD 77 0B
Store Register A back to the diskette flags at Index Register IY+0BH.
470F
GOSUB to 48D1H to set the diskette's geometry (DCT+0BH-11H) for the new density.
4712
JUMP to 47C4H to read the sector once more in the new density; its result is returned.
4715
GOSUB to 45A2H, which calls 4718H with the registers saved and returns to the caller of 4715H.
4718
GOSUB to 48D1H to set the geometry (DCT+0BH-11H) from the density and surface count the drive control table holds now.
471B
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H: Register D = cylinder 0, Register E = sector 0.
471E
GOSUB to 475BH (DHOME) to restore the head to cylinder 0.
4721
GOSUB to 4700H to read cylinder 0, sector 0 into the buffer at Register Pair HL, switching the density once when the read fails.
4724
RET NZ C0
If the NZ FLAG is set (it could not be read in either density), RETurn with the error code in Register A.
4725
INC HL 23
INCrement Register Pair HL by 1, into the sector just read.
4726
INC HL 23
INCrement Register Pair HL by 1 to its byte 2, the directory cylinder (14H on the master, the BOOT/SYS sector 0 bytes 00H FEH 14H).
4727
LD A,(HL) 7E
Load Register A with the directory cylinder from Register Pair HL.
4728
AND 7FH E6 7F
AND Register A with 7FH to drop bit 7 of the directory cylinder byte.
472A
LD (IY+12H),A FD 77 12
Store Register A to the directory cylinder at Index Register IY+12H.
472D
RES 0,(IY+03H) FD CB 03 86
Reset bit 0 of the drive flags at Index Register IY+03H: the diskette is logged.
4731
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: no error.
4732
RET C9
RETurn with Register A = 00H: the diskette is logged.
4733H - DCHECK
Function 0: select the drive and wait for an index pulse to go by. Register A returns 00H with the Z FLAG set when the drive is ready, and the C FLAG set as well when the diskette (status bit 6) or the drive (DCT+03H bit 6) is write protected; when no index pulse comes within the count, Register A returns FFH with the NZ FLAG set.
4733
GOSUB to 4870H to select the drive, set the density and wait for the motor when the drive needs it.
4736
GOSUB to 48BFH to send two Force Interrupt commands (D0H), which leave the controller showing the drive's status.
4739
LD HL,3155H 21 55 31
Load Register Pair HL with 3155H, the count of status reads to wait for the index pulses.
473C
GOSUB to 474EH to count down and read the status; the Z FLAG is set when the index bit is off.
473F
If the NZ FLAG is set (the index hole is under the sensor), JUMP back to 473CH until it has gone by.
4741
GOSUB to 474EH to count down and read the status again.
4744
If the Z FLAG is set (no index yet), JUMP back to 4741H until the next index pulse.
4746
OR (IY+03H) FD B6 03
OR Register A (the status: bit 6 write protect) with the drive flags at Index Register IY+03H (bit 6 the drive's write protect flag).
4749
RLCA 07
Rotate Register A left: bit 6, write protected, moves to bit 7.
474A
AND 80H E6 80
AND Register A with 80H to keep only the write protect bit.
474C
ADD A,A 87
ADD Register A to itself: bit 7 goes into the C FLAG and Register A becomes 00H with the Z FLAG set.
474D
RET C9
RETurn: Register A = 00H, the Z FLAG set (ready) and the C FLAG set when write protected.
474E
DEC HL 2B
DECrement Register Pair HL, the count of status reads left, by 1.
474F
LD A,H 7C
Load Register A with Register H, the high byte of the count.
4750
OR L B5
OR Register A with Register L. The Z FLAG is set when the count in Register Pair HL has run out.
4751
If the Z FLAG is set (the count ran out), JUMP to 4758H: no index pulse, the drive is not ready.
4753
IN A,(F0H) DB F0
Read the status register of the controller, port F0H, into Register A.
4755
BIT 1,A CB 4F
Test bit 1 of Register A, the index bit of the status after a Force Interrupt.
4757
RET C9
RETurn with the Z FLAG set when the index bit is off.
4758
POP HL E1
Restore Register Pair HL from the top of the stack: the return into the wait loop is dropped.
4759
DEC A 3D
DECrement Register A (00H) by 1: Register A = FFH and the NZ FLAG set, the drive is not ready.
475A
RET C9
RETurn to the caller of DCHECK with Register A = FFH and the NZ FLAG set.
475BH - DHOME, and Waiting for a Command
Function 1: send the Restore command and wait for it. 4767H sends any command in Register A and waits while the controller is busy, sending the drive select again on each status read so the motor keeps running, then lets the head settle and returns the not ready, seek error and CRC error bits of the status.
475B
GOSUB to 4870H to select the drive, set the density and wait for the motor when the drive needs it.
475E
LD (IY+09H),00H FD 36 09 00
Store 00H into the head position at Index Register IY+09H: after the restore the head is over cylinder 0.
4762
LD A,(IY+04H) FD 7E 04
Load Register A with the step rate code from Index Register IY+04H.
4765
OR 08H F6 08
OR Register A with 08H: Register A = the Restore command (bits 7-4 0000) with the head loaded (bit 3) and the drive's step rate (bits 1-0).
4767
GOSUB to 48C9H to send the command in Register A to the controller's command register, port F0H, and wait for the status to settle.
476A
IN A,(F0H) DB F0
Read the status register, port F0H, into Register A.
476C
RRCA 0F
Rotate Register A right: bit 0, BUSY, goes into the C FLAG.
476D
If the C FLAG is set (still busy), GOSUB to 489FH to send the drive select value of 4295H to port F4H again, which keeps the motor running.
4770
If the C FLAG is set (still busy), JUMP back to 476AH.
4772
PUSH BC C5
Save Register Pair BC to the top of the stack.
4773
LD BC,04B0H 01 B0 04
Load Register Pair BC with 04B0H, the length of the delay.
4776
GOSUB to the ROM's delay at 0060H, which counts Register Pair BC down to zero: the head settles.
4779
POP BC C1
Restore Register Pair BC from the top of the stack.
477A
IN A,(F0H) DB F0
Read the status register, port F0H, into Register A again.
477C
AND 98H E6 98
AND Register A with 98H: bit 7 not ready, bit 4 seek error, bit 3 CRC error. The Z FLAG is set when none is set.
477E
RET C9
RETurn with Register A = the error bits of the status.
477FH - DSEEK
Function 2: select the drive and the side, put the sector in the sector register (port F2H) and, unless the head is already there, seek cylinder Register D (two steps a cylinder when DCT+03H bit 2 is set). Sectors at or above the sectors per track (DCT+0DH) are on side 1: bit 4 of the drive select value is set and the sectors per track are taken off. Register A returns 00H with the Z FLAG set, or the status error bits of the seek.
477F
GOSUB to 4870H to select the drive, set the density and wait for the motor when the drive needs it.
4782
PUSH DE D5
Save Register Pair DE (Register D the cylinder, Register E the sector) to the top of the stack.
4783
PUSH HL E5
Save Register Pair HL (the buffer) to the top of the stack.
4784
LD HL,4295H 21 95 42
Point Register Pair HL to 4295H, the drive select value 4870H has just built.
4787
LD A,E 7B
Load Register A with Register E, the sector number given.
4788
SUB (IY+0DH) FD 96 0D
SUBtract the sectors per track at Index Register IY+0DH from Register A. The C FLAG is set when the sector is on side 0.
478B
If the C FLAG is set (side 0), JUMP to 4790H.
478D
SET 4,(HL) CB E6
Side 1: set bit 4, the side select, of the drive select value at Register Pair HL (4295H).
478F
LD E,A 5F
Load Register E with Register A, the sector number within side 1.
4790
LD A,E 7B
Load Register A with Register E, the sector within its side.
4791
OUT (F2H),A D3 F2
Write Register A to port F2H, the controller's sector register.
4793
GOSUB to 489FH to send the drive select value of 4295H (with the side) to port F4H.
4796
POP HL E1
Restore Register Pair HL (the buffer) from the top of the stack.
4797
POP DE D1
Restore Register Pair DE from the top of the stack: Register D = the cylinder, Register E = the sector as given.
4798
IN A,(F1H) DB F1
Read port F1H, the controller's track register, into Register A: the cylinder the head is over.
479A
SUB D 92
SUBtract Register D, the cylinder wanted, from Register A. The Z FLAG is set when the head is already there.
479B
RET Z C8
If the Z FLAG is set, RETurn with Register A = 00H: no seek is needed.
479C
BIT 2,(IY+03H) FD CB 03 56
Test bit 2 of the drive flags at Index Register IY+03H, the double step switch.
47A0
LD A,D 7A
Load Register A with Register D, the cylinder wanted.
47A1
If the Z FLAG is set (no double step), JUMP to 47AAH with Register A = the cylinder.
47A3
IN A,(F1H) DB F1
Double step: read the track register, port F1H, into Register A.
47A5
ADD A,A 87
Double Register A: the head's cylinder in steps.
47A6
OUT (F1H),A D3 F1
Write Register A to the track register, port F1H, so the controller counts in steps.
47A8
LD A,D 7A
Load Register A with Register D, the cylinder wanted.
47A9
ADD A,A 87
Double Register A: the cylinder wanted in steps.
47AA
OUT (F3H),A D3 F3
Write Register A, the target, to port F3H, the controller's data register, for the Seek command.
47AC
LD A,(IY+04H) FD 7E 04
Load Register A with the step rate code from Index Register IY+04H.
47AF
OR 18H F6 18
OR Register A with 18H: Register A = the Seek command (bits 7-4 0001) with the head loaded (bit 3) and the drive's step rate.
47B1
GOSUB to 4767H to send the Seek command and wait for it. Register A returns its error bits.
47B4
PUSH AF F5
Save Register Pair AF (the result of the seek) to the top of the stack.
47B5
LD (IY+09H),D FD 72 09
Store Register D, the cylinder wanted, into the head position at Index Register IY+09H.
47B8
LD A,D 7A
Load Register A with Register D, the cylinder.
47B9
OUT (F1H),A D3 F1
Write Register A to the track register, port F1H: after a double step seek it holds the cylinder again, not the step count.
47BB
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the error bits of the seek.
47BC
RET C9
RETurn with the Z FLAG set when the seek had no error.
47BDH - The Sector Functions and Their Parameter Blocks
Functions 3, 4, 5, 7, 8 and 9 each call 47E3H with a four byte parameter block after the CALL: the controller command, the number of tries, the first error code (01H for a read, 09H for a write) and the kind (01H a read, 02H a write, 04H a track write; the transfer tests only bit 0, so a track write is handled like a write). SWRITE first loads Register D with the directory cylinder and goes on into DWRITA.
47BD
DREAD: GOSUB to 47E3H, which takes the four bytes at 47C0H as its parameters and does not return here.
47C0-47C3
DEFB 80H, 05H, 01H, 01H 80 05 01 01
The DREAD parameters: command 80H (Read Sector), five tries, first error code 01H, a read.
| 1793 FDC Command: 80H (10000000) | | Function Description |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | Command=Read Sector (bits 7-5 = 100) m = 0: one sector S = 0: side to compare (used only when C = 1) E = 0: no 15 ms delay C = 0: side compare off |
47C4
DVERF: GOSUB to 47E3H with the four bytes at 47C7H as its parameters.
47C7-47CA
DEFB 80H, 01H, 01H, 01H 80 01 01 01
The DVERF parameters: command 80H (Read Sector), one try, first error code 01H, a read.
47CB
DWRITE: GOSUB to 47E3H with the four bytes at 47CEH as its parameters.
47CE-47D1
DEFB A0H, 05H, 09H, 02H A0 05 09 02
The DWRITE parameters: command A0H (Write Sector with the normal data address mark), five tries, first error code 09H, a write.
| 1793 FDC Command: A0H (10100000) | | Function Description |
| 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | | Command=Write Sector (bits 7-5 = 101) m = 0: one sector S = 0: side to compare (used only when C = 1) E = 0: no 15 ms delay C = 0: side compare off a0 = 0: data address mark FBH (normal) |
47D2
LD D,(IY+12H) FD 56 12
SWRITE: load Register D with the directory cylinder from Index Register IY+12H, then go on into DWRITA.
47D5
DWRITA: GOSUB to 47E3H with the four bytes at 47D8H as its parameters.
47D8-47DB
DEFB A1H, 05H, 09H, 02H A1 05 09 02
The DWRITA and SWRITE parameters: command A1H (Write Sector with the deleted data address mark the directory uses), five tries, first error code 09H, a write.
| 1793 FDC Command: A1H (10100001) | | Function Description |
| 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | | Command=Write Sector (bits 7-5 = 101) m = 0: one sector S = 0: side to compare (used only when C = 1) E = 0: no 15 ms delay C = 0: side compare off a0 = 1: data address mark F8H (deleted) |
47DC
DFORMT: GOSUB to 47E3H with the four bytes at 47DFH as its parameters.
47DF-47E2
DEFB F0H, 05H, 09H, 04H F0 05 09 04
The DFORMT parameters: command F0H (Write Track, bits 7-4 1111), five tries, first error code 09H, kind 04H: bit 0 clear, so like a write the drive's write protect flag is checked (47E5H) and the buffer is sent byte by byte.
47E3H - The Sector Transfer
Entered from the function routines with the parameter block's address on the stack. A write is refused when the drive's write protect flag is set; then the head is placed (DSEEK) and the command sent with interrupts off. The first byte is moved once the controller has data or is no longer busy; the rest go in a loop that holds the processor in wait states (bit 6 of the drive select at port F4H) until each byte is ready. The loop has no exit of its own: the controller's interrupt request at the end of the command raises a non maskable interrupt (enabled through port E4H), and the NMI vector 4049H, set by the start-up to JP 4842H, ends it. A failed try is retried, after a restore unless the error was lost data; write protect and the record type bit end the tries at once. The error code is the block's first error code plus the number of the lowest error bit of the status.
47E3
POP IX DD E1
Restore Index Register IX from the top of the stack: Index Register IX = the parameter block after the function's CALL, which is not returned to; the transfer returns to the caller of the function.
47E5
BIT 0,(IX+03H) DD CB 03 46
Test bit 0 of the kind at Index Register IX+03H, the read bit.
47E9
If the NZ FLAG is set (a read), JUMP to 47F3H.
47EB
LD A,(IY+03H) FD 7E 03
A write: load Register A with the drive flags at Index Register IY+03H.
47EE
AND 40H E6 40
AND Register A with 40H, bit 6, the drive's write protect flag.
47F0
If the NZ FLAG is set (the drive is write protected), JUMP to 4866H with Register A = 40H: error 09H plus 6, 0FH, Write protected disk.
47F3
PUSH HL E5
Save Register Pair HL (the buffer) to the top of the stack.
47F4
LD B,(IX+01H) DD 46 01
Load Register B with the number of tries from Index Register IX+01H.
47F7
LD HL,A2EDH 21 ED A2
Load Register Pair HL with A2EDH, the bytes EDH A2H of INI, which reads a byte from port Register C into the buffer.
47FA
BIT 0,(IX+03H) DD CB 03 46
Test bit 0 of the kind at Index Register IX+03H again, the read bit.
47FE
If the NZ FLAG is set (a read), JUMP to 4803H with Register Pair HL = INI.
4800
LD HL,A3EDH 21 ED A3
A write: load Register Pair HL with A3EDH, the bytes EDH A3H of OUTI, which sends a byte from the buffer to port Register C.
4803
LD (4830H),HL 22 30 48
Store Register Pair HL, the transfer instruction, over 4830H-4831H, the first byte's transfer.
4806
LD (483DH),HL 22 3D 48
Store Register Pair HL over 483DH-483EH, the transfer of the byte loop.
4809
POP HL E1
Restore Register Pair HL (the buffer) from the top of the stack.
480A
Each try starts here: GOSUB to 477FH (DSEEK) to select the drive and side, set the sector register and seek cylinder Register D.
480D
If the NZ FLAG is set (the seek failed), JUMP to 4866H to turn the status bits in Register A into the error code.
480F
PUSH BC C5
Save Register Pair BC (Register B the tries left) to the top of the stack.
4810
PUSH DE D5
Save Register Pair DE (Register D the cylinder, Register E the sector) to the top of the stack.
4811
PUSH HL E5
Save Register Pair HL (the buffer) to the top of the stack.
4812
LD BC,03F3H 01 F3 03
Load Register Pair BC with 03F3H: Register B = 03H, the mask of the BUSY and DATA REQUEST bits, and Register C = F3H, the controller's data register, the port of INI and OUTI.
4815
LD A,(4295H) 3A 95 42
Load Register A with the drive select value at 4295H, built by 4870H and given its side by DSEEK.
4818
LD D,A 57
Load Register D with Register A, the drive select value.
4819
SET 6,D CB F2
Set bit 6 of Register D, the wait state switch: sent to port F4H in the byte loop, it holds the processor until the controller is ready.
481B
LD E,02H 1E 02
Load Register E with 02H, the mask of the DATA REQUEST bit of the status.
481D
LD A,(4296H) 3A 96 42
Load Register A with the NMI mask value at 4296H, 00H in the file.
4820
SET 7,A CB FF
Set bit 7 of Register A, the enable of the NMI from the controller's interrupt request.
| Port E4H (NMI Mask): 80H (10000000) | | Function Description |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | Bit 7 = 1: NMI from the controller's interrupt request (INTRQ) enabled Bit 6 = 0: NMI from the motor time-out disabled Bits 5-0: not used |
4822
OUT (E4H),A D3 E4
Write Register A to port E4H, the NMI mask: the end of the command will now raise a non maskable interrupt.
4824
LD A,(IX+00H) DD 7E 00
Load Register A with the controller command from the parameter block at Index Register IX+00H.
4827
GOSUB to 48C8H to disable interrupts, send the command in Register A to port F0H and wait for the status to settle.
482A
IN A,(F0H) DB F0
Read the status register, port F0H, into Register A.
482C
AND B A0
AND Register A with Register B (03H): bit 0 BUSY and bit 1 DATA REQUEST.
482D
If the parity is odd (exactly one of the two bits set: busy with no data yet), JUMP back to 482AH. The loop ends when both are set (the first byte is ready) or both are clear (the command has ended).
4830
NOP 00
Two NOP bytes in the file at 4830H-4831H; 4803H stores INI or OUTI over them, which moves the first byte between port Register C (F3H) and the buffer at Register Pair HL, INCrements Register Pair HL and DECrements Register B. This row is the first of the two bytes.
4831
NOP 00
The second byte of the transfer instruction stored at 4803H (A2H of INI or A3H of OUTI); 00H in the file.
4832
RRCA 0F
Rotate Register A (the two status bits) right: bit 0, BUSY, goes into the C FLAG.
4833
If the NC FLAG is set (the controller is no longer busy), JUMP to 4843H to end the transfer.
4835
LD A,D 7A
The byte loop: load Register A with Register D, the drive select value with the wait state bit.
4836
OUT (F4H),A D3 F4
Write Register A to port F4H, the drive select: the processor waits in wait states until the controller has the next byte or ends the command.
4838
IN A,(F0H) DB F0
Read the status register, port F0H, into Register A.
483A
AND E A3
AND Register A with Register E (02H), the DATA REQUEST bit.
483B
If the Z FLAG is set (no byte ready), JUMP back to 4835H.
483D
NOP 00
Two NOP bytes in the file at 483DH-483EH; 4806H stores INI or OUTI over them, which moves the next byte between port Register C (F3H) and the buffer at Register Pair HL and INCrements Register Pair HL. This row is the first of the two bytes.
483E
NOP 00
The second byte of the transfer instruction stored at 4806H (A2H of INI or A3H of OUTI); 00H in the file.
483F
JUMP back to 4835H for the next byte. The loop is left only through the NMI at the end of the command (4842H).
4842
POP AF F1
The NMI comes here through 0066H and the vector 4049H (JP 4842H, set by the start-up): restore Register Pair AF from the top of the stack, which drops the address the NMI pushed, the place in the byte loop.
4843
LD A,(4296H) 3A 96 42
Load Register A with the NMI mask value at 4296H.
4846
OUT (E4H),A D3 E4
Write Register A to port E4H, the NMI mask: the controller's interrupt request no longer raises an NMI.
4848
EI FB
Enable interrupts, which 48C8H disabled before the command was sent.
4849
POP HL E1
Restore Register Pair HL (the buffer) from the top of the stack.
484A
POP DE D1
Restore Register Pair DE (Register D the cylinder, Register E the sector) from the top of the stack.
484B
POP BC C1
Restore Register Pair BC from the top of the stack: Register B = the tries left.
484C
IN A,(F0H) DB F0
Read the status register, port F0H, into Register A, the result of the command.
484E
AND FCH E6 FC
AND Register A with FCH, keeping the error bits 7-2. The Z FLAG is set when there is no error.
| 1793 Status after Read/Write Sector, AND FCH | | Function Description |
| N | W | R | F | C | L | 0 | 0 | | N: 1 = not ready W: 1 = write protected (write) R: 1 = deleted data mark F8H (read), write fault (write) F: 1 = record not found C: 1 = CRC error L: 1 = lost data Bits 1-0 (data request, busy): removed by AND FCH |
4850
RET Z C8
If the Z FLAG is set, RETurn with Register A = 00H: the sector was moved.
4851
DEC B 05
DECrement Register B, the count of tries left, by 1.
4852
If the Z FLAG is set (no tries left), JUMP to 4866H to return the error code.
4854
BIT 2,A CB 57
Test bit 2 of Register A, the lost data bit of the status.
4856
If the NZ FLAG is set (lost data), JUMP back to 480AH to try again without a restore.
4858
CP 20H FE 20
Compare Register A against 20H, the record type bit alone (the deleted data mark of a read).
485A
If the Z FLAG is set (only the record type bit), JUMP to 4866H: it is not retried; SREAD takes the error code 06H as a good directory read.
485C
CP 40H FE 40
Compare Register A against 40H, the write protect bit alone.
485E
If the Z FLAG is set (write protected), JUMP to 4866H: it is not retried.
4860
Any other error: GOSUB to 475BH (DHOME) to restore the head to cylinder 0.
4863
JUMP back to 480AH to seek again and try once more.
4866
LD B,A 47
Error code: load Register B with Register A, the error bits of the status.
4867
LD A,(IX+02H) DD 7E 02
Load Register A with the first error code from the parameter block at Index Register IX+02H (01H for a read, 09H for a write).
486A
RRC B CB 08
Rotate Register B right: its lowest bit goes into the C FLAG.
486C
RET C D8
If the C FLAG is set (the lowest error bit is found), RETurn with the error code in Register A and the NZ FLAG set.
486D
INC A 3C
INCrement Register A by 1, the next error code.
486E
JUMP back to 486AH to test the next bit of Register B.
4870H - Selecting the Drive
Builds the drive select value at 4295H from the drive's physical number and density (48A5H); when the drive is not the one used last (4294H) it stores the new drive and loads the drive's head position into the track register. A drive whose DCT+03H bit 4 is set and which reports not ready gets a delay for its motor to come up to speed. The select value goes to port F4H.
4870
PUSH BC C5
Save Register Pair BC to the top of the stack.
4871
GOSUB to 48A5H to build the drive select value at 4295H.
4874
LD BC,4294H 01 94 42
Point Register Pair BC to 4294H, the drive used last.
4877
LD A,(BC) 0A
Load Register A with the drive used last from Register Pair BC (4294H).
4878
CP (IY+0AH) FD BE 0A
Compare Register A against the physical drive number at Index Register IY+0AH.
487B
If the Z FLAG is set (the same drive), JUMP to 4886H.
487D
LD A,(IY+0AH) FD 7E 0A
Load Register A with the physical drive number from Index Register IY+0AH.
4880
LD (BC),A 02
Store Register A to 4294H at Register Pair BC: the new drive used last.
4881
LD A,(IY+09H) FD 7E 09
Load Register A with the head position of the drive from Index Register IY+09H.
4884
OUT (F1H),A D3 F1
Write Register A to port F1H, the track register: the controller knows where the new drive's head is.
4886
BIT 4,(IY+03H) FD CB 03 66
Test bit 4 of the drive flags at Index Register IY+03H, the motor delay switch.
488A
If the Z FLAG is set (no motor delay), JUMP to 489AH.
488C
IN A,(F0H) DB F0
Read the status register, port F0H, into Register A.
488E
RLCA 07
Rotate Register A left: bit 7, not ready, goes into the C FLAG.
488F
If the NC FLAG is set (the drive is ready), JUMP to 489AH: its motor is already running.
4891
GOSUB to 489FH to send the drive select value of 4295H to port F4H, which starts the motor.
4894
LD BC,8000H 01 00 80
Load Register Pair BC with 8000H, the length of the motor delay.
4897
GOSUB to the ROM's delay at 0060H, which counts Register Pair BC down to zero while the motor comes up to speed.
489A
GOSUB to 489FH to send the drive select value of 4295H to port F4H.
489D
POP BC C1
Restore Register Pair BC from the top of the stack.
489E
RET C9
RETurn with the drive selected and its motor running.
489F
LD A,(4295H) 3A 95 42
Load Register A with the drive select value at 4295H.
48A2
OUT (F4H),A D3 F4
Write Register A to port F4H, the drive select and options latch.
| Port F4H: Drive Select and Options | | Function Description |
| D | W | P | S | d3 | d2 | d1 | d0 | | D (bit 7): 1 = double density (MFM), 0 = single density (FM) W (bit 6): 1 = wait states while the controller has no data ready P (bit 5): 1 = write precompensation S (bit 4): 0 = side 0, 1 = side 1 d3-d0: one bit per drive, 1 = selected |
48A4
RET C9
RETurn with Register A = the drive select value.
48A5
LD A,(IY+0AH) FD 7E 0A
Load Register A with the physical drive number from Index Register IY+0AH.
48A8
AND 03H E6 03
AND Register A with 03H: the physical drive, 0-3.
48AA
RLCA 07
Rotate Register A left (the first of three): the drive number times 2.
48AB
RLCA 07
Rotate Register A left again: the drive number times 4.
48AC
RLCA 07
Rotate Register A left again: the drive number times 8, the bit number field of a SET instruction.
48AD
OR C7H F6 C7
OR Register A with C7H: Register A = C7H, CFH, D7H or DFH, the second byte of SET 0,A, SET 1,A, SET 2,A or SET 3,A.
48AF
LD (48BAH),A 32 BA 48
Store Register A to 48BAH, the second byte of the SET at 48B9H, so it sets the drive's select bit.
48B2
LD A,(IY+0BH) FD 7E 0B
Load Register A with the diskette flags at Index Register IY+0BH.
48B5
AND 80H E6 80
AND Register A with 80H to keep bit 7, the density: 80H for double density, the density bit of port F4H.
48B7
OR 20H F6 20
OR Register A with 20H, bit 5 of port F4H, write precompensation.
48B9
SET 0,A CB C7
Set the drive's bit in Register A: SET 0,A in the file, its second byte at 48BAH stored by 48AFH (bit 0 drive 0 up to bit 3 drive 3).
48BB
LD (4295H),A 32 95 42
Store Register A to 4295H, the drive select value, side 0 (DSEEK sets bit 4 for side 1).
48BE
RET C9
RETurn with Register A = the drive select value.
48BFH - Sending a Command and Setting the Geometry
48BFH sends two Force Interrupt commands. 48C8H disables interrupts and 48C9H sends a command to port F0H and waits while the controller's status settles. 48D1H sets DCT+0BH-11H from the table at 48FAH, by density (DCT+0BH bit 7) and surface count (DCT+0CH).
48BF
LD A,D0H 3E D0
Load Register A with D0H, the Force Interrupt command with no interrupt condition.
| 1793 FDC Command: D0H (11010000) | | Function Description |
| 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | | Command=Force Interrupt (bits 7-4 = 1101) I3-I0 = 0000: end the command without an interrupt |
48C1
GOSUB to 48C9H to send it to port F0H, the command register.
48C4
LD A,D0H 3E D0
Load Register A with D0H again, the second Force Interrupt.
48C6
JUMP to 48C9H to send it and return from there.
48C8
DI F3
Disable interrupts: the sector transfer runs with them off (4848H enables them again).
48C9
OUT (F0H),A D3 F0
Write Register A, the command, to port F0H, the controller's command register.
48CB
LD A,0EH 3E 0E
Load Register A with 0EH, the count of the settling delay.
48CD
DEC A 3D
DECrement Register A, the count of the settling delay, by 1.
48CE
If the NZ FLAG is set, JUMP back to 48CDH: the controller's status is valid after the delay.
48D0
RET C9
RETurn with Register A = 00H once the delay has run out.
48D1
GOSUB to 45A2H, which calls 48D4H with the registers saved and returns to the caller of 48D1H.
48D4
LD A,(IY+0BH) FD 7E 0B
Load Register A with the diskette flags at Index Register IY+0BH.
48D7
RLCA 07
Rotate Register A left: bit 7, the density, moves to bit 0.
48D8
RLCA 07
Rotate Register A left again: the density is now bit 1.
48D9
AND 02H E6 02
AND Register A with 02H to keep the density bit: 02H for double density.
48DB
LD E,A 5F
Load Register E with Register A, the density bit.
48DC
LD A,(IY+0CH) FD 7E 0C
Load Register A with the surface count from Index Register IY+0CH.
48DF
DEC A 3D
DECrement Register A by 1: 00H for one side, 01H for two.
48E0
OR E B3
OR Register A with Register E: Register A = the table entry, 0 single density one side up to 3 double density two sides.
48E1
LD E,07H 1E 07
Load Register E with 07H, the length of a table entry.
48E3
GOSUB to 493EH to multiply Register A by Register E: Register A = the offset of the entry.
48E6
LD E,A 5F
Load Register E with Register A, the offset of the entry.
48E7
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the offset.
48E9
LD HL,48FAH 21 FA 48
Point Register Pair HL to 48FAH, the geometry table.
48EC
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL points to the entry.
48ED
LD E,0BH 1E 0B
Load Register E with 0BH, the offset of DCT+0BH; Register D is still 00H.
48EF
ADD IY,DE FD 19
ADD Register Pair DE to Index Register IY: Index Register IY points to DCT+0BH (the registers are put back by 45A2H).
48F1
PUSH IY FD E5
Save Index Register IY to the top of the stack.
48F3
POP DE D1
Restore Register Pair DE from the top of the stack: Register Pair DE = DCT+0BH.
48F4
LD BC,0007H 01 07 00
Load Register Pair BC with 0007H, the length of an entry.
48F7
LDIR ED B0
Copy the seven bytes from the entry at Register Pair HL to DCT+0BH-11H at Register Pair DE, Register Pair BC counting down.
48F9
RET C9
RETurn with the drive control table set for the diskette.
48FA-4900
DEFB 40H, 01H, 0AH, 0AH, 05H, 02H, 0AH 40 01 0A 0A 05 02 0A
Entry 0, single density one side: DCT+0BH 40H (protected directory, single density), one surface, 10 sectors per track, a 10 sector directory, 5 sectors per granule, 2 granules per cylinder, 10 sectors per cylinder.
4901-4907
DEFB 40H, 02H, 0AH, 0AH, 05H, 04H, 14H 40 02 0A 0A 05 04 14
Entry 1, single density two sides: 40H, two surfaces, 10 sectors per track, a 10 sector directory, 5 sectors per granule, 4 granules per cylinder, 20 (14H) sectors per cylinder.
4908-490E
DEFB C0H, 01H, 12H, 12H, 06H, 03H, 12H C0 01 12 12 06 03 12
Entry 2, double density one side: C0H (double density, protected directory), one surface, 18 (12H) sectors per track, an 18 sector directory, 6 sectors per granule, 3 granules per cylinder, 18 sectors per cylinder.
490F-4915
DEFB C0H, 02H, 12H, 12H, 06H, 06H, 24H C0 02 12 12 06 06 24
Entry 3, double density two sides: C0H, two surfaces, 18 sectors per track, an 18 sector directory, 6 sectors per granule, 6 granules per cylinder, 36 (24H) sectors per cylinder.
4916H - Reading and Writing a Directory Entry's Sector
4916H reads, 491FH writes, the directory sector holding the entry of logical file number Register B on drive Register C, through the buffer at 4300H; Register Pair HL returns the entry's address in the buffer. A logical file number holds the entry's position: bits 7-5 the entry within its sector (32 bytes each), bits 4-0 the sector less 2 (sectors 0 and 1 are the GAT and the HIT). Register D is set to the directory cylinder by SREAD or SWRITE.
4916
LD A,06H 3E 06
Load Register A with 06H, the SREAD function of DISKIO%.
4918
GOSUB to 4928H to read the directory sector of logical file number Register B.
491B
RET Z C8
If the Z FLAG is set (read), RETurn with Register Pair HL pointing to the entry.
491C
LD A,11H 3E 11
Load Register A with 11H, the error code Directory read error; the NZ FLAG stays set.
491E
RET C9
RETurn with Register A = 11H and the NZ FLAG set.
491F
LD A,07H 3E 07
Load Register A with 07H, the SWRITE function of DISKIO%.
4921
GOSUB to 4928H to write the directory sector of logical file number Register B from the buffer.
4924
RET Z C8
If the Z FLAG is set (the sector was written), RETurn with Register A = 00H.
4925
LD A,12H 3E 12
Load Register A with 12H, the error code Directory write error; the NZ FLAG stays set.
4927
RET C9
RETurn with Register A = 12H and the NZ FLAG set.
4928
PUSH DE D5
Save Register Pair DE to the top of the stack.
4929
PUSH AF F5
Save Register Pair AF (Register A the DISKIO% function) to the top of the stack.
492A
LD A,B 78
Load Register A with Register B, the logical file number.
492B
AND E0H E6 E0
AND Register A with E0H: the entry's offset within its sector (00H, 20H ... E0H).
492D
LD L,A 6F
Load Register L with Register A, the entry's offset.
492E
LD H,43H 26 43
Load Register H with 43H: Register Pair HL = 4300H plus the offset, where the entry will be in the buffer.
4930
XOR B A8
XOR Register A (the offset bits) with Register B: Register A = bits 4-0 of the logical file number.
4931
ADD A,02H C6 02
ADD 02H to Register A: Register A = the directory sector.
4933
LD E,A 5F
Load Register E with Register A, the sector for DISKIO%.
4934
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the function.
4935
PUSH HL E5
Save Register Pair HL (the entry's address) to the top of the stack.
4936
LD L,00H 2E 00
Load Register L with 00H: Register Pair HL = 4300H, the sector buffer.
4938
GOSUB to 4488H (DISKIO%) to read or write sector Register E of the directory cylinder of drive Register C at 4300H.
493B
POP HL E1
Restore Register Pair HL from the top of the stack: Register Pair HL = the entry in the buffer.
493C
POP DE D1
Restore Register Pair DE from the top of the stack.
493D
RET C9
RETurn with the Z FLAG set when DISKIO% succeeded.
493EH - The Arithmetic Routines
493EH: Register A = Register A times Register E (the low eight bits). 494DH: Register A = Register E divided by Register A, Register E = the remainder. 4961H, MULT@ (444BH): Register Pair HL times Register A, a 24 bit product in Register Pair HL (high bytes) and Register A (low byte). 497BH, DIVD@ (444EH): Register Pair HL divided by Register A, the quotient in Register Pair HL and the remainder in Register A.
493E
PUSH BC C5
Save Register Pair BC to the top of the stack.
493F
LD D,A 57
Load Register D with Register A, the multiplicand.
4940
XOR A AF
Set Register A, the product, to 00H by XORing it with itself.
4941
LD B,08H 06 08
Load Register B with 08H, the eight bits of the multiplier Register E.
4943
ADD A,A 87
Double Register A, the product so far, for the next multiplier bit.
4944
SLA E CB 23
Shift Register E left: its highest bit goes into the C FLAG.
4946
If the NC FLAG is set (the bit was 0), JUMP to 4949H.
4948
ADD A,D 82
ADD Register D, the multiplicand, to Register A.
4949
DECrement Register B and loop back to 4943H while Register B is not zero.
494B
POP BC C1
Restore Register Pair BC from the top of the stack.
494C
RET C9
RETurn with Register A = the product (Register E is 00H, Register D the multiplicand).
494D
PUSH BC C5
Save Register Pair BC to the top of the stack.
494E
LD C,A 4F
Load Register C with Register A, the divisor.
494F
LD B,08H 06 08
Load Register B with 08H, the eight bits of the dividend Register E.
4951
XOR A AF
Set Register A, the remainder, to 00H by XORing it with itself.
4952
SLA E CB 23
Shift Register E left: its highest bit goes into the C FLAG and a 0 into its bit 0.
4954
RLA 17
Rotate Register A left through the carry: the bit joins the remainder.
4955
CP C B9
Compare Register A against Register C, the divisor. The C FLAG is set when the remainder is smaller.
4956
If the C FLAG is set, JUMP to 495AH: this quotient bit is 0.
4958
SUB C 91
SUBtract Register C, the divisor, from Register A.
4959
INC E 1C
INCrement Register E by 1: this quotient bit is 1.
495A
DECrement Register B and loop back to 4952H while Register B is not zero.
495C
LD C,A 4F
Load Register C with Register A, the remainder.
495D
LD A,E 7B
Load Register A with Register E, the quotient.
495E
LD E,C 59
Load Register E with Register C, the remainder.
495F
POP BC C1
Restore Register Pair BC from the top of the stack.
4960
RET C9
RETurn with Register A = the quotient and Register E = the remainder.
4961
PUSH BC C5
MULT@: save Register Pair BC to the top of the stack.
4962
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the multiplicand.
4963
LD C,A 4F
Load Register C with Register A, the multiplier.
4964
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, the product.
4967
LD A,L 7D
Load Register A with Register L (00H), the top byte of the 24 bit product.
4968
LD B,08H 06 08
Load Register B with 08H, the eight bits of the multiplier Register C.
496A
ADD HL,HL 29
Double Register Pair HL, the low 16 bits of the product.
496B
RLA 17
Rotate Register A left through the carry, taking the bit out of Register Pair HL: Register A and Register Pair HL are the 24 bit product doubled.
496C
RLC C CB 01
Rotate Register C left: the highest multiplier bit goes into the C FLAG.
496E
If the NC FLAG is set (the bit was 0), JUMP to 4973H.
4970
ADD HL,DE 19
ADD Register Pair DE, the multiplicand, to Register Pair HL.
4971
ADC A,00H CE 00
ADD 00H and the carry of 4970H to Register A, the top byte of the product.
4973
DECrement Register B and loop back to 496AH while Register B is not zero.
4975
LD C,A 4F
Load Register C with Register A, the top byte.
4976
LD A,L 7D
Load Register A with Register L, the low byte.
4977
LD L,H 6C
Load Register L with Register H, the middle byte.
4978
LD H,C 61
Load Register H with Register C, the top byte: Register Pair HL = the product divided by 256.
4979
POP BC C1
Restore Register Pair BC from the top of the stack.
497A
RET C9
RETurn with Register Pair HL = the high 16 bits and Register A = the low byte of the product; Register Pair DE holds the multiplicand.
497B
PUSH DE D5
DIVD@: save Register Pair DE to the top of the stack.
497C
LD D,A 57
Load Register D with Register A, the divisor.
497D
LD E,10H 1E 10
Load Register E with 10H, the sixteen bits of the dividend Register Pair HL.
497F
XOR A AF
Set Register A, the remainder, to 00H by XORing it with itself.
4980
ADD HL,HL 29
Double Register Pair HL: its highest bit goes into the C FLAG and a 0 into its bit 0.
4981
RLA 17
Rotate Register A left through the carry: the bit joins the remainder.
4982
If the C FLAG is set (the remainder overflowed eight bits, so it is larger than the divisor), JUMP to 4987H.
4984
CP D BA
Compare Register A against Register D, the divisor.
4985
If the C FLAG is set (the remainder is smaller), JUMP to 4989H: this quotient bit is 0.
4987
SUB D 92
SUBtract Register D, the divisor, from Register A.
4988
INC L 2C
INCrement Register L by 1: this quotient bit is 1.
4989
DEC E 1D
DECrement Register E, the count of dividend bits left.
498A
If the NZ FLAG is set (bits remain), JUMP back to 4980H for the next one.
498C
POP DE D1
Restore Register Pair DE from the top of the stack.
498D
RET C9
RETurn with Register Pair HL = the quotient and Register A = the remainder.
498EH - The Overlay Request Handler
RST 28H (400CH) comes here with a request code in Register A. Request code 01H runs the BREAK vector at 42ADH unless the BREAK key is disabled. Any other code names an overlay (bits 7-4, the system number less 1) and a routine (bits 3-0): the overlay is loaded unless it is resident (429DH for SYS1-SYS8 at 4E00H, 429EH for SYS9-SYS16 at 5200H), the routine's address is taken from the table at the overlay's transfer address (entry = bits 3-0 less 2) and the routine runs with every register but Register Pair AF as the caller left them. It returns through 49E7H, which puts back the word at 429AH-429BH.
498E
INC SP 33
INCrement the Stack Pointer by 1, the first of two.
498F
INC SP 33
INCrement the Stack Pointer by 1 again: the return address the RST 28H pushed (the byte after the RST in the entry point) is dropped, so the top of the stack is the return to the caller of the entry point.
4990
CP 01H FE 01
Compare Register A, the request code, against 01H.
4992
If the NZ FLAG is set (an overlay request), JUMP to 499EH.
4994
LD HL,4297H 21 97 42
Request 01H: point Register Pair HL to 4297H, SFLAG1$.
4997
BIT 0,(HL) CB 46
Test bit 0 of SFLAG1$ at Register Pair HL (4297H), the BREAK key disable flag.
4999
If the Z FLAG is set (the BREAK key is enabled), JUMP to 42ADH, the BREAK vector, which returns to the caller.
499C
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG.
499D
RET C9
RETurn with Register A = 00H: the BREAK key is disabled.
499E
PUSH HL E5
Save Register Pair HL to the top of the stack.
499F
LD HL,(429AH) 2A 9A 42
Load Register Pair HL with the word at 429AH-429BH.
49A2
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: the word goes to the stack and Register Pair HL is the caller's again.
49A3
PUSH HL E5
Save Register Pair HL to the top of the stack.
49A4
LD HL,49E7H 21 E7 49
Load Register Pair HL with 49E7H, where the routine is to return.
49A7
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: 49E7H goes to the stack above the saved word, and Register Pair HL is the caller's again.
49A8
PUSH HL E5
Save Register Pair HL to the top of the stack.
49A9
PUSH DE D5
Save Register Pair DE to the top of the stack.
49AA
PUSH BC C5
Save Register Pair BC to the top of the stack.
49AB
LD HL,429BH 21 9B 42
Point Register Pair HL to 429BH, the DEBUG on BREAK switch.
49AE
LD (HL),00H 36 00
Store 00H into the switch at Register Pair HL (429BH): BREAK does not enter DEBUG while the overlay runs.
49B0
INC HL 23
INCrement Register Pair HL by 1 to 429CH, the request code.
49B1
LD (HL),A 77
Store Register A, the request code, to 429CH at Register Pair HL.
49B2
INC HL 23
INCrement Register Pair HL by 1 to 429DH, OVLYL$.
49B3
LD DE,429FH 11 9F 42
Point Register Pair DE to 429FH, the low overlay's table address.
49B6
OR A B7
OR Register A with itself to test bit 7 of the request code.
49B7
If the P FLAG is set (bit 7 clear: SYS1-SYS8), JUMP to 49BEH with Register Pair HL = 429DH and Register Pair DE = 429FH.
49BA
INC HL 23
A high overlay (SYS9-SYS16): INCrement Register Pair HL by 1 to 429EH, OVLYH$.
49BB
LD DE,42A1H 11 A1 42
Point Register Pair DE to 42A1H, the high overlay's table address.
49BE
AND F0H E6 F0
AND Register A with F0H to keep the overlay bits of the request code.
49C0
CP (HL) BE
Compare Register A against the resident overlay at Register Pair HL (429DH or 429EH).
49C1
LD (HL),A 77
Store Register A to the overlay byte at Register Pair HL: it names the overlay that will be resident.
49C2
If the Z FLAG is set (the overlay is already in memory), JUMP to 49CFH.
49C4
GOSUB to 49EDH to load the overlay named by Register A. Register Pair HL returns its transfer address.
49C7
If the NZ FLAG is set (it could not be loaded), JUMP to 4A3EH: System error.
49C9
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = 429FH or 42A1H, Register Pair DE = the transfer address.
49CA
LD (HL),E 73
Store Register E, the low byte of the transfer address, to the table address at Register Pair HL.
49CB
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
49CC
LD (HL),D 72
Store Register D, the high byte, to Register Pair HL.
49CD
JUMP to 49D3H with Register Pair DE = the routine table.
49CF
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = 429FH or 42A1H.
49D0
LD E,(HL) 5E
Load Register E with the low byte of the resident overlay's table address from Register Pair HL.
49D1
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
49D2
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the routine table.
49D3
LD A,(429CH) 3A 9C 42
Load Register A with the request code at 429CH.
49D6
AND 0FH E6 0F
AND Register A with 0FH to keep the routine number.
49D8
SUB 02H D6 02
SUBtract 02H from Register A: routine 2 is the first entry of the table.
49DA
ADD A,A 87
Double Register A, the offset of the routine's word.
49DB
LD L,A 6F
Load Register L with Register A, the offset of the entry in the table.
49DC
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = the offset.
49DE
ADD HL,DE 19
ADD Register Pair DE (the routine table) to Register Pair HL: Register Pair HL points to the routine's entry.
49DF
LD A,(HL) 7E
Load Register A with the low byte of the routine's address from Register Pair HL.
49E0
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
49E1
LD H,(HL) 66
Load Register H with the high byte from Register Pair HL.
49E2
LD L,A 6F
Load Register L with Register A: Register Pair HL = the routine.
49E3
POP BC C1
Restore Register Pair BC from the top of the stack, as the caller had it.
49E4
POP DE D1
Restore Register Pair DE from the top of the stack, as the caller had it.
49E5
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: the routine's address goes to the stack and Register Pair HL is the caller's.
49E6
RET C9
RETurn, which jumps to the routine; it returns to 49E7H.
49E7
EX (SP),HL E3
The routine returns here: exchange the top of the Stack Pointer with Register Pair HL, so Register Pair HL = the word saved from 429AH-429BH and the routine's Register Pair HL goes to the stack.
49E8
LD (429AH),HL 22 9A 42
Store Register Pair HL back to 429AH-429BH, as they were before the request.
49EB
POP HL E1
Restore Register Pair HL from the top of the stack, as the routine left it.
49EC
RET C9
RETurn to the caller of the entry point with the routine's results.
49EDH - Loading an Overlay
Register A = the overlay bits of a request code. The /SYS files have fixed directory entries on drive 0: SYS0/SYS is logical file number 2 (sector 4, entry 0) and SYSn/SYS is n + 2, running on into the second and third entries of the sectors when the directory ends. The routine reads the entry, checks that it is an active system file, sets up the system file control block at 42CEH with the file's first segment and loads the file through 4A9BH, which returns its transfer address in Register Pair HL.
49ED
PUSH DE D5
Save Register Pair DE (429FH or 42A1H) to the top of the stack.
49EE
PUSH IY FD E5
Save Index Register IY to the top of the stack.
49F0
RLCA 07
Rotate Register A left (the first of four, swapping its two halves).
49F1
RLCA 07
Rotate Register A left (the second of four), the overlay bits moving down.
49F2
RLCA 07
Rotate Register A left (the third of four), the overlay bits moving down.
49F3
RLCA 07
Rotate Register A left: the four overlay bits are now bits 3-0, the system number less 1.
49F4
ADD A,03H C6 03
ADD 03H to Register A: Register A = the system number plus 2, the logical file number of its entry when the directory is long enough.
49F6
LD B,A 47
Load Register B with Register A, the logical file number.
49F7
LD C,00H 0E 00
Load Register C with 00H: the /SYS files are read from drive 0.
49F9
GOSUB to 45D4H (LOCDCT%) to point Index Register IY to drive 0's drive control table.
49FC
LD A,B 78
Load Register A with Register B, the logical file number.
49FD
ADD A,02H C6 02
ADD 02H to Register A: Register A = its sector in the directory.
49FF
SUB (IY+0EH) FD 96 0E
SUBtract the directory length at Index Register IY+0EH from Register A. The C FLAG is set when the sector is inside the directory.
4A02
If the C FLAG is set, JUMP to 4A11H: the entry is the first of its sector.
4A04
LD B,A 47
Load Register B with Register A, the sector past the end, less 2: the sector of the second entry.
4A05
SET 5,B CB E8
Set bit 5 of Register B: entry 1 of that sector.
4A07
ADD A,02H C6 02
ADD 02H to Register A, the sector of the second entry.
4A09
SUB (IY+0EH) FD 96 0E
SUBtract the directory length at Index Register IY+0EH from Register A. The C FLAG is set when that sector is inside the directory.
4A0C
If the C FLAG is set, JUMP to 4A11H with Register B = the second entry.
4A0E
SET 6,A CB F7
Set bit 6 of Register A: entry 2 of the sector Register A gives.
4A10
LD B,A 47
Load Register B with Register A, the logical file number of the third entry.
4A11
LD A,B 78
Load Register A with Register B, the logical file number.
4A12
LD (42D5H),A 32 D5 42
Store Register A to 42D5H, FCB+07H of the system file control block.
4A15
XOR A AF
Set Register A to 00H by XORing it with itself.
4A16
LD (42CFH),A 32 CF 42
Store Register A (00H) to 42CFH, the flags of the system file control block.
4A19
LD (42D8H),A 32 D8 42
Store Register A (00H) to 42D8H, the low byte of its next record number: the file is read from its first sector.
4A1C
GOSUB to 4916H to read the directory sector of logical file number Register B (drive Register C, 0) into 4300H; Register Pair HL returns the entry.
4A1F
If the NZ FLAG is set (Directory read error), JUMP to 4A3AH to return the error.
4A21
LD A,(HL) 7E
Load Register A with the entry's flags from Register Pair HL.
4A22
CPL 2F
Complement Register A, so the flag bits that must be set become 0.
4A23
AND 50H E6 50
AND Register A with 50H: the inverted bit 6 (system file) and bit 4 (active). The Z FLAG is set when both bits were set.
4A25
LD A,18H 3E 18
Load Register A with 18H, the error code File not in directory (the flags are kept).
4A27
If the NZ FLAG is set (not an active system file), JUMP to 4A3AH to return error 18H.
4A29
LD DE,0016H 11 16 00
Load Register Pair DE with 0016H, the offset of the first segment descriptor in the entry.
4A2C
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL points to the first segment descriptor.
4A2D
LD DE,42DCH 11 DC 42
Point Register Pair DE to 42DCH, FCB+0EH of the system file control block.
4A30
LDI ED A0
Copy the cylinder byte of the descriptor from Register Pair HL to Register Pair DE, incrementing both and decrementing Register Pair BC.
4A32
LDI ED A0
Copy the granule byte of the descriptor from Register Pair HL to Register Pair DE, incrementing both and decrementing Register Pair BC.
4A34
LD DE,42CEH 11 CE 42
Point Register Pair DE to 42CEH, the system file control block.
4A37
GOSUB to 4A9BH to load the file of the file control block at Register Pair DE. Register Pair HL returns its transfer address.
4A3A
POP IY FD E1
Restore Index Register IY from the top of the stack.
4A3C
POP DE D1
Restore Register Pair DE from the top of the stack.
4A3D
RET C9
RETurn with the Z FLAG set when the overlay was loaded.
4A3EH - System Error
An overlay could not be loaded: its overlay byte is set to FFH, so the next request loads it again, System error is displayed and DOSPLUS returns to the command level through ABORT@.
4A3E
LD HL,429CH 21 9C 42
Point Register Pair HL to 429CH, the request code.
4A41
BIT 7,(HL) CB 7E
Test bit 7 of the request code at Register Pair HL (429CH). The Z FLAG is set for a low overlay.
4A43
INC HL 23
INCrement Register Pair HL by 1 to 429DH, OVLYL$.
4A44
If the Z FLAG is set (a low overlay), JUMP to 4A47H.
4A46
INC HL 23
INCrement Register Pair HL by 1 to 429EH, OVLYH$.
4A47
LD (HL),FFH 36 FF
Store FFH to the overlay byte at Register Pair HL: no overlay of that group is resident.
4A49
LD HL,4A52H 21 52 4A
Point Register Pair HL to 4A52H, the text System error.
4A4C
GOSUB to 4467H (DSPLY@) to display the text at Register Pair HL.
4A4F
JUMP to 4030H, ABORT@, back to the DOSPLUS command level.
4A52-4A5E
DEFM "System error" / DEFB 0DH 53 79 73 74 65 6D 20 65 72 72 6F 72 0D
The text System error, ended by a carriage return.
4A5FH - RUN@
RUN@ (4433H): load the program file of the file control block at Register Pair DE and run it. The run access flag (bit 1 of SFLAG1$) is set during the load so a run only file may be opened. The program starts with Register Pair BC = LOW$ and Register Pair DE = HMEM$. When the DEBUG flag (bit 2 of SFLAG1$) is set, a program opened with an access level below 6 starts in DEBUG@ instead; for one with level 6 or 7 the DEBUG on BREAK switch at 429BH is set to the level less 6. A load error goes to ERROR@.
4A5F
PUSH HL E5
Save Register Pair HL to the top of the stack.
4A60
LD HL,4297H 21 97 42
Point Register Pair HL to 4297H, SFLAG1$, the system flags.
4A63
SET 1,(HL) CB CE
Set bit 1 of SFLAG1$ at Register Pair HL (4297H), the run access flag.
4A65
PUSH HL E5
Save Register Pair HL (4297H) to the top of the stack.
4A66
GOSUB to 4430H (LOAD@) to load the file of the file control block at Register Pair DE. Register Pair HL returns its transfer address.
4A69
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: the transfer address goes to the stack and Register Pair HL = 4297H.
4A6A
RES 1,(HL) CB 8E
Reset bit 1 of SFLAG1$ at Register Pair HL (4297H): the load is over.
4A6C
If the NZ FLAG is set (the load failed), JUMP to 4409H (ERROR@) with the error code in Register A.
4A6F
BIT 2,(HL) CB 56
Test bit 2 of SFLAG1$ at Register Pair HL (4297H), the DEBUG flag. The Z FLAG is set when DEBUG is off.
4A71
INC DE 13
INCrement Register Pair DE by 1 to FCB+01H of the file control block.
4A72
LD A,(DE) 1A
Load Register A with the file flags at Register Pair DE: bits 0-2 the access level the file was opened with.
4A73
LD BC,(42A7H) ED 4B A7 42
Load Register Pair BC with LOW$ at 42A7H, for the program.
4A77
LD DE,(4411H) ED 5B 11 44
Load Register Pair DE with HMEM$ at 4411H, for the program.
4A7B
POP HL E1
Restore Register Pair HL from the top of the stack: the transfer address.
4A7C
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: the transfer address goes to the stack as the return address and Register Pair HL is the caller's again.
4A7D
RET Z C8
If the Z FLAG is set (DEBUG is off), RETurn, which starts the program at its transfer address.
4A7E
AND 07H E6 07
AND Register A with 07H to keep the access level.
4A80
SUB 06H D6 06
SUBtract 06H from Register A. The C FLAG is set for an access level below 6.
4A82
If the C FLAG is set, JUMP to 440DH (DEBUG@): the monitor starts with the program's transfer address on the stack.
4A85
LD (429BH),A 32 9B 42
Store Register A (the access level less 6: 00H or 01H) to the DEBUG on BREAK switch at 429BH.
4A88
RET C9
RETurn, which starts the program at its transfer address.
4A89H - LOAD@ and the Program Loader
LOAD@ (4430H) opens the file of the file control block at Register Pair DE with a record length of 256 and its buffer at 4300H, then the loader at 4A9BH reads it record by record: type 01H a load block (length, address, then the bytes, each checked after it is stored), type 02H the transfer address, which ends the load, any other type below 20H skipped. 4AD5H supplies the next byte, reading a sector through READ@ each time the buffer is used up. Errors return with bit 6 of the error code set: 1FH Program not found, 22H a record type of 20H or more (not a program file), 23H memory that does not keep a byte, or the error of OPEN@ or READ@.
4A89
LD B,00H 06 00
LOAD@: load Register B with 00H, the logical record length for OPEN@: 256.
4A8B
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the buffer for the file.
4A8E
GOSUB to 4424H (OPEN@) to open the file of the file control block at Register Pair DE.
4A91
If the Z FLAG is set (opened), JUMP to 4A9BH to load it.
4A93
CP 18H FE 18
Compare Register A, the error code, against 18H, File not in directory.
4A95
If the NZ FLAG is set (another error), JUMP to 4AEFH to return it.
4A97
LD A,1FH 3E 1F
Load Register A with 1FH, the error code Program not found, in place of 18H.
4A99
JUMP to 4AEFH to return error 1FH with bit 6 set.
4A9B
PUSH DE D5
The loader: save Register Pair DE (the file control block) to the top of the stack.
4A9C
LD E,FFH 1E FF
Load Register E with FFH, the buffer position before the first byte, so the first byte asked for reads a sector.
4A9E
GOSUB to 4AD5H for the next byte: the record type.
4AA1
CP 20H FE 20
Compare Register A against 20H. The NC FLAG is set for a type of 20H or more.
4AA3
If the NC FLAG is set (not a load file record), JUMP to 4AE6H: error 22H.
4AA5
LD H,A 67
Load Register H with Register A, the record type.
4AA6
GOSUB to 4AD5H for the next byte: the record length.
4AA9
LD B,A 47
Load Register B with Register A, the record length.
4AAA
GOSUB to 4AD5H for the next byte: the low byte of the address, or the first byte of the record.
4AAD
LD L,A 6F
Load Register L with Register A, the low address byte or the first byte of the record.
4AAE
DEC H 25
DECrement Register H, the record type, by 1. The Z FLAG is set for type 01H.
4AAF
If the Z FLAG is set (a load block), JUMP to 4AC3H.
4AB1
DEC H 25
DECrement Register H by 1 again. The Z FLAG is set for type 02H.
4AB2
If the NZ FLAG is set (another type), JUMP to 4ABBH to skip the record.
4AB4
The transfer record: GOSUB to 4AD5H for the high byte of the transfer address.
4AB7
LD H,A 67
Load Register H with Register A: Register Pair HL = the transfer address.
4AB8
POP DE D1
Restore Register Pair DE (the file control block) from the top of the stack.
4AB9
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: no error.
4ABA
RET C9
RETurn with Register Pair HL = the transfer address.
4ABB
DEC B 05
Skip a record: DECrement Register B, the bytes of the record left.
4ABC
If the Z FLAG is set (the record is used up), JUMP back to 4A9EH for the next record.
4ABE
GOSUB to 4AD5H to take the next byte of the record, which is not used.
4AC1
JUMP back to 4ABBH to count off the byte just skipped.
4AC3
A load block: GOSUB to 4AD5H for the high byte of the load address.
4AC6
LD H,A 67
Load Register H with Register A: Register Pair HL = the load address.
4AC7
DEC B 05
DECrement Register B, the record length, by 1 for the address's low byte.
4AC8
DEC B 05
DECrement Register B by 1 for its high byte: Register B = the bytes to load (a length of 02H gives 00H, 256 bytes).
4AC9
GOSUB to 4AD5H for the next byte of the load block in Register A.
4ACC
LD (HL),A 77
Store Register A to memory at Register Pair HL.
4ACD
CP (HL) BE
Compare Register A against the byte at Register Pair HL, to see whether memory kept it.
4ACE
If the NZ FLAG is set (it did not: read only or missing memory), JUMP to 4AE9H: error 23H.
4AD0
INC HL 23
INCrement Register Pair HL by 1 to the next load address.
4AD1
DECrement Register B and loop back to 4AC9H while Register B is not zero.
4AD3
JUMP back to 4A9EH for the next record: the load block is in memory.
4AD5
INC E 1C
The next byte: INCrement Register E, the buffer position, by 1.
4AD6
If the NZ FLAG is set (the position is still in the buffer), JUMP to 4AE4H to take the byte.
4AD8
POP AF F1
The buffer is used up: restore Register Pair AF from the top of the stack, which takes off the return address into the loader.
4AD9
POP DE D1
Restore Register Pair DE from the top of the stack: the file control block the loader saved at 4A9BH.
4ADA
PUSH DE D5
Save Register Pair DE (the file control block) to the top of the stack again.
4ADB
PUSH AF F5
Save Register Pair AF (the return address into the loader) to the top of the stack again.
4ADC
GOSUB to 4436H (READ@) to read the next sector of the file at Register Pair DE into its buffer at 4300H.
4ADF
LD DE,4300H 11 00 43
Point Register Pair DE to 4300H, the first byte of the buffer.
4AE2
If the NZ FLAG is set (the read failed), JUMP to 4AEDH to return the error.
4AE4
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the buffer position.
4AE5
RET C9
RETurn with Register A = the next byte of the file and Register E its position.
4AE6
LD A,22H 3E 22
Load Register A with 22H, the error code for a file that is not a program file.
4AE8
LD DE,233EH 11 3E 23
Load Register Pair DE with 233EH. The load only steps over 4AE9H-4AEAH: the memory error at 4ACEH jumps to 4AE9H, where the bytes 3EH 23H read LD A,23H, the error code Memory fault during program load.
4AEB
LD DE,D1D5H 11 D5 D1
Load Register Pair DE with D1D5H. The load only steps over 4AECH-4AEDH: the read error at 4AE2H jumps to 4AEDH, where D1H reads POP DE and takes off the return into the loader so the next POP finds the file control block.
4AEE
POP DE D1
Restore Register Pair DE from the top of the stack: the file control block the loader saved at 4A9BH.
4AEF
OR 40H F6 40
OR Register A with 40H: bit 6 is set in the error code returned. The NZ FLAG is set.
4AF1
RET C9
RETurn with Register A = the error code and the NZ FLAG set.
4AF2H - POSN@, REW@, PEOF@ and BKSP@
POSN@ (4442H) sets the position of the file control block at Register Pair DE to logical record Register Pair BC and sets the random access flag (bit 6 of FCB+01H). For a blocked file (bit 7 of FCB+01H) the record number times the record length gives the sector (Register Pair BC) and the byte in it (Register A); otherwise Register Pair BC is the sector. 4B09H stores the byte offset to FCB+05H; when the buffer holds the sector of the old position (bit 5 of FCB+01H clear) and the sector changes, an updated buffer is written first (4C7CH) and bit 5 is set, so the next access reads the new sector. The sector goes to FCB+0AH-0BH and 4CC5H returns the end of file status. REW@ (443FH) positions to the start of the file, PEOF@ (4448H) to its end and BKSP@ (4445H) one logical record back. All four run under 4CE5H, which checks that the file is open, points Index Register IX to it and saves the registers.
4AF2
POSN@: GOSUB to 4CE5H, which checks that the file control block at Register Pair DE is open, points Index Register IX to it, saves the registers and runs the rest of this routine with Register A = 00H; for a file that is not open the caller gets error 26H.
4AF5
SET 6,(IX+01H) DD CB 01 F6
Set bit 6 of FCB+01H at Index Register IX+01H, the random access flag: writing before the end of the file no longer shrinks it (4C9BH).
4AF9
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of FCB+01H at Index Register IX+01H, the blocked records flag.
4AFD
If the Z FLAG is set (not blocked: Register Pair BC is the sector), JUMP to 4B09H with Register A = 00H, the start of the sector.
4AFF
LD H,B 60
Load Register H with Register B, the high byte of the record number.
4B00
LD L,C 69
Load Register L with Register C: Register Pair HL = the logical record number.
4B01
LD A,(IX+09H) DD 7E 09
Load Register A with the logical record length at Index Register IX+09H (FCB+09H).
4B04
GOSUB to 4961H (MULT@) to multiply Register Pair HL by Register A: the high bytes of the 24 bit product return in Register Pair HL (the sector of the file) and its low byte in Register A (where the record starts in that sector).
4B07
LD B,H 44
Load Register B with Register H, the high byte of the sector.
4B08
LD C,L 4D
Load Register C with Register L: Register Pair BC = the sector of the file that holds the record.
4B09
LD (IX+05H),A DD 77 05
Store Register A, the byte offset of the record in its sector, to FCB+05H at Index Register IX+05H.
4B0C
BIT 5,(IX+01H) DD CB 01 6E
Test bit 5 of FCB+01H at Index Register IX+01H. The bytes use it the opposite way to the manual: set, the buffer does not hold sector FCB+0AH-0BH and is read before its next byte is used; clear, it holds it.
4B10
If the NZ FLAG is set (the buffer is to be read anyway), JUMP to 4B27H to store the new sector.
4B12
LD L,(IX+0AH) DD 6E 0A
Load Register L with the low byte of the next record number at Index Register IX+0AH (FCB+0AH).
4B15
LD H,(IX+0BH) DD 66 0B
Load Register H with the high byte at Index Register IX+0BH: Register Pair HL = the sector the buffer holds.
4B18
OR A B7
OR Register A with itself to clear the C FLAG for the subtraction.
4B19
SBC HL,BC ED 42
SUBtract Register Pair BC, the new sector, from Register Pair HL. The Z FLAG is set when they are the same.
4B1B
If the Z FLAG is set (the record is in the sector already in the buffer), JUMP to 4B27H; the buffer stays as it is.
4B1D
PUSH BC C5
Save Register Pair BC (the new sector) to the top of the stack.
4B1E
GOSUB to 4C7CH to write the buffer to the file if it holds updated bytes of a blocked file.
4B21
POP BC C1
Restore Register Pair BC (the new sector) from the top of the stack.
4B22
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4B23
SET 5,(IX+01H) DD CB 01 EE
Set bit 5 of FCB+01H at Index Register IX+01H: the buffer does not hold the new sector, so the next access reads it.
4B27
LD (IX+0AH),C DD 71 0A
Store Register C, the low byte of the new sector, to the next record number at Index Register IX+0AH (FCB+0AH).
4B2A
LD (IX+0BH),B DD 70 0B
Store Register B, the high byte, to Index Register IX+0BH.
4B2D
JUMP to 4CC5H to compare the new position with the end of the file: Register A returns 00H (Z FLAG) before the end, 1CH at the end, 1DH past it.
4B30
REW@: GOSUB to 4CE5H to check the file control block at Register Pair DE and run the rest under Index Register IX, with Register A = 00H.
4B33
LD B,A 47
Load Register B with Register A (00H), the high byte of the first sector.
4B34
LD C,A 4F
Load Register C with Register A: Register Pair BC = 0000H, the first sector.
4B35
JUMP to 4B09H to position to byte 00H of sector 0000H. REW@ enters after the SET of the random access flag, which it leaves as it was.
4B37
PEOF@: GOSUB to 4CE5H to check the file control block at Register Pair DE and run the rest under Index Register IX.
4B3A
LD C,(IX+0CH) DD 4E 0C
Load Register C with the low byte of the ending record number at Index Register IX+0CH (FCB+0CH), the count of full sectors.
4B3D
LD B,(IX+0DH) DD 46 0D
Load Register B with the high byte at Index Register IX+0DH: Register Pair BC = the sector after the last full one.
4B40
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file byte at Index Register IX+08H (FCB+08H), the bytes used in the last sector.
4B43
JUMP to 4B09H to position there. The end of file test at 4CC5H then returns 1CH, which the manual tells the caller to ignore.
4B45
BKSP@: GOSUB to 4CE5H to check the file control block at Register Pair DE and run the rest under Index Register IX, with Register A = 00H.
4B48
LD C,(IX+0AH) DD 4E 0A
Load Register C with the low byte of the next record number at Index Register IX+0AH (FCB+0AH).
4B4B
LD B,(IX+0BH) DD 46 0B
Load Register B with the high byte at Index Register IX+0BH: Register Pair BC = the current sector.
4B4E
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of FCB+01H at Index Register IX+01H, the blocked records flag.
4B52
If the Z FLAG is set (not blocked), JUMP to 4B5EH to step back one sector with Register A = 00H.
4B54
LD A,(IX+09H) DD 7E 09
Load Register A with the logical record length at Index Register IX+09H (FCB+09H).
4B57
NEG ED 44
NEGate Register A: 256 less the record length (00H for a length of 256).
4B59
ADD A,(IX+05H) DD 86 05
ADD the byte offset at Index Register IX+05H (FCB+05H) to Register A. The C FLAG is set when the offset is at least the record length, so the previous record starts in the same sector.
4B5C
If the C FLAG is set, JUMP to 4B09H with Register A = the offset less the record length and Register Pair BC = the same sector.
4B5E
DEC BC 0B
DECrement Register Pair BC by 1: the previous record starts in the sector before, at offset Register A (the offset less the record length, plus 256). From sector 0000H the result is FFFFH, as the manual says.
4B5F
JUMP to 4B09H to position to the previous record.
4B61H - READ@ and WRITE@
READ@ (4436H) reads the next logical record of the file at Register Pair DE: a file that is not blocked reads its next sector into its buffer (4C03H); a blocked file takes the record length's bytes one at a time through 4BA6H into the user record at Register Pair HL. WRITE@ (4439H) and VER@ (443CH) both come to 4B7CH: the buffer is written as the next sector (4C3EH), or the record's bytes are put one at a time through 4BC9H. VER@ has no code of its own: every sector write is read back when the verify switch (bit 3 of SFLAG1$) is on (4C67H).
4B61
READ@: GOSUB to 4CE5H to check the file control block at Register Pair DE and run the rest under Index Register IX.
4B64
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of FCB+01H at Index Register IX+01H, the blocked records flag.
4B68
If the Z FLAG is set (not blocked), JUMP to 4C03H to read the next sector into the file's buffer.
4B6B
LD B,(IX+09H) DD 46 09
Load Register B with the logical record length at Index Register IX+09H (FCB+09H), the count of bytes to take (00H gives 256).
4B6E
PUSH BC C5
Save Register Pair BC (the count) to the top of the stack.
4B6F
PUSH HL E5
Save Register Pair HL (the user record pointer) to the top of the stack.
4B70
GOSUB to 4BA6H for the next byte of the file in Register A.
4B73
POP HL E1
Restore Register Pair HL from the top of the stack.
4B74
POP BC C1
Restore Register Pair BC from the top of the stack.
4B75
RET NZ C0
If the NZ FLAG is set (end of file or a read error), RETurn with the error code in Register A.
4B76
LD (HL),A 77
Store Register A, the byte, to the user record at Register Pair HL.
4B77
INC HL 23
INCrement Register Pair HL by 1 to the next byte of the record.
4B78
DECrement Register B and loop back to 4B6EH while Register B is not zero.
4B7A
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: the record is read.
4B7B
RET C9
RETurn with the record in the user record at Register Pair HL and no error.
4B7C
WRITE@ and VER@: GOSUB to 4CE5H to check the file control block at Register Pair DE and run the rest under Index Register IX.
4B7F
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of FCB+01H at Index Register IX+01H, the blocked records flag.
4B83
If the Z FLAG is set (not blocked), JUMP to 4C3EH to write the buffer as the next sector.
4B86
LD B,(IX+09H) DD 46 09
Load Register B with the logical record length at Index Register IX+09H (FCB+09H), the count of bytes to put (00H gives 256).
4B89
LD A,(HL) 7E
Load Register A with the next byte of the user record at Register Pair HL.
4B8A
INC HL 23
INCrement Register Pair HL by 1 past the byte.
4B8B
PUSH BC C5
Save Register Pair BC (the count) to the top of the stack.
4B8C
PUSH HL E5
Save Register Pair HL (the user record pointer) to the top of the stack.
4B8D
GOSUB to 4BC9H to put the byte in Register A into the file.
4B90
POP HL E1
Restore Register Pair HL from the top of the stack.
4B91
POP BC C1
Restore Register Pair BC from the top of the stack.
4B92
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4B93
DECrement Register B and loop back to 4B89H while Register B is not zero.
4B95
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: the record is written.
4B96
RET C9
RETurn to the caller with the record written and no error.
4B97H - Character I/O on a File, and the Byte Routines
4563H comes to 4B97H when a character I/O call (GET@, PUT@ or a control call) names an open file control block: Index Register IX points to it, Register B is the I/O type (bit 0 set for input) and Register C the character to put. The file is switched to blocked records (bit 7 of FCB+01H) and one byte is read (4BA6H) or written (4BC9H). 4BA6H returns the byte at FCB+05H of the buffer, reading the sector first when bit 5 of FCB+01H is set, and moves on, writing an updated buffer back and stepping to the next sector at the end of one. 4BC9H stores a byte the same way, reading the sector first when it holds bytes of the file, sets the buffer updated flag (bit 4) and moves the end of the file where it is due (4C92H).
4B97
PUSH IX DD E5
Save Index Register IX, the file control block, to the top of the stack.
4B99
POP DE D1
Restore it into Register Pair DE from the top of the stack: Register Pair DE = the file control block, as 4CE5H needs it.
4B9A
GOSUB to 4CE5H to check the file control block at Register Pair DE and run the rest under Index Register IX with the registers saved.
4B9D
SET 7,(IX+01H) DD CB 01 FE
Set bit 7 of FCB+01H at Index Register IX+01H: character I/O always uses blocked records, a byte at a time.
4BA1
LD A,C 79
Load Register A with Register C, the character to put.
4BA2
BIT 0,B CB 40
Test bit 0 of Register B, the I/O type: set for input (GET@).
4BA4
If the Z FLAG is set (output, or a control call, which also puts the character), JUMP to 4BC9H to write Register A.
4BA6
Read a byte: GOSUB to 4CC5H for the end of file status of the position.
4BA9
RET NZ C0
If the NZ FLAG is set (at or past the end: 1CH or 1DH), RETurn with the code in Register A.
4BAA
BIT 5,(IX+01H) DD CB 01 6E
Test bit 5 of FCB+01H at Index Register IX+01H: set when the buffer does not hold the sector to read from.
4BAE
If the NZ FLAG is set, GOSUB to 4C10H to read sector FCB+0AH-0BH into the buffer.
4BB1
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn with the error code in Register A.
4BB2
GOSUB to 4CB3H: Register Pair DE returns the address of the byte at FCB+05H in the buffer.
4BB5
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE.
4BB6
LD (4BC6H),A 32 C6 4B
Store Register A into 4BC6H, the operand of the LD A,00H at 4BC5H, to keep the byte while the position moves on.
4BB9
INC (IX+05H) DD 34 05
INCrement the byte offset at Index Register IX+05H (FCB+05H) by 1. The Z FLAG is set when it wraps to 00H: the sector is used up.
4BBC
If the NZ FLAG is set, JUMP to 4BC5H to return the byte.
4BBE
GOSUB to 4C7CH to write the buffer back if it holds updated bytes.
4BC1
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4BC2
GOSUB to 4C86H to step the next record number to the next sector and mark the buffer to be read.
4BC5
LD A,00H 3E 00
Load Register A with the byte read: the operand at 4BC6H, 00H in the file, is the byte stored there at 4BB6H.
4BC7
CP A BF
Compare Register A against itself to set the Z FLAG: no error.
4BC8
RET C9
RETurn with Register A = the byte and the Z FLAG set.
4BC9
LD (4C00H),A 32 00 4C
Write a byte: store Register A into 4C00H, the operand of the LD A,00H at 4BFFH, to keep the byte.
4BCC
BIT 5,(IX+01H) DD CB 01 6E
Test bit 5 of FCB+01H at Index Register IX+01H: set when the buffer does not hold the sector to write into.
4BD0
If the Z FLAG is set (the buffer holds it), JUMP to 4BE5H to store the byte.
4BD2
GOSUB to 4CC5H for the end of file status of the position.
4BD5
If the Z FLAG is set (before the end: the sector holds bytes of the file), JUMP to 4BE1H to read it first.
4BD7
RES 5,(IX+01H) DD CB 01 AE
Reset bit 5 of FCB+01H at Index Register IX+01H: at or past the end, the buffer is taken as the sector.
4BDB
LD A,(IX+05H) DD 7E 05
Load Register A with the byte offset at Index Register IX+05H (FCB+05H).
4BDE
OR A B7
OR Register A with itself to test the offset for 00H.
4BDF
If the Z FLAG is set (a new sector starts: nothing of the file is in it), JUMP to 4BE5H without reading.
4BE1
GOSUB to 4C10H to read sector FCB+0AH-0BH into the buffer, so the bytes already in it are kept.
4BE4
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn with the error code in Register A.
4BE5
GOSUB to 4CB3H: Register Pair DE returns the address of the byte at FCB+05H in the buffer.
4BE8
LD A,(4C00H) 3A 00 4C
Load Register A with the byte to write from 4C00H, where 4BC9H kept it.
4BEB
LD (DE),A 12
Store Register A to the buffer at Register Pair DE.
4BEC
SET 4,(IX+01H) DD CB 01 E6
Set bit 4 of FCB+01H at Index Register IX+01H, the buffer updated flag.
4BF0
INC (IX+05H) DD 34 05
INCrement the byte offset at Index Register IX+05H (FCB+05H) by 1. The Z FLAG is set when it wraps to 00H: the sector is full.
4BF3
If the NZ FLAG is set (room is left in the sector), JUMP to 4BFCH.
4BF5
GOSUB to 4C4AH to write the full buffer to the file.
4BF8
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4BF9
GOSUB to 4C86H to step the next record number to the next sector and mark the buffer to be read.
4BFC
GOSUB to 4C92H to set the modified flag and move the end of the file to the new position where it is due.
4BFF
LD A,00H 3E 00
Load Register A with the byte written; the operand at 4C00H was stored at 4BC9H.
4C01
CP A BF
Compare Register A against itself to set the Z FLAG: no error.
4C02
RET C9
RETurn with Register A = the byte and the Z FLAG set.
4C03H - Reading and Writing a Whole Sector
4C03H (READ@ of a file that is not blocked) reads sector FCB+0AH-0BH into the buffer and steps to the next sector. 4C10H reads the sector of the next record number: a file opened with an access level of 6 or 7 is refused unless a program is being loaded (bit 1 of SFLAG1$); the cylinder and sector come from 4D07H and DISKIO% function 3 (DREAD) reads it. 4C3EH (WRITE@ of a file that is not blocked) writes the buffer and steps on. 4C4AH writes the sector: an access level of 5 or more is refused, the sector is written with function 5 (DWRITE) and, with the verify switch on, read back with function 4 (DVERF). A refusal returns error 25H, Illegal access attempted to protected file.
4C03
READ@ of a sector: GOSUB to 4CC5H for the end of file status of the position.
4C06
RET NZ C0
If the NZ FLAG is set (at or past the end), RETurn with 1CH or 1DH in Register A.
4C07
GOSUB to 4C10H to read sector FCB+0AH-0BH into the file's buffer.
4C0A
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn with the error code in Register A.
4C0B
GOSUB to 4C86H to step the next record number to the next sector.
4C0E
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: no error.
4C0F
RET C9
RETurn with the sector in the file's buffer and no error.
4C10
LD A,(IX+01H) DD 7E 01
Read a sector: load Register A with the flags at Index Register IX+01H (FCB+01H); bits 0-2 the access level.
4C13
LD HL,4297H 21 97 42
Point Register Pair HL to 4297H, SFLAG1$, the system flags.
4C16
BIT 1,(HL) CB 4E
Test bit 1 of SFLAG1$ at Register Pair HL (4297H), the run access flag, set while RUN@ loads a program.
4C18
If the NZ FLAG is set (a program is being loaded), JUMP to 4C24H: an execute only file may be read.
4C1A
AND 07H E6 07
AND Register A with 07H to keep the access level.
4C1C
CP 06H FE 06
Compare Register A against 06H. The C FLAG is set for a level below 6, which allows reading.
4C1E
If the C FLAG is set, JUMP to 4C24H to read the sector.
4C20
LD A,25H 3E 25
Load Register A with 25H, the error code Illegal access attempted to protected file.
4C22
OR A B7
OR Register A with itself to set the NZ FLAG.
4C23
RET C9
RETurn with error 25H in Register A and the NZ FLAG set.
4C24
GOSUB to 4D07H for the place of sector FCB+0AH-0BH: Register C the drive, Register D the cylinder, Register E the sector.
4C27
RET NZ C0
If the NZ FLAG is set (the sector could not be found), RETurn with the error code in Register A.
4C28
RES 5,(IX+01H) DD CB 01 AE
Reset bit 5 of FCB+01H at Index Register IX+01H: the buffer is to hold the next record number's sector.
4C2C
LD L,(IX+03H) DD 6E 03
Load Register L with the low byte of the buffer address at Index Register IX+03H (FCB+03H).
4C2F
LD H,(IX+04H) DD 66 04
Load Register H with the high byte at Index Register IX+04H: Register Pair HL = the file's buffer.
4C32
LD A,03H 3E 03
Load Register A with 03H, the DISKIO% function DREAD.
4C34
GOSUB to 4488H (DISKIO%) to read the sector into the buffer at Register Pair HL.
4C37
RET Z C8
If the Z FLAG is set (no error), RETurn with Register A = 00H.
4C38
SUB 06H D6 06
SUBtract 06H from Register A. The Z FLAG is set for error 06H, a sector with the locked/deleted data mark the directory sectors carry, which is taken as a good read.
4C3A
RET Z C8
If the Z FLAG is set, RETurn with Register A = 00H and no error.
4C3B
ADD A,06H C6 06
ADD 06H to Register A to give back the error code. The NZ FLAG is set.
4C3D
RET C9
RETurn with the read error code in Register A.
4C3E
WRITE@ of a sector: GOSUB to 4C4AH to write the buffer as sector FCB+0AH-0BH.
4C41
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4C42
GOSUB to 4C86H to step the next record number to the next sector.
4C45
GOSUB to 4C92H to set the modified flag and move the end of the file where it is due.
4C48
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: no error.
4C49
RET C9
RETurn with the sector written, the position moved on and no error.
4C4A
LD A,(IX+01H) DD 7E 01
Write a sector: load Register A with the flags at Index Register IX+01H (FCB+01H).
4C4D
AND 07H E6 07
AND Register A with 07H to keep the access level.
4C4F
CP 05H FE 05
Compare Register A against 05H. The C FLAG is set for a level below 5, which allows writing.
4C51
If the C FLAG is set, JUMP to 4C57H to write the sector.
4C53
LD A,25H 3E 25
Load Register A with 25H, the error code Illegal access attempted to protected file.
4C55
OR A B7
OR Register A with itself to set the NZ FLAG.
4C56
RET C9
RETurn with error 25H in Register A and the NZ FLAG set.
4C57
GOSUB to 4D07H for the place of sector FCB+0AH-0BH: Register C the drive, Register D the cylinder, Register E the sector.
4C5A
RET NZ C0
If the NZ FLAG is set (the sector could not be found or the file could not be extended), RETurn with the error code in Register A.
4C5B
LD L,(IX+03H) DD 6E 03
Load Register L with the low byte of the buffer address at Index Register IX+03H (FCB+03H).
4C5E
LD H,(IX+04H) DD 66 04
Load Register H with the high byte at Index Register IX+04H: Register Pair HL = the file's buffer.
4C61
LD A,05H 3E 05
Load Register A with 05H, the DISKIO% function DWRITE.
4C63
GOSUB to 4488H (DISKIO%) to write the buffer at Register Pair HL to the sector.
4C66
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4C67
LD HL,4297H 21 97 42
Point Register Pair HL to 4297H, SFLAG1$, the system flags.
4C6A
BIT 3,(HL) CB 5E
Test bit 3 of SFLAG1$ at Register Pair HL (4297H), the verify switch.
4C6C
If the Z FLAG is set (verify is off), JUMP to 4C77H.
4C6E
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the system buffer, for the verify.
4C71
LD A,04H 3E 04
Load Register A with 04H, the DISKIO% function DVERF, which reads the sector back.
4C73
GOSUB to 4488H (DISKIO%) to verify the sector just written.
4C76
RET NZ C0
If the NZ FLAG is set (the sector does not read back), RETurn with the error code in Register A.
4C77
RES 4,(IX+01H) DD CB 01 A6
Reset bit 4 of FCB+01H at Index Register IX+01H: the buffer's bytes are on the diskette, no longer updated.
4C7B
RET C9
RETurn with the Z FLAG set from the write or the verify.
4C7CH - Buffer and Position Helpers
4C7CH writes the buffer of a blocked file when it holds updated bytes (bits 7 and 4 of FCB+01H). 4C86H steps the next record number on by one sector and sets bit 5, the buffer is to be read. 4C92H runs after each write: it sets the modified flag (bit 6 of FCB+02H) and, unless a random access file is written before its end, makes the position the end of the file (FCB+08H, FCB+0CH-0DH), so a sequential write shrinks the file to the last byte written. 4CB3H gives the address of the current byte in the buffer.
4C7C
LD A,(IX+01H) DD 7E 01
Load Register A with the flags at Index Register IX+01H (FCB+01H).
4C7F
CPL 2F
Complement Register A: bits 7 (blocked) and 4 (updated) are now clear when they were set.
4C80
AND 90H E6 90
AND Register A with 90H to keep bits 7 and 4. The Z FLAG is set when both flags were set.
4C82
If the Z FLAG is set (a blocked buffer holds updated bytes), JUMP to 4C4AH to write it, which returns to the caller.
4C84
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: nothing to write.
4C85
RET C9
RETurn with Register A = 00H and no error: nothing was written.
4C86
SET 5,(IX+01H) DD CB 01 EE
Set bit 5 of FCB+01H at Index Register IX+01H: the buffer does not hold the new next sector.
4C8A
INC (IX+0AH) DD 34 0A
INCrement the low byte of the next record number at Index Register IX+0AH (FCB+0AH) by 1.
4C8D
RET NZ C0
If the NZ FLAG is set (no carry into the high byte), RETurn.
4C8E
INC (IX+0BH) DD 34 0B
INCrement the high byte at Index Register IX+0BH by 1 for the carry.
4C91
RET C9
RETurn with the next record number one sector on.
4C92
SET 6,(IX+02H) DD CB 02 F6
Set bit 6 of FCB+02H at Index Register IX+02H, the modified flag: the file has been written to.
4C96
GOSUB to 4CC5H for the end of file status of the position.
4C99
If the NZ FLAG is set (at or past the end), JUMP to 4CA0H: the end moves to the position.
4C9B
BIT 6,(IX+01H) DD CB 01 76
Test bit 6 of FCB+01H at Index Register IX+01H, the random access flag set by POSN@.
4C9F
RET NZ C0
If the NZ FLAG is set (random access), RETurn: the end of the file stays where it is.
4CA0
LD A,(IX+05H) DD 7E 05
Load Register A with the byte offset at Index Register IX+05H (FCB+05H).
4CA3
LD (IX+08H),A DD 77 08
Store Register A to the end of file byte at Index Register IX+08H (FCB+08H).
4CA6
LD A,(IX+0AH) DD 7E 0A
Load Register A with the low byte of the next record number at Index Register IX+0AH (FCB+0AH).
4CA9
LD (IX+0CH),A DD 77 0C
Store Register A to the low byte of the ending record number at Index Register IX+0CH (FCB+0CH).
4CAC
LD A,(IX+0BH) DD 7E 0B
Load Register A with the high byte of the next record number at Index Register IX+0BH.
4CAF
LD (IX+0DH),A DD 77 0D
Store Register A to the high byte of the ending record number at Index Register IX+0DH: the end of the file is now the position.
4CB2
RET C9
RETurn with the end of the file moved to the position.
4CB3
LD A,(IX+05H) DD 7E 05
Load Register A with the byte offset at Index Register IX+05H (FCB+05H).
4CB6
LD C,A 4F
Load Register C with Register A, the offset in the buffer.
4CB7
ADD A,(IX+03H) DD 86 03
ADD the low byte of the buffer address at Index Register IX+03H (FCB+03H) to Register A.
4CBA
LD E,A 5F
Load Register E with Register A, the low byte of the byte's address.
4CBB
LD A,(IX+04H) DD 7E 04
Load Register A with the high byte of the buffer address at Index Register IX+04H.
4CBE
ADC A,00H CE 00
ADD 00H and the C FLAG of the low byte to Register A.
4CC0
LD D,A 57
Load Register D with Register A: Register Pair DE = the address of the current byte in the buffer.
4CC1
RET C9
RETurn with Register Pair DE = the byte's address and Register C = the offset.
4CC2H - CKEOF@ and the End of File Test
CKEOF@ (4457H) checks the file at Register Pair DE, then 4CC5H compares the position (FCB+0AH-0BH and FCB+05H) with the end (FCB+0CH-0DH and FCB+08H): Register A returns 00H with the Z FLAG set before the end, 1CH (Attempted to read past eof) at the end and 1DH (Attempted to read outside of file limits) past it, both with the NZ FLAG set.
4CC2
CKEOF@: GOSUB to 4CE5H to check the file control block at Register Pair DE and run the rest under Index Register IX with the registers saved.
4CC5
LD A,(IX+0BH) DD 7E 0B
Load Register A with the high byte of the next record number at Index Register IX+0BH (FCB+0BH).
4CC8
CP (IX+0DH) DD BE 0D
Compare Register A against the high byte of the ending record number at Index Register IX+0DH.
4CCB
If the NZ FLAG is set (they differ), JUMP to 4CE0H; the C FLAG tells which is the higher.
4CCD
LD A,(IX+0AH) DD 7E 0A
Load Register A with the low byte of the next record number at Index Register IX+0AH.
4CD0
CP (IX+0CH) DD BE 0C
Compare Register A against the low byte of the ending record number at Index Register IX+0CH.
4CD3
If the NZ FLAG is set (they differ), JUMP to 4CE0H.
4CD5
LD A,(IX+05H) DD 7E 05
The same sector: load Register A with the byte offset at Index Register IX+05H (FCB+05H).
4CD8
SUB (IX+08H) DD 96 08
SUBtract the end of file byte at Index Register IX+08H (FCB+08H) from Register A.
4CDB
If the NZ FLAG is set (they differ), JUMP to 4CE0H.
4CDD
OR 1CH F6 1C
OR Register A (00H) with 1CH: Register A = 1CH, Attempted to read past eof, and the NZ FLAG is set.
4CDF
RET C9
RETurn with Register A = 1CH: the position is the end of the file.
4CE0
LD A,1DH 3E 1D
Load Register A with 1DH, the error code Attempted to read outside of file limits.
4CE2
RET NC D0
If the NC FLAG is set (the position is past the end), RETurn with Register A = 1DH and the NZ FLAG from the compare.
4CE3
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: the position is before the end.
4CE4
RET C9
RETurn with Register A = 00H: the position is before the end of the file.
4CE5H - Checking a File Control Block
Called first by each file routine (POSN@, REW@, PEOF@, BKSP@, READ@, WRITE@, character I/O on a file, CKEOF@). When bit 7 of the type byte at Register Pair DE is clear the file is not open: the routine's own return address is dropped and error 26H (I/O attempted to unopen file) goes back to the routine's caller. Otherwise Index Register IX is pointed to the file control block, Index Registers IX and IY and Register Pairs HL, DE and BC are saved, 4CFAH is put on the stack as the routine's return and the rest of the routine is entered with Register A = 00H; when it returns, 4CFAH restores the registers, so only Register Pair AF carries the result back.
4CE5
LD A,(DE) 1A
Load Register A with the type byte of the file control block at Register Pair DE (80H when open).
4CE6
RLCA 07
Rotate Register A left: bit 7 goes to the C FLAG.
4CE7
If the NC FLAG is set (bit 7 clear: not an open file), JUMP to 4D02H.
4CE9
POP AF F1
Restore Register Pair AF from the top of the stack: the return address into the routine that called 4CE5H, which is put back last.
4CEA
PUSH DE D5
Save Register Pair DE, the file control block, to the top of the stack.
4CEB
EX (SP),IX DD E3
Exchange the top of the Stack Pointer with Index Register IX: Index Register IX = the file control block and the caller's Index Register IX is on the stack.
4CED
PUSH IY FD E5
Save Index Register IY to the top of the stack.
4CEF
PUSH HL E5
Save Register Pair HL to the top of the stack.
4CF0
PUSH DE D5
Save Register Pair DE to the top of the stack.
4CF1
PUSH BC C5
Save Register Pair BC to the top of the stack.
4CF2
PUSH HL E5
Save Register Pair HL to the top of the stack once more, to make a place for the next word.
4CF3
LD HL,4CFAH 21 FA 4C
Load Register Pair HL with 4CFAH, the routine that restores the registers.
4CF6
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: 4CFAH goes to the stack, where the routine will return, and Register Pair HL is the caller's again.
4CF7
PUSH AF F5
Save Register Pair AF, the return address into the routine, to the top of the stack.
4CF8
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG.
4CF9
RET C9
RETurn into the routine with Register A = 00H; the routine returns to 4CFAH.
4CFA
POP BC C1
Restore Register Pair BC from the top of the stack, as the caller had it.
4CFB
POP DE D1
Restore Register Pair DE from the top of the stack, as the caller had it.
4CFC
POP HL E1
Restore Register Pair HL from the top of the stack, as the caller had it.
4CFD
POP IY FD E1
Restore Index Register IY from the top of the stack, as the caller had it.
4CFF
POP IX DD E1
Restore Index Register IX from the top of the stack, as the caller had it.
4D01
RET C9
RETurn to the caller of the file routine with Register Pair AF as the routine left it.
4D02
POP AF F1
Restore Register Pair AF from the top of the stack: the return address into the routine is dropped.
4D03
LD A,26H 3E 26
Load Register A with 26H, the error code I/O attempted to unopen file.
4D05
OR A B7
OR Register A with itself to set the NZ FLAG.
4D06
RET C9
RETurn to the caller of the file routine with error 26H in Register A.
4D07H - The Record Locator
Finds sector FCB+0AH-0BH of the file at Index Register IX on the diskette. The sector number divided by the sectors per granule gives the granule of the file and the sector within it. The segment list at FCB+0EH-1FH holds five segments: the descriptor at FCB+0EH (the segment that starts the file), then four 4 byte elements at FCB+10H, FCB+14H, FCB+18H and FCB+1CH, each the count of granules of the file before the segment (two bytes) and the segment's descriptor (the cylinder, then the starting granule in bits 7-5 and the granules less 1 in bits 4-0); a cylinder of FFH marks an empty entry. When the granule is in a segment of the list and that segment is the third, fourth or fifth, its element is moved to the second place and the ones between move up (4D89H-4DA6H), so the list keeps the segments used last. When it is in none, SYS4/SYS is called (request 33H), and the low overlay that was resident is loaded back. Register C returns the drive, Register D the cylinder and Register E the sector.
4D07
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4D0A
GOSUB to 45D4H (LOCDCT%): Index Register IY returns the drive control table of drive Register C.
4D0D
LD L,(IX+0AH) DD 6E 0A
Load Register L with the low byte of the next record number at Index Register IX+0AH (FCB+0AH).
4D10
LD H,(IX+0BH) DD 66 0B
Load Register H with the high byte at Index Register IX+0BH: Register Pair HL = the sector of the file.
4D13
LD A,(IY+0FH) FD 7E 0F
Load Register A with the sectors per granule at Index Register IY+0FH (DCT+0FH).
4D16
GOSUB to 497BH (DIVD@): Register Pair HL returns the granule of the file and Register A the sector within it.
4D19
LD (4DC3H),A 32 C3 4D
Store Register A, the sector within the granule, into 4DC3H, the operand of the ADD A,00H at 4DC2H.
4D1C
PUSH IX DD E5
Save Index Register IX, the file control block, to the top of the stack.
4D1E
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: Register Pair HL = the file control block and the granule goes to the stack.
4D1F
LD BC,000EH 01 0E 00
Load Register Pair BC with 000EH, the offset of the segment list.
4D22
ADD HL,BC 09
ADD Register Pair BC to Register Pair HL: Register Pair HL points to FCB+0EH, the first segment descriptor.
4D23
POP BC C1
Restore Register Pair BC from the top of the stack: Register Pair BC = the granule of the file to find.
4D24
LD A,05H 3E 05
Load Register A with 05H, the number of segments in the list.
4D26
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H: the first segment starts at granule 0 of the file.
4D29
PUSH AF F5
Save Register Pair AF, the count of segments left, to the top of the stack.
4D2A
LD A,(HL) 7E
Load Register A with the segment's cylinder at Register Pair HL.
4D2B
INC HL 23
INCrement Register Pair HL by 1 to the segment's granule byte.
4D2C
INC A 3C
INCrement Register A by 1. The Z FLAG is set for a cylinder of FFH, an empty entry.
4D2D
If the Z FLAG is set, JUMP to 4D3AH to go on to the next element.
4D2F
PUSH HL E5
Save Register Pair HL (the granule byte) to the top of the stack.
4D30
LD H,D 62
Load Register H with Register D, the high byte of the granules before the segment.
4D31
LD L,E 6B
Load Register L with Register E: Register Pair HL = the granule of the file the segment starts with.
4D32
XOR A AF
Set Register A to 00H by XORing it with itself, which also clears the C FLAG.
4D33
SBC HL,BC ED 42
SUBtract Register Pair BC, the granule wanted, from Register Pair HL.
4D35
If the C FLAG is set (the segment starts before the granule), JUMP to 4D45H to see whether it reaches it.
4D37
POP HL E1
Restore Register Pair HL (the granule byte) from the top of the stack.
4D38
If the Z FLAG is set (the granule is the segment's first), JUMP to 4D81H with Register A = 00H, the granule's place in the segment.
4D3A
INC HL 23
The next element: INCrement Register Pair HL by 1 to its count of granules.
4D3B
POP AF F1
Restore Register Pair AF, the count of segments left, from the top of the stack.
4D3C
DEC A 3D
DECrement Register A, the count of segments left, by 1.
4D3D
If the Z FLAG is set (the five are used up), JUMP to 4D58H to call SYS4/SYS.
4D3F
LD E,(HL) 5E
Load Register E with the low byte of the count at Register Pair HL.
4D40
INC HL 23
INCrement Register Pair HL by 1 to the high byte of the count.
4D41
LD D,(HL) 56
Load Register D with the high byte at Register Pair HL: Register Pair DE = the granules of the file before the next segment.
4D42
INC HL 23
INCrement Register Pair HL by 1 to the next segment's cylinder.
4D43
JUMP back to 4D29H to test the next segment of the list.
4D45
INC H 24
INCrement Register H by 1. The Z FLAG is set when Register Pair HL was FF00H-FFFFH: the granule is less than 256 granules into the segment.
4D46
LD A,L 7D
Load Register A with Register L: minus the granule's distance from the segment's start.
4D47
POP HL E1
Restore Register Pair HL (the granule byte) from the top of the stack.
4D48
If the NZ FLAG is set (too far), JUMP back to 4D3AH for the next element.
4D4A
PUSH DE D5
Save Register Pair DE to the top of the stack.
4D4B
LD E,A 5F
Load Register E with Register A, minus the distance.
4D4C
LD A,(HL) 7E
Load Register A with the segment's granule byte at Register Pair HL.
4D4D
AND 1FH E6 1F
AND Register A with 1FH to keep the segment's granules less 1.
4D4F
ADD A,E 83
ADD Register E to Register A. The C FLAG is set when the distance is within the segment.
4D50
LD A,E 7B
Load Register A with Register E, minus the distance.
4D51
POP DE D1
Restore Register Pair DE from the top of the stack.
4D52
If the NC FLAG is set (the segment ends before the granule), JUMP back to 4D3AH for the next element.
4D54
NEG ED 44
NEGate Register A: the granule's place in the segment.
4D56
JUMP to 4D81H with the segment found in the list.
4D58
LD A,(4DC3H) 3A C3 4D
Not in the list: load Register A with the sector within the granule from 4DC3H.
4D5B
PUSH AF F5
Save Register Pair AF to the top of the stack.
4D5C
LD A,(429DH) 3A 9D 42
Load Register A with OVLYL$ at 429DH, the low overlay now in memory.
4D5F
ADD A,02H C6 02
ADD 02H to Register A: the request code of routine 2 of that overlay, which in each of SYS1/SYS-SYS8/SYS is XOR A and RET.
4D61
PUSH AF F5
Save Register Pair AF (the request that brings the overlay back) to the top of the stack.
4D62
LD A,33H 3E 33
Load Register A with 33H, the request code of routine 3 of SYS4/SYS.
4D64
GOSUB to 499EH, the overlay request handler, to load SYS4/SYS over the low overlay and run its routine 3 with Index Register IX at the file control block. Its results are used below: the flags, Register A, Register Pair HL and, with the C FLAG set, Register Pairs BC and DE.
4D67
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: Register Pair HL = the saved request and Register Pair HL from SYS4/SYS goes to the stack.
4D68
PUSH AF F5
Save Register Pair AF, the result of SYS4/SYS, to the top of the stack.
4D69
LD A,H 7C
Load Register A with Register H, the request code that brings the old overlay back.
4D6A
CP 12H FE 12
Compare Register A against 12H, the code for SYS2/SYS.
4D6C
If the NZ FLAG is set (it was not SYS2/SYS), GOSUB to 499EH to load the old overlay back and run its routine 2. With no low overlay resident (OVLYL$ FFH) the code is 01H, the BREAK request.
4D6F
POP AF F1
Restore Register Pair AF, the result of SYS4/SYS, from the top of the stack.
4D70
POP HL E1
Restore Register Pair HL, the value SYS4/SYS returned, from the top of the stack.
4D71
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: Register Pair HL = the sector within the granule saved at 4D5BH (in Register H), and SYS4/SYS's Register Pair HL goes back to the stack.
4D72
PUSH AF F5
Save Register Pair AF, the result of SYS4/SYS, to the top of the stack.
4D73
LD A,H 7C
Load Register A with Register H, the sector within the granule.
4D74
LD (4DC3H),A 32 C3 4D
Store Register A back into 4DC3H, the operand of the ADD A,00H at 4DC2H: the overlay loads read their files through this locator, which overwrote it.
4D77
POP AF F1
Restore Register Pair AF, the result of SYS4/SYS, from the top of the stack.
4D78
LD (4DB0H),A 32 B0 4D
Store Register A, the granule's place in the segment, into 4DB0H, the operand of the ADD A,00H at 4DAFH.
4D7B
POP HL E1
Restore Register Pair HL, the value SYS4/SYS returned, from the top of the stack.
4D7C
RET NZ C0
If the NZ FLAG is set (SYS4/SYS returned an error), RETurn with the error code in Register A.
4D7D
If the C FLAG is set, JUMP to 4DA0H to store the segment SYS4/SYS returned (Register Pair BC the descriptor, Register Pair DE the granules before it) in the list at Register Pair HL.
4D7F
JUMP to 4DA9H with Register H = the segment's granule byte and Register L its cylinder.
4D81
LD (4DB0H),A 32 B0 4D
The segment is in the list: store Register A, the granule's place in the segment, into 4DB0H, the operand of the ADD A,00H at 4DAFH.
4D84
LD B,(HL) 46
Load Register B with the segment's granule byte at Register Pair HL.
4D85
DEC HL 2B
DECrement Register Pair HL by 1 to the segment's cylinder.
4D86
LD C,(HL) 4E
Load Register C with the cylinder at Register Pair HL.
4D87
INC HL 23
INCrement Register Pair HL by 1 back to the granule byte.
4D88
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the count of segments left, 5 for the first segment down to 1 for the fifth.
4D89
CPL 2F
Complement Register A, the count of segments left.
4D8A
ADD A,04H C6 04
ADD 04H to Register A. The C FLAG is set for the third, fourth and fifth segments (a count of 3, 2 or 1).
4D8C
If the NC FLAG is set (the first or second segment), JUMP to 4DA7H: the list is left as it is.
4D8E
INC A 3C
INCrement Register A by 1: 1, 2 or 3, the elements to move.
4D8F
RLCA 07
Rotate Register A left, the elements times 2.
4D90
RLCA 07
Rotate Register A left again: Register A = 4, 8 or 12, the bytes to move.
4D91
PUSH BC C5
Save Register Pair BC (the descriptor found) to the top of the stack.
4D92
PUSH DE D5
Save Register Pair DE (the granules before it) to the top of the stack.
4D93
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the found element's last byte (its granule byte).
4D94
LD HL,FFFCH 21 FC FF
Load Register Pair HL with FFFCH, minus 4, the length of an element.
4D97
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL = the last byte of the element before it.
4D98
LD B,00H 06 00
Load Register B with 00H, the high byte of the count.
4D9A
LD C,A 4F
Load Register C with Register A: Register Pair BC = the bytes to move.
4D9B
LDDR ED B8
Move Register Pair BC bytes from Register Pair HL to Register Pair DE, last byte first: the elements from the second place on move up one place, over the one found.
4D9D
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the last byte of the second place, now free.
4D9E
POP DE D1
Restore Register Pair DE (the granules before the segment) from the top of the stack.
4D9F
POP BC C1
Restore Register Pair BC (the descriptor) from the top of the stack.
4DA0
LD (HL),B 70
Store Register B, the granule byte, at Register Pair HL.
4DA1
DEC HL 2B
DECrement Register Pair HL by 1 to the cylinder's place.
4DA2
LD (HL),C 71
Store Register C, the cylinder, at Register Pair HL.
4DA3
DEC HL 2B
DECrement Register Pair HL by 1 to the high byte of the count.
4DA4
LD (HL),D 72
Store Register D, the high byte of the granules before the segment, at Register Pair HL.
4DA5
DEC HL 2B
DECrement Register Pair HL by 1 to the low byte of the count.
4DA6
LD (HL),E 73
Store Register E, the low byte, at Register Pair HL: the segment is now the second element of the list.
4DA7
LD H,B 60
Load Register H with Register B, the granule byte of the segment.
4DA8
LD L,C 69
Load Register L with Register C, the cylinder of the segment.
4DA9
LD A,H 7C
Load Register A with Register H, the granule byte.
4DAA
RLCA 07
Rotate Register A left, the first of three rotations.
4DAB
RLCA 07
Rotate Register A left, the second of three rotations.
4DAC
RLCA 07
Rotate Register A left a third time: the starting granule (bits 7-5) is in bits 2-0.
4DAD
AND 07H E6 07
AND Register A with 07H to keep the starting granule.
4DAF
ADD A,00H C6 00
ADD the granule's place in the segment to Register A; the operand at 4DB0H, 00H in the file, was stored at 4D78H or 4D81H.
4DB1
LD E,A 5F
Load Register E with Register A, the granule counted from the start of the segment's cylinder.
4DB2
LD A,(IY+10H) FD 7E 10
Load Register A with the granules per cylinder at Index Register IY+10H (DCT+10H).
4DB5
GOSUB to 494DH: Register A = Register E divided by Register A (the cylinders on from the segment's) and Register E = the remainder (the granule within its cylinder).
4DB8
ADD A,L 85
ADD Register L, the segment's cylinder, to Register A.
4DB9
LD D,A 57
Load Register D with Register A, the cylinder of the sector.
4DBA
LD A,(IY+0FH) FD 7E 0F
Load Register A with the sectors per granule at Index Register IY+0FH (DCT+0FH).
4DBD
PUSH DE D5
Save Register Pair DE to the top of the stack.
4DBE
GOSUB to 493EH: Register A = Register A times Register E, the first sector of the granule.
4DC1
POP DE D1
Restore Register Pair DE from the top of the stack.
4DC2
ADD A,00H C6 00
ADD the sector within the granule to Register A; the operand at 4DC3H, 00H in the file, was stored at 4D19H or 4D74H.
4DC4
LD E,A 5F
Load Register E with Register A, the sector on the cylinder.
4DC5
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4DC8
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG.
4DC9
RET C9
RETurn with Register C = the drive, Register D = the cylinder and Register E = the sector.
4DCAH - The Keyboard Driver
The start-up puts 4DCAH in the keyboard DCB (4016H) unless SHIFT and the up arrow are held at boot. With a DO file active (bit 5 of SFLAG1$) the next character comes from the DO file (DODCB$, 42A9H) through GET@, and the DO flag is cleared at the file's end; otherwise the driver goes on to the ROM's keyboard routine at 3024H. Before either it stores 15H at 41FFH, the low byte of the word the ROM's keyboard routine keeps at 41FFH-4200H (its 33E2H and 33F3H).
4DCA
LD HL,4297H 21 97 42
Point Register Pair HL to 4297H, SFLAG1$, the system flags.
4DCD
BIT 5,(HL) CB 6E
Test bit 5 of SFLAG1$ at Register Pair HL (4297H), the DO file active flag. The Z FLAG is set when no DO file is active.
4DCF
LD A,15H 3E 15
Load Register A with 15H, for the ROM's keyboard word at 41FFH; the LD does not change the Z FLAG of the test.
4DD1
LD (41FFH),A 32 FF 41
Store Register A (15H) to 41FFH, the low byte of the word the ROM's keyboard routine keeps at 41FFH-4200H (read at its 33E2H, stored at its 33F3H).
4DD4
If the Z FLAG is set (no DO file), JUMP to 3024H, the ROM's keyboard routine, which scans the keyboard and returns the key in Register A.
4DD7
LD DE,(42A9H) ED 5B A9 42
Load Register Pair DE with DODCB$ at 42A9H, the DO file's file control block.
4DDB
GOSUB to 0013H (GET@) for the next character of the DO file in Register A.
4DDE
LD C,A 4F
Load Register C with Register A, the character from the DO file.
4DDF
GOSUB to 4457H (CKEOF@) to test the DO file for its end.
4DE2
If the Z FLAG is set (more to come), JUMP to 4DE6H.
4DE4
RES 5,(HL) CB AE
Reset bit 5 of SFLAG1$ at Register Pair HL (4297H): the DO file is finished and the keyboard is used again.
4DE6
LD A,C 79
Load Register A with Register C, the character from the DO file.
4DE7
OR A B7
OR Register A with itself to set the flags for the character.
4DE8
RET C9
RETurn with Register A = the character from the DO file.
4DE9-4DFF
DEFS 23
Not in the file: the rest of the 4000H-4DFFH area the manual gives SYS0/SYS. The start-up follows at 4E00H.
4E00H - The Start-Up
The transfer address of SYS0/SYS, entered from the boot sector with BOOT/SYS sector 2 at 5200H. It finds the top of memory, sets HMEM$ (4411H), LOW$ (42A7H), the command buffer and BREAK$, enables the I/O bus through port ECH, installs the real time clock vector (4046H) and the NMI vector (4049H), puts the ROM's clock task into slot 7, copies the drive and screen settings of BOOT/SYS sector 2, reads the key held at boot, installs the keyboard driver, then displays the heading and the logo, asks for the date and the time when the boot flags say so, and runs the automatic command of drive 0's GAT. 4E00H-50F2H is overwritten by the first low overlay.
4E00
DI F3
Disable interrupts. The start-up runs with them off; SYS1/SYS's command level enables them (its 4E16H).
4E01
IM 1 ED 56
Set interrupt mode 1: every interrupt is a RST 38H.
4E03
LD SP,41E5H 31 E5 41
Load the Stack Pointer with 41E5H, the system stack.
4E06
LD HL,402DH 21 2D 40
Load Register Pair HL with 402DH, EXIT@, the return to the command level.
4E09
PUSH HL E5
Save Register Pair HL (402DH) to the top of the stack: the start-up's last RET goes to EXIT@ and the DOS command level.
4E0A
LD HL,FFFFH 21 FF FF
Load Register Pair HL with FFFFH, the highest address to test.
4E0D
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL.
4E0E
CPL 2F
Complement Register A, the byte to test with.
4E0F
LD (HL),A 77
Store Register A, the complement, to Register Pair HL.
4E10
CP (HL) BE
Compare Register A against the byte at Register Pair HL. The Z FLAG is set when memory kept it.
4E11
CPL 2F
Complement Register A back to the byte as it was.
4E12
LD (HL),A 77
Store Register A back to Register Pair HL, as it was.
4E13
If the Z FLAG is set (memory is there), JUMP to 4E1BH: Register Pair HL is the top of memory.
4E15
LD A,H 7C
Load Register A with Register H, the high byte of the address tested.
4E16
SUB 40H D6 40
SUBtract 40H from Register A: the next address down is 16K lower.
4E18
LD H,A 67
Load Register H with Register A: Register Pair HL = BFFFH, 7FFFH or 3FFFH next.
4E19
JUMP back to 4E0DH to test the next address down.
4E1B
LD (42A5H),HL 22 A5 42
Store Register Pair HL, the top of memory, to 42A5H.
4E1E
LD (4411H),HL 22 11 44
Store Register Pair HL, the top of memory, to HMEM$ at 4411H.
4E21
LD HL,5200H 21 00 52
Load Register Pair HL with 5200H, the first address above the low overlays.
4E24
LD (42A7H),HL 22 A7 42
Store Register Pair HL (5200H) to LOW$ at 42A7H, the lowest address free for programs.
4E27
LD HL,4210H 21 10 42
Point Register Pair HL to 4210H, the ROM's image of port ECH.
4E2A
SET 4,(HL) CB E6
Set bit 4 of the image at Register Pair HL (4210H), the enable of the external I/O bus.
4E2C
LD A,(HL) 7E
Load Register A with the image at Register Pair HL (4210H).
4E2D
OUT (ECH),A D3 EC
Write Register A to port ECH, the miscellaneous control latch: the I/O bus is enabled.
4E2F
LD A,0DH 3E 0D
Load Register A with 0DH, a carriage return, for the empty command.
4E31
LD HL,4225H 21 25 42
Point Register Pair HL to 4225H, INPBUF$, the command buffer.
4E34
LD (42A3H),HL 22 A3 42
Store Register Pair HL (4225H) to the command buffer pointer at 42A3H.
4E37
LD (HL),A 77
Store Register A (0DH) at Register Pair HL: INPBUF$ holds an empty command.
4E38
LD A,C9H 3E C9
Load Register A with C9H, the code of a RET instruction.
4E3A
LD (42ADH),A 32 AD 42
Store Register A (C9H) to BREAK$ at 42ADH: the BREAK vector returns at once.
4E3D
XOR A AF
Set Register A to 00H by XORing it with itself.
4E3E
LD (4214H),A 32 14 42
Store Register A (00H) to 4214H, a byte of the ROM's RAM.
4E41
LD (429BH),A 32 9B 42
Store Register A (00H) to 429BH, the DEBUG on BREAK switch: BREAK does not enter DEBUG.
4E44
LD B,07H 06 07
Load Register B with 07H, the number of keyboard rows.
4E46
LD HL,4036H 21 36 40
Point Register Pair HL to 4036H, the keyboard row images.
4E49
LD (HL),A 77
Store Register A (00H) at Register Pair HL: no keys down in the row.
4E4A
INC HL 23
INCrement Register Pair HL by 1 to the next row image.
4E4B
DECrement Register B and loop back to 4E49H while Register B is not zero.
4E4D
LD A,C3H 3E C3
Load Register A with C3H, the code of a JP instruction.
4E4F
LD (4046H),A 32 46 40
Store Register A (C3H) to 4046H, the real time clock vector.
4E52
LD (4049H),A 32 49 40
Store Register A (C3H) to 4049H, the NMI vector.
4E55
LD HL,4657H 21 57 46
Load Register Pair HL with 4657H, the clock task.
4E58
LD (4047H),HL 22 47 40
Store Register Pair HL (4657H) to 4047H-4048H: 4046H now holds JP 4657H.
4E5B
LD HL,4842H 21 42 48
Load Register Pair HL with 4842H, the end of a sector transfer.
4E5E
LD (404AH),HL 22 4A 40
Store Register Pair HL (4842H) to 404AH-404BH: 4049H now holds JP 4842H, so the NMI at the end of a disk command ends the transfer loop.
4E61
LD A,07H 3E 07
Load Register A with 07H, slot 7, a fast slot.
4E63
LD DE,469FH 11 9F 46
Load Register Pair DE with 469FH, the task block of the ROM's clock task (46A1H, JP 3529H).
4E66
GOSUB to 4413H (SET@) to put the task block at Register Pair DE into slot Register A.
4E69
LD C,00H 0E 00
Load Register C with 00H, drive 0, the first drive to set.
4E6B
GOSUB to 44A3H (LOCDCT%): Index Register IY returns the drive control table of drive Register C.
4E6E
LD A,(5216H) 3A 16 52
Load Register A with the default step rate, BOOT/SYS sector 2 byte 16H at 5216H.
4E71
LD (IY+04H),A FD 77 04
Store Register A to the step rate code at Index Register IY+04H (DCT+04H).
4E74
LD A,03H 3E 03
Load Register A with 03H, the last drive to set.
4E76
INC C 0C
INCrement Register C, the drive, by 1 to the next drive.
4E77
CP C B9
Compare Register A against Register C. The NC FLAG is set while Register C is 3 or less.
4E78
If the NC FLAG is set, JUMP back to 4E6BH for the next drive.
4E7A
LD A,(5213H) 3A 13 52
Load Register A with the cursor blink switch, byte 13H at 5213H.
4E7D
LD (401CH),A 32 1C 40
Store Register A to 401CH, the cursor blink switch in the keyboard DCB.
4E80
LD A,(5214H) 3A 14 52
Load Register A with the cursor character, byte 14H at 5214H.
4E83
LD (4023H),A 32 23 40
Store Register A to 4023H, the cursor character in the video DCB.
4E86
LD A,(5215H) 3A 15 52
Load Register A with the caps switch, byte 15H at 5215H.
4E89
LD (4019H),A 32 19 40
Store Register A to 4019H, the caps switch in the keyboard DCB.
4E8C
LD BC,(5217H) ED 4B 17 52
Load Register Pair BC with bytes 17H-18H at 5217H: Register C = the port, Register B = the value.
4E90
OUT (C),B ED 41
Output Register B to the port in Register C. With the master's bytes, 00H goes to port 00H.
4E92
GOSUB to 002BH (KBD@) to scan the keyboard once: Register A returns the key held at boot, or 00H.
4E95
LD (4F84H),A 32 84 4F
Store Register A, the key, into 4F84H, the operand of the LD A,00H at 4F83H, for the test after the prompts.
4E98
CP 1BH FE 1B
Compare Register A against 1BH, SHIFT with the up arrow. The manual says this key boots with only the ROM drivers; the bytes skip only the keyboard driver below, the rest of the start-up runs as usual.
4E9A
If the Z FLAG is set (SHIFT and the up arrow are held), JUMP to 4EA2H: the ROM's keyboard driver is kept.
4E9C
LD HL,4DCAH 21 CA 4D
Load Register Pair HL with 4DCAH, the DOSPLUS keyboard driver.
4E9F
LD (4016H),HL 22 16 40
Store Register Pair HL (4DCAH) to 4016H, the driver address of the keyboard DCB.
4EA2
LD HL,4EC5H 21 C5 4E
Load Register Pair HL with 4EC5H, where the start-up goes on.
4EA5
PUSH HL E5
Save Register Pair HL (4EC5H) to the top of the stack, the return of 4EC0H or of the alternate system driver.
4EA6
LD HL,5203H 21 03 52
Point Register Pair HL to 5203H, the perishable DCT bytes in BOOT/SYS sector 2.
4EA9
LD C,00H 0E 00
Load Register C with 00H, drive 0, the drive that was booted.
4EAB
GOSUB to 44A3H (LOCDCT%): Index Register IY returns the drive control table of drive 0.
4EAE
LD DE,000BH 11 0B 00
Load Register Pair DE with 000BH, the offset of the perishable bytes.
4EB1
ADD IY,DE FD 19
ADD Register Pair DE to Index Register IY: Index Register IY points to DCT+0BH of drive 0.
4EB3
PUSH IY FD E5
Save Index Register IY (DCT+0BH) to the top of the stack.
4EB5
POP DE D1
Restore Register Pair DE from the top of the stack: Register Pair DE = DCT+0BH of drive 0.
4EB6
LD BC,0009H 01 09 00
Load Register Pair BC with 0009H, the nine bytes DCT+0BH-13H.
4EB9
LDIR ED B0
Move Register Pair BC bytes from Register Pair HL (5203H on) to Register Pair DE: drive 0 takes the geometry of the diskette booted.
4EBB
LD A,(5210H) 3A 10 52
Load Register A with the boot flags, byte 10H at 5210H.
4EBE
BIT 0,A CB 47
Test bit 0 of Register A, the alternate system driver flag.
4EC0
RET Z C8
If the Z FLAG is set (no alternate driver), RETurn to 4EC5H.
4EC1
LD HL,(5211H) 2A 11 52
Load Register Pair HL with the alternate system driver's address, bytes 11H-12H at 5211H.
4EC4
JP (HL) E9
JUMP to the alternate system driver at Register Pair HL; it returns to 4EC5H.
4EC5
LD HL,4FD8H 21 D8 4F
Point Register Pair HL to 4FD8H, the heading.
4EC8
GOSUB to 4467H (DSPLY@) to clear the screen and display the heading and the copyright line.
4ECB
LD HL,504DH 21 4D 50
Point Register Pair HL to 504DH, the DOSPLUS logo.
4ECE
LD A,(5210H) 3A 10 52
Load Register A with the boot flags at 5210H.
4ED1
BIT 1,A CB 4F
Test bit 1 of Register A, the boot flag that asks for the logo.
4ED3
If the NZ FLAG is set, GOSUB to 4467H (DSPLY@) to display the logo.
4ED6
LD HL,42BBH 21 BB 42
Point Register Pair HL to 42BBH, the saved date.
4ED9
LD A,(HL) 7E
Load Register A with the year byte at Register Pair HL.
4EDA
OR A B7
OR Register A with itself to test the year for 00H.
4EDB
If the Z FLAG is set (no date saved), JUMP to 4EE9H.
4EDD
CP 64H FE 64
Compare Register A against 64H (100), above the last year byte.
4EDF
If the NC FLAG is set (100 or more: not a date), JUMP to 4EE9H.
4EE1
LD DE,421AH 11 1A 42
Point Register Pair DE to 421AH, DATE$, the system date.
4EE4
LD BC,0003H 01 03 00
Load Register Pair BC with 0003H, the year, day and month.
4EE7
LDIR ED B0
Move Register Pair BC bytes from Register Pair HL to Register Pair DE: DATE$ = the date saved by an earlier start-up.
4EE9
LD IX,4217H DD 21 17 42
Point Index Register IX to 4217H, TIME$, with DATE$ at Index Register IX+03H.
4EED
LD A,(5210H) 3A 10 52
Load Register A with the boot flags at 5210H.
4EF0
BIT 2,A CB 57
Test bit 2 of Register A, the date prompt flag.
4EF2
If the Z FLAG is set (no date prompt), JUMP to 4F2BH.
4EF4
LD HL,503FH 21 3F 50
Point Register Pair HL to 503FH, the Date: prompt.
4EF7
GOSUB to 4467H (DSPLY@) to display the date prompt.
4EFA
LD B,0AH 06 0A
Load Register B with 0AH, the longest answer accepted.
4EFC
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the buffer for the answer.
4EFF
GOSUB to 0040H (KEYIN@), the ROM's line input: Register B returns the length typed, the C FLAG set for BREAK.
4F02
If the C FLAG is set (BREAK), JUMP to 4F2BH: the date is not changed.
4F04
INC B 04
INCrement Register B by 1, the first half of a test for 00H.
4F05
DEC B 05
DECrement Register B by 1, to set the Z FLAG for a length of 00H.
4F06
If the Z FLAG is set (only ENTER), JUMP to 4F2BH: the date is not changed.
4F08
GOSUB to 4FABH for the first number, the month, in Register E.
4F0B
LD (IX+05H),E DD 73 05
Store Register E to the month of DATE$ at Index Register IX+05H (421CH).
4F0E
GOSUB to 4FABH for the second number, the day, in Register E.
4F11
LD (IX+04H),E DD 73 04
Store Register E to the day of DATE$ at Index Register IX+04H (421BH).
4F14
GOSUB to 4FABH for the third number, the year, in Register Pair DE.
4F17
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the year.
4F18
LD A,64H 3E 64
Load Register A with 64H (100), the divisor for the year.
4F1A
GOSUB to 497BH (DIVD@) to divide Register Pair HL by Register A: Register A returns the year mod 100, so 1983 and 83 both give 83.
4F1D
LD (IX+03H),A DD 77 03
Store Register A to the year of DATE$ at Index Register IX+03H (421AH).
4F20
LD HL,421AH 21 1A 42
Point Register Pair HL to 421AH, DATE$, the date just typed.
4F23
LD DE,42BBH 11 BB 42
Point Register Pair DE to 42BBH, the saved date.
4F26
LD BC,0003H 01 03 00
Load Register Pair BC with 0003H, the three bytes of the date.
4F29
LDIR ED B0
Move Register Pair BC bytes from Register Pair HL to Register Pair DE: the date is kept at 42BBH for a later start-up (4ED6H).
4F2B
LD A,(5210H) 3A 10 52
Load Register A with the boot flags at 5210H.
4F2E
BIT 3,A CB 5F
Test bit 3 of Register A, the time prompt flag.
4F30
If the Z FLAG is set (no time prompt), JUMP to 4F58H.
4F32
LD HL,5046H 21 46 50
Point Register Pair HL to 5046H, the Time: prompt.
4F35
GOSUB to 4467H (DSPLY@) to display the time prompt.
4F38
LD B,08H 06 08
Load Register B with 08H, the longest answer accepted.
4F3A
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the buffer for the answer.
4F3D
GOSUB to 0040H (KEYIN@) for the line typed: Register B returns its length, the C FLAG set for BREAK.
4F40
If the C FLAG is set (BREAK), JUMP to 4F58H: the time is not changed.
4F42
INC B 04
INCrement Register B by 1, the first half of a test for 00H.
4F43
DEC B 05
DECrement Register B by 1, to set the Z FLAG for a length of 00H.
4F44
If the Z FLAG is set (only ENTER), JUMP to 4F58H: the time is not changed.
4F46
GOSUB to 4FABH for the first number, the hours, in Register E.
4F49
LD (IX+02H),E DD 73 02
Store Register E to the hours of TIME$ at Index Register IX+02H (4219H).
4F4C
GOSUB to 4FABH for the minutes in Register E.
4F4F
LD (IX+01H),E DD 73 01
Store Register E to the minutes of TIME$ at Index Register IX+01H (4218H).
4F52
GOSUB to 4FABH for the seconds in Register E.
4F55
LD (IX+00H),E DD 73 00
Store Register E to the seconds of TIME$ at Index Register IX+00H (4217H).
4F58
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the buffer for the GAT.
4F5B
LD C,00H 0E 00
Load Register C with 00H, drive 0, the system drive.
4F5D
LD E,00H 1E 00
Load Register E with 00H, sector 0 of the directory cylinder, the GAT.
4F5F
LD A,06H 3E 06
Load Register A with 06H, the DISKIO% function SREAD.
4F61
GOSUB to 4488H (DISKIO%) to read the GAT of drive 0 into 4300H.
4F64
If the NZ FLAG is set (it could not be read), JUMP to 4409H (ERROR@) with the error code in Register A.
4F67
LD HL,43E0H 21 E0 43
Point Register Pair HL to 43E0H, the AUTO command (GAT bytes E0H-FFH).
4F6A
LD B,20H 06 20
Load Register B with 20H, the 32 bytes of the field.
4F6C
LD A,(HL) 7E
Load Register A with the next character at Register Pair HL.
4F6D
CP 2AH FE 2A
Compare Register A against 2AH, an asterisk: the non-breakable AUTO.
4F6F
If the NZ FLAG is set (not an asterisk), JUMP to 4F75H.
4F71
SET 0,E CB C3
Set bit 0 of Register E: the ENTER and D keys do not stop the command.
4F73
JUMP to 4F7BH for the next character of the field.
4F75
CP 21H FE 21
Compare Register A against 21H, an exclamation mark: the invisible AUTO.
4F77
If the NZ FLAG is set (neither), JUMP to 4F7FH: the command starts here.
4F79
SET 1,E CB CB
Set bit 1 of Register E: the command is not displayed.
4F7B
INC HL 23
INCrement Register Pair HL by 1 to the next character of the field.
4F7C
DECrement Register B and loop back to 4F6CH while Register B is not zero.
4F7E
RET C9
RETurn to EXIT@ (402DH): the field holds only switch characters.
4F7F
BIT 0,E CB 43
Test bit 0 of Register E, the non-breakable switch.
4F81
If the NZ FLAG is set, JUMP to 4F8FH: the keys held at boot are not looked at.
4F83
LD A,00H 3E 00
Load Register A with the key held at boot; the operand at 4F84H, 00H in the file, was stored at 4E95H.
4F85
CP 0DH FE 0D
Compare Register A against 0DH, the ENTER key.
4F87
RET Z C8
If the Z FLAG is set (ENTER held), RETurn to EXIT@ (402DH) without the AUTO command.
4F88
AND 5FH E6 5F
AND Register A with 5FH, which makes a lower case letter upper case.
4F8A
CP 44H FE 44
Compare Register A against 44H, the letter D.
4F8C
If the Z FLAG is set (D held), JUMP to 440DH (DEBUG@): the monitor starts with EXIT@ (402DH) on the stack.
4F8F
LD A,(HL) 7E
Load Register A with the character at Register Pair HL.
4F90
CP 21H FE 21
Compare Register A against 21H. The C FLAG is set for a space or a control character such as 0DH.
4F92
RET C D8
If the C FLAG is set (no command), RETurn to EXIT@ (402DH).
4F93
PUSH DE D5
Save Register Pair DE (Register E the switches) to the top of the stack.
4F94
LD DE,4225H 11 25 42
Point Register Pair DE to 4225H, INPBUF$, the command buffer.
4F97
LD C,B 48
Load Register C with Register B, the bytes left in the field.
4F98
LD B,00H 06 00
Load Register B with 00H: Register Pair BC = the count of bytes left.
4F9A
LDIR ED B0
Move Register Pair BC bytes from Register Pair HL to Register Pair DE: the rest of the field goes to INPBUF$.
4F9C
LD A,0DH 3E 0D
Load Register A with 0DH, a carriage return, to end the command.
4F9E
LD (DE),A 12
Store Register A (0DH) at Register Pair DE, after the bytes copied.
4F9F
POP DE D1
Restore Register Pair DE (the switches) from the top of the stack.
4FA0
LD HL,4225H 21 25 42
Point Register Pair HL to 4225H, the command in INPBUF$.
4FA3
BIT 1,E CB 4B
Test bit 1 of Register E, the invisible switch.
4FA5
If the Z FLAG is set (a visible AUTO), GOSUB to 4467H (DSPLY@) to display the command.
4FA8
JUMP to 4405H (CMNDI@) to run the command at Register Pair HL, with EXIT@ (402DH) on the stack.
4FABH - Reading a Number Typed at a Prompt
4FABH returns in Register Pair DE the decimal number at Register Pair HL in the answer typed. A character other than a digit ends the number and is passed over, so 1/2/83, 1-2-83 and 1 2 83 are all read the same way. The 0DH that ends the answer, any other control character, or a semicolon ends it with the C FLAG set and is not passed over, so the numbers after it are 0. 4FCDH returns the next character.
4FAB
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the number so far.
4FAE
GOSUB to 4FCDH for the next character of the answer at Register Pair HL.
4FB1
RET C D8
If the C FLAG is set (the end of the answer or a semicolon), RETurn with the number in Register Pair DE.
4FB2
SUB 30H D6 30
SUBtract 30H, the character 0, from Register A.
4FB4
If the C FLAG is set (below 0), JUMP to 4FBAH: a separator.
4FB6
CP 0AH FE 0A
Compare Register A against 0AH, one more than the highest digit.
4FB8
If the C FLAG is set (a digit 0-9), JUMP to 4FBEH to add it in.
4FBA
ADD A,30H C6 30
ADD 30H to Register A to give back the character.
4FBC
OR A B7
OR Register A with itself to clear the C FLAG.
4FBD
RET C9
RETurn with the number in Register Pair DE: the separator ends it and has been passed over.
4FBE
PUSH HL E5
Save Register Pair HL (the answer pointer) to the top of the stack.
4FBF
LD H,D 62
Load Register H with Register D, the high byte of the number so far.
4FC0
LD L,E 6B
Load Register L with Register E: Register Pair HL = the number so far.
4FC1
ADD HL,HL 29
ADD Register Pair HL to itself: Register Pair HL = the number times 2.
4FC2
ADD HL,HL 29
ADD Register Pair HL to itself: Register Pair HL = the number times 4.
4FC3
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL = the number times 5.
4FC4
ADD HL,HL 29
ADD Register Pair HL to itself: Register Pair HL = the number times 10.
4FC5
LD E,A 5F
Load Register E with Register A, the value of the digit.
4FC6
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the digit.
4FC8
ADD HL,DE 19
ADD Register Pair DE (the digit) to Register Pair HL.
4FC9
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the number so far.
4FCA
POP HL E1
Restore Register Pair HL (the answer pointer) from the top of the stack.
4FCB
JUMP back to 4FAEH for the next character of the answer.
4FCD
LD A,(HL) 7E
Load Register A with the character at Register Pair HL.
4FCE
CP 20H FE 20
Compare Register A against 20H, a space, the lowest printable character.
4FD0
RET C D8
If the C FLAG is set (a control character: the 0DH that ends the answer), RETurn with the C FLAG set and Register Pair HL left on it.
4FD1
CP 3BH FE 3B
Compare Register A against 3BH, a semicolon, which ends the answer.
4FD3
SCF 37
Set the C FLAG, for the return at 4FD4H when the character is a semicolon.
4FD4
RET Z C8
If the Z FLAG is set (a semicolon), RETurn with the C FLAG set and Register Pair HL left on it.
4FD5
INC HL 23
INCrement Register Pair HL by 1 past the character.
4FD6
OR A B7
OR Register A with itself to clear the C FLAG.
4FD7
RET C9
RETurn with the character in Register A and the NC FLAG set.
4FD8H - The Start-Up's Texts
The heading (4FD8H), the two prompts (503FH, 5046H) and the DOSPLUS logo (504DH), each sent by DSPLY@, which stops at an 03H (the cursor stays on the line) or after a 0DH. The logo is three lines of TRS-80 graphics characters (80H-BFH, the six blocks of a character cell in bits 0-5) with 20H for blank cells.
4FD8-503E
DEFB 1CH,1FH / DEFM "DOSPLUS - Model III Disk Operating System - 3.50" / DEFB 0AH / DEFM "(c)(p) Copyright 1983, Micro-Systems Software Inc." / DEFB 0AH,0DH 1C 1F 44 4F 53 50 4C 55 53 20 2D 20 4D 6F 64 65 6C 20 49 49 49 20 44 69 73 6B 20 4F 70 65 72 61 74 69 6E 67 20 53 79 73 74 65 6D 20 2D 20 33 2E 35 30 0A 28 63 29 28 70 29 20 43 6F 70 79 72 69 67 68 74 20 31 39 38 33 2C 20 4D 69 63 72 6F 2D 53 79 73 74 65 6D 73 20 53 6F 66 74 77 61 72 65 20 49 6E 63 2E 0A 0D
The heading, displayed by 4EC8H: 1CH (cursor home) and 1FH (clear to the end of the screen), the system name and version 3.50, a line feed, the copyright line, a line feed, and the 0DH that ends the text.
503F-5045
DEFM "Date: " / DEFB 03H 44 61 74 65 3A 20 03
The date prompt, displayed by 4EF7H when bit 2 of the boot flags is set; 03H ends it with the cursor after it for the answer.
5046-504C
DEFM "Time: " / DEFB 03H 54 69 6D 65 3A 20 03
The time prompt, displayed by 4F35H when bit 3 of the boot flags is set; 03H ends it with the cursor after it for the answer.
504D-5083
DEFB 8FH,BFH,BFH,8FH,8FH,BFH,B0H,20H,BFH,BFH,8FH,8FH,BFH,BFH,20H,BFH,BFH,8FH,8FH,8FH,8FH,20H,8FH,BFH,BFH,8FH,8FH,BFH,BFH,20H,8FH,BFH,BFH,8FH,20H,20H,20H,8FH,BFH,BFH,8FH,20H,8FH,BFH,BFH,8FH,20H,BFH,BFH,8FH,8FH,8FH,8FH,20H,0AH 8F BF BF 8F 8F BF B0 20 BF BF 8F 8F BF BF 20 BF BF 8F 8F 8F 8F 20 8F BF BF 8F 8F BF BF 20 8F BF BF 8F 20 20 20 8F BF BF 8F 20 8F BF BF 8F 20 BF BF 8F 8F 8F 8F 20 0A
The first line of the logo, 54 graphics and blank cells, then 0AH, a line feed.
5084-50BA
DEFB 20H,BFH,BFH,20H,20H,BFH,BFH,20H,BFH,BFH,20H,20H,BFH,BFH,20H,8FH,8FH,8CH,8CH,BCH,BCH,20H,20H,BFH,BFH,8CH,8CH,8FH,8FH,20H,20H,BFH,BFH,20H,20H,20H,20H,20H,BFH,BFH,20H,20H,20H,BFH,BFH,20H,20H,8FH,8FH,8CH,8CH,BCH,BCH,20H,0AH 20 BF BF 20 20 BF BF 20 BF BF 20 20 BF BF 20 8F 8F 8C 8C BC BC 20 20 BF BF 8C 8C 8F 8F 20 20 BF BF 20 20 20 20 20 BF BF 20 20 20 BF BF 20 20 8F 8F 8C 8C BC BC 20 0A
The second line of the logo, 54 graphics and blank cells, then 0AH, a line feed.
50BB-50F1
DEFB BCH,BFH,BFH,BCH,BCH,BFH,83H,20H,BFH,BFH,BCH,BCH,BFH,BFH,20H,BCH,BCH,BCH,BCH,BFH,BFH,20H,BCH,BFH,BFH,BCH,20H,20H,20H,20H,BCH,BFH,BFH,BCH,BCH,BCH,BFH,20H,BFH,BFH,BCH,BCH,BCH,BFH,BFH,20H,20H,BCH,BCH,BCH,BCH,BFH,BFH,20H,0AH BC BF BF BC BC BF 83 20 BF BF BC BC BF BF 20 BC BC BC BC BF BF 20 BC BF BF BC 20 20 20 20 BC BF BF BC BC BC BF 20 BF BF BC BC BC BF BF 20 20 BC BC BC BC BF BF 20 0A
The third line of the logo, 54 graphics and blank cells, then 0AH, a line feed.
50F2
DEFB 0DH 0D
The 0DH that ends the logo, displayed by 4ED3H when bit 1 of the boot flags is set. It is the last byte of SYS0/SYS.