400CH - Restart Vectors and the ROM Device Control Blocks
The Model I 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; the device control blocks stay in RAM the ROM set up and are not part of the file.
400C
JUMP to 4984H, the overlay request handler. The ROM's RST 28H instruction 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 4984H loads the /SYS overlay the code names and runs the routine in it.
400F
JUMP to 440DH, DEBUG@. The ROM's RST 30H instruction comes here, so an RST 30H placed in a program enters the DEBUG monitor through the system entry point at 440DH.
4012
JUMP to 4581H, the interrupt handler. The ROM's RST 38H comes here: in interrupt mode 1 (selected by the start-up at 4E01H) every interrupt of the expansion interface (the real time clock 40 times a second and the floppy disk controller) 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 (4369H) points here. DCB+01H-02H (4016H-4017H) holds the driver address: the start-up stores 4DC0H there at 4E97H unless the key read at 4E8AH is 1BH. DCB+04H (4019H) is the caps switch (4E81H, from 5215H) and DCB+07H (401CH) the cursor blink switch (4E75H, from 5213H).
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 (4374H) points here. DCB+06H (4023H) is the cursor character, stored by the start-up at 4E7BH from 5214H.
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 (437FH) 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 also arrives here.
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 (4A45H).
4033
JUMP to 44E1H, the character I/O routine. The ROM's device routine at 03C2H jumps to 4033H when the type byte of the control block Register Pair DE points to lacks the bit Register B asks for (01H input, 02H output, 04H control); 44E1H then serves files, FORCE, JOIN and NIL devices.
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 (4E39H-4E40H) and the keyboard scan at 4DD9H compares each row with its image here.
403E
DEFB 35H 35
OSVER$, the DOS version in BCD: 35H, version 3, release 5.
403F
DEFB 01H 01
01H. No instruction of SYS0/SYS reads or writes 403FH, and no other system file of this diskette refers to it.
4040
DEFS 1
The 25 millisecond tick count, in the ROM's RAM: the real time clock task increments it at 45D4H and uses its two low bits to pick one of the four slow interrupt slots.
4041-4043
DEFS 3
TIME$, the system time: seconds (4041H), minutes (4042H) and hours (4043H). The time task at 4612H counts it up once a second, GTTIME@ (446DH) converts it to text, and the start-up stores the time typed at boot (4F46H-4F55H).
4044-4046
DEFS 3
DATE$, the system date: year (4044H, the last two digits: the start-up keeps the remainder of the year typed divided by 100), day (4045H) and month (4046H). GTDATE@ (4470H) converts it to text; the start-up fills it from the date typed at boot (4F08H-4F1DH) or from the copy at 4315H (4ED6H-4EE7H).
4047-4048
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 (4A69H).
4049-404A
DEFS 2
HMEM$, the highest address free for programs: the start-up stores the top of memory it finds here (4E1EH); RUN@ passes it to a program in Register Pair DE (4A6DH).
404BH - Interrupt Latch Copy, Enable Mask and Vectors
The interrupt handler at 4581H reads the expansion interface's interrupt latch (37E0H), keeps it at 404BH, masks it with the enable bits at 404CH and calls the vector of each latch bit that is set, from bit 0 up: bit n has its vector at 404DH + 2n.
404B
DEFB 00H 00
The interrupt latch copy: the handler stores the byte read from 37E0H here at 4589H, then works on Register A. No instruction of SYS0/SYS reads it back.
404C
DEFB 00H 00
The interrupt enable mask: the handler ANDs the latch with it at 458BH, so only the sources whose bits are set here are served. The start-up clears it (4E45H) and then sets bit 7, the real time clock (4E4EH), and bit 6, the floppy disk controller (4E57H).
404D-404E
DEFW 460EH 0E 46
The vector of latch bit 0: 460EH, a RET. No handler is installed for bit 0.
404F-4050
DEFW 460EH 0E 46
The vector of latch bit 1: 460EH, a RET. No handler is installed for bit 1.
4051-4052
DEFW 460EH 0E 46
The vector of latch bit 2: 460EH, a RET. No handler is installed for bit 2.
4053-4054
DEFW 460EH 0E 46
The vector of latch bit 3: 460EH, a RET. No handler is installed for bit 3.
4055-4056
DEFW 460EH 0E 46
The vector of latch bit 4: 460EH, a RET. No handler is installed for bit 4.
4057-4058
DEFW 460EH 0E 46
The vector of latch bit 5: 460EH, a RET. No handler is installed for bit 5.
4059-405A
DEFW 460EH 0E 46
The vector of latch bit 6, the floppy disk controller: 460EH in the file; the start-up replaces it with 4737H (4E50H-4E53H), which reads the controller's status at 37ECH and so clears its interrupt request.
405B-405C
DEFW 460EH 0E 46
The vector of latch bit 7, the real time clock: 460EH in the file; the start-up replaces it with 45C7H (4E47H-4E4AH), the clock task that runs the interrupt slots and counts the time.
4300H - System Variables at 4300H-435BH
Bytes SYS0/SYS keeps below its code: the drive and density of the last disk access, the drive select value, the system flags SFLAG1$, the last error code, the RS-232 settings, the overlay request state and the overlay bytes OVLYL$ and OVLYH$ (4300H-430BH are in the file); then the overlay table addresses, the command buffer and its pointer, the BREAK vector, the saved date and the top of memory and DO block pointers, which the start-up and the other routines fill.
4300
DEFB 00H 00
The drive and density of the last disk access: bit 7 the density bit (bit 7 of DCT+0BH) and bits 0-1 the physical drive number (DCT+0AH). The disk routine at 484CH compares the new drive with it (485BH); when they differ it stores the new value (485EH), switches the double density adapter (489FH) and loads the drive's head position into the track register (4862H-4865H). The start-up stores drive 0's density bit here (4EB8H).
4301
DEFB 01H 01
The drive select value: 4884H writes it to the drive select latch 37E1H before each controller command (472AH, 4752H, 4874H, 487FH). 488BH-489BH builds it from the physical drive number (01H, 02H, 04H or 08H for drives 0-3), and 474BH sets bit 3 for side 1. 01H in the file: drive 0, side 0.
4302
DEFB 00H 00
SFLAG1$, the system flags: bit 0 the BREAK key disable (tested by the request code 01H at 498DH), bit 1 the run access flag (set by RUN@ at 4A59H, cleared at 4A60H, tested at 4C0CH), bit 2 DEBUG (tested by RUN@ at 4A65H), bit 3 the verify after write switch (4C60H), bit 5 an active DO file (4DC3H, cleared at 4DD4H). The manual gives bit 6 as the DO block allocated flag; SYS0/SYS does not test bit 6.
4303
DEFB 00H 00
00H. No instruction of SYS0/SYS refers to 4303H, and no other system file of this diskette refers to it.
4304
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.
4305
DEFB 55H 55
The RS-232 baud rate value, 55H: SYS16/SYS outputs it to port E9H, the baud rate register of the RS-232 interface (its 577CH), and SYS13/SYS points Index Register IX here (its 533DH). Each four bit half is a rate code. SYS0/SYS does not use it.
4306
DEFB E5H E5
The RS-232 control value, E5H: SYS16/SYS outputs it to port EAH, the control register of the RS-232 interface (its 5781H). SYS0/SYS does not use it.
4307
DEFB 00H 00
The low byte of a word the overlay request handler saves on the stack (4995H) and puts back when the requested routine returns (49DEH), so a request made inside an overlay leaves 4307H-4308H as they were. SYS5/SYS stores Register Pair HL into the word (its 4E49H).
4308
DEFB 00H 00
The high byte of the word at 4307H 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@ (459DH-45ABH). The overlay request handler clears it during each request (49A1H-49A4H), RUN@ sets it from the access level of the program it runs (4A7BH) and the start-up clears it (4E36H).
4309
DEFB FFH FF
The request code of the last overlay request, stored by the handler at 49A7H: bits 7-4 the overlay (the system number less 1), bits 3-0 the routine in it, read at 49C9H. When an overlay cannot be loaded, 4A34H tests its bit 7 to choose the overlay byte to set to FFH. FFH in the file.
430A
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 49B6H and stores it at 49B7H; FFH, none, so the first request loads one. 4D52H reads it.
430B
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 430AH for requests with bit 7 set (49B0H). FFH, none.
430C-430D
DEFS 2
The address of the resident low overlay's routine table: the transfer address the loader returns in Register Pair HL, stored at 49BFH-49C2H after a load and read at 49C5H-49C8H when the overlay is already in memory. The handler takes the routine's address from the table (49C9H-49D8H).
430E-430F
DEFS 2
The address of the resident high overlay's routine table, kept like 430CH for requests with bit 7 set (49B1H).
4310-4311
DEFS 2
The command buffer pointer: the start-up stores 4318H here (4E29H-4E2CH). SYS1/SYS (its 4E3AH-4E4EH) and SYS12/SYS (its 5278H) read and move it.
4312-4314
DEFS 3
BREAK$, the BREAK key vector: the start-up stores C9H, a RET, at 4312H (4E30H-4E32H). The request code 01H jumps to it when bit 0 of SFLAG1$ is clear (498FH); a program may install a jump to its own routine here.
4315-4317
DEFS 3
The saved date, year, day and month like DATE$: the start-up copies it to 4044H-4046H 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).
4318-4357
DEFS 64
INPBUF$, the 64 byte command buffer: the start-up puts a 0DH at 4318H (4E2FH) and copies the automatic command of the diskette into it (4F94H-4F9EH) before running it through 4405H.
4358-4359
DEFS 2
The top of memory: the highest address the start-up's memory test finds, stored at 4E1BH. SYS16/SYS reads it.
435A-435B
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 (4DC7H).
4369H - 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% (4488H, 456FH) 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 43CBH.
4369-4373
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.
4374-437E
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.
437F-4389
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.
438A-4394
DEFW 43CBH / DEFW FFFFH x 3 / DEFB 08H / DEFM "RS" CB 43 FF FF FF FF FF FF 08 52 53
Device 3, @RS the RS-232 interface: the NIL control block at 43CBH until a driver is assigned, no filter table, no linking DCB, no saved driver, saved type 08H (NIL), name RS.
4395-439F
DEFW 43CBH / DEFW FFFFH x 3 / DEFB 08H / DEFM "U1" CB 43 FF FF FF FF FF FF 08 55 31
Device 4, @U1 the first user device: the NIL control block at 43CBH, no filter table, no linking DCB, no saved driver, saved type 08H, name U1.
43A0-43AA
DEFW 43CBH / DEFW FFFFH x 3 / DEFB 08H / DEFM "U2" CB 43 FF FF FF FF FF FF 08 55 32
Device 5, @U2 the second user device: the NIL control block at 43CBH, no filter table, no linking DCB, no saved driver, saved type 08H, name U2.
43ABH - 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% (448BH, 4557H) loads Index Register IY from the entry of drive Register C. Drives 0-3 have their tables at 448EH-44DDH; drives 4-7 point to the NIL control block at 43CBH.
43AB-43AE
DEFW 448EH / DEFM "0 " 8E 44 30 20
Drive 0: its drive control table is at 448EH; name 0 and a blank.
43AF-43B2
DEFW 44A2H / DEFM "1 " A2 44 31 20
Drive 1: its drive control table is at 44A2H; name 1 and a blank.
43B3-43B6
DEFW 44B6H / DEFM "2 " B6 44 32 20
Drive 2: its drive control table is at 44B6H; name 2 and a blank.
43B7-43BA
DEFW 44CAH / DEFM "3 " CA 44 33 20
Drive 3: its drive control table is at 44CAH; name 3 and a blank.
43BB-43BE
DEFW 43CBH / DEFM "4 " CB 43 34 20
Drive 4: no drive control table of its own, the NIL control block at 43CBH; name 4 and a blank.
43BF-43C2
DEFW 43CBH / DEFM "5 " CB 43 35 20
Drive 5: the NIL control block at 43CBH; name 5 and a blank.
43C3-43C6
DEFW 43CBH / DEFM "6 " CB 43 36 20
Drive 6: the NIL control block at 43CBH; name 6 and a blank.
43C7-43CA
DEFW 43CBH / DEFM "7 " CB 43 37 20
Drive 7: the NIL control block at 43CBH; name 7 and a blank.
43CBH - The NIL Control Block and the System File Control Block
43CBH is the control block of every device and drive that has none: type 08H, NIL. 43CEH-43EDH is the 32 byte file control block the overlay loader opens each /SYS file in (49E3H-4A2DH), with its buffer at 4200H; its first 16 bytes are in the file, the rest of its segment list is not.
43CB
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 (4509H-450FH) and DISKIO% returns error 08H for a NIL drive (4667H-466FH).
43CC-43CD
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 43CBH first.
43CE
DEFB 80H 80
The system file control block, FCB+00H: 80H, the type byte of an open file.
43CF
DEFB 00H 00
FCB+01H, the file flags: the overlay loader clears them at 4A0CH, so the access code (bits 0-2) is 0, full access, and the file is read sector by sector (bit 7 clear).
43D0
DEFB 00H 00
FCB+02H, the second flag byte (bit 7 non-shrinkable, bit 6 modified): 00H.
43D1-43D2
DEFW 4200H 00 42
FCB+03H-04H, the address of the file's 256 byte buffer: 4200H, where READ@ puts each sector of the /SYS file being loaded.
43D3
DEFB 00H 00
FCB+05H, the offset of the next byte in the buffer: 00H.
43D4
DEFB 00H 00
FCB+06H, the drive: 00H, the /SYS files are read from drive 0.
43D5
DEFB 00H 00
FCB+07H, the logical file number, the position of the /SYS file's directory entry: the overlay loader stores it at 4A08H for each overlay it loads.
43D6
DEFB 00H 00
FCB+08H, the end of file byte (the bytes used in the last sector): 00H.
43D7
DEFB 00H 00
FCB+09H, the logical record length: 00H, 256 bytes.
43D8-43D9
DEFW 0000H 00 00
FCB+0AH-0BH, the next record number: the overlay loader clears 43D8H at 4A0FH so each /SYS file is read from its first sector.
43DA-43DB
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.
43DC-43DD
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 (4A1FH-4A28H).
43DE-43ED
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 4CFDH walks (4D1FH-4D39H).
4400H - The System Entry Points
The documented entry points of DOSPLUS, 4400H-448DH. 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 4984H. 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, 441FH, 4423H, 4427H, 442BH, 442FH, 4461H-4466H): SYS0/SYS does not load them.
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 4984H, 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 (4984H). 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 4984H, 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 (4984H). The bytes are 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 4984H, with Register A = 43H: SYS5/SYS is loaded and its routine 3 takes the error code from the stack.
440D
DEBUG@: JUMP to 445DH, which requests the DEBUG monitor in SYS6/SYS. RST 30H (400FH), the BREAK key when 4308H is set (45A5H) and the start-up's D key (4F8CH) come here.
4410
SET@, insert a task into the interrupt chain: JUMP to 45FBH with Register A = the slot number and Register Pair DE = the task block.
4413
RESET@, remove the task of a slot from the interrupt chain: JUMP to 45F8H with Register A = the slot number.
4416
A second SET@ entry: JUMP to 45FBH, the same routine as 4410H, with Register A = the slot number and Register Pair DE = the task block.
4419
A second RESET@ entry: JUMP to 45F8H, the same routine as 4413H, with Register A = the slot number.
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 4984H, 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 (4984H). The bytes are 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 4984H, 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 (4984H). The bytes are 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 4A84H.
4426
RST 28H EF
RST 28H to 400CH and the overlay request handler at 4984H, 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 (4984H). The bytes are 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 4984H, 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 (4984H). The bytes are 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 4984H, 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 (4984H). The bytes are whatever memory held.
4430
LOAD@, load a program file: JUMP to 4A7FH, 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 4A5CH.
4433
RUN@, load a program file and run it: JUMP to 4A55H.
4436
READ@, read the next record of an open file: JUMP to 4B57H. The loader reads each sector of a program file through it (4AD2H).
4439
WRITE@, write the next record of an open file: JUMP to 4B72H.
443C
VER@, write with verification: JUMP to 4B72H, the same routine as WRITE@; the read after write check depends on bit 3 of SFLAG1$ (4302H) for both.
443F
REW@, rewind a file to its first record: JUMP to 4B26H.
4442
POSN@, position a file at the record in Register Pair BC: JUMP to 4AE8H.
4445
BKSP@, back a file up one record: JUMP to 4B3BH.
4448
PEOF@, position a file at its end: JUMP to 4B2DH.
444B
MULT@, multiply Register Pair HL by Register A: JUMP to 4957H.
444E
DIVD@, divide Register Pair HL by Register A, the quotient in Register Pair HL and the remainder in Register A: JUMP to 4971H.
4451
CKEOF@, test a file for its end: JUMP to 4CB8H. The keyboard driver uses it for a DO file (4DCFH).
4454
LD A,75H 3E 75
FILPTR@: load Register A with 75H, the request code of routine 5 of SYS8/SYS.
4456
RST 28H EF
RST 28H to 400CH and the overlay request handler at 4984H, with Register A = 75H: routine 5 of SYS8/SYS.
4457
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.
4459
RST 28H EF
RST 28H to 400CH and the overlay request handler at 4984H, with Register A = 76H: routine 6 of SYS8/SYS.
445A
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.
445C
RST 28H EF
RST 28H to 400CH and the overlay request handler at 4984H, with Register A = 74H: routine 4 of SYS8/SYS.
445D
PUSH AF F5
The DEBUG@ routine (440DH jumps here): 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.
445E
LD A,53H 3E 53
Load Register A with 53H, the request code of routine 3 of SYS6/SYS, the DEBUG monitor.
4460
RST 28H EF
RST 28H to 400CH and the overlay request handler at 4984H, with Register A = 53H: SYS6/SYS is loaded and its routine 3 runs the monitor.
4461-4466
DEFS 6
Not in the file: the RST 28H of the DEBUG@ request at 4460H does not return here, and DSPLY@ starts at 4467H. The six bytes are whatever memory held.
4467
DSPLY@, display the text at Register Pair HL up to a 03H or 0DH: JUMP to 4540H.
446A
PRINT@, print the text at Register Pair HL up to a 03H or 0DH: JUMP to 453CH.
446D
GTTIME@, the time as HH:MM:SS at Register Pair HL: JUMP to 463DH.
4470
GTDATE@, the date as MM/DD/YY at Register Pair HL: JUMP to 4658H.
4473
LD A,07H 3E 07
FEXT@, add a default extension to a file specification: 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 4984H, with Register A = 07H: routine 7 of SYS1/SYS.
4476
LD A,08H 3E 08
PARAM@, scan a parameter field: 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 4984H, with Register A = 08H: routine 8 of SYS1/SYS.
4479
LD A,63H 3E 63
EVAL@, the command evaluator: 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 4984H, with Register A = 63H: routine 3 of SYS7/SYS.
447C
LD A,64H 3E 64
WILD@, set or compare a wildmask: 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 4984H, with Register A = 64H: routine 4 of SYS7/SYS.
447F
LD A,65H 3E 65
LOCDEV@, find a device number from its 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 4984H, with Register A = 65H: routine 5 of SYS7/SYS.
4482
LD A,73H 3E 73
SORT@, sort a list in memory: 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 4984H, with Register A = 73H: routine 3 of SYS8/SYS.
4485
DISKIO%, the sector I/O routine: JUMP to 465FH with Register A = the function, Register C = the drive, Register D = the cylinder, Register E = the sector and Register Pair HL = the buffer. Every disk access of SYS0/SYS goes through here.
4488
LOCDCB%, the DCB address of a device: JUMP to 456FH with Register A = the device number; Register Pair DE returns the address.
448B
LOCDCT%, the drive control table of a drive: JUMP to 4557H with Register C = the drive; Index Register IY returns the table's address.
448EH - The Drive Control Tables of Drives 0-3
Four 20 byte drive control tables (DCTs), at 448EH, 44A2H, 44B6H and 44CAH, the ones DCTTBL (43ABH) points to. Bytes +00H-0AH describe the drive and stay as CONFIG sets them; bytes +0BH-13H describe the diskette and are set again from the table at 48F0H when the drive is logged (46CCH-46E8H, 48C7H-48EFH); the start-up copies drive 0's from sector 2 of BOOT/SYS (4E9EH-4EB1H) and stores the step rate code of 5216H into +04H of all four (4E61H-4E70H). The file holds the values of a one sided, ten sector single density diskette of 35 cylinders.
448E
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 4667H.
448F-4490
DEFW 4679H 79 46
DCT+01H-02H of drive 0, the driver address: 4679H, the floppy disk driver of SYS0/SYS. DISKIO% jumps to it at 4670H-4678H.
4491
DEFB 10H 10
DCT+03H of drive 0, the drive flags: 10H, bit 4 set, a delay after the motor starts (tested at 4868H); bit 6 clear, not write protected (47AFH); bit 2 clear, no double step (475CH); bit 0 clear, no log pending (46ACH).
4492
DEFB 03H 03
DCT+04H of drive 0, the step rate code: 03H, ORed into the restore (471EH) and seek (476FH) commands. The start-up replaces it with the default step rate of 5216H.
4493
DEFB 00H 00
DCT+05H of drive 0, the head offset of a partitioned volume: 00H, none.
4494-4495
DEFW 0000H 00 00
DCT+06H-07H of drive 0, the cylinder offset of a partitioned volume: 0000H, none.
4496
DEFB 00H 00
DCT+08H of drive 0, the sector offset, the number of the first sector of a track: 00H.
4497
DEFB 11H 11
DCT+09H of drive 0, the cylinder the head is over: 11H in the file. A restore sets it to 00H (471AH), a seek to the new cylinder (4778H), and it goes to the track register when the drive is selected (4862H-4865H).
4498
DEFB 00H 00
DCT+0AH of drive 0, the physical drive number: 00H, from which 488BH builds the drive select value.
4499
DEFB 40H 40
DCT+0BH of drive 0, the diskette flags: 40H, bit 6 set (a protected directory) and bit 7 clear (single density, tested at 4853H and 48A1H).
449A
DEFB 01H 01
DCT+0CH of drive 0, the surface count: 01H, one sided.
449B
DEFB 0AH 0A
DCT+0DH of drive 0, the sectors per track: 0AH, ten. A sector number at or above it is on side 1 (4745H-474DH).
449C
DEFB 0AH 0A
DCT+0EH of drive 0, the directory length in sectors: 0AH, ten. The overlay loader works out the /SYS file positions from it (49F5H, 49FFH).
449D
DEFB 05H 05
DCT+0FH of drive 0, the sectors per granule: 05H. The record locator divides by it (4D09H) and multiplies back (4DB0H).
449E
DEFB 02H 02
DCT+10H of drive 0, the granules per cylinder: 02H. The record locator divides by it (4DA8H).
449F
DEFB 0AH 0A
DCT+11H of drive 0, the sectors per cylinder: 0AH, ten.
44A0
DEFB 11H 11
DCT+12H of drive 0, the directory cylinder: 11H, cylinder 17. The directory routines read it at 46B4H and 4796H.
44A1
DEFB 23H 23
DCT+13H of drive 0, the cylinder count: 23H, 35 cylinders.
44A2
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 4667H.
44A3-44A4
DEFW 4679H 79 46
DCT+01H-02H of drive 1, the driver address: 4679H, the floppy disk driver of SYS0/SYS. DISKIO% jumps to it at 4670H-4678H.
44A5
DEFB 10H 10
DCT+03H of drive 1, the drive flags: 10H, bit 4 set, a delay after the motor starts (tested at 4868H); bit 6 clear, not write protected (47AFH); bit 2 clear, no double step (475CH); bit 0 clear, no log pending (46ACH).
44A6
DEFB 03H 03
DCT+04H of drive 1, the step rate code: 03H, ORed into the restore (471EH) and seek (476FH) commands. The start-up replaces it with the default step rate of 5216H.
44A7
DEFB 00H 00
DCT+05H of drive 1, the head offset of a partitioned volume: 00H, none.
44A8-44A9
DEFW 0000H 00 00
DCT+06H-07H of drive 1, the cylinder offset of a partitioned volume: 0000H, none.
44AA
DEFB 00H 00
DCT+08H of drive 1, the sector offset, the number of the first sector of a track: 00H.
44AB
DEFB 11H 11
DCT+09H of drive 1, the cylinder the head is over: 11H in the file. A restore sets it to 00H (471AH), a seek to the new cylinder (4778H), and it goes to the track register when the drive is selected (4862H-4865H).
44AC
DEFB 01H 01
DCT+0AH of drive 1, the physical drive number: 01H, from which 488BH builds the drive select value.
44AD
DEFB 40H 40
DCT+0BH of drive 1, the diskette flags: 40H, bit 6 set (a protected directory) and bit 7 clear (single density, tested at 4853H and 48A1H).
44AE
DEFB 01H 01
DCT+0CH of drive 1, the surface count: 01H, one sided.
44AF
DEFB 0AH 0A
DCT+0DH of drive 1, the sectors per track: 0AH, ten. A sector number at or above it is on side 1 (4745H-474DH).
44B0
DEFB 0AH 0A
DCT+0EH of drive 1, the directory length in sectors: 0AH, ten. The overlay loader works out the /SYS file positions from it (49F5H, 49FFH).
44B1
DEFB 05H 05
DCT+0FH of drive 1, the sectors per granule: 05H. The record locator divides by it (4D09H) and multiplies back (4DB0H).
44B2
DEFB 02H 02
DCT+10H of drive 1, the granules per cylinder: 02H. The record locator divides by it (4DA8H).
44B3
DEFB 0AH 0A
DCT+11H of drive 1, the sectors per cylinder: 0AH, ten.
44B4
DEFB 11H 11
DCT+12H of drive 1, the directory cylinder: 11H, cylinder 17. The directory routines read it at 46B4H and 4796H.
44B5
DEFB 23H 23
DCT+13H of drive 1, the cylinder count: 23H, 35 cylinders.
44B6
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 4667H.
44B7-44B8
DEFW 4679H 79 46
DCT+01H-02H of drive 2, the driver address: 4679H, the floppy disk driver of SYS0/SYS. DISKIO% jumps to it at 4670H-4678H.
44B9
DEFB 10H 10
DCT+03H of drive 2, the drive flags: 10H, bit 4 set, a delay after the motor starts (tested at 4868H); bit 6 clear, not write protected (47AFH); bit 2 clear, no double step (475CH); bit 0 clear, no log pending (46ACH).
44BA
DEFB 03H 03
DCT+04H of drive 2, the step rate code: 03H, ORed into the restore (471EH) and seek (476FH) commands. The start-up replaces it with the default step rate of 5216H.
44BB
DEFB 00H 00
DCT+05H of drive 2, the head offset of a partitioned volume: 00H, none.
44BC-44BD
DEFW 0000H 00 00
DCT+06H-07H of drive 2, the cylinder offset of a partitioned volume: 0000H, none.
44BE
DEFB 00H 00
DCT+08H of drive 2, the sector offset, the number of the first sector of a track: 00H.
44BF
DEFB 11H 11
DCT+09H of drive 2, the cylinder the head is over: 11H in the file. A restore sets it to 00H (471AH), a seek to the new cylinder (4778H), and it goes to the track register when the drive is selected (4862H-4865H).
44C0
DEFB 02H 02
DCT+0AH of drive 2, the physical drive number: 02H, from which 488BH builds the drive select value.
44C1
DEFB 40H 40
DCT+0BH of drive 2, the diskette flags: 40H, bit 6 set (a protected directory) and bit 7 clear (single density, tested at 4853H and 48A1H).
44C2
DEFB 01H 01
DCT+0CH of drive 2, the surface count: 01H, one sided.
44C3
DEFB 0AH 0A
DCT+0DH of drive 2, the sectors per track: 0AH, ten. A sector number at or above it is on side 1 (4745H-474DH).
44C4
DEFB 0AH 0A
DCT+0EH of drive 2, the directory length in sectors: 0AH, ten. The overlay loader works out the /SYS file positions from it (49F5H, 49FFH).
44C5
DEFB 05H 05
DCT+0FH of drive 2, the sectors per granule: 05H. The record locator divides by it (4D09H) and multiplies back (4DB0H).
44C6
DEFB 02H 02
DCT+10H of drive 2, the granules per cylinder: 02H. The record locator divides by it (4DA8H).
44C7
DEFB 0AH 0A
DCT+11H of drive 2, the sectors per cylinder: 0AH, ten.
44C8
DEFB 11H 11
DCT+12H of drive 2, the directory cylinder: 11H, cylinder 17. The directory routines read it at 46B4H and 4796H.
44C9
DEFB 23H 23
DCT+13H of drive 2, the cylinder count: 23H, 35 cylinders.
44CA
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 4667H.
44CB-44CC
DEFW 4679H 79 46
DCT+01H-02H of drive 3, the driver address: 4679H, the floppy disk driver of SYS0/SYS. DISKIO% jumps to it at 4670H-4678H.
44CD
DEFB 10H 10
DCT+03H of drive 3, the drive flags: 10H, bit 4 set, a delay after the motor starts (tested at 4868H); bit 6 clear, not write protected (47AFH); bit 2 clear, no double step (475CH); bit 0 clear, no log pending (46ACH).
44CE
DEFB 03H 03
DCT+04H of drive 3, the step rate code: 03H, ORed into the restore (471EH) and seek (476FH) commands. The start-up replaces it with the default step rate of 5216H.
44CF
DEFB 00H 00
DCT+05H of drive 3, the head offset of a partitioned volume: 00H, none.
44D0-44D1
DEFW 0000H 00 00
DCT+06H-07H of drive 3, the cylinder offset of a partitioned volume: 0000H, none.
44D2
DEFB 00H 00
DCT+08H of drive 3, the sector offset, the number of the first sector of a track: 00H.
44D3
DEFB 11H 11
DCT+09H of drive 3, the cylinder the head is over: 11H in the file. A restore sets it to 00H (471AH), a seek to the new cylinder (4778H), and it goes to the track register when the drive is selected (4862H-4865H).
44D4
DEFB 03H 03
DCT+0AH of drive 3, the physical drive number: 03H, from which 488BH builds the drive select value.
44D5
DEFB 40H 40
DCT+0BH of drive 3, the diskette flags: 40H, bit 6 set (a protected directory) and bit 7 clear (single density, tested at 4853H and 48A1H).
44D6
DEFB 01H 01
DCT+0CH of drive 3, the surface count: 01H, one sided.
44D7
DEFB 0AH 0A
DCT+0DH of drive 3, the sectors per track: 0AH, ten. A sector number at or above it is on side 1 (4745H-474DH).
44D8
DEFB 0AH 0A
DCT+0EH of drive 3, the directory length in sectors: 0AH, ten. The overlay loader works out the /SYS file positions from it (49F5H, 49FFH).
44D9
DEFB 05H 05
DCT+0FH of drive 3, the sectors per granule: 05H. The record locator divides by it (4D09H) and multiplies back (4DB0H).
44DA
DEFB 02H 02
DCT+10H of drive 3, the granules per cylinder: 02H. The record locator divides by it (4DA8H).
44DB
DEFB 0AH 0A
DCT+11H of drive 3, the sectors per cylinder: 0AH, ten.
44DC
DEFB 11H 11
DCT+12H of drive 3, the directory cylinder: 11H, cylinder 17. The directory routines read it at 46B4H and 4796H.
44DD
DEFB 23H 23
DCT+13H of drive 3, the cylinder count: 23H, 35 cylinders.
44DEH - Character I/O: Files, FORCE, JOIN and NIL
4033H comes to 44E1H from the ROM's device routine (03C2H) when a control block's type byte lacks the bit 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 03DDH. A file control block (type 80H) goes to the file routine at 4B8DH; 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.
44DE
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.
44DF
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 44E1H.
44E1
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).
44E4
CP 80H FE 80
Compare Register A against 80H, the type byte of an open file control block.
44E6
If the Z FLAG is set (the control block is a file: 80H), JUMP to 4B8DH to read or write the character Register C from or to the file.
44E9
LD L,(IX+01H) DD 6E 01
Load Register L with the low byte of the driver address from Index Register IX+01H.
44EC
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.
44EF
BIT 4,A CB 67
Test bit 4 of Register A, the FORCE flag of the type byte.
44F1
If the NZ FLAG is set (the device is FORCEd), JUMP back to 44DEH to go on with the DCB Register Pair HL points to.
44F3
BIT 5,A CB 6F
Test bit 5 of Register A, the JOIN flag of the type byte at Index Register IX+00H.
44F5
If the Z FLAG is set (not JOINed), JUMP to 4507H; Register Pair HL is the device's own driver.
44F7
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.
44F8
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.
44F9
INC HL 23
INCrement Register Pair HL by 1 to the high byte of the linking DCB address.
44FA
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.
44FB
INC HL 23
INCrement Register Pair HL by 1 to ENTRY+06H, the driver address saved by the JOIN.
44FC
PUSH DE D5
Save Register Pair DE (the linking DCB) to the top of the stack, for 4514H.
44FD
LD E,(HL) 5E
Load Register E with the low byte of the saved driver address from Register Pair HL.
44FE
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
44FF
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the device's own driver.
4500
INC HL 23
INCrement Register Pair HL by 1 to ENTRY+08H, the type byte saved by the JOIN.
4501
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.
4502
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the device's own driver.
4503
LD DE,4514H 11 14 45
Load Register Pair DE with 4514H, where the driver is to return so the linked device is served next.
4506
PUSH DE D5
Save Register Pair DE (4514H) to the top of the stack as the driver's return address.
4507
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.
4508
RET Z C8
If the Z FLAG is set, RETurn to the caller: the driver cannot do the I/O asked for.
4509
LD A,(IX+00H) DD 7E 00
Load Register A with the type byte at Index Register IX+00H again.
450C
CPL 2F
Complement Register A, so a set NIL bit (bit 3) becomes 0.
450D
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.
450F
RET Z C8
If the Z FLAG is set (a NIL device), RETurn to the caller with nothing done.
4510
LD A,B 78
Load Register A with Register B, the I/O type.
4511
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).
4513
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 4511H.
4514
POP IX DD E1
A JOINed device's driver returns here (4503H): restore Index Register IX from the top of the stack, the linking DCB pushed at 44FCH.
4516
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.
4517
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.
4518
LD A,B 78
Load Register A with Register B, the I/O type.
4519
CP 02H FE 02
Compare Register A against 02H. The C FLAG is set for input.
451B
If the C FLAG is set (Register B was 01H, an input), JUMP to 4520H.
451D
POP AF F1
Output or control: restore Register Pair AF from the top of the stack (the first device's result is not kept).
451E
JUMP to 44E1H to do the same output or control with the linked device at Index Register IX.
4520
POP AF F1
Input: restore Register Pair AF from the top of the stack, the result of the first device.
4521
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.
4522
RET NZ C0
If the NZ FLAG is set (the first device gave a character), RETurn with it in Register A.
4523
JUMP to 44E1H to ask the linked device at Index Register IX for a character instead.
4525H - Call a Routine With the Registers Saved
Called with the address of a routine on the stack under the return address: CALL 4525H 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. DISKIO% (465FH), DSPLY@ and PRINT@ (4542H), the logging routine (46D0H) and 48C7H use it.
4525
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 4525H, and the old Register Pair HL goes to the stack.
4526
LD (4532H),HL 22 32 45
Store Register Pair HL into the operand of the CALL at 4531H (4532H-4533H), so 4531H calls the code after the caller's CALL 4525H.
4529
POP HL E1
Restore Register Pair HL from the top of the stack, the value it had at the CALL.
452A
PUSH BC C5
Save Register Pair BC to the top of the stack.
452B
PUSH DE D5
Save Register Pair DE to the top of the stack.
452C
PUSH HL E5
Save Register Pair HL to the top of the stack.
452D
PUSH IX DD E5
Save Index Register IX to the top of the stack.
452F
PUSH IY FD E5
Save Index Register IY to the top of the stack.
4531
GOSUB to the routine whose address 4526H stored into this operand (0000H in the file), with all registers as the caller left them.
4534
POP IY FD E1
Restore Index Register IY from the top of the stack.
4536
POP IX DD E1
Restore Index Register IX from the top of the stack.
4538
POP HL E1
Restore Register Pair HL from the top of the stack.
4539
POP DE D1
Restore Register Pair DE from the top of the stack.
453A
POP BC C1
Restore Register Pair BC from the top of the stack.
453B
RET C9
RETurn to the caller of the routine that called 4525H, with Register Pair AF as the wrapped routine left it.
453CH - 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.
453C
LD A,02H 3E 02
PRINT@: load Register A with 02H, the device number of @PR.
453E
JUMP to 4542H with Register A = 02H, the printer, to share the text loop.
4540
LD A,01H 3E 01
DSPLY@: load Register A with 01H, the device number of @DO.
4542
GOSUB to 4525H, which calls 4545H with the registers saved and, when the text is out, returns to the caller of DSPLY@ or PRINT@ with them restored.
4545
GOSUB to 456FH (LOCDCB%) to load Register Pair DE with the DCB address of device Register A.
4548
LD A,(HL) 7E
Load Register A with the next character of the text at Register Pair HL.
4549
CP 03H FE 03
Compare Register A against 03H, the end of text character that leaves the cursor where it is.
454B
RET Z C8
If the Z FLAG is set (03H), RETurn: the 03H is not output.
454C
PUSH AF F5
Save Register Pair AF (Register A the character) to the top of the stack.
454D
GOSUB to the ROM's output routine at 001BH, which sends Register A to the control block at Register Pair DE.
4550
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the character just output.
4551
INC HL 23
INCrement Register Pair HL by 1 to the next character.
4552
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return.
4554
If the NZ FLAG is set (not a carriage return), JUMP back to 4548H for the next character.
4556
RET C9
RETurn: the 0DH has been output and ends the text.
4557H - LOCDCT% and LOCDCB%
LOCDCT% (448BH): Index Register IY = the drive control table address of drive Register C, from DCTTBL at 43ABH. LOCDCB% (4488H): Register Pair DE = the DCB address of device Register A, from the DCB table at 4369H.
4557
PUSH DE D5
LOCDCT%: save Register Pair DE to the top of the stack.
4558
LD IY,43ABH FD 21 AB 43
Point Index Register IY to 43ABH, the start of DCTTBL.
455C
LD A,C 79
Load Register A with Register C, the drive number.
455D
ADD A,A 87
Double Register A: Register A = the drive number times 2.
455E
ADD A,A 87
Double Register A again: Register A = the drive times 4, the offset of its 4 byte entry.
455F
LD E,A 5F
Load Register E with Register A, the offset of the entry in DCTTBL.
4560
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the offset.
4562
ADD IY,DE FD 19
ADD Register Pair DE to Index Register IY: Index Register IY points to the drive's DCTTBL entry.
4564
LD E,(IY+00H) FD 5E 00
Load Register E with the low byte of the DCT address from Index Register IY+00H.
4567
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.
456A
PUSH DE D5
Save Register Pair DE (the DCT address) to the top of the stack, to move it into Index Register IY.
456B
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.
456D
POP DE D1
Restore Register Pair DE from the top of the stack, its value at the call.
456E
RET C9
RETurn with Index Register IY pointing to the drive control table.
456F
PUSH HL E5
LOCDCB%: save Register Pair HL to the top of the stack.
4570
LD HL,4369H 21 69 43
Point Register Pair HL to 4369H, the start of the DCB table.
4573
LD E,0BH 1E 0B
Load Register E with 0BH, the length of a DCB table entry.
4575
GOSUB to 4934H to multiply Register A (the device number) by Register E: Register A = the offset of the device's entry.
4578
LD E,A 5F
Load Register E with Register A, the offset of the entry in the DCB table.
4579
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the offset.
457B
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL points to the device's DCB table entry.
457C
LD E,(HL) 5E
Load Register E with the low byte of the DCB address from Register Pair HL.
457D
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
457E
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.
457F
POP HL E1
Restore Register Pair HL from the top of the stack.
4580
RET C9
RETurn with Register Pair DE = the DCB address.
4581H - The Interrupt Handler
RST 38H (4012H) comes here for every interrupt. The handler reads the interrupt latch at 37E0H (reading it also clears the real time clock's request), calls the vector of each set and enabled latch bit, and then, when the BREAK key is down and the DEBUG on BREAK switch at 4308H is set, enters DEBUG@ in place of returning to the interrupted program.
4581
PUSH HL E5
Save Register Pair HL to the top of the stack.
4582
PUSH AF F5
Save Register Pair AF to the top of the stack.
4583
LD A,(37E0H) 3A E0 37
Load Register A with the interrupt latch at 37E0H: bit 7 the real time clock, bit 6 the floppy disk controller.
4586
LD HL,404BH 21 4B 40
Point Register Pair HL to 404BH, the latch copy.
4589
LD (HL),A 77
Store Register A (the latch) to the latch copy at Register Pair HL (404BH).
458A
INC HL 23
INCrement Register Pair HL by 1 to 404CH, the enable mask.
458B
AND (HL) A6
AND Register A with the enable mask at Register Pair HL (404CH): Register A keeps only the enabled interrupt bits.
458C
If the Z FLAG is set (no enabled interrupt is pending), JUMP to 4596H to check the BREAK key.
458E
INC HL 23
INCrement Register Pair HL by 1 to the low byte of the next vector (first 404DH, the vector of bit 0).
458F
RRA 1F
Rotate Register A right through the carry: the lowest latch bit left goes into the C FLAG.
4590
If the C FLAG is set (this bit's interrupt is pending), JUMP to 45B0H to call its vector at Register Pair HL.
4592
INC HL 23
INCrement Register Pair HL by 1 to the high byte of the vector.
4593
OR A B7
OR Register A with itself to test the latch bits left. The Z FLAG is set when none is left.
4594
If the NZ FLAG is set (a set bit remains), JUMP back to 458EH for the next vector.
4596
LD HL,3840H 21 40 38
Point Register Pair HL to 3840H, keyboard row 6 (ENTER, CLEAR, BREAK, the arrows and the space bar).
4599
BIT 2,(HL) CB 56
Test bit 2 of the keyboard row at Register Pair HL (3840H), the BREAK key.
459B
If the Z FLAG is set (BREAK is not down), JUMP to 45ACH to return to the interrupted program.
459D
LD HL,4308H 21 08 43
Point Register Pair HL to 4308H, the DEBUG on BREAK switch.
45A0
XOR A AF
Set Register A to 00H by XORing it with itself.
45A1
CP (HL) BE
Compare Register A (00H) against the switch at Register Pair HL (4308H).
45A2
If the Z FLAG is set (the switch is 00H), JUMP to 45ACH: BREAK does not enter DEBUG.
45A4
LD (HL),A 77
Store Register A (00H) to the switch at Register Pair HL (4308H): the switch is used once.
45A5
LD HL,440DH 21 0D 44
Load Register Pair HL with 440DH, the DEBUG@ entry point.
45A8
POP AF F1
Restore Register Pair AF from the top of the stack, as the interrupted program had it.
45A9
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.
45AA
EI FB
Enable interrupts, which the RST 38H left disabled.
45AB
RET C9
RETurn to 440DH: DEBUG@ starts with every register as the interrupted program left it and the program's address on the stack.
45AC
POP AF F1
Restore Register Pair AF from the top of the stack.
45AD
POP HL E1
Restore Register Pair HL from the top of the stack.
45AE
EI FB
Enable interrupts, which the RST 38H left disabled.
45AF
RET C9
RETurn to the interrupted program with its registers as they were.
45B0
PUSH AF F5
Save Register Pair AF (Register A the latch bits still to serve) to the top of the stack.
45B1
PUSH BC C5
Save Register Pair BC to the top of the stack.
45B2
PUSH DE D5
Save Register Pair DE to the top of the stack.
45B3
PUSH HL E5
Save Register Pair HL (the address of the vector) to the top of the stack.
45B4
PUSH IX DD E5
Save Index Register IX to the top of the stack. Index Register IY is not saved: an interrupt routine must leave it alone.
45B6
LD DE,45BFH 11 BF 45
Load Register Pair DE with 45BFH, where the vector's routine is to return.
45B9
PUSH DE D5
Save Register Pair DE (45BFH) to the top of the stack as the return address.
45BA
LD E,(HL) 5E
Load Register E with the low byte of the vector from Register Pair HL.
45BB
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
45BC
LD D,(HL) 56
Load Register D with the high byte of the vector from Register Pair HL: Register Pair DE = the routine.
45BD
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the routine.
45BE
JP (HL) E9
JUMP to the routine at Register Pair HL, which returns to 45BFH.
45BF
POP IX DD E1
Restore Index Register IX from the top of the stack.
45C1
POP HL E1
Restore Register Pair HL (the address of the vector) from the top of the stack.
45C2
POP DE D1
Restore Register Pair DE from the top of the stack.
45C3
POP BC C1
Restore Register Pair BC from the top of the stack.
45C4
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the latch bits still to serve.
45C5
JUMP back to 4592H to go on to the next vector.
45C7H - The Clock Task and the Interrupt Slots
The vector of latch bit 7 (405BH), installed by the start-up: on every tick of the real time clock (every 25 milliseconds) it runs the tasks of slots 4 and 5, the fast chain, and then one of slots 0-3, the slow chain, in turn, so each slow slot runs every 100 milliseconds. A slot holds the address of a task block whose first word is the task's address; the task runs with Index Register IX pointing to its block. SET@ and RESET@ change the slots.
45C7
LD A,04H 3E 04
Load Register A with 04H, fast slot 4, which runs on every tick.
45C9
GOSUB to 45D8H to run the task of slot Register A (4).
45CC
LD A,05H 3E 05
Load Register A with 05H, fast slot 5, which runs on every tick.
45CE
GOSUB to 45D8H to run the task of slot Register A (5).
45D1
LD HL,4040H 21 40 40
Point Register Pair HL to 4040H, the tick count.
45D4
INC (HL) 34
INCrement the tick count at Register Pair HL (4040H) by 1.
45D5
LD A,(HL) 7E
Load Register A with the tick count at Register Pair HL (4040H).
45D6
AND 03H E6 03
AND Register A with 03H: Register A = the slow slot whose turn it is (0-3); the code falls into 45D8H to run it.
45D8
ADD A,A 87
Run the task of slot Register A: double Register A, the offset of the slot's word.
45D9
LD L,A 6F
Load Register L with Register A, the offset of the slot in the slot table.
45DA
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = the offset.
45DC
LD BC,45ECH 01 EC 45
Load Register Pair BC with 45ECH, the slot table.
45DF
ADD HL,BC 09
ADD Register Pair BC to Register Pair HL: Register Pair HL points to the slot.
45E0
LD E,(HL) 5E
Load Register E with the low byte of the task block address from Register Pair HL.
45E1
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
45E2
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the task block.
45E3
PUSH DE D5
Save Register Pair DE (the task block) to the top of the stack.
45E4
POP IX DD E1
Restore Index Register IX from the top of the stack: Index Register IX = the task block, as the task expects.
45E6
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the task block.
45E7
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.
45E8
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
45E9
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the task.
45EA
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the task.
45EB
JP (HL) E9
JUMP to the task at Register Pair HL; its RET returns to the caller of 45D8H.
45EC-45ED
DEFW 460CH 0C 46
Slot 0 (slow, every 100 milliseconds): 460CH, the empty task block.
45EE-45EF
DEFW 460CH 0C 46
Slot 1 (slow): 460CH, the empty task block. The manual gives slot 1 to the cursor blink of the @DO driver.
45F0-45F1
DEFW 460CH 0C 46
Slot 2 (slow): 460CH, the empty task block. The clock display task block at 462FH is meant for this slot.
45F2-45F3
DEFW 460CH 0C 46
Slot 3 (slow): 460CH in the file; the start-up installs the time task block 460FH here (4E59H-4E5EH).
45F4-45F5
DEFW 460CH 0C 46
Slot 4 (fast, every 25 milliseconds): 460CH, the empty task block.
45F6-45F7
DEFW 460CH 0C 46
Slot 5 (fast): 460CH, the empty task block. The manual gives slot 5 to the spooler of the @PR driver.
45F8H - RESET@ and SET@
RESET@ (4413H, 4419H): put the empty task block 460CH into slot Register A. SET@ (4410H, 4416H): put the task block Register Pair DE into slot Register A. A slot number of 06H or more is ignored. Register Pair BC is altered.
45F8
LD DE,460CH 11 0C 46
RESET@: load Register Pair DE with 460CH, the empty task block, and go on into SET@.
45FB
CP 06H FE 06
SET@: compare Register A (the slot) against 06H, the number of slots.
45FD
RET NC D0
If the NC FLAG is set (slot 6 or more), RETurn with nothing changed.
45FE
ADD A,A 87
Double Register A, the offset of the slot's word.
45FF
LD L,A 6F
Load Register L with Register A, the offset of the slot in the slot table.
4600
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = the offset.
4602
LD BC,45ECH 01 EC 45
Load Register Pair BC with 45ECH, the slot table.
4605
ADD HL,BC 09
ADD Register Pair BC to Register Pair HL: Register Pair HL points to the slot.
4606
DI F3
Disable interrupts, so the clock task cannot run the slot while its two bytes are changed.
4607
LD (HL),E 73
Store Register E, the low byte of the task block, to the slot at Register Pair HL.
4608
INC HL 23
INCrement Register Pair HL by 1 to the high byte of the slot.
4609
LD (HL),D 72
Store Register D, the high byte of the task block, to the slot at Register Pair HL.
460A
EI FB
Enable interrupts again: the slot holds the new task block.
460B
RET C9
RETurn to the caller of SET@ or RESET@ with the slot changed.
460C-460D
DEFW 460EH 0E 46
The empty task block: its task address is 460EH, a RET. Every slot and every interrupt vector starts with it.
460E
RET C9
RETurn at once: the empty task and the empty interrupt vector, which do nothing.
460FH - The Time Task
Task block 460FH, which the start-up puts into slot 3: every 100 milliseconds its task counts down the byte at 4611H, and on every tenth call it adds one second to TIME$ (4041H-4043H), carrying into the minutes and hours.
460F-4610
DEFW 4612H 12 46
The time task block: the task address, 4612H.
4611
DEFB 0AH 0A
The task block's count of calls left to the next second: 0AH, ten calls of 100 milliseconds.
4612
DEC (IX+02H) DD 35 02
DECrement the count at Index Register IX+02H (4611H) by 1.
4615
RET NZ C0
If the NZ FLAG is set (the second is not over), RETurn.
4616
LD (IX+02H),0AH DD 36 02 0A
Store 0AH into the count at Index Register IX+02H (4611H) for the next second.
461A
LD DE,462CH 11 2C 46
Point Register Pair DE to 462CH, the limits of the seconds, minutes and hours.
461D
LD HL,4041H 21 41 40
Point Register Pair HL to 4041H, the seconds of TIME$.
4620
LD B,03H 06 03
Load Register B with 03H, the three fields to count: seconds, minutes, hours.
4622
INC (HL) 34
INCrement the field at Register Pair HL by 1.
4623
LD A,(DE) 1A
Load Register A with the field's limit from Register Pair DE.
4624
SUB (HL) 96
SUBtract the field at Register Pair HL from Register A. The Z FLAG is set when the field has reached its limit.
4625
RET NZ C0
If the NZ FLAG is set (no carry into the next field), RETurn.
4626
LD (HL),A 77
Store Register A (00H) to the field at Register Pair HL: it starts again from zero.
4627
INC HL 23
INCrement Register Pair HL by 1 to the next field.
4628
INC DE 13
INCrement Register Pair DE by 1 to the next limit.
4629
DECrement Register B and loop back to 4622H while Register B is not zero, to carry into the next field.
462B
RET C9
RETurn: at 24 hours the hours go back to 00H; the date is not changed.
462C-462E
DEFB 3CH, 3CH, 18H 3C 3C 18
The limits of the time fields: 60 seconds, 60 minutes, 24 hours.
462FH - The Clock Display Task, GTTIME@ and GTDATE@
Task block 462FH: every tenth call its task writes the time into the top line of the screen at 3C35H. GTTIME@ (446DH) writes TIME$ at Register Pair HL as HH:MM:SS, GTDATE@ (4470H) writes DATE$ as MM/DD/YY; both leave Register Pair HL after the last digit.
462F-4630
DEFW 4632H 32 46
The clock display task block: the task address, 4632H.
4631
DEFB 0AH 0A
The task block's count of calls left to the next display: 0AH.
4632
DEC (IX+02H) DD 35 02
DECrement the count at Index Register IX+02H (4631H) by 1.
4635
RET NZ C0
If the NZ FLAG is set (not yet the tenth call), RETurn.
4636
LD (IX+02H),0AH DD 36 02 0A
Store 0AH into the count at Index Register IX+02H (4631H).
463A
LD HL,3C35H 21 35 3C
Point Register Pair HL to 3C35H, column 53 of the top line of the screen, and go on into GTTIME@ to write the time there.
463D
LD DE,4043H 11 43 40
GTTIME@: point Register Pair DE to 4043H, the hours of TIME$, the first field written.
4640
LD C,3AH 0E 3A
Load Register C with 3AH, the colon written between the fields.
4642
LD B,03H 06 03
Load Register B with 03H, the three fields to write, each as two digits.
4644
LD A,(DE) 1A
Load Register A with the field at Register Pair DE.
4645
DEC DE 1B
DECrement Register Pair DE by 1 to the next field (TIME$ and DATE$ are written from their highest byte down).
4646
LD (HL),2FH 36 2F
Store 2FH, the character below 0, to Register Pair HL, the tens digit.
4648
INC (HL) 34
INCrement the tens digit at Register Pair HL by 1.
4649
SUB 0AH D6 0A
SUBtract 0AH from Register A, the field, one ten at a time.
464B
If the NC FLAG is set (Register A was 10 or more), JUMP back to 4648H to count another ten.
464D
ADD A,3AH C6 3A
ADD 3AH to Register A: Register A (the units less ten) becomes the ASCII units digit.
464F
INC HL 23
INCrement Register Pair HL by 1 to the units position.
4650
LD (HL),A 77
Store Register A, the units digit, to Register Pair HL.
4651
INC HL 23
INCrement Register Pair HL by 1 past the digits.
4652
DEC B 05
DECrement Register B, the count of fields still to write.
4653
RET Z C8
If the Z FLAG is set (all three fields written), RETurn.
4654
LD (HL),C 71
Store Register C, the separator (a colon or a slash), to Register Pair HL.
4655
INC HL 23
INCrement Register Pair HL by 1 past the separator.
4656
JUMP back to 4644H to write the next field after the separator.
4658
LD DE,4046H 11 46 40
GTDATE@: point Register Pair DE to 4046H, the month of DATE$, the first field written.
465B
LD C,2FH 0E 2F
Load Register C with 2FH, the slash written between the fields.
465D
JUMP to 4642H to write the month, day and year fields of DATE$.
465FH - DISKIO%
DISKIO% (4485H): 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 are saved around the call (4525H). A NIL drive returns error 08H; otherwise the routine jumps to the driver address in the drive's drive control table with Index Register IY pointing to the table. On return Register A is the error code and the Z FLAG is set when there was none.
465F
GOSUB to 4525H, which calls 4662H 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.
4662
PUSH AF F5
Save Register Pair AF (Register A the function) to the top of the stack.
4663
GOSUB to 4557H (LOCDCT%) to point Index Register IY to the drive control table of drive Register C.
4666
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the function.
4667
BIT 3,(IY+00H) FD CB 00 5E
Test bit 3, the NIL flag, of the type byte at Index Register IY+00H.
466B
If the Z FLAG is set (the drive is not NIL), JUMP to 4670H.
466D
LD A,08H 3E 08
Load Register A with 08H, the error code for a drive that is not available; the NZ FLAG from 4667H stays set.
466F
RET C9
RETurn with Register A = 08H and the NZ FLAG set.
4670
PUSH HL E5
Save Register Pair HL (the buffer) to the top of the stack.
4671
LD L,(IY+01H) FD 6E 01
Load Register L with the low byte of the driver address from Index Register IY+01H.
4674
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.
4677
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.
4678
RET C9
RETurn, which jumps to the driver (4679H for drives 0-3) with Register A the function and Index Register IY the drive control table.
4679H - The Floppy Disk Driver: Function Dispatch
The driver of the drive control tables at 448EH-44DDH. Register A (the function, 0-9) picks the routine from the table at 4689H; the routine is entered by a RET with Register Pair HL restored.
4679
PUSH HL E5
Save Register Pair HL (the buffer) to the top of the stack.
467A
LD HL,4689H 21 89 46
Point Register Pair HL to 4689H, the table of the ten function routines.
467D
ADD A,A 87
Double Register A, the function: Register A = the offset of its word in the table.
467E
ADD A,L 85
ADD Register L (89H, the low byte of 4689H) to Register A.
467F
LD L,A 6F
Load Register L with Register A, the low byte of the table entry's address.
4680
If the NC FLAG is set (no carry from the low byte), JUMP to 4683H.
4682
INC H 24
INCrement Register H by 1, the carry into the high byte of the entry's address.
4683
LD A,(HL) 7E
Load Register A with the low byte of the routine's address from the table entry at Register Pair HL.
4684
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
4685
LD H,(HL) 66
Load Register H with the high byte of the routine's address from Register Pair HL.
4686
LD L,A 6F
Load Register L with Register A: Register Pair HL = the function's routine.
4687
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.
4688
RET C9
RETurn, which jumps to the function's routine.
4689-468A
DEFW 46EEH EE 46
Function 0, DCHECK, test whether the drive is ready: 46EEH.
468B-468C
DEFW 4717H 17 47
Function 1, DHOME, restore the head to cylinder 0: 4717H.
468D-468E
DEFW 473DH 3D 47
Function 2, DSEEK, seek cylinder Register D and set up sector Register E: 473DH.
468F-4690
DEFW 4781H 81 47
Function 3, DREAD, read a sector into the buffer, five tries: 4781H.
4691-4692
DEFW 4788H 88 47
Function 4, DVERF, read a sector back to verify it, one try: 4788H.
4693-4694
DEFW 478FH 8F 47
Function 5, DWRITE, write the buffer to a sector, five tries: 478FH.
4695-4696
DEFW 469DH 9D 46
Function 6, SREAD, read a sector of the directory cylinder: 469DH.
4697-4698
DEFW 4796H 96 47
Function 7, SWRITE, write a sector of the directory cylinder: 4796H.
4699-469A
DEFW 4799H 99 47
Function 8, DWRITA, write a sector with the directory's data address mark: 4799H.
469B-469C
DEFW 47A0H A0 47
Function 9, DFORMT, write a whole track: 47A0H.
469DH - 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 a special data address mark, so a good directory read ends in error 06H (the record type status), which SREAD turns into success. When the read fails the density is switched and the read tried again (46BEH). A drive whose log flag (bit 0 of DCT+03H) is set is logged first: the density and geometry are found from cylinder 0, sector 0 (46CCH).
469D
GOSUB to 46ACH 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.
46A0
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.
46A2
RET Z C8
If the Z FLAG is set, RETurn with Register A = 00H, success.
46A3
GOSUB to 46B0H to read the sector again (after 46BEH may have switched the density).
46A6
SUB 06H D6 06
SUBtract 06H from Register A. The Z FLAG is set when the directory mark was read this time.
46A8
RET Z C8
If the Z FLAG is set, RETurn with Register A = 00H, success.
46A9
LD A,11H 3E 11
Load Register A with 11H, the error code for a directory read error; the NZ FLAG from 46A6H stays set.
46AB
RET C9
RETurn with Register A = 11H and the NZ FLAG set.
46AC
BIT 0,(IY+03H) FD CB 03 46
Test bit 0 of the drive flags at Index Register IY+03H, the log flag.
46B0
If the NZ FLAG is set (the diskette is to be logged), GOSUB to 46CCH to log it.
46B3
RET NZ C0
If the NZ FLAG is set (the logging failed), RETurn with its error code in Register A.
46B4
LD D,(IY+12H) FD 56 12
Load Register D with the directory cylinder from Index Register IY+12H.
46B7
GOSUB to 4788H (DVERF) to read cylinder Register D, sector Register E into the buffer at Register Pair HL, one try.
46BA
RET Z C8
If the Z FLAG is set (the sector was read with a normal data address mark), RETurn with Register A = 00H.
46BB
CP 06H FE 06
Compare Register A, the error code, against 06H, the record type error the directory mark gives.
46BD
RET Z C8
If the Z FLAG is set (the directory mark was read), RETurn with Register A = 06H.
46BE
LD A,(IY+0BH) FD 7E 0B
Any other error: load Register A with the diskette flags at Index Register IY+0BH.
46C1
XOR 80H EE 80
XOR Register A with 80H to switch bit 7, the density.
46C3
LD (IY+0BH),A FD 77 0B
Store Register A back to the diskette flags at Index Register IY+0BH.
46C6
GOSUB to 48C7H to set the diskette's geometry (DCT+0BH-11H) for the new density.
46C9
JUMP to 4788H to read the sector once more in the new density; its result is returned.
46CC
RES 7,(IY+0BH) FD CB 0B BE
Log the diskette: reset bit 7 of the diskette flags at Index Register IY+0BH, so the first try is single density.
46D0
GOSUB to 4525H, which calls 46D3H with the registers saved and returns to the caller of 46CCH.
46D3
GOSUB to 48C7H to set the geometry of a single density diskette.
46D6
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H: Register D = cylinder 0, Register E = sector 0, the boot sector.
46D9
GOSUB to 4717H (DHOME) to restore the head to cylinder 0.
46DC
GOSUB to 46B7H to read cylinder 0, sector 0 into the buffer at Register Pair HL, switching the density once when the read fails.
46DF
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.
46E0
INC HL 23
INCrement Register Pair HL by 1, into the boot sector just read.
46E1
INC HL 23
INCrement Register Pair HL by 1 to its byte 2, the directory cylinder FORMAT writes there.
46E2
LD A,(HL) 7E
Load Register A with the directory cylinder from Register Pair HL.
46E3
AND 7FH E6 7F
AND Register A with 7FH to drop bit 7 of the directory cylinder byte.
46E5
LD (IY+12H),A FD 77 12
Store Register A to the directory cylinder at Index Register IY+12H.
46E8
RES 0,(IY+03H) FD CB 03 86
Reset bit 0 of the drive flags at Index Register IY+03H: the diskette is logged.
46EC
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: no error.
46ED
RET C9
RETurn with Register A = 00H: the diskette is logged.
46EEH - 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 (or the drive's write protect flag in DCT+03H) is write protected. With no index pulse before the count at 46F4H runs out, Register A returns FFH with the NZ FLAG set.
46EE
GOSUB to 484CH to select the drive, set the density and wait for the motor when the drive needs it.
46F1
GOSUB to 48B1H to send two Force Interrupt commands (D0H), which leave the controller showing the drive's status.
46F4
LD HL,3155H 21 55 31
Load Register Pair HL with 3155H, the count of status reads to wait for the index pulses.
46F7
GOSUB to 4709H to count down and read the status; the Z FLAG is set when the index bit is off.
46FA
If the NZ FLAG is set (the index hole is under the sensor), JUMP back to 46F7H until it has gone by.
46FC
GOSUB to 4709H to count down and read the status again.
46FF
If the Z FLAG is set (no index yet), JUMP back to 46FCH until the next index pulse.
4701
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).
4704
RLCA 07
Rotate Register A left: bit 6, write protected, moves to bit 7.
4705
AND 80H E6 80
AND Register A with 80H to keep only the write protect bit.
4707
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.
4708
RET C9
RETurn: Register A = 00H, the Z FLAG set (ready) and the C FLAG set when write protected.
4709
DEC HL 2B
DECrement Register Pair HL, the count of status reads left, by 1.
470A
LD A,H 7C
Load Register A with Register H, the high byte of the count.
470B
OR L B5
OR Register A with Register L. The Z FLAG is set when the count in Register Pair HL has run out.
470C
If the Z FLAG is set (no index pulses in time), JUMP to 4714H.
470E
LD A,(37ECH) 3A EC 37
Load Register A with the controller status at 37ECH.
4711
BIT 1,A CB 4F
Test bit 1 of Register A, the index bit of the status after a Force Interrupt.
4713
RET C9
RETurn with the Z FLAG set when the index bit is off.
4714
POP HL E1
Restore Register Pair HL from the top of the stack: the return into the wait loop is dropped.
4715
DEC A 3D
DECrement Register A (00H) by 1: Register A = FFH and the NZ FLAG set, the drive is not ready.
4716
RET C9
RETurn to the caller of DISKIO% with Register A = FFH.
4717H - DHOME, and Waiting for a Command
Function 1: send the Restore command and wait for it. 4723H sends any command in Register A and waits while the controller is busy, keeping the drive selected so its motor stays on; 4737H returns the status AND 98H (not ready, seek error, CRC error). 4737H is also the interrupt vector of the floppy disk controller (4059H): reading the status clears its interrupt.
4717
GOSUB to 484CH to select the drive, set the density and wait for the motor when the drive needs it.
471A
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.
471E
LD A,(IY+04H) FD 7E 04
Load Register A with the step rate code from Index Register IY+04H.
4721
OR 08H F6 08
OR Register A with 08H: Register A = the Restore command with the head loaded and the drive's step rate.
4723
GOSUB to 48BEH to send the command in Register A to the controller at 37ECH.
4726
LD A,(37ECH) 3A EC 37
Load Register A with the controller status at 37ECH.
4729
RRCA 0F
Rotate Register A right: bit 0, BUSY, goes into the C FLAG.
472A
If the C FLAG is set (still busy), GOSUB to 4884H to select the drive again, which keeps its motor running.
472D
If the C FLAG is set (still busy), JUMP back to 4726H.
472F
PUSH BC C5
Save Register Pair BC to the top of the stack.
4730
LD BC,08FCH 01 FC 08
Load Register Pair BC with 08FCH, the length of the delay.
4733
GOSUB to the ROM's delay at 0060H, which counts Register Pair BC down to zero: the head settles.
4736
POP BC C1
Restore Register Pair BC from the top of the stack.
4737
LD A,(37ECH) 3A EC 37
Load Register A with the controller status at 37ECH (as the interrupt vector, this read clears the controller's interrupt).
473A
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.
473C
RET C9
RETurn with Register A = the error bits of the status.
473DH - DSEEK
Function 2: select the drive and the side, put the sector in the sector register and, unless the head is already there, seek cylinder Register D (two steps a cylinder when DCT+03H bit 2 asks for it). A sector number at or above the sectors per track is on side 1. Register A returns the status AND 98H, or 00H when no seek was needed.
473D
GOSUB to 484CH to select the drive, set the density and wait for the motor when the drive needs it.
4740
PUSH DE D5
Save Register Pair DE (Register D the cylinder, Register E the sector) to the top of the stack.
4741
PUSH HL E5
Save Register Pair HL (the buffer) to the top of the stack.
4742
LD HL,4301H 21 01 43
Point Register Pair HL to 4301H, the drive select value 484CH has just built.
4745
LD A,E 7B
Load Register A with Register E, the sector number given.
4746
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.
4749
If the C FLAG is set (side 0), JUMP to 474EH.
474B
SET 3,(HL) CB DE
Side 1: set bit 3, the side select, of the drive select value at Register Pair HL (4301H).
474D
LD E,A 5F
Load Register E with Register A, the sector number within side 1.
474E
LD A,E 7B
Load Register A with Register E, the sector within its side.
474F
LD (37EEH),A 32 EE 37
Store Register A to the controller's sector register at 37EEH.
4752
GOSUB to 4884H to send the drive select value (with the side) to 37E1H.
4755
POP HL E1
Restore Register Pair HL (the buffer) from the top of the stack.
4756
POP DE D1
Restore Register Pair DE from the top of the stack: Register D = the cylinder, Register E = the sector as given.
4757
LD A,(37EDH) 3A ED 37
Load Register A with the controller's track register at 37EDH, the cylinder the head is over.
475A
SUB D 92
SUBtract Register D, the cylinder wanted, from Register A. The Z FLAG is set when the head is already there.
475B
RET Z C8
If the Z FLAG is set, RETurn with Register A = 00H: no seek is needed.
475C
BIT 2,(IY+03H) FD CB 03 56
Test bit 2 of the drive flags at Index Register IY+03H, the double step switch.
4760
LD A,D 7A
Load Register A with Register D, the cylinder wanted.
4761
If the Z FLAG is set (no double step), JUMP to 476CH.
4763
LD A,(37EDH) 3A ED 37
Double step: load Register A with the track register at 37EDH.
4766
ADD A,A 87
Double Register A: the head's position in physical tracks.
4767
LD (37EDH),A 32 ED 37
Store Register A back to the track register at 37EDH.
476A
LD A,D 7A
Load Register A with Register D, the cylinder wanted.
476B
ADD A,A 87
Double Register A: the physical track wanted.
476C
LD (37EFH),A 32 EF 37
Store Register A, the track to seek, to the controller's data register at 37EFH.
476F
LD A,(IY+04H) FD 7E 04
Load Register A with the step rate code from Index Register IY+04H.
4772
OR 18H F6 18
OR Register A with 18H: Register A = the Seek command with the head loaded and the drive's step rate.
4774
GOSUB to 4723H to send the command in Register A and wait for it; Register A returns the status AND 98H.
4777
PUSH AF F5
Save Register Pair AF (the result) to the top of the stack.
4778
LD (IY+09H),D FD 72 09
Store Register D, the cylinder, to the head position at Index Register IY+09H.
477B
LD A,D 7A
Load Register A with Register D, the cylinder.
477C
LD (37EDH),A 32 ED 37
Store Register A to the track register at 37EDH, so it holds the cylinder (not the doubled track).
477F
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the status AND 98H.
4780
RET C9
RETurn with the Z FLAG set when the seek succeeded.
4781H - The Sector Functions and Their Parameter Blocks
Functions 3, 4, 5, 7, 8 and 9 each call 47A7H with a four byte parameter block after the CALL: +00H the controller command, +01H the number of tries, +02H the first error code, +03H the kind of transfer (bit 0 set for a read). 47A7H takes the block's address from the stack and does not return to it.
4781
DREAD: GOSUB to 47A7H with the parameter block at 4784H.
4784-4787
DEFB 88H, 05H, 01H, 01H 88 05 01 01
The DREAD parameters: command 88H (Read Sector), five tries, first error code 01H, a read.
4788
DVERF: GOSUB to 47A7H with the parameter block at 478BH.
478B-478E
DEFB 88H, 01H, 01H, 01H 88 01 01 01
The DVERF parameters: command 88H (Read Sector), one try, first error code 01H, a read.
478F
DWRITE: GOSUB to 47A7H with the parameter block at 4792H.
4792-4795
DEFB A8H, 05H, 09H, 02H A8 05 09 02
The DWRITE parameters: command A8H (Write Sector with the normal data address mark), five tries, first error code 09H, a write.
4796
LD D,(IY+12H) FD 56 12
SWRITE: load Register D with the directory cylinder from Index Register IY+12H and go on into DWRITA.
4799
DWRITA: GOSUB to 47A7H with the parameter block at 479CH.
479C-479F
DEFB A9H, 05H, 09H, 02H A9 05 09 02
The DWRITA and SWRITE parameters: command A9H (Write Sector with the special data address mark the directory uses), five tries, first error code 09H, a write.
47A0
DFORMT: GOSUB to 47A7H with the parameter block at 47A3H.
47A3-47A6
DEFB F0H, 05H, 09H, 04H F0 05 09 04
The DFORMT parameters: command F0H (Write Track), five tries, first error code 09H, a write (bit 0 clear).
47A7H - 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), the command sent with interrupts off, and each byte moved between the controller's data register 37EFH and the buffer while DATA REQUEST is set, until BUSY goes off. A failed try is retried, after a restore unless the error was lost data; write protect and the record type of a read 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.
47A7
POP IX DD E1
Restore Index Register IX from the top of the stack: Index Register IX = the address after the CALL, the parameter block.
47A9
BIT 0,(IX+03H) DD CB 03 46
Test bit 0 of the kind of transfer at Index Register IX+03H. The NZ FLAG is set for a read.
47AD
If the NZ FLAG is set (a read), JUMP to 47B7H.
47AF
LD A,(IY+03H) FD 7E 03
A write: load Register A with the drive flags at Index Register IY+03H.
47B2
AND 40H E6 40
AND Register A with 40H, the drive's write protect flag.
47B4
If the NZ FLAG is set (write protected), JUMP to 4842H to turn Register A (40H, bit 6) into the error code: 09H + 6 = 0FH.
47B7
LD B,(IX+01H) DD 46 01
Load Register B with the number of tries from Index Register IX+01H.
47BA
GOSUB to 473DH (DSEEK) to select the drive and side, load the sector register and seek cylinder Register D.
47BD
If the NZ FLAG is set (the seek failed), JUMP to 4842H to make the error code from the status bits in Register A.
47C0
PUSH BC C5
Save Register Pair BC (Register B the tries left) to the top of the stack.
47C1
PUSH DE D5
Save Register Pair DE (the cylinder and sector) to the top of the stack.
47C2
PUSH HL E5
Save Register Pair HL (the buffer) to the top of the stack.
47C3
LD B,H 44
Load Register B with Register H, the high byte of the buffer.
47C4
LD C,L 4D
Load Register C with Register L: Register Pair BC = the buffer pointer.
47C5
LD DE,37EFH 11 EF 37
Point Register Pair DE to 37EFH, the controller's data register.
47C8
LD HL,37ECH 21 EC 37
Point Register Pair HL to 37ECH, the controller's command and status register.
47CB
BIT 0,(IX+03H) DD CB 03 46
Test bit 0 of the kind of transfer at Index Register IX+03H. The Z FLAG is set for a write.
47CF
If the Z FLAG is set (a write), JUMP to 47EFH.
47D1
Read: GOSUB to 48BAH to send the command at Index Register IX+00H (88H) with interrupts disabled.
47D4
LD A,(HL) 7E
Load Register A with the status at Register Pair HL (37ECH).
47D5
AND 03H E6 03
AND Register A with 03H to keep bit 1, DATA REQUEST, and bit 0, BUSY.
47D7
If the parity is odd (exactly one of the two bits is set: busy and no byte yet), JUMP back to 47D4H. The loop ends when the first byte is ready or the command has ended.
47DA
LD A,(DE) 1A
Load Register A with the byte in the data register at Register Pair DE (37EFH).
47DB
LD (BC),A 02
Store Register A to the buffer at Register Pair BC.
47DC
INC BC 03
INCrement Register Pair BC by 1 to the next buffer position.
47DD
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH).
47DF
If the NZ FLAG is set (the next byte is ready), JUMP back to 47DAH to take it.
47E1
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH) again.
47E3
If the NZ FLAG is set (a byte is ready), JUMP back to 47DAH to take it.
47E5
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH) a third time.
47E7
If the NZ FLAG is set (a byte is ready), JUMP back to 47DAH to take it.
47E9
BIT 0,(HL) CB 46
Test bit 0, BUSY, of the status at Register Pair HL (37ECH).
47EB
If the NZ FLAG is set (the read goes on), JUMP back to 47DDH to wait for the next byte.
47ED
JUMP to 4821H: BUSY is off and the read has ended.
47EF
Write: GOSUB to 48BAH to send the command at Index Register IX+00H (A8H, A9H or F0H) with interrupts disabled.
47F2
LD A,(BC) 0A
Load Register A with the first byte to write from the buffer at Register Pair BC.
47F3
BIT 0,(HL) CB 46
Test bit 0, BUSY, of the status at Register Pair HL (37ECH).
47F5
If the Z FLAG is set (the command has already ended, an error), JUMP to 4821H.
47F7
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH).
47F9
If the Z FLAG is set (the controller does not want a byte yet), JUMP back to 47F3H.
47FB
LD (DE),A 12
Store Register A, the first byte, to the data register at Register Pair DE (37EFH).
47FC
INC BC 03
INCrement Register Pair BC by 1 to the next buffer position.
47FD
LD A,(BC) 0A
Load Register A with the next byte from the buffer at Register Pair BC.
47FE
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH).
4800
If the Z FLAG is set (not wanted yet), JUMP back to 47FEH.
4802
LD (DE),A 12
Store Register A to the data register at Register Pair DE (37EFH).
4803
INC BC 03
INCrement Register Pair BC by 1 to the next buffer position.
4804
LD A,(BC) 0A
Load Register A with the next byte from the buffer at Register Pair BC, ready before the controller asks for it.
4805
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH).
4807
If the NZ FLAG is set (the byte is wanted), JUMP back to 4802H to store it.
4809
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH), a second time.
480B
If the NZ FLAG is set (the byte is wanted), JUMP back to 4802H to store it.
480D
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH), a third time.
480F
If the NZ FLAG is set (the byte is wanted), JUMP back to 4802H to store it.
4811
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH), a fourth time.
4813
If the NZ FLAG is set (the byte is wanted), JUMP back to 4802H to store it.
4815
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH), a fifth time.
4817
If the NZ FLAG is set (the byte is wanted), JUMP back to 4802H to store it.
4819
BIT 1,(HL) CB 4E
Test bit 1, DATA REQUEST, of the status at Register Pair HL (37ECH), a sixth time.
481B
If the NZ FLAG is set (the byte is wanted), JUMP back to 4802H to store it.
481D
BIT 0,(HL) CB 46
Test bit 0, BUSY, of the status at Register Pair HL (37ECH).
481F
If the NZ FLAG is set (the write goes on), JUMP back to 4805H.
4821
LD A,(HL) 7E
Load Register A with the final status at Register Pair HL (37ECH).
4822
EI FB
Enable interrupts, disabled since the command was sent (48BDH).
4823
POP HL E1
Restore Register Pair HL (the buffer) from the top of the stack.
4824
POP DE D1
Restore Register Pair DE (the cylinder and sector) from the top of the stack.
4825
POP BC C1
Restore Register Pair BC (Register B the tries left) from the top of the stack.
4826
AND FCH E6 FC
AND Register A with FCH to drop BUSY and DATA REQUEST: the error bits of the status. The Z FLAG is set when there are none.
4828
RET Z C8
If the Z FLAG is set, RETurn with Register A = 00H: the transfer succeeded.
4829
DEC B 05
DECrement Register B, the count of tries left for this transfer.
482A
If the Z FLAG is set (no tries left), JUMP to 4842H to make the error code.
482C
BIT 2,A CB 57
Test bit 2 of Register A, LOST DATA: the buffer was not served in time.
482E
If the NZ FLAG is set (lost data), JUMP to 483FH to try again at once, without a restore.
4830
CP 20H FE 20
Compare Register A against 20H: bit 5 alone, the record type of a read (the directory mark) or a write fault.
4832
If the Z FLAG is set, JUMP to 4842H: no more tries.
4834
CP 40H FE 40
Compare Register A against 40H: bit 6 alone, the other record type bit of a read or write protect.
4836
If the Z FLAG is set, JUMP to 4842H: no more tries.
4838
CP 60H FE 60
Compare Register A against 60H: both record type bits.
483A
If the Z FLAG is set, JUMP to 4842H: no more tries.
483C
Any other error: GOSUB to 4717H (DHOME) to restore the head to cylinder 0 before the next try.
483F
JUMP to 47BAH to seek and try the transfer again.
4842
LD B,A 47
Make the error code: load Register B with Register A, the error bits of the status.
4843
LD A,(IX+02H) DD 7E 02
Load Register A with the first error code of the function from Index Register IX+02H (01H for reads, 09H for writes).
4846
RRC B CB 08
Rotate Register B right: the next status bit goes into the C FLAG.
4848
RET C D8
If the C FLAG is set (the lowest set error bit), RETurn with Register A = the error code and the NZ FLAG set (Register B is not zero).
4849
INC A 3C
INCrement Register A by 1 for the next status bit.
484A
JUMP back to 4846H to test the next status bit in Register B.
484CH - Selecting the Drive
Builds the drive select value at 4301H from the drive's physical number, and when the drive or its density differs from the last access (4300H) switches the double density adapter and loads the drive's head position into the track register. When the drive asks for a motor delay (DCT+03H bit 4) and reports not ready, it is selected and a delay run before the second select. 4884H sends the select value to the drive select latch 37E1H.
484C
PUSH HL E5
Save Register Pair HL to the top of the stack.
484D
GOSUB to 488BH to build the drive select value at 4301H from the physical drive number.
4850
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the drive and density of the last access.
4853
LD A,(IY+0BH) FD 7E 0B
Load Register A with the diskette flags at Index Register IY+0BH.
4856
AND 80H E6 80
AND Register A with 80H to keep bit 7, the density.
4858
OR (IY+0AH) FD B6 0A
OR Register A with the physical drive number at Index Register IY+0AH: Register A = the density and the drive.
485B
CP (HL) BE
Compare Register A against the last access at Register Pair HL (4300H).
485C
If the Z FLAG is set (the same drive and density), JUMP to 4868H.
485E
LD (HL),A 77
Store Register A to 4300H at Register Pair HL, the new drive and density.
485F
GOSUB to 489FH to switch the double density adapter to the drive's density.
4862
LD A,(IY+09H) FD 7E 09
Load Register A with the drive's head position from Index Register IY+09H.
4865
LD (37EDH),A 32 ED 37
Store Register A to the controller's track register at 37EDH: the controller now knows where this drive's head is.
4868
BIT 4,(IY+03H) FD CB 03 66
Test bit 4 of the drive flags at Index Register IY+03H, the motor delay switch.
486C
If the Z FLAG is set (no motor delay), JUMP to 487FH.
486E
LD A,(37ECH) 3A EC 37
Load Register A with the controller status at 37ECH.
4871
RLCA 07
Rotate Register A left: bit 7, NOT READY, goes into the C FLAG.
4872
If the NC FLAG is set (the drive is ready, its motor running), JUMP to 487FH.
4874
GOSUB to 4884H to select the drive, which starts its motor.
4877
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, the delay count (65536 passes).
487A
DEC HL 2B
DECrement Register Pair HL, the delay count, by 1.
487B
LD A,H 7C
Load Register A with Register H, the high byte of the count.
487C
OR L B5
OR Register A with Register L. The Z FLAG is set when Register Pair HL is zero.
487D
If the NZ FLAG is set, JUMP back to 487AH: the motor comes up to speed.
487F
GOSUB to 4884H to select the drive through the latch at 37E1H.
4882
POP HL E1
Restore Register Pair HL from the top of the stack.
4883
RET C9
RETurn with the drive selected and the density set.
4884
LD A,(4301H) 3A 01 43
Load Register A with the drive select value at 4301H.
4887
LD (37E1H),A 32 E1 37
Store Register A to the drive select latch at 37E1H: the drive is selected (its motor turned on) and, with bit 3, side 1.
488A
RET C9
RETurn with Register A = the drive select value.
488B
LD A,(IY+0AH) FD 7E 0A
Load Register A with the physical drive number at Index Register IY+0AH.
488E
AND 03H E6 03
AND Register A with 03H: the physical drives 0-3.
4890
RLCA 07
Rotate Register A left (the drive number, first of three).
4891
RLCA 07
Rotate Register A left (the drive number, second of three).
4892
RLCA 07
Rotate Register A left: the drive number is now in bits 3-4.
4893
OR C7H F6 C7
OR Register A with C7H: Register A = the second byte of a SET n,A instruction for bit n = the drive number.
4895
LD (489AH),A 32 9A 48
Store Register A to 489AH, the second byte of the SET instruction at 4899H.
4898
XOR A AF
Set Register A to 00H by XORing it with itself.
4899
SET 0,A CB C7
Set bit 0 of Register A. The bit number is the one 4895H stored, so Register A = 01H, 02H, 04H or 08H, the select bit of the drive.
489B
LD (4301H),A 32 01 43
Store Register A to the drive select value at 4301H (side 0).
489E
RET C9
RETurn with the drive select value built at 4301H.
489FH - Switching the Density, Sending a Command and Setting the Geometry
489FH writes FFH (double density) or FEH (single density) to 37ECH, the commands the double density adapter DOSPLUS ships for takes; RS/TXT on the diskette patches these bytes for the Radio Shack Double Density Kit (80H or A0H stored to 37EEH). 48BEH stores a command to 37ECH and waits for the controller to take it. 48C7H copies the diskette geometry for the density and side count of the drive control table from the table at 48F0H into DCT+0BH-11H.
489F
LD A,FFH 3E FF
Load Register A with FFH, the adapter's double density command.
48A1
BIT 7,(IY+0BH) FD CB 0B 7E
Test bit 7 of the diskette flags at Index Register IY+0BH, the density.
48A5
If the NZ FLAG is set (double density), JUMP to 48A9H with Register A = FFH.
48A7
LD A,FEH 3E FE
Load Register A with FEH, the adapter's single density command.
48A9
GOSUB to 48BEH to store Register A to 37ECH: the adapter switches density.
48AC
LD A,00H 3E 00
Load Register A with 00H for the controller's sector register.
48AE
LD (37EEH),A 32 EE 37
Store Register A (00H) to the controller's sector register at 37EEH.
48B1
LD A,D0H 3E D0
Load Register A with D0H, the Force Interrupt command with no condition, which ends any command.
48B3
GOSUB to 48BEH to send Register A (D0H) to the controller.
48B6
LD A,D0H 3E D0
Load Register A with D0H, Force Interrupt, again.
48B8
JUMP to 48BEH to send Register A (D0H) to the controller and return.
48BA
LD A,(IX+00H) DD 7E 00
Load Register A with the controller command at Index Register IX+00H, the parameter block of the function.
48BD
DI F3
Disable interrupts for the transfer; 4822H enables them again.
48BE
LD (37ECH),A 32 EC 37
Store Register A, the command, to the controller at 37ECH.
48C1
LD A,0EH 3E 0E
Load Register A with 0EH, the count of a short delay.
48C3
DEC A 3D
DECrement Register A, the count of the short delay, by 1.
48C4
If the NZ FLAG is set, JUMP back to 48C3H: the controller has time to take the command and set BUSY.
48C6
RET C9
RETurn with the command sent to the controller.
48C7
GOSUB to 4525H, which calls 48CAH with the registers saved and returns to the caller of 48C7H.
48CA
LD A,(IY+0BH) FD 7E 0B
Load Register A with the diskette flags at Index Register IY+0BH.
48CD
RLCA 07
Rotate Register A left: bit 7, the density, goes to bit 0.
48CE
RLCA 07
Rotate Register A left again: the density is now bit 1.
48CF
AND 02H E6 02
AND Register A with 02H to keep only the density bit.
48D1
LD E,A 5F
Load Register E with Register A: 00H single density, 02H double density.
48D2
LD A,(IY+0CH) FD 7E 0C
Load Register A with the surface count at Index Register IY+0CH.
48D5
DEC A 3D
DECrement Register A by 1: 00H one sided, 01H two sided.
48D6
OR E B3
OR Register A with Register E: Register A = the table entry, 0-3.
48D7
LD E,07H 1E 07
Load Register E with 07H, the length of a table entry.
48D9
GOSUB to 4934H to multiply Register A by Register E: Register A = the entry's offset.
48DC
LD E,A 5F
Load Register E with Register A, the offset of the entry in the table.
48DD
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the offset.
48DF
LD HL,48F0H 21 F0 48
Point Register Pair HL to 48F0H, the geometry table.
48E2
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL points to the entry.
48E3
LD E,0BH 1E 0B
Load Register E with 0BH, the offset of the perishable bytes of the drive control table (Register D is 00H).
48E5
ADD IY,DE FD 19
ADD Register Pair DE to Index Register IY: Index Register IY points to DCT+0BH.
48E7
PUSH IY FD E5
Save Index Register IY to the top of the stack.
48E9
POP DE D1
Restore Register Pair DE from the top of the stack: Register Pair DE = DCT+0BH, the destination.
48EA
LD BC,0007H 01 07 00
Load Register Pair BC with 0007H, the seven bytes DCT+0BH-11H.
48ED
LDIR ED B0
Copy the entry from Register Pair HL to Register Pair DE, Register Pair BC bytes: the flags, surfaces, sectors per track, directory length, sectors per granule, granules per cylinder and sectors per cylinder.
48EF
RET C9
RETurn to 4534H, where 4525H restores Index Register IY and the others.
48F0-48F6
DEFB 40H, 01H, 0AH, 0AH, 05H, 02H, 0AH 40 01 0A 0A 05 02 0A
Entry 0, single density, one side: flags 40H (protected directory), 1 surface, 10 sectors per track, a directory of 10 sectors, 5 sectors per granule, 2 granules and 10 sectors per cylinder.
48F7-48FD
DEFB 40H, 02H, 0AH, 0AH, 05H, 04H, 14H 40 02 0A 0A 05 04 14
Entry 1, single density, two sides: flags 40H, 2 surfaces, 10 sectors per track, a directory of 10 sectors, 5 sectors per granule, 4 granules and 20 sectors per cylinder.
48FE-4904
DEFB C0H, 01H, 12H, 12H, 06H, 03H, 12H C0 01 12 12 06 03 12
Entry 2, double density, one side: flags C0H (double density, protected directory), 1 surface, 18 sectors per track, a directory of 18 sectors, 6 sectors per granule, 3 granules and 18 sectors per cylinder.
4905-490B
DEFB C0H, 02H, 12H, 12H, 06H, 06H, 24H C0 02 12 12 06 06 24
Entry 3, double density, two sides: flags C0H, 2 surfaces, 18 sectors per track, a directory of 18 sectors, 6 sectors per granule, 6 granules and 36 sectors per cylinder.
490CH - Reading and Writing a Directory Entry's Sector
490CH reads, 4915H writes, the directory sector holding the entry of logical file number Register B on drive Register C, through the buffer at 4200H; 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.
490C
LD A,06H 3E 06
Load Register A with 06H, the SREAD function of DISKIO%.
490E
GOSUB to 491EH to read the directory sector of logical file number Register B.
4911
RET Z C8
If the Z FLAG is set (read), RETurn with Register Pair HL pointing to the entry.
4912
LD A,11H 3E 11
Load Register A with 11H, the error code Directory read error; the NZ FLAG stays set.
4914
RET C9
RETurn with Register A = 11H and the NZ FLAG set.
4915
LD A,07H 3E 07
Load Register A with 07H, the SWRITE function of DISKIO%.
4917
GOSUB to 491EH to write the directory sector of logical file number Register B from the buffer.
491A
RET Z C8
If the Z FLAG is set (the sector was written), RETurn with Register A = 00H.
491B
LD A,12H 3E 12
Load Register A with 12H, the error code Directory write error; the NZ FLAG stays set.
491D
RET C9
RETurn with Register A = 12H and the NZ FLAG set.
491E
PUSH DE D5
Save Register Pair DE to the top of the stack.
491F
PUSH AF F5
Save Register Pair AF (Register A the DISKIO% function) to the top of the stack.
4920
LD A,B 78
Load Register A with Register B, the logical file number.
4921
AND E0H E6 E0
AND Register A with E0H: the entry's offset within its sector (00H, 20H ... E0H).
4923
LD L,A 6F
Load Register L with Register A, the entry's offset.
4924
LD H,42H 26 42
Load Register H with 42H: Register Pair HL = 4200H plus the offset, where the entry will be in the buffer.
4926
XOR B A8
XOR Register A (the offset bits) with Register B: Register A = bits 4-0 of the logical file number.
4927
ADD A,02H C6 02
ADD 02H to Register A: Register A = the directory sector.
4929
LD E,A 5F
Load Register E with Register A, the sector for DISKIO%.
492A
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the function.
492B
PUSH HL E5
Save Register Pair HL (the entry's address) to the top of the stack.
492C
LD L,00H 2E 00
Load Register L with 00H: Register Pair HL = 4200H, the sector buffer.
492E
GOSUB to 4485H (DISKIO%) to read or write sector Register E of the directory cylinder of drive Register C at 4200H.
4931
POP HL E1
Restore Register Pair HL from the top of the stack: Register Pair HL = the entry in the buffer.
4932
POP DE D1
Restore Register Pair DE from the top of the stack.
4933
RET C9
RETurn with the Z FLAG set when DISKIO% succeeded.
4934H - The Arithmetic Routines
4934H: Register A = Register A times Register E (the low eight bits). 4943H: Register A = Register E divided by Register A, Register E = the remainder. 4957H, MULT@ (444BH): Register Pair HL times Register A, a 24 bit product in Register Pair HL (high bytes) and Register A (low byte). 4971H, DIVD@ (444EH): Register Pair HL divided by Register A, the quotient in Register Pair HL and the remainder in Register A.
4934
PUSH BC C5
Save Register Pair BC to the top of the stack.
4935
LD D,A 57
Load Register D with Register A, the multiplicand.
4936
XOR A AF
Set Register A, the product, to 00H by XORing it with itself.
4937
LD B,08H 06 08
Load Register B with 08H, the eight bits of the multiplier Register E.
4939
ADD A,A 87
Double Register A, the product so far, for the next multiplier bit.
493A
SLA E CB 23
Shift Register E left: its highest bit goes into the C FLAG.
493C
If the NC FLAG is set (the bit was 0), JUMP to 493FH.
493E
ADD A,D 82
ADD Register D, the multiplicand, to Register A.
493F
DECrement Register B and loop back to 4939H while Register B is not zero.
4941
POP BC C1
Restore Register Pair BC from the top of the stack.
4942
RET C9
RETurn with Register A = the product (Register E is 00H, Register D the multiplicand).
4943
PUSH BC C5
Save Register Pair BC to the top of the stack.
4944
LD C,A 4F
Load Register C with Register A, the divisor.
4945
LD B,08H 06 08
Load Register B with 08H, the eight bits of the dividend Register E.
4947
XOR A AF
Set Register A, the remainder, to 00H by XORing it with itself.
4948
SLA E CB 23
Shift Register E left: its highest bit goes into the C FLAG and a 0 into its bit 0.
494A
RLA 17
Rotate Register A left through the carry: the bit joins the remainder.
494B
CP C B9
Compare Register A against Register C, the divisor. The C FLAG is set when the remainder is smaller.
494C
If the C FLAG is set, JUMP to 4950H: this quotient bit is 0.
494E
SUB C 91
SUBtract Register C, the divisor, from Register A.
494F
INC E 1C
INCrement Register E by 1: this quotient bit is 1.
4950
DECrement Register B and loop back to 4948H while Register B is not zero.
4952
LD C,A 4F
Load Register C with Register A, the remainder.
4953
LD A,E 7B
Load Register A with Register E, the quotient.
4954
LD E,C 59
Load Register E with Register C, the remainder.
4955
POP BC C1
Restore Register Pair BC from the top of the stack.
4956
RET C9
RETurn with Register A = the quotient and Register E = the remainder.
4957
PUSH BC C5
MULT@: save Register Pair BC to the top of the stack.
4958
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the multiplicand.
4959
LD C,A 4F
Load Register C with Register A, the multiplier.
495A
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, the product.
495D
LD A,L 7D
Load Register A with Register L (00H), the top byte of the 24 bit product.
495E
LD B,08H 06 08
Load Register B with 08H, the eight bits of the multiplier Register C.
4960
ADD HL,HL 29
Double Register Pair HL, the low 16 bits of the product.
4961
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.
4962
RLC C CB 01
Rotate Register C left: the highest multiplier bit goes into the C FLAG.
4964
If the NC FLAG is set (the bit was 0), JUMP to 4969H.
4966
ADD HL,DE 19
ADD Register Pair DE, the multiplicand, to Register Pair HL.
4967
ADC A,00H CE 00
ADD 00H and the carry of 4966H to Register A, the top byte of the product.
4969
DECrement Register B and loop back to 4960H while Register B is not zero.
496B
LD C,A 4F
Load Register C with Register A, the top byte.
496C
LD A,L 7D
Load Register A with Register L, the low byte.
496D
LD L,H 6C
Load Register L with Register H, the middle byte.
496E
LD H,C 61
Load Register H with Register C, the top byte: Register Pair HL = the product divided by 256.
496F
POP BC C1
Restore Register Pair BC from the top of the stack.
4970
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.
4971
PUSH DE D5
DIVD@: save Register Pair DE to the top of the stack.
4972
LD D,A 57
Load Register D with Register A, the divisor.
4973
LD E,10H 1E 10
Load Register E with 10H, the sixteen bits of the dividend Register Pair HL.
4975
XOR A AF
Set Register A, the remainder, to 00H by XORing it with itself.
4976
ADD HL,HL 29
Double Register Pair HL: its highest bit goes into the C FLAG and a 0 into its bit 0.
4977
RLA 17
Rotate Register A left through the carry: the bit joins the remainder.
4978
If the C FLAG is set (the remainder overflowed eight bits, so it is larger than the divisor), JUMP to 497DH.
497A
CP D BA
Compare Register A against Register D, the divisor.
497B
If the C FLAG is set (the remainder is smaller), JUMP to 497FH: this quotient bit is 0.
497D
SUB D 92
SUBtract Register D, the divisor, from Register A.
497E
INC L 2C
INCrement Register L by 1: this quotient bit is 1.
497F
DEC E 1D
DECrement Register E, the count of dividend bits left.
4980
If the NZ FLAG is set (bits remain), JUMP back to 4976H for the next one.
4982
POP DE D1
Restore Register Pair DE from the top of the stack.
4983
RET C9
RETurn with Register Pair HL = the quotient and Register A = the remainder.
4984H - The Overlay Request Handler
RST 28H (400CH) comes here with a request code in Register A. Request code 01H runs the BREAK vector at 4312H 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 (430AH for SYS1-SYS8 at 4E00H, 430BH 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 49DDH, which puts back the word at 4307H-4308H.
4984
INC SP 33
INCrement the Stack Pointer by 1, the first of two.
4985
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.
4986
CP 01H FE 01
Compare Register A, the request code, against 01H.
4988
If the NZ FLAG is set (an overlay request), JUMP to 4994H.
498A
LD HL,4302H 21 02 43
Request 01H: point Register Pair HL to 4302H, SFLAG1$.
498D
BIT 0,(HL) CB 46
Test bit 0 of SFLAG1$ at Register Pair HL (4302H), the BREAK key disable flag.
498F
If the Z FLAG is set (the BREAK key is enabled), JUMP to 4312H, the BREAK vector, which returns to the caller.
4992
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG.
4993
RET C9
RETurn with Register A = 00H: the BREAK key is disabled.
4994
PUSH HL E5
Save Register Pair HL to the top of the stack.
4995
LD HL,(4307H) 2A 07 43
Load Register Pair HL with the word at 4307H-4308H.
4998
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.
4999
PUSH HL E5
Save Register Pair HL to the top of the stack.
499A
LD HL,49DDH 21 DD 49
Load Register Pair HL with 49DDH, where the routine is to return.
499D
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: 49DDH goes to the stack above the saved word, and Register Pair HL is the caller's again.
499E
PUSH HL E5
Save Register Pair HL to the top of the stack.
499F
PUSH DE D5
Save Register Pair DE to the top of the stack.
49A0
PUSH BC C5
Save Register Pair BC to the top of the stack.
49A1
LD HL,4308H 21 08 43
Point Register Pair HL to 4308H, the DEBUG on BREAK switch.
49A4
LD (HL),00H 36 00
Store 00H into the switch at Register Pair HL (4308H): BREAK does not enter DEBUG while the overlay runs.
49A6
INC HL 23
INCrement Register Pair HL by 1 to 4309H, the request code.
49A7
LD (HL),A 77
Store Register A, the request code, to 4309H at Register Pair HL.
49A8
INC HL 23
INCrement Register Pair HL by 1 to 430AH, OVLYL$.
49A9
LD DE,430CH 11 0C 43
Point Register Pair DE to 430CH, the low overlay's table address.
49AC
OR A B7
OR Register A with itself to test bit 7 of the request code.
49AD
If the P FLAG is set (bit 7 clear: SYS1-SYS8), JUMP to 49B4H with Register Pair HL = 430AH and Register Pair DE = 430CH.
49B0
INC HL 23
A high overlay (SYS9-SYS16): INCrement Register Pair HL by 1 to 430BH, OVLYH$.
49B1
LD DE,430EH 11 0E 43
Point Register Pair DE to 430EH, the high overlay's table address.
49B4
AND F0H E6 F0
AND Register A with F0H to keep the overlay bits of the request code.
49B6
CP (HL) BE
Compare Register A against the resident overlay at Register Pair HL (430AH or 430BH).
49B7
LD (HL),A 77
Store Register A to the overlay byte at Register Pair HL: it names the overlay that will be resident.
49B8
If the Z FLAG is set (the overlay is already in memory), JUMP to 49C5H.
49BA
GOSUB to 49E3H to load the overlay named by Register A. Register Pair HL returns its transfer address.
49BD
If the NZ FLAG is set (it could not be loaded), JUMP to 4A34H: System error.
49BF
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = 430CH or 430EH, Register Pair DE = the transfer address.
49C0
LD (HL),E 73
Store Register E, the low byte of the transfer address, to the table address at Register Pair HL.
49C1
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
49C2
LD (HL),D 72
Store Register D, the high byte, to Register Pair HL.
49C3
JUMP to 49C9H with Register Pair DE = the routine table.
49C5
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = 430CH or 430EH.
49C6
LD E,(HL) 5E
Load Register E with the low byte of the resident overlay's table address from Register Pair HL.
49C7
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
49C8
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the routine table.
49C9
LD A,(4309H) 3A 09 43
Load Register A with the request code at 4309H.
49CC
AND 0FH E6 0F
AND Register A with 0FH to keep the routine number.
49CE
SUB 02H D6 02
SUBtract 02H from Register A: routine 2 is the first entry of the table.
49D0
ADD A,A 87
Double Register A, the offset of the routine's word.
49D1
LD L,A 6F
Load Register L with Register A, the offset of the entry in the table.
49D2
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = the offset.
49D4
ADD HL,DE 19
ADD Register Pair DE (the routine table) to Register Pair HL: Register Pair HL points to the routine's entry.
49D5
LD A,(HL) 7E
Load Register A with the low byte of the routine's address from Register Pair HL.
49D6
INC HL 23
INCrement Register Pair HL by 1 to the high byte.
49D7
LD H,(HL) 66
Load Register H with the high byte from Register Pair HL.
49D8
LD L,A 6F
Load Register L with Register A: Register Pair HL = the routine.
49D9
POP BC C1
Restore Register Pair BC from the top of the stack, as the caller had it.
49DA
POP DE D1
Restore Register Pair DE from the top of the stack, as the caller had it.
49DB
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.
49DC
RET C9
RETurn, which jumps to the routine; it returns to 49DDH.
49DD
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 4307H-4308H and the routine's Register Pair HL goes to the stack.
49DE
LD (4307H),HL 22 07 43
Store Register Pair HL back to 4307H-4308H, as they were before the request.
49E1
POP HL E1
Restore Register Pair HL from the top of the stack, as the routine left it.
49E2
RET C9
RETurn to the caller of the entry point with the routine's results.
49E3H - 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 43CEH with the file's first segment and loads the file through 4A91H, which returns its transfer address in Register Pair HL.
49E3
PUSH DE D5
Save Register Pair DE (430CH or 430EH) to the top of the stack.
49E4
PUSH IY FD E5
Save Index Register IY to the top of the stack.
49E6
RLCA 07
Rotate Register A left (the first of four, swapping its two halves).
49E7
RLCA 07
Rotate Register A left (the second of four), the overlay bits moving down.
49E8
RLCA 07
Rotate Register A left (the third of four), the overlay bits moving down.
49E9
RLCA 07
Rotate Register A left: the four overlay bits are now bits 3-0, the system number less 1.
49EA
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.
49EC
LD B,A 47
Load Register B with Register A, the logical file number.
49ED
LD C,00H 0E 00
Load Register C with 00H: the /SYS files are read from drive 0.
49EF
GOSUB to 4557H (LOCDCT%) to point Index Register IY to drive 0's drive control table.
49F2
LD A,B 78
Load Register A with Register B, the logical file number.
49F3
ADD A,02H C6 02
ADD 02H to Register A: Register A = its sector in the directory.
49F5
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.
49F8
If the C FLAG is set, JUMP to 4A07H: the entry is the first of its sector.
49FA
LD B,A 47
Load Register B with Register A, the sector past the end, less 2: the sector of the second entry.
49FB
SET 5,B CB E8
Set bit 5 of Register B: entry 1 of that sector.
49FD
ADD A,02H C6 02
ADD 02H to Register A, the sector of the second entry.
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 that sector is inside the directory.
4A02
If the C FLAG is set, JUMP to 4A07H with Register B = the second entry.
4A04
SET 6,A CB F7
Set bit 6 of Register A: entry 2 of the sector Register A gives.
4A06
LD B,A 47
Load Register B with Register A, the logical file number of the third entry.
4A07
LD A,B 78
Load Register A with Register B, the logical file number.
4A08
LD (43D5H),A 32 D5 43
Store Register A to 43D5H, FCB+07H of the system file control block.
4A0B
XOR A AF
Set Register A to 00H by XORing it with itself.
4A0C
LD (43CFH),A 32 CF 43
Store Register A (00H) to 43CFH, the flags of the system file control block.
4A0F
LD (43D8H),A 32 D8 43
Store Register A (00H) to 43D8H, the low byte of its next record number: the file is read from its first sector.
4A12
GOSUB to 490CH to read the directory sector of logical file number Register B (drive Register C, 0) into 4200H; Register Pair HL returns the entry.
4A15
If the NZ FLAG is set (Directory read error), JUMP to 4A30H to return the error.
4A17
LD A,(HL) 7E
Load Register A with the entry's flags from Register Pair HL.
4A18
CPL 2F
Complement Register A, so the flag bits that must be set become 0.
4A19
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.
4A1B
LD A,18H 3E 18
Load Register A with 18H, the error code File not in directory (the flags are kept).
4A1D
If the NZ FLAG is set (not an active system file), JUMP to 4A30H to return error 18H.
4A1F
LD DE,0016H 11 16 00
Load Register Pair DE with 0016H, the offset of the first segment descriptor in the entry.
4A22
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL points to the first segment descriptor.
4A23
LD DE,43DCH 11 DC 43
Point Register Pair DE to 43DCH, FCB+0EH of the system file control block.
4A26
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.
4A28
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.
4A2A
LD DE,43CEH 11 CE 43
Point Register Pair DE to 43CEH, the system file control block.
4A2D
GOSUB to 4A91H to load the file of the file control block at Register Pair DE. Register Pair HL returns its transfer address.
4A30
POP IY FD E1
Restore Index Register IY from the top of the stack.
4A32
POP DE D1
Restore Register Pair DE from the top of the stack.
4A33
RET C9
RETurn with the Z FLAG set when the overlay was loaded.
4A34H - 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@.
4A34
LD HL,4309H 21 09 43
Point Register Pair HL to 4309H, the request code.
4A37
BIT 7,(HL) CB 7E
Test bit 7 of the request code at Register Pair HL (4309H). The Z FLAG is set for a low overlay.
4A39
INC HL 23
INCrement Register Pair HL by 1 to 430AH, OVLYL$.
4A3A
If the Z FLAG is set (a low overlay), JUMP to 4A3DH.
4A3C
INC HL 23
INCrement Register Pair HL by 1 to 430BH, OVLYH$.
4A3D
LD (HL),FFH 36 FF
Store FFH to the overlay byte at Register Pair HL: no overlay of that group is resident.
4A3F
LD HL,4A48H 21 48 4A
Point Register Pair HL to 4A48H, the text System error.
4A42
GOSUB to 4467H (DSPLY@) to display the text at Register Pair HL.
4A45
JUMP to 4030H, ABORT@, back to the DOSPLUS command level.
4A48-4A54
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.
4A55H - 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 4308H is set to the level less 6. A load error goes to ERROR@.
4A55
PUSH HL E5
Save Register Pair HL to the top of the stack.
4A56
LD HL,4302H 21 02 43
Point Register Pair HL to 4302H, SFLAG1$, the system flags.
4A59
SET 1,(HL) CB CE
Set bit 1 of SFLAG1$ at Register Pair HL (4302H), the run access flag.
4A5B
PUSH HL E5
Save Register Pair HL (4302H) to the top of the stack.
4A5C
GOSUB to 4430H (LOAD@) to load the file of the file control block at Register Pair DE. Register Pair HL returns its transfer address.
4A5F
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 = 4302H.
4A60
RES 1,(HL) CB 8E
Reset bit 1 of SFLAG1$ at Register Pair HL (4302H): the load is over.
4A62
If the NZ FLAG is set (the load failed), JUMP to 4409H (ERROR@) with the error code in Register A.
4A65
BIT 2,(HL) CB 56
Test bit 2 of SFLAG1$ at Register Pair HL (4302H), the DEBUG flag. The Z FLAG is set when DEBUG is off.
4A67
INC DE 13
INCrement Register Pair DE by 1 to FCB+01H of the file control block.
4A68
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.
4A69
LD BC,(4047H) ED 4B 47 40
Load Register Pair BC with LOW$ at 4047H, for the program.
4A6D
LD DE,(4049H) ED 5B 49 40
Load Register Pair DE with HMEM$ at 4049H, for the program.
4A71
POP HL E1
Restore Register Pair HL from the top of the stack: the transfer address.
4A72
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.
4A73
RET Z C8
If the Z FLAG is set (DEBUG is off), RETurn, which starts the program at its transfer address.
4A74
AND 07H E6 07
AND Register A with 07H to keep the access level.
4A76
SUB 06H D6 06
SUBtract 06H from Register A. The C FLAG is set for an access level below 6.
4A78
If the C FLAG is set, JUMP to 440DH (DEBUG@): the monitor starts with the program's transfer address on the stack.
4A7B
LD (4308H),A 32 08 43
Store Register A (the access level less 6: 00H or 01H) to the DEBUG on BREAK switch at 4308H.
4A7E
RET C9
RETurn, which starts the program at its transfer address.
4A7FH - 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 4200H, then the loader at 4A91H 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. 4ACBH 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@.
4A7F
LD B,00H 06 00
LOAD@: load Register B with 00H, the logical record length for OPEN@: 256.
4A81
LD HL,4200H 21 00 42
Point Register Pair HL to 4200H, the buffer for the file.
4A84
GOSUB to 4424H (OPEN@) to open the file of the file control block at Register Pair DE.
4A87
If the Z FLAG is set (opened), JUMP to 4A91H to load it.
4A89
CP 18H FE 18
Compare Register A, the error code, against 18H, File not in directory.
4A8B
If the NZ FLAG is set (another error), JUMP to 4AE5H to return it.
4A8D
LD A,1FH 3E 1F
Load Register A with 1FH, the error code Program not found, in place of 18H.
4A8F
JUMP to 4AE5H to return error 1FH with bit 6 set.
4A91
PUSH DE D5
The loader: save Register Pair DE (the file control block) to the top of the stack.
4A92
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.
4A94
GOSUB to 4ACBH for the next byte: the record type.
4A97
CP 20H FE 20
Compare Register A against 20H. The NC FLAG is set for a type of 20H or more.
4A99
If the NC FLAG is set (not a load file record), JUMP to 4ADCH: error 22H.
4A9B
LD H,A 67
Load Register H with Register A, the record type.
4A9C
GOSUB to 4ACBH for the next byte: the record length.
4A9F
LD B,A 47
Load Register B with Register A, the record length.
4AA0
GOSUB to 4ACBH for the next byte: the low byte of the address, or the first byte of the record.
4AA3
LD L,A 6F
Load Register L with Register A, the low address byte or the first byte of the record.
4AA4
DEC H 25
DECrement Register H, the record type, by 1. The Z FLAG is set for type 01H.
4AA5
If the Z FLAG is set (a load block), JUMP to 4AB9H.
4AA7
DEC H 25
DECrement Register H by 1 again. The Z FLAG is set for type 02H.
4AA8
If the NZ FLAG is set (another type), JUMP to 4AB1H to skip the record.
4AAA
The transfer record: GOSUB to 4ACBH for the high byte of the transfer address.
4AAD
LD H,A 67
Load Register H with Register A: Register Pair HL = the transfer address.
4AAE
POP DE D1
Restore Register Pair DE (the file control block) from the top of the stack.
4AAF
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: no error.
4AB0
RET C9
RETurn with Register Pair HL = the transfer address.
4AB1
DEC B 05
Skip a record: DECrement Register B, the bytes of the record left.
4AB2
If the Z FLAG is set (the record is used up), JUMP back to 4A94H for the next record.
4AB4
GOSUB to 4ACBH to take the next byte of the record, which is not used.
4AB7
JUMP back to 4AB1H to count off the byte just skipped.
4AB9
A load block: GOSUB to 4ACBH for the high byte of the load address.
4ABC
LD H,A 67
Load Register H with Register A: Register Pair HL = the load address.
4ABD
DEC B 05
DECrement Register B, the record length, by 1 for the address's low byte.
4ABE
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).
4ABF
GOSUB to 4ACBH for the next byte of the load block in Register A.
4AC2
LD (HL),A 77
Store Register A to memory at Register Pair HL.
4AC3
CP (HL) BE
Compare Register A against the byte at Register Pair HL, to see whether memory kept it.
4AC4
If the NZ FLAG is set (it did not: read only or missing memory), JUMP to 4ADFH: error 23H.
4AC6
INC HL 23
INCrement Register Pair HL by 1 to the next load address.
4AC7
DECrement Register B and loop back to 4ABFH while Register B is not zero.
4AC9
JUMP back to 4A94H for the next record: the load block is in memory.
4ACB
INC E 1C
The next byte: INCrement Register E, the buffer position, by 1.
4ACC
If the NZ FLAG is set (the position is still in the buffer), JUMP to 4ADAH to take the byte.
4ACE
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.
4ACF
POP DE D1
Restore Register Pair DE from the top of the stack: the file control block the loader saved at 4A91H.
4AD0
PUSH DE D5
Save Register Pair DE (the file control block) to the top of the stack again.
4AD1
PUSH AF F5
Save Register Pair AF (the return address into the loader) to the top of the stack again.
4AD2
GOSUB to 4436H (READ@) to read the next sector of the file at Register Pair DE into its buffer at 4200H.
4AD5
LD DE,4200H 11 00 42
Point Register Pair DE to 4200H, the first byte of the buffer.
4AD8
If the NZ FLAG is set (the read failed), JUMP to 4AE3H to return the error.
4ADA
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the buffer position.
4ADB
RET C9
RETurn with Register A = the next byte of the file and Register E its position.
4ADC
LD A,22H 3E 22
Load Register A with 22H, the error code for a file that is not a program file.
4ADE
LD DE,233EH 11 3E 23
Load Register Pair DE with 233EH. The load only steps over 4ADFH-4AE0H: the memory error at 4AC4H jumps to 4ADFH, where the bytes 3EH 23H read LD A,23H, the error code Memory fault during program load.
4AE1
LD DE,D1D5H 11 D5 D1
Load Register Pair DE with D1D5H. The load only steps over 4AE2H-4AE3H: the read error at 4AD8H jumps to 4AE3H, where D1H reads POP DE and takes off the return into the loader so the next POP finds the file control block.
4AE4
POP DE D1
Restore Register Pair DE from the top of the stack: the file control block the loader saved at 4A91H.
4AE5
OR 40H F6 40
OR Register A with 40H: bit 6 is set in the error code returned. The NZ FLAG is set.
4AE7
RET C9
RETurn with Register A = the error code and the NZ FLAG set.
4AE8H - 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. 4AFFH 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 (4C72H) and bit 5 is set, so the next access reads the new sector. The sector goes to FCB+0AH-0BH and 4CBBH 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 4CDBH, which checks that the file is open, points Index Register IX to it and saves the registers.
4AE8
POSN@: GOSUB to 4CDBH, 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.
4AEB
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 (4C91H).
4AEF
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of FCB+01H at Index Register IX+01H, the blocked records flag.
4AF3
If the Z FLAG is set (not blocked: Register Pair BC is the sector), JUMP to 4AFFH with Register A = 00H, the start of the sector.
4AF5
LD H,B 60
Load Register H with Register B, the high byte of the record number.
4AF6
LD L,C 69
Load Register L with Register C: Register Pair HL = the logical record number.
4AF7
LD A,(IX+09H) DD 7E 09
Load Register A with the logical record length at Index Register IX+09H (FCB+09H).
4AFA
GOSUB to 4957H (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).
4AFD
LD B,H 44
Load Register B with Register H, the high byte of the sector.
4AFE
LD C,L 4D
Load Register C with Register L: Register Pair BC = the sector of the file that holds the record.
4AFF
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.
4B02
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.
4B06
If the NZ FLAG is set (the buffer is to be read anyway), JUMP to 4B1DH to store the new sector.
4B08
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).
4B0B
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.
4B0E
OR A B7
OR Register A with itself to clear the C FLAG for the subtraction.
4B0F
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.
4B11
If the Z FLAG is set (the record is in the sector already in the buffer), JUMP to 4B1DH; the buffer stays as it is.
4B13
PUSH BC C5
Save Register Pair BC (the new sector) to the top of the stack.
4B14
GOSUB to 4C72H to write the buffer to the file if it holds updated bytes of a blocked file.
4B17
POP BC C1
Restore Register Pair BC (the new sector) from the top of the stack.
4B18
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4B19
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.
4B1D
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).
4B20
LD (IX+0BH),B DD 70 0B
Store Register B, the high byte, to Index Register IX+0BH.
4B23
JUMP to 4CBBH 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.
4B26
REW@: GOSUB to 4CDBH to check the file control block at Register Pair DE and run the rest under Index Register IX, with Register A = 00H.
4B29
LD B,A 47
Load Register B with Register A (00H), the high byte of the first sector.
4B2A
LD C,A 4F
Load Register C with Register A: Register Pair BC = 0000H, the first sector.
4B2B
JUMP to 4AFFH to position to byte 00H of sector 0000H. REW@ enters after the SET of the random access flag, which it leaves as it was.
4B2D
PEOF@: GOSUB to 4CDBH to check the file control block at Register Pair DE and run the rest under Index Register IX.
4B30
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.
4B33
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.
4B36
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.
4B39
JUMP to 4AFFH to position there. The end of file test at 4CBBH then returns 1CH, which the manual tells the caller to ignore.
4B3B
BKSP@: GOSUB to 4CDBH to check the file control block at Register Pair DE and run the rest under Index Register IX, with Register A = 00H.
4B3E
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).
4B41
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.
4B44
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of FCB+01H at Index Register IX+01H, the blocked records flag.
4B48
If the Z FLAG is set (not blocked), JUMP to 4B54H to step back one sector with Register A = 00H.
4B4A
LD A,(IX+09H) DD 7E 09
Load Register A with the logical record length at Index Register IX+09H (FCB+09H).
4B4D
NEG ED 44
NEGate Register A: 256 less the record length (00H for a length of 256).
4B4F
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.
4B52
If the C FLAG is set, JUMP to 4AFFH with Register A = the offset less the record length and Register Pair BC = the same sector.
4B54
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.
4B55
JUMP to 4AFFH to position to the previous record.
4B57H - 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 (4BF9H); a blocked file takes the record length's bytes one at a time through 4B9CH into the user record at Register Pair HL. WRITE@ (4439H) and VER@ (443CH) both come to 4B72H: the buffer is written as the next sector (4C34H), or the record's bytes are put one at a time through 4BBFH. VER@ has no code of its own: every sector write is read back when the verify switch (bit 3 of SFLAG1$) is on (4C5DH).
4B57
READ@: GOSUB to 4CDBH to check the file control block at Register Pair DE and run the rest under Index Register IX.
4B5A
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of FCB+01H at Index Register IX+01H, the blocked records flag.
4B5E
If the Z FLAG is set (not blocked), JUMP to 4BF9H to read the next sector into the file's buffer.
4B61
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).
4B64
PUSH BC C5
Save Register Pair BC (the count) to the top of the stack.
4B65
PUSH HL E5
Save Register Pair HL (the user record pointer) to the top of the stack.
4B66
GOSUB to 4B9CH for the next byte of the file in Register A.
4B69
POP HL E1
Restore Register Pair HL from the top of the stack.
4B6A
POP BC C1
Restore Register Pair BC from the top of the stack.
4B6B
RET NZ C0
If the NZ FLAG is set (end of file or a read error), RETurn with the error code in Register A.
4B6C
LD (HL),A 77
Store Register A, the byte, to the user record at Register Pair HL.
4B6D
INC HL 23
INCrement Register Pair HL by 1 to the next byte of the record.
4B6E
DECrement Register B and loop back to 4B64H while Register B is not zero.
4B70
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: the record is read.
4B71
RET C9
RETurn with the record in the user record at Register Pair HL and no error.
4B72
WRITE@ and VER@: GOSUB to 4CDBH to check the file control block at Register Pair DE and run the rest under Index Register IX.
4B75
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of FCB+01H at Index Register IX+01H, the blocked records flag.
4B79
If the Z FLAG is set (not blocked), JUMP to 4C34H to write the buffer as the next sector.
4B7C
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).
4B7F
LD A,(HL) 7E
Load Register A with the next byte of the user record at Register Pair HL.
4B80
INC HL 23
INCrement Register Pair HL by 1 past the byte.
4B81
PUSH BC C5
Save Register Pair BC (the count) to the top of the stack.
4B82
PUSH HL E5
Save Register Pair HL (the user record pointer) to the top of the stack.
4B83
GOSUB to 4BBFH to put the byte in Register A into the file.
4B86
POP HL E1
Restore Register Pair HL from the top of the stack.
4B87
POP BC C1
Restore Register Pair BC from the top of the stack.
4B88
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4B89
DECrement Register B and loop back to 4B7FH while Register B is not zero.
4B8B
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: the record is written.
4B8C
RET C9
RETurn to the caller with the record written and no error.
4B8DH - Character I/O on a File, and the Byte Routines
44E6H comes to 4B8DH 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 (4B9CH) or written (4BBFH). 4B9CH 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. 4BBFH 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 (4C88H).
4B8D
PUSH IX DD E5
Save Index Register IX, the file control block, to the top of the stack.
4B8F
POP DE D1
Restore it into Register Pair DE from the top of the stack: Register Pair DE = the file control block, as 4CDBH needs it.
4B90
GOSUB to 4CDBH to check the file control block at Register Pair DE and run the rest under Index Register IX with the registers saved.
4B93
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.
4B97
LD A,C 79
Load Register A with Register C, the character to put.
4B98
BIT 0,B CB 40
Test bit 0 of Register B, the I/O type: set for input (GET@).
4B9A
If the Z FLAG is set (output, or a control call, which also puts the character), JUMP to 4BBFH to write Register A.
4B9C
Read a byte: GOSUB to 4CBBH for the end of file status of the position.
4B9F
RET NZ C0
If the NZ FLAG is set (at or past the end: 1CH or 1DH), RETurn with the code in Register A.
4BA0
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.
4BA4
If the NZ FLAG is set, GOSUB to 4C06H to read sector FCB+0AH-0BH into the buffer.
4BA7
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn with the error code in Register A.
4BA8
GOSUB to 4CA9H: Register Pair DE returns the address of the byte at FCB+05H in the buffer.
4BAB
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE.
4BAC
LD (4BBCH),A 32 BC 4B
Store Register A into 4BBCH, the operand of the LD A,00H at 4BBBH, to keep the byte while the position moves on.
4BAF
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.
4BB2
If the NZ FLAG is set, JUMP to 4BBBH to return the byte.
4BB4
GOSUB to 4C72H to write the buffer back if it holds updated bytes.
4BB7
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4BB8
GOSUB to 4C7CH to step the next record number to the next sector and mark the buffer to be read.
4BBB
LD A,00H 3E 00
Load Register A with the byte read; the operand at 4BBCH was stored at 4BACH.
4BBD
CP A BF
Compare Register A against itself to set the Z FLAG: no error.
4BBE
RET C9
RETurn with Register A = the byte and the Z FLAG set.
4BBF
LD (4BF6H),A 32 F6 4B
Write a byte: store Register A into 4BF6H, the operand of the LD A,00H at 4BF5H, to keep the byte.
4BC2
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.
4BC6
If the Z FLAG is set (the buffer holds it), JUMP to 4BDBH to store the byte.
4BC8
GOSUB to 4CBBH for the end of file status of the position.
4BCB
If the Z FLAG is set (before the end: the sector holds bytes of the file), JUMP to 4BD7H to read it first.
4BCD
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.
4BD1
LD A,(IX+05H) DD 7E 05
Load Register A with the byte offset at Index Register IX+05H (FCB+05H).
4BD4
OR A B7
OR Register A with itself to test the offset for 00H.
4BD5
If the Z FLAG is set (a new sector starts: nothing of the file is in it), JUMP to 4BDBH without reading.
4BD7
GOSUB to 4C06H to read sector FCB+0AH-0BH into the buffer, so the bytes already in it are kept.
4BDA
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn with the error code in Register A.
4BDB
GOSUB to 4CA9H: Register Pair DE returns the address of the byte at FCB+05H in the buffer.
4BDE
LD A,(4BF6H) 3A F6 4B
Load Register A with the byte to write from 4BF6H, where 4BBFH kept it.
4BE1
LD (DE),A 12
Store Register A to the buffer at Register Pair DE.
4BE2
SET 4,(IX+01H) DD CB 01 E6
Set bit 4 of FCB+01H at Index Register IX+01H, the buffer updated flag.
4BE6
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.
4BE9
If the NZ FLAG is set (room is left in the sector), JUMP to 4BF2H.
4BEB
GOSUB to 4C40H to write the full buffer to the file.
4BEE
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4BEF
GOSUB to 4C7CH to step the next record number to the next sector and mark the buffer to be read.
4BF2
GOSUB to 4C88H to set the modified flag and move the end of the file to the new position where it is due.
4BF5
LD A,00H 3E 00
Load Register A with the byte written; the operand at 4BF6H was stored at 4BBFH.
4BF7
CP A BF
Compare Register A against itself to set the Z FLAG: no error.
4BF8
RET C9
RETurn with Register A = the byte and the Z FLAG set.
4BF9H - Reading and Writing a Whole Sector
4BF9H (READ@ of a file that is not blocked) reads sector FCB+0AH-0BH into the buffer and steps to the next sector. 4C06H 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 4CFDH and DISKIO% function 3 (DREAD) reads it. 4C34H (WRITE@ of a file that is not blocked) writes the buffer and steps on. 4C40H 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.
4BF9
READ@ of a sector: GOSUB to 4CBBH for the end of file status of the position.
4BFC
RET NZ C0
If the NZ FLAG is set (at or past the end), RETurn with 1CH or 1DH in Register A.
4BFD
GOSUB to 4C06H to read sector FCB+0AH-0BH into the file's buffer.
4C00
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn with the error code in Register A.
4C01
GOSUB to 4C7CH to step the next record number to the next sector.
4C04
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: no error.
4C05
RET C9
RETurn with the sector in the file's buffer and no error.
4C06
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.
4C09
LD HL,4302H 21 02 43
Point Register Pair HL to 4302H, SFLAG1$, the system flags.
4C0C
BIT 1,(HL) CB 4E
Test bit 1 of SFLAG1$ at Register Pair HL (4302H), the run access flag, set while RUN@ loads a program.
4C0E
If the NZ FLAG is set (a program is being loaded), JUMP to 4C1AH: an execute only file may be read.
4C10
AND 07H E6 07
AND Register A with 07H to keep the access level.
4C12
CP 06H FE 06
Compare Register A against 06H. The C FLAG is set for a level below 6, which allows reading.
4C14
If the C FLAG is set, JUMP to 4C1AH to read the sector.
4C16
LD A,25H 3E 25
Load Register A with 25H, the error code Illegal access attempted to protected file.
4C18
OR A B7
OR Register A with itself to set the NZ FLAG.
4C19
RET C9
RETurn with error 25H in Register A and the NZ FLAG set.
4C1A
GOSUB to 4CFDH for the place of sector FCB+0AH-0BH: Register C the drive, Register D the cylinder, Register E the sector.
4C1D
RET NZ C0
If the NZ FLAG is set (the sector could not be found), RETurn with the error code in Register A.
4C1E
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.
4C22
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).
4C25
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.
4C28
LD A,03H 3E 03
Load Register A with 03H, the DISKIO% function DREAD.
4C2A
GOSUB to 4485H (DISKIO%) to read the sector into the buffer at Register Pair HL.
4C2D
RET Z C8
If the Z FLAG is set (no error), RETurn with Register A = 00H.
4C2E
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.
4C30
RET Z C8
If the Z FLAG is set, RETurn with Register A = 00H and no error.
4C31
ADD A,06H C6 06
ADD 06H to Register A to give back the error code. The NZ FLAG is set.
4C33
RET C9
RETurn with the read error code in Register A.
4C34
WRITE@ of a sector: GOSUB to 4C40H to write the buffer as sector FCB+0AH-0BH.
4C37
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4C38
GOSUB to 4C7CH to step the next record number to the next sector.
4C3B
GOSUB to 4C88H to set the modified flag and move the end of the file where it is due.
4C3E
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: no error.
4C3F
RET C9
RETurn with the sector written, the position moved on and no error.
4C40
LD A,(IX+01H) DD 7E 01
Write a sector: load Register A with the flags at Index Register IX+01H (FCB+01H).
4C43
AND 07H E6 07
AND Register A with 07H to keep the access level.
4C45
CP 05H FE 05
Compare Register A against 05H. The C FLAG is set for a level below 5, which allows writing.
4C47
If the C FLAG is set, JUMP to 4C4DH to write the sector.
4C49
LD A,25H 3E 25
Load Register A with 25H, the error code Illegal access attempted to protected file.
4C4B
OR A B7
OR Register A with itself to set the NZ FLAG.
4C4C
RET C9
RETurn with error 25H in Register A and the NZ FLAG set.
4C4D
GOSUB to 4CFDH for the place of sector FCB+0AH-0BH: Register C the drive, Register D the cylinder, Register E the sector.
4C50
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.
4C51
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).
4C54
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.
4C57
LD A,05H 3E 05
Load Register A with 05H, the DISKIO% function DWRITE.
4C59
GOSUB to 4485H (DISKIO%) to write the buffer at Register Pair HL to the sector.
4C5C
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error code in Register A.
4C5D
LD HL,4302H 21 02 43
Point Register Pair HL to 4302H, SFLAG1$, the system flags.
4C60
BIT 3,(HL) CB 5E
Test bit 3 of SFLAG1$ at Register Pair HL (4302H), the verify switch.
4C62
If the Z FLAG is set (verify is off), JUMP to 4C6DH.
4C64
LD HL,4200H 21 00 42
Point Register Pair HL to 4200H, the system buffer, for the verify.
4C67
LD A,04H 3E 04
Load Register A with 04H, the DISKIO% function DVERF, which reads the sector back.
4C69
GOSUB to 4485H (DISKIO%) to verify the sector just written.
4C6C
RET NZ C0
If the NZ FLAG is set (the sector does not read back), RETurn with the error code in Register A.
4C6D
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.
4C71
RET C9
RETurn with the Z FLAG set from the write or the verify.
4C72H - Buffer and Position Helpers
4C72H writes the buffer of a blocked file when it holds updated bytes (bits 7 and 4 of FCB+01H). 4C7CH steps the next record number on by one sector and sets bit 5, the buffer is to be read. 4C88H 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. 4CA9H gives the address of the current byte in the buffer.
4C72
LD A,(IX+01H) DD 7E 01
Load Register A with the flags at Index Register IX+01H (FCB+01H).
4C75
CPL 2F
Complement Register A: bits 7 (blocked) and 4 (updated) are now clear when they were set.
4C76
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.
4C78
If the Z FLAG is set (a blocked buffer holds updated bytes), JUMP to 4C40H to write it, which returns to the caller.
4C7A
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: nothing to write.
4C7B
RET C9
RETurn with Register A = 00H and no error: nothing was written.
4C7C
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.
4C80
INC (IX+0AH) DD 34 0A
INCrement the low byte of the next record number at Index Register IX+0AH (FCB+0AH) by 1.
4C83
RET NZ C0
If the NZ FLAG is set (no carry into the high byte), RETurn.
4C84
INC (IX+0BH) DD 34 0B
INCrement the high byte at Index Register IX+0BH by 1 for the carry.
4C87
RET C9
RETurn with the next record number one sector on.
4C88
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.
4C8C
GOSUB to 4CBBH for the end of file status of the position.
4C8F
If the NZ FLAG is set (at or past the end), JUMP to 4C96H: the end moves to the position.
4C91
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@.
4C95
RET NZ C0
If the NZ FLAG is set (random access), RETurn: the end of the file stays where it is.
4C96
LD A,(IX+05H) DD 7E 05
Load Register A with the byte offset at Index Register IX+05H (FCB+05H).
4C99
LD (IX+08H),A DD 77 08
Store Register A to the end of file byte at Index Register IX+08H (FCB+08H).
4C9C
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).
4C9F
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).
4CA2
LD A,(IX+0BH) DD 7E 0B
Load Register A with the high byte of the next record number at Index Register IX+0BH.
4CA5
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.
4CA8
RET C9
RETurn with the end of the file moved to the position.
4CA9
LD A,(IX+05H) DD 7E 05
Load Register A with the byte offset at Index Register IX+05H (FCB+05H).
4CAC
LD C,A 4F
Load Register C with Register A, the offset in the buffer.
4CAD
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.
4CB0
LD E,A 5F
Load Register E with Register A, the low byte of the byte's address.
4CB1
LD A,(IX+04H) DD 7E 04
Load Register A with the high byte of the buffer address at Index Register IX+04H.
4CB4
ADC A,00H CE 00
ADD 00H and the C FLAG of the low byte to Register A.
4CB6
LD D,A 57
Load Register D with Register A: Register Pair DE = the address of the current byte in the buffer.
4CB7
RET C9
RETurn with Register Pair DE = the byte's address and Register C = the offset.
4CB8H - CKEOF@ and the End of File Test
CKEOF@ (4451H) checks the file at Register Pair DE, then 4CBBH 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.
4CB8
CKEOF@: GOSUB to 4CDBH to check the file control block at Register Pair DE and run the rest under Index Register IX with the registers saved.
4CBB
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).
4CBE
CP (IX+0DH) DD BE 0D
Compare Register A against the high byte of the ending record number at Index Register IX+0DH.
4CC1
If the NZ FLAG is set (they differ), JUMP to 4CD6H; the C FLAG tells which is the higher.
4CC3
LD A,(IX+0AH) DD 7E 0A
Load Register A with the low byte of the next record number at Index Register IX+0AH.
4CC6
CP (IX+0CH) DD BE 0C
Compare Register A against the low byte of the ending record number at Index Register IX+0CH.
4CC9
If the NZ FLAG is set (they differ), JUMP to 4CD6H.
4CCB
LD A,(IX+05H) DD 7E 05
The same sector: load Register A with the byte offset at Index Register IX+05H (FCB+05H).
4CCE
SUB (IX+08H) DD 96 08
SUBtract the end of file byte at Index Register IX+08H (FCB+08H) from Register A.
4CD1
If the NZ FLAG is set (they differ), JUMP to 4CD6H.
4CD3
OR 1CH F6 1C
OR Register A (00H) with 1CH: Register A = 1CH, Attempted to read past eof, and the NZ FLAG is set.
4CD5
RET C9
RETurn with Register A = 1CH: the position is the end of the file.
4CD6
LD A,1DH 3E 1D
Load Register A with 1DH, the error code Attempted to read outside of file limits.
4CD8
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.
4CD9
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: the position is before the end.
4CDA
RET C9
RETurn with Register A = 00H: the position is before the end of the file.
4CDBH - 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, 4CF0H 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, 4CF0H restores the registers, so only Register Pair AF carries the result back.
4CDB
LD A,(DE) 1A
Load Register A with the type byte of the file control block at Register Pair DE (80H when open).
4CDC
RLCA 07
Rotate Register A left: bit 7 goes to the C FLAG.
4CDD
If the NC FLAG is set (bit 7 clear: not an open file), JUMP to 4CF8H.
4CDF
POP AF F1
Restore Register Pair AF from the top of the stack: the return address into the routine that called 4CDBH, which is put back last.
4CE0
PUSH DE D5
Save Register Pair DE, the file control block, to the top of the stack.
4CE1
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.
4CE3
PUSH IY FD E5
Save Index Register IY to the top of the stack.
4CE5
PUSH HL E5
Save Register Pair HL to the top of the stack.
4CE6
PUSH DE D5
Save Register Pair DE to the top of the stack.
4CE7
PUSH BC C5
Save Register Pair BC to the top of the stack.
4CE8
PUSH HL E5
Save Register Pair HL to the top of the stack once more, to make a place for the next word.
4CE9
LD HL,4CF0H 21 F0 4C
Load Register Pair HL with 4CF0H, the routine that restores the registers.
4CEC
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: 4CF0H goes to the stack, where the routine will return, and Register Pair HL is the caller's again.
4CED
PUSH AF F5
Save Register Pair AF, the return address into the routine, to the top of the stack.
4CEE
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG.
4CEF
RET C9
RETurn into the routine with Register A = 00H; the routine returns to 4CF0H.
4CF0
POP BC C1
Restore Register Pair BC from the top of the stack, as the caller had it.
4CF1
POP DE D1
Restore Register Pair DE from the top of the stack, as the caller had it.
4CF2
POP HL E1
Restore Register Pair HL from the top of the stack, as the caller had it.
4CF3
POP IY FD E1
Restore Index Register IY from the top of the stack, as the caller had it.
4CF5
POP IX DD E1
Restore Index Register IX from the top of the stack, as the caller had it.
4CF7
RET C9
RETurn to the caller of the file routine with Register Pair AF as the routine left it.
4CF8
POP AF F1
Restore Register Pair AF from the top of the stack: the return address into the routine is dropped.
4CF9
LD A,26H 3E 26
Load Register A with 26H, the error code I/O attempted to unopen file.
4CFB
OR A B7
OR Register A with itself to set the NZ FLAG.
4CFC
RET C9
RETurn to the caller of the file routine with error 26H in Register A.
4CFDH - 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 (4D7FH-4D9CH), 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.
4CFD
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4D00
GOSUB to 4557H (LOCDCT%): Index Register IY returns the drive control table of drive Register C.
4D03
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).
4D06
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.
4D09
LD A,(IY+0FH) FD 7E 0F
Load Register A with the sectors per granule at Index Register IY+0FH (DCT+0FH).
4D0C
GOSUB to 4971H (DIVD@): Register Pair HL returns the granule of the file and Register A the sector within it.
4D0F
LD (4DB9H),A 32 B9 4D
Store Register A, the sector within the granule, into 4DB9H, the operand of the ADD A,00H at 4DB8H.
4D12
PUSH IX DD E5
Save Index Register IX, the file control block, to the top of the stack.
4D14
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.
4D15
LD BC,000EH 01 0E 00
Load Register Pair BC with 000EH, the offset of the segment list.
4D18
ADD HL,BC 09
ADD Register Pair BC to Register Pair HL: Register Pair HL points to FCB+0EH, the first segment descriptor.
4D19
POP BC C1
Restore Register Pair BC from the top of the stack: Register Pair BC = the granule of the file to find.
4D1A
LD A,05H 3E 05
Load Register A with 05H, the number of segments in the list.
4D1C
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H: the first segment starts at granule 0 of the file.
4D1F
PUSH AF F5
Save Register Pair AF, the count of segments left, to the top of the stack.
4D20
LD A,(HL) 7E
Load Register A with the segment's cylinder at Register Pair HL.
4D21
INC HL 23
INCrement Register Pair HL by 1 to the segment's granule byte.
4D22
INC A 3C
INCrement Register A by 1. The Z FLAG is set for a cylinder of FFH, an empty entry.
4D23
If the Z FLAG is set, JUMP to 4D30H to go on to the next element.
4D25
PUSH HL E5
Save Register Pair HL (the granule byte) to the top of the stack.
4D26
LD H,D 62
Load Register H with Register D, the high byte of the granules before the segment.
4D27
LD L,E 6B
Load Register L with Register E: Register Pair HL = the granule of the file the segment starts with.
4D28
XOR A AF
Set Register A to 00H by XORing it with itself, which also clears the C FLAG.
4D29
SBC HL,BC ED 42
SUBtract Register Pair BC, the granule wanted, from Register Pair HL.
4D2B
If the C FLAG is set (the segment starts before the granule), JUMP to 4D3BH to see whether it reaches it.
4D2D
POP HL E1
Restore Register Pair HL (the granule byte) from the top of the stack.
4D2E
If the Z FLAG is set (the granule is the segment's first), JUMP to 4D77H with Register A = 00H, the granule's place in the segment.
4D30
INC HL 23
The next element: INCrement Register Pair HL by 1 to its count of granules.
4D31
POP AF F1
Restore Register Pair AF, the count of segments left, from the top of the stack.
4D32
DEC A 3D
DECrement Register A, the count of segments left, by 1.
4D33
If the Z FLAG is set (the five are used up), JUMP to 4D4EH to call SYS4/SYS.
4D35
LD E,(HL) 5E
Load Register E with the low byte of the count at Register Pair HL.
4D36
INC HL 23
INCrement Register Pair HL by 1 to the high byte of the count.
4D37
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.
4D38
INC HL 23
INCrement Register Pair HL by 1 to the next segment's cylinder.
4D39
JUMP back to 4D1FH to test the next segment of the list.
4D3B
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.
4D3C
LD A,L 7D
Load Register A with Register L: minus the granule's distance from the segment's start.
4D3D
POP HL E1
Restore Register Pair HL (the granule byte) from the top of the stack.
4D3E
If the NZ FLAG is set (too far), JUMP back to 4D30H for the next element.
4D40
PUSH DE D5
Save Register Pair DE to the top of the stack.
4D41
LD E,A 5F
Load Register E with Register A, minus the distance.
4D42
LD A,(HL) 7E
Load Register A with the segment's granule byte at Register Pair HL.
4D43
AND 1FH E6 1F
AND Register A with 1FH to keep the segment's granules less 1.
4D45
ADD A,E 83
ADD Register E to Register A. The C FLAG is set when the distance is within the segment.
4D46
LD A,E 7B
Load Register A with Register E, minus the distance.
4D47
POP DE D1
Restore Register Pair DE from the top of the stack.
4D48
If the NC FLAG is set (the segment ends before the granule), JUMP back to 4D30H for the next element.
4D4A
NEG ED 44
NEGate Register A: the granule's place in the segment.
4D4C
JUMP to 4D77H with the segment found in the list.
4D4E
LD A,(4DB9H) 3A B9 4D
Not in the list: load Register A with the sector within the granule from 4DB9H.
4D51
PUSH AF F5
Save Register Pair AF to the top of the stack.
4D52
LD A,(430AH) 3A 0A 43
Load Register A with OVLYL$ at 430AH, the low overlay now in memory.
4D55
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.
4D57
PUSH AF F5
Save Register Pair AF (the request that brings the overlay back) to the top of the stack.
4D58
LD A,33H 3E 33
Load Register A with 33H, the request code of routine 3 of SYS4/SYS.
4D5A
GOSUB to 4994H, 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.
4D5D
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.
4D5E
PUSH AF F5
Save Register Pair AF, the result of SYS4/SYS, to the top of the stack.
4D5F
LD A,H 7C
Load Register A with Register H, the request code that brings the old overlay back.
4D60
CP 12H FE 12
Compare Register A against 12H, the code for SYS2/SYS.
4D62
If the NZ FLAG is set (it was not SYS2/SYS), GOSUB to 4994H 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.
4D65
POP AF F1
Restore Register Pair AF, the result of SYS4/SYS, from the top of the stack.
4D66
POP HL E1
Restore Register Pair HL, the value SYS4/SYS returned, from the top of the stack.
4D67
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 4D51H (in Register H), and SYS4/SYS's Register Pair HL goes back 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 sector within the granule.
4D6A
LD (4DB9H),A 32 B9 4D
Store Register A back into 4DB9H, the operand of the ADD A,00H at 4DB8H: the overlay loads read their files through this locator, which overwrote it.
4D6D
POP AF F1
Restore Register Pair AF, the result of SYS4/SYS, from the top of the stack.
4D6E
LD (4DA6H),A 32 A6 4D
Store Register A, the granule's place in the segment, into 4DA6H, the operand of the ADD A,00H at 4DA5H.
4D71
POP HL E1
Restore Register Pair HL, the value SYS4/SYS returned, from the top of the stack.
4D72
RET NZ C0
If the NZ FLAG is set (SYS4/SYS returned an error), RETurn with the error code in Register A.
4D73
If the C FLAG is set, JUMP to 4D96H 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.
4D75
JUMP to 4D9FH with Register H = the segment's granule byte and Register L its cylinder.
4D77
LD (4DA6H),A 32 A6 4D
The segment is in the list: store Register A, the granule's place in the segment, into 4DA6H, the operand of the ADD A,00H at 4DA5H.
4D7A
LD B,(HL) 46
Load Register B with the segment's granule byte at Register Pair HL.
4D7B
DEC HL 2B
DECrement Register Pair HL by 1 to the segment's cylinder.
4D7C
LD C,(HL) 4E
Load Register C with the cylinder at Register Pair HL.
4D7D
INC HL 23
INCrement Register Pair HL by 1 back to the granule byte.
4D7E
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.
4D7F
CPL 2F
Complement Register A, the count of segments left.
4D80
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).
4D82
If the NC FLAG is set (the first or second segment), JUMP to 4D9DH: the list is left as it is.
4D84
INC A 3C
INCrement Register A by 1: 1, 2 or 3, the elements to move.
4D85
RLCA 07
Rotate Register A left, the elements times 2.
4D86
RLCA 07
Rotate Register A left again: Register A = 4, 8 or 12, the bytes to move.
4D87
PUSH BC C5
Save Register Pair BC (the descriptor found) to the top of the stack.
4D88
PUSH DE D5
Save Register Pair DE (the granules before it) to the top of the stack.
4D89
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the found element's last byte (its granule byte).
4D8A
LD HL,FFFCH 21 FC FF
Load Register Pair HL with FFFCH, minus 4, the length of an element.
4D8D
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL = the last byte of the element before it.
4D8E
LD B,00H 06 00
Load Register B with 00H, the high byte of the count.
4D90
LD C,A 4F
Load Register C with Register A: Register Pair BC = the bytes to move.
4D91
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.
4D93
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the last byte of the second place, now free.
4D94
POP DE D1
Restore Register Pair DE (the granules before the segment) from the top of the stack.
4D95
POP BC C1
Restore Register Pair BC (the descriptor) from the top of the stack.
4D96
LD (HL),B 70
Store Register B, the granule byte, at Register Pair HL.
4D97
DEC HL 2B
DECrement Register Pair HL by 1 to the cylinder's place.
4D98
LD (HL),C 71
Store Register C, the cylinder, at Register Pair HL.
4D99
DEC HL 2B
DECrement Register Pair HL by 1 to the high byte of the count.
4D9A
LD (HL),D 72
Store Register D, the high byte of the granules before the segment, at Register Pair HL.
4D9B
DEC HL 2B
DECrement Register Pair HL by 1 to the low byte of the count.
4D9C
LD (HL),E 73
Store Register E, the low byte, at Register Pair HL: the segment is now the second element of the list.
4D9D
LD H,B 60
Load Register H with Register B, the granule byte of the segment.
4D9E
LD L,C 69
Load Register L with Register C, the cylinder of the segment.
4D9F
LD A,H 7C
Load Register A with Register H, the granule byte.
4DA0
RLCA 07
Rotate Register A left, the first of three rotations.
4DA1
RLCA 07
Rotate Register A left, the second of three rotations.
4DA2
RLCA 07
Rotate Register A left a third time: the starting granule (bits 7-5) is in bits 2-0.
4DA3
AND 07H E6 07
AND Register A with 07H to keep the starting granule.
4DA5
ADD A,00H C6 00
ADD the granule's place in the segment to Register A; the operand at 4DA6H was stored at 4D6EH or 4D77H.
4DA7
LD E,A 5F
Load Register E with Register A, the granule counted from the start of the segment's cylinder.
4DA8
LD A,(IY+10H) FD 7E 10
Load Register A with the granules per cylinder at Index Register IY+10H (DCT+10H).
4DAB
GOSUB to 4943H: 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).
4DAE
ADD A,L 85
ADD Register L, the segment's cylinder, to Register A.
4DAF
LD D,A 57
Load Register D with Register A, the cylinder of the sector.
4DB0
LD A,(IY+0FH) FD 7E 0F
Load Register A with the sectors per granule at Index Register IY+0FH (DCT+0FH).
4DB3
PUSH DE D5
Save Register Pair DE to the top of the stack.
4DB4
GOSUB to 4934H: Register A = Register A times Register E, the first sector of the granule.
4DB7
POP DE D1
Restore Register Pair DE from the top of the stack.
4DB8
ADD A,00H C6 00
ADD the sector within the granule to Register A; the operand at 4DB9H was stored at 4D0FH or 4D6AH.
4DBA
LD E,A 5F
Load Register E with Register A, the sector on the cylinder.
4DBB
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4DBE
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG.
4DBF
RET C9
RETurn with Register C = the drive, Register D = the cylinder and Register E = the sector.
4DC0H - The Keyboard Driver
The start-up puts 4DC0H 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$, 435AH), and bit 5 is cleared at its end. Otherwise the keyboard is scanned the way the ROM's 03E3H does it, with a delay (04DFH counts of 0060H) added to let a new key settle before 03FBH (in ROM 1.3 a JP 011CH) decodes it.
4DC0
LD HL,4302H 21 02 43
Point Register Pair HL to 4302H, SFLAG1$, the system flags.
4DC3
BIT 5,(HL) CB 6E
Test bit 5 of SFLAG1$ at Register Pair HL (4302H), the DO file active flag.
4DC5
If the Z FLAG is set (no DO file), JUMP to 4DD9H to scan the keyboard.
4DC7
LD DE,(435AH) ED 5B 5A 43
Load Register Pair DE with DODCB$ at 435AH, the DO file's file control block.
4DCB
GOSUB to 0013H (GET@) for the next character of the DO file in Register A.
4DCE
LD C,A 4F
Load Register C with Register A, the character from the DO file.
4DCF
GOSUB to 4451H (CKEOF@) to test the DO file for its end.
4DD2
If the Z FLAG is set (more to come), JUMP to 4DD6H.
4DD4
RES 5,(HL) CB AE
Reset bit 5 of SFLAG1$ at Register Pair HL (4302H): the DO file is finished and the keyboard is used again.
4DD6
LD A,C 79
Load Register A with Register C, the character from the DO file.
4DD7
OR A B7
OR Register A with itself to set the flags for the character.
4DD8
RET C9
RETurn with Register A = the character from the DO file.
4DD9
LD HL,4036H 21 36 40
Point Register Pair HL to 4036H, the keyboard row images.
4DDC
LD BC,3801H 01 01 38
Load Register Pair BC with 3801H, the address of keyboard row 0.
4DDF
LD D,00H 16 00
Load Register D with 00H, the number of the row being scanned.
4DE1
LD A,(BC) 0A
Load Register A with the keys down in the row at Register Pair BC.
4DE2
LD E,A 5F
Load Register E with Register A, the keys down now.
4DE3
XOR (HL) AE
XOR Register A with the row's image at Register Pair HL: the keys that changed.
4DE4
LD (HL),E 73
Store Register E, the keys down now, as the row's image at Register Pair HL.
4DE5
AND E A3
AND Register A with Register E: the keys newly down.
4DE6
If the NZ FLAG is set (a new key), JUMP to 4DF0H.
4DE8
INC D 14
INCrement Register D, the number of the row, by 1.
4DE9
INC L 2C
INCrement Register L by 1 to the next row image.
4DEA
RLC C CB 01
Rotate Register C left: the address bit of the next row.
4DEC
If the P FLAG is set (Register C has not reached 80H: rows 0-6), JUMP back to 4DE1H.
4DEF
RET C9
RETurn with Register A = 00H: no new key is down.
4DF0
LD E,A 5F
Load Register E with Register A, the new keys of the row.
4DF1
PUSH BC C5
Save Register Pair BC, the row address, to the top of the stack.
4DF2
LD BC,04DFH 01 DF 04
Load Register Pair BC with 04DFH, the delay count.
4DF5
GOSUB to 0060H, the ROM's delay loop, which counts Register Pair BC down to zero.
4DF8
POP BC C1
Restore Register Pair BC, the row address, from the top of the stack.
4DF9
LD A,(BC) 0A
Load Register A with the keys of the row at Register Pair BC again.
4DFA
AND E A3
AND Register A with Register E: the new keys still down.
4DFB
RET Z C8
If the Z FLAG is set (the key went up again: a bounce), RETurn with Register A = 00H.
4DFC
JUMP to 03FBH in the ROM with Register D = the row and Register E = the key bits: in ROM 1.3, 03FBH jumps to 011CH, which waits again (0500H counts), reads the row once more and decodes the key.
4DFF
DEFS 1
Not in the file: the last byte 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$, LOW$, the command buffer and BREAK$, installs the clock and disk controller interrupt vectors and the time task, sets the step rate of drives 0-3 and the cursor and caps switches from sector 2, outputs sector 2's boot port byte, installs the keyboard driver 4DC0H (unless SHIFT and the up arrow are held), copies the diskette's geometry into drive 0's table and runs the alternate system driver when there is one. Then it displays the heading and the logo, asks for the date and the time as sector 2's flags say, reads the GAT of drive 0 and runs its AUTO command: ENTER held at boot skips it and D starts DEBUG@ instead, unless the command starts with an asterisk. Its last return goes to EXIT@. The first low overlay to load overwrites this code (4E00H-50F0H).
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,41FCH 31 FC 41
Load the Stack Pointer with 41FCH, 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 (4358H),HL 22 58 43
Store Register Pair HL, the top of memory, to 4358H.
4E1E
LD (4049H),HL 22 49 40
Store Register Pair HL, the top of memory, to HMEM$ at 4049H.
4E21
LD HL,5200H 21 00 52
Load Register Pair HL with 5200H, the first address above the low overlays.
4E24
LD (4047H),HL 22 47 40
Store Register Pair HL (5200H) to LOW$ at 4047H.
4E27
LD A,0DH 3E 0D
Load Register A with 0DH, a carriage return, for the empty command.
4E29
LD HL,4318H 21 18 43
Point Register Pair HL to 4318H, INPBUF$, the command buffer.
4E2C
LD (4310H),HL 22 10 43
Store Register Pair HL (4318H) to the command buffer pointer at 4310H.
4E2F
LD (HL),A 77
Store Register A (0DH) at Register Pair HL: INPBUF$ holds an empty command.
4E30
LD A,C9H 3E C9
Load Register A with C9H, the code of a RET instruction.
4E32
LD (4312H),A 32 12 43
Store Register A (C9H) to BREAK$ at 4312H: the BREAK vector returns at once.
4E35
XOR A AF
Set Register A to 00H by XORing it with itself.
4E36
LD (4308H),A 32 08 43
Store Register A (00H) to the DEBUG on BREAK switch at 4308H.
4E39
LD B,07H 06 07
Load Register B with 07H, the number of keyboard rows.
4E3B
LD HL,4036H 21 36 40
Point Register Pair HL to 4036H, the keyboard row images.
4E3E
LD (HL),A 77
Store Register A (00H) at Register Pair HL: no keys down in the row.
4E3F
INC HL 23
INCrement Register Pair HL by 1 to the next row image.
4E40
DECrement Register B and loop back to 4E3EH while Register B is not zero.
4E42
LD HL,404CH 21 4C 40
Point Register Pair HL to 404CH, the interrupt enable mask.
4E45
LD (HL),00H 36 00
Store 00H into the mask at Register Pair HL: no interrupt source is served yet.
4E47
LD DE,45C7H 11 C7 45
Load Register Pair DE with 45C7H, the clock task.
4E4A
LD (405BH),DE ED 53 5B 40
Store Register Pair DE (45C7H) to 405BH, the vector of latch bit 7, the real time clock.
4E4E
SET 7,(HL) CB FE
Set bit 7 of the mask at Register Pair HL (404CH): the clock interrupt is served.
4E50
LD DE,4737H 11 37 47
Load Register Pair DE with 4737H, which reads the status of the floppy disk controller.
4E53
LD (4059H),DE ED 53 59 40
Store Register Pair DE (4737H) to 4059H, the vector of latch bit 6, the floppy disk controller.
4E57
SET 6,(HL) CB F6
Set bit 6 of the mask at Register Pair HL (404CH): the controller's interrupt is served.
4E59
LD A,03H 3E 03
Load Register A with 03H, interrupt slot 3, the last of the slow chain.
4E5B
LD DE,460FH 11 0F 46
Load Register Pair DE with 460FH, the time task block.
4E5E
GOSUB to 4410H (SET@) to put the time task block at Register Pair DE into slot Register A.
4E61
LD C,00H 0E 00
Load Register C with 00H, drive 0, the first drive to set.
4E63
GOSUB to 448BH (LOCDCT%): Index Register IY returns the drive control table of drive Register C.
4E66
LD A,(5216H) 3A 16 52
Load Register A with the default step rate, BOOT/SYS sector 2 byte 16H at 5216H.
4E69
LD (IY+04H),A FD 77 04
Store Register A to the step rate code at Index Register IY+04H (DCT+04H).
4E6C
LD A,03H 3E 03
Load Register A with 03H, the last drive to set.
4E6E
INC C 0C
INCrement Register C, the drive, by 1 to the next drive.
4E6F
CP C B9
Compare Register A against Register C. The NC FLAG is set while Register C is 3 or less.
4E70
If the NC FLAG is set, JUMP back to 4E63H for the next drive.
4E72
LD A,(5213H) 3A 13 52
Load Register A with the cursor blink switch, byte 13H at 5213H.
4E75
LD (401CH),A 32 1C 40
Store Register A to 401CH, the cursor blink switch in the keyboard DCB.
4E78
LD A,(5214H) 3A 14 52
Load Register A with the cursor character, byte 14H at 5214H.
4E7B
LD (4023H),A 32 23 40
Store Register A to 4023H, the cursor character in the video DCB.
4E7E
LD A,(5215H) 3A 15 52
Load Register A with the caps switch, byte 15H at 5215H.
4E81
LD (4019H),A 32 19 40
Store Register A to 4019H, the caps switch in the keyboard DCB.
4E84
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.
4E88
OUT (C),B ED 41
Output Register B to the port in Register C. With the master's bytes, 00H goes to port 00H.
4E8A
GOSUB to 002BH (KBD@) to scan the keyboard once: Register A returns the key held at boot, or 00H.
4E8D
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.
4E90
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.
4E92
If the Z FLAG is set (SHIFT and the up arrow are held), JUMP to 4E9AH: the ROM's keyboard driver is kept.
4E94
LD HL,4DC0H 21 C0 4D
Load Register Pair HL with 4DC0H, the DOSPLUS keyboard driver.
4E97
LD (4016H),HL 22 16 40
Store Register Pair HL (4DC0H) to 4016H, the driver address of the keyboard DCB.
4E9A
LD HL,4EC5H 21 C5 4E
Load Register Pair HL with 4EC5H, where the start-up goes on.
4E9D
PUSH HL E5
Save Register Pair HL (4EC5H) to the top of the stack, the return of 4EC0H or of the alternate system driver.
4E9E
LD C,00H 0E 00
Load Register C with 00H, drive 0, the drive that was booted.
4EA0
GOSUB to 448BH (LOCDCT%): Index Register IY returns the drive control table of drive 0.
4EA3
PUSH IY FD E5
Save Index Register IY, the drive control table, to the top of the stack.
4EA5
POP HL E1
Restore it into Register Pair HL from the top of the stack.
4EA6
LD DE,000BH 11 0B 00
Load Register Pair DE with 000BH, the offset of the perishable bytes.
4EA9
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL = DCT+0BH of drive 0.
4EAA
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = DCT+0BH of drive 0.
4EAB
LD HL,5203H 21 03 52
Point Register Pair HL to 5203H, the perishable bytes in BOOT/SYS sector 2.
4EAE
LD BC,0009H 01 09 00
Load Register Pair BC with 0009H, the nine bytes DCT+0BH-13H.
4EB1
LDIR ED B0
Move Register Pair BC bytes from Register Pair HL to Register Pair DE: drive 0 takes the geometry of the diskette booted.
4EB3
LD A,(IY+0BH) FD 7E 0B
Load Register A with DCT+0BH at Index Register IY+0BH.
4EB6
AND 80H E6 80
AND Register A with 80H to keep bit 7, double density.
4EB8
LD (4300H),A 32 00 43
Store Register A to 4300H, the drive and density of the last disk access: drive 0 at this density.
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,504BH 21 4B 50
Point Register Pair HL to 504BH, 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,4315H 21 15 43
Point Register Pair HL to 4315H, 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,4044H 11 44 40
Point Register Pair DE to 4044H, 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,4041H DD 21 41 40
Point Index Register IX to 4041H, 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,503DH 21 3D 50
Point Register Pair HL to 503DH, 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,4200H 21 00 42
Point Register Pair HL to 4200H, 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 (4046H).
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 (4045H).
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 4971H (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 (4044H).
4F20
LD HL,4044H 21 44 40
Point Register Pair HL to 4044H, DATE$, the date just typed.
4F23
LD DE,4315H 11 15 43
Point Register Pair DE to 4315H, 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 4315H 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,5044H 21 44 50
Point Register Pair HL to 5044H, 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,4200H 21 00 42
Point Register Pair HL to 4200H, 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 (4043H).
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 (4042H).
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 (4041H).
4F58
LD HL,4200H 21 00 42
Point Register Pair HL to 4200H, 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 4485H (DISKIO%) to read the GAT of drive 0 into 4200H.
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,42E0H 21 E0 42
Point Register Pair HL to 42E0H, 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 was stored at 4E8DH.
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,4318H 11 18 43
Point Register Pair DE to 4318H, 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,4318H 21 18 43
Point Register Pair HL to 4318H, 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 (503DH, 5044H) and the DOSPLUS logo (504BH), 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-503C
DEFB 1CH,1FH / DEFM "DOSPLUS - Model I 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 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.
503D-5043
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.
5044-504A
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.
504B-5081
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.
5082-50B8
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.
50B9-50EF
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.
50F0
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.