3C00H - Sign-On Screen (Video Memory, Data)
Four load blocks of SYS0/SYS go straight into video memory (3C00H-3FFFH, 64 characters by 16 rows): while the boot sector loads the file, the sign-on lines and the LDOS logo appear on the screen. They are data, not code. SYS0/SYS's reset later adds the diskette name and date (3CD1H, 3CE5H), the date and time prompts (3F17H, 3F57H) and the day and date line it builds from them.
3C00-3C39
DEFM " L D O S - The Logical Disk Operating System - Ver 5.3.1" 20 20 20 4C 20 44 20 4F 20 53 20 2D 20 54 68 65 20 4C 6F 67 69 63 61 6C 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 56 65 72 20 35 2E 33 2E 31
Screen row 0, columns 0-57: the title line, three spaces then L D O S - The Logical Disk Operating System - Ver 5.3.1.
3C3A-3C45
DEFS 12
Not in the file: screen row 0, columns 58-63, and row 1, columns 0-5, keep whatever the screen held when the boot sector ran.
3C46-3C76
DEFM "Copyright 1991 MISOSYS, Inc., All rights reserved" 43 6F 70 79 72 69 67 68 74 20 31 39 39 31 20 4D 49 53 4F 53 59 53 2C 20 49 6E 63 2E 2C 20 41 6C 6C 20 72 69 67 68 74 73 20 72 65 73 65 72 76 65 64
Screen row 1, columns 6-54: the copyright line, in capitals and small letters as the file holds it.
3C77-3D3F
DEFS 201
Not in the file: the rest of row 1 and rows 2-4 (3C77H-3D3FH). SYS0/SYS's reset writes the name of the diskette in drive 0 at 3CD1H-3CD8H and its date at 3CE5H-3CECH (row 3, 4FEBH-4FF9H).
3D40-3D4F
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 20 20 20 20 20 20
Screen row 5, columns 0-15, the top row of the logo: a space, then the upright of the L (BFH BFH at columns 1-2) and 13 spaces. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3D50-3D5F
DEFB 20H, BFH, BFH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, AFH, BDH, B4H, 20H, 20H, 20H, 20H 20 BF BF 8F 8F 8F 8F 8F 8F AF BD B4 20 20 20 20
Screen row 5, columns 16-31, the top row of the logo: the top of the D: upright BFH BFH, bar 8FH x 6, the corner AFH BDH B4H, then spaces. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3D60-3D6F
DEFB 20H, BFH, BFH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, BFH, BFH, 20H, 20H, 20H 20 BF BF 8F 8F 8F 8F 8F 8F 8F 8F BF BF 20 20 20
Screen row 5, columns 32-47, the top row of the logo: the top of the O: upright BFH BFH, bar 8FH x 8, upright BFH BFH, then spaces. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3D70-3D7F
DEFB 20H, BFH, BFH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, BFH, BFH, 20H, 54H, 4DH 20 BF BF 8F 8F 8F 8F 8F 8F 8F 8F BF BF 20 54 4D
Screen row 5, columns 48-63, the top row of the logo: the top of the S: BFH BFH, bar 8FH x 8, BFH BFH, a space and TM (54H 4DH) at columns 62-63. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3D80-3D8F
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 20 20 20 20 20 20
Screen row 6, columns 0-15, the second row of the logo: a space, the upright of the L (BFH BFH) and spaces. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3D90-3D9F
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 82H, BFH, BDH, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 82 BF BD 20 20 20
Screen row 6, columns 16-31, the second row of the logo: the D: its left upright BFH BFH, spaces, then the curve 82H BFH BDH at columns 25-27. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3DA0-3DAF
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, BFH, BFH, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 20 BF BF 20 20 20
Screen row 6, columns 32-47, the second row of the logo: the O: left upright BFH BFH, spaces, right upright BFH BFH. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3DB0-3DBF
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 20 20 20 20 20 20
Screen row 6, columns 48-63, the second row of the logo: the S: its left upright BFH BFH at columns 48-49 and spaces. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3DC0-3DCF
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 20 20 20 20 20 20
Screen row 7, columns 0-15, the third row of the logo: a space, the upright of the L (BFH BFH) and spaces. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3DD0-3DDF
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, BFH, BFH, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 20 BF BF 20 20 20
Screen row 7, columns 16-31, the third row of the logo: the D: left upright BFH BFH, spaces, right side BFH BFH at columns 26-27. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3DE0-3DEF
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, BFH, BFH, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 20 BF BF 20 20 20
Screen row 7, columns 32-47, the third row of the logo: the O: left upright BFH BFH, spaces, right upright BFH BFH. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3DF0-3DFF
DEFB 20H, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, 8FH, BFH, BFH, 20H, 20H, 20H 20 8F 8F 8F 8F 8F 8F 8F 8F 8F 8F BF BF 20 20 20
Screen row 7, columns 48-63, the third row of the logo: the middle bar of the S: 8FH x 10 at columns 48-57 and BFH BFH at columns 58-59. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3E00-3E0F
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 20 20 20 20 20 20
Screen row 8, columns 0-15, the fourth row of the logo: a space, the upright of the L (BFH BFH) and spaces. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3E10-3E1F
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, A0H, BFH, 9FH, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 A0 BF 9F 20 20 20
Screen row 8, columns 16-31, the fourth row of the logo: the D: left upright BFH BFH, spaces, the curve A0H BFH 9FH at columns 25-27. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3E20-3E2F
DEFB 20H, BFH, BFH, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, BFH, BFH, 20H, 20H, 20H 20 BF BF 20 20 20 20 20 20 20 20 BF BF 20 20 20
Screen row 8, columns 32-47, the fourth row of the logo: the O: left upright BFH BFH, spaces, right upright BFH BFH. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3E30-3E3F
DEFB 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, 20H, BFH, BFH, 20H, 20H, 20H 20 20 20 20 20 20 20 20 20 20 20 BF BF 20 20 20
Screen row 8, columns 48-63, the fourth row of the logo: the S: its right upright BFH BFH at columns 58-59 and spaces. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3E40-3E4F
DEFB 20H, BFH, BFH, BCH, BCH, BCH, BCH, BCH, BCH, BCH, BCH, BFH, BFH, 20H, 20H, 20H 20 BF BF BC BC BC BC BC BC BC BC BF BF 20 20 20
Screen row 9, columns 0-15, the bottom row of the logo: a space, the foot of the L: BFH BFH and the bar BCH x 8, BFH BFH at columns 11-12. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3E50-3E5F
DEFB 20H, BFH, BFH, BCH, BCH, BCH, BCH, BCH, BCH, BEH, 9FH, 87H, 20H, 20H, 20H, 20H 20 BF BF BC BC BC BC BC BC BE 9F 87 20 20 20 20
Screen row 9, columns 16-31, the bottom row of the logo: the bottom of the D: upright BFH BFH, bar BCH x 6, the corner BEH 9FH 87H. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3E60-3E6F
DEFB 20H, BFH, BFH, BCH, BCH, BCH, BCH, BCH, BCH, BCH, BCH, BFH, BFH, 20H, 20H, 20H 20 BF BF BC BC BC BC BC BC BC BC BF BF 20 20 20
Screen row 9, columns 32-47, the bottom row of the logo: the bottom of the O: BFH BFH, bar BCH x 8, BFH BFH. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3E70-3E7F
DEFB 20H, BFH, BFH, BCH, BCH, BCH, BCH, BCH, BCH, BCH, BCH, BFH, BFH, 20H, 20H, 20H 20 BF BF BC BC BC BC BC BC BC BC BF BF 20 20 20
Screen row 9, columns 48-63, the bottom row of the logo: the bottom of the S: BFH BFH, bar BCH x 8, BFH BFH. Codes 80H-BFH are graphics characters (two by three blocks, bit 0 the top left block up to bit 5 the bottom right), 20H is a space.
3E80-3FFF
DEFS 384
Not in the file: screen rows 10-15. SYS0/SYS's reset puts the Date? prompt at 3F17H (row 12) and the Time? prompt at 3F57H (row 13), and moves the cursor to 3F40H (row 13, column 0) before it returns (5075H-5078H).
400CH - Restart Vectors
The Model III ROM sends its RST 28H, RST 30H and RST 38H restarts through these three bytes each (ROM 0028H, 0030H and 0038H jump to 400CH, 400FH and 4012H). SYS0/SYS loads a JP into each: the supervisor call dispatcher, the DEBUG entry and the interrupt service routine. RST 28H with a request code in Register A is how every overlay of the system is called.
400C
Jump to 4BCCH, the supervisor call dispatcher. ROM 0028H (RST 28H) comes here with the request code in Register A (for example 93H, return to LDOS Ready, from 402DH). 4BCCH loads the system file the code names into 4E00H when it is not already there and runs it.
400F
Jump to 440DH, which saves Register Pair AF and issues request 87H (load and run SYS5/SYS, the DEBUG monitor). ROM 0030H (RST 30H, the breakpoint instruction DEBUG plants) comes here; SYS0/SYS's own 4C72H jumps here to enter DEBUG before a loaded program runs, and SYS5/SYS reads this vector (its 4F98H).
4012
Jump to 44A5H, the interrupt service routine. ROM 0038H (RST 38H, the maskable interrupt in mode 1) comes here on every interrupt. SYS0/SYS's reset stores C3H (the JP) here again as its last step (507BH-507EH); BACKUP/CMD, FORMAT/CMD and QFB/CMD address 4012H too.
4015H - Device Control Blocks of the Keyboard, Video and Printer
The ROM's three device control blocks, eight bytes each, loaded with exactly the bytes of the ROM's power-up copy at 36BFH-36D6H: +00H the type of device, +01H-+02H the address of its driver, +03H-+07H the driver's own bytes. SYS0/SYS's reset then points the keyboard block at 41EDH, the video block at 4DB2H (unless RIGHT ARROW is held) and the printer block at 41E5H, and saves the addresses it installs at 42B8H, 42BAH and 42BCH.
4015
DEFB 01H 01
4015H, KIDCB$, the keyboard's device control block, +00H: 01H, the device type (an input device). SYS2/SYS (its 4F0BH), SYS6/SYS and SYS11/SYS (its 4EBDH, 4F6CH) address the block from here.
4016-4017
DEFW 3024H 24 30
4016H-4017H, KIDCB$ +01H-+02H: 3024H, the ROM's keyboard driver (a JP 338EH). SYS0/SYS's reset replaces it with 41EDH (4E4EH-4E51H), which calls the @KITSK hook at 4285H first and then jumps to 3024H.
4018
DEFB 00H 00
4018H, KIDCB$ +03H: 00H, the ROM keyboard driver's image of the SHIFT row (3880H) from its last scan (the ROM reads it at 3396H).
4019
DEFB 01H 01
4019H, KIDCB$ +04H: 01H, the ROM keyboard driver's caps lock switch: not 00H, so letters come as capitals until the caps lock is toggled.
401A
DEFB 07H 07
401AH, KIDCB$ +05H: 07H, the cursor blink countdown of the ROM's real time clock routine (353BH-3541H), reloaded with 07H each time it reaches 0.
401B
DEFB 00H 00
401BH, KIDCB$ +06H: 00H, the blink phase the ROM's real time clock routine flips between the cursor character and a space (3543H-3549H).
401C
DEFB 00H 00
401CH, KIDCB$ +07H: 00H, the blink switch: the ROM's real time clock routine blinks the cursor only while it is 00H (3535H). SYS0/SYS's video driver at 4DB2H sets its bit 7 while the ROM's video driver runs (4DB2H, 4DB9H). SYSTEM (BLINK) of SYS7/SYS stores 00H here to blink and FFH to stop (its 5331H).
401D
DEFB 07H 07
401DH, DODCB$, the video display's device control block, +00H: 07H, the device type (input, output and control). @DSPLY (4D39H) and @LOGOT (428AH) send their text to the block at 401DH.
401E-401F
DEFW 0473H 73 04
401EH-401FH, DODCB$ +01H-+02H: 0473H, the ROM's video driver (its first instruction is DI). SYS0/SYS's reset replaces it with 4DB2H, which runs the ROM's driver from 0474H with interrupts left on, unless RIGHT ARROW is held at boot (4E57H-4E68H), and saves the address in force at 42BAH.
4020-4021
DEFW 3C00H 00 3C
4020H-4021H, DODCB$ +03H-+04H: 3C00H, the cursor position in video memory (the top left corner). SYS0/SYS sets it for each boot prompt (4228H, 4F5EH) and leaves it at 3F40H, row 13, after the reset (5075H-5078H); BASIC/CMD, FED/CMD and many other programs read and set it.
4022
DEFB 00H 00
4022H, DODCB$ +05H: 00H, the character under the cursor, or 00H when the cursor is off; the ROM's real time clock routine blinks a cursor only while it is not 00H (352FH-3533H).
4023
DEFB B0H B0
4023H, DODCB$ +06H: B0H, the cursor character the ROM's real time clock routine puts on the screen in the visible phase of the blink (354FH). SYSTEM (BLINK) of SYS7/SYS stores the cursor character here (its 532DH).
4024
DEFB 00H 00
4024H, DODCB$ +07H: 00H, the switch the ROM's video driver toggles (0560H-0569H): while it is 00H the driver shows the codes C0H-FFH as runs of spaces (04B7H-04BEH). DEBUG (SYS7/SYS, its 5220H) stores 00H here.
4025
DEFB 06H 06
4025H, PRDCB$, the printer's device control block, +00H: 06H, the device type (output and control). @PRINT (4D4EH) sends its text to the block at 4025H; BASIC/CMD, FED/CMD and LCOMM/CMD address it too.
4026-4027
DEFW 03C2H C2 03
4026H-4027H, PRDCB$ +01H-+02H: 03C2H, the ROM's printer driver. SYS0/SYS's reset replaces it with 41E5H (4E6EH-4E71H), which answers a control request with the printer status, and saves 41E5H at 42BCH.
4028
DEFB 43H 43
4028H, PRDCB$ +03H: 43H (67), the lines on a printer page, the ROM's default; the ROM's printer driver compares the line count with it (0434H).
4029
DEFB 01H 01
4029H, PRDCB$ +04H: 01H, the line count of the page being printed; the ROM's printer driver adds one at each line (042EH) and puts 01H back at the top of a page (0439H).
402A
DEFB 00H 00
402AH, PRDCB$ +05H: 00H, the count of characters printed on the line, which the ROM's printer driver clears at each carriage return (03DFH, 0415H).
402B
DEFB FFH FF
402BH, PRDCB$ +06H: FFH, the width of a printed line that the ROM's printer driver compares the character count with (0403H-0409H); FFH, the ROM's default.
402C
DEFB 52H 52
402CH, PRDCB$ +07H: 52H, the last byte of the printer block as the ROM's power-up copy loads it. No instruction of the LDOS files on this diskette addresses it.
402DH - @EXIT and @ABORT
The two ways a program ends. Both issue request 93H, which runs the LDOS Ready command loop of SYS1/SYS. Programs JP to 402DH (@EXIT) when they finish and to 4030H (@ABORT) when they stop on an error; SYS1/SYS pushes 402DH as the return address of a command it runs (its 4E58H).
402D
LD A,93H 3E 93
@EXIT: load Register A with 93H, the request code of SYS1/SYS's function 10H, the LDOS Ready command loop: the normal end of a program.
402F
RST 28H EF
RST 28H: call the supervisor dispatcher (400CH, 4BCCH) with the request code 93H in Register A. SYS1/SYS displays LDOS Ready and waits for the next command; it does not return here.
4030
LD A,93H 3E 93
@ABORT: load Register A with 93H, the same request code as @EXIT: the end of a program after an error. 44FDH (the cassette BREAK exit) and SYS4/SYS come here.
4032
RST 28H EF
RST 28H: call the supervisor dispatcher with the request code in Register A (93H): LDOS Ready.
4033
@DVRHK: jump to 4D65H. The ROM's character input and output routine jumps to 4033H when the type of a device control block does not match the request; 4D65H takes the address in the block at Index Register IX and enters it, or hands an open file to 48ECH.
4036-403C
DEFB FFH x 7 FF x 7
4036H-403CH: the ROM keyboard driver's work area, one byte for each keyboard row, the keys it last saw held. FFH in every byte makes every key held while SYS0/SYS loads count as already seen, so a key held during the boot is not taken as typed.
403D
@ADTSK: jump to 4552H to add a task: Register A = the task slot (0-11) and Register Pair DE = the task's block, whose first word is the address of its routine. SYS0/SYS's interrupt routine does not use the ROM's vector that was at 403DH.
4040
@RMTSK: jump to 454FH to remove the task in slot Register A: its entry in the task table at 4500H gets the empty block 455FH. LCOMM/CMD and SYS6/SYS call 4040H.
4043
@RPTSK: jump to 4561H. A task routine calls it to have its next run start at the instruction after the CALL; the task ends for this tick.
4046-40AC
DEFS 103
Not in the file: 4046H-40ACH. 4046H-4048H, @KLTSK, keeps the JP opcode of the ROM's clock vector; the reset saves the ROM's address there (3529H) at 4BBCH and puts 454AH in its place (4E01H-4E12H). 4049H-404BH is the NMI vector (the reset stores 46F9H at 404AH, 4E07H-4E0CH) and 405DH-408AH, DBGSV$, gets the end of the reset (5036H-503CH).
40AD
DEFB 00H 00
40ADH: one byte of 00H loaded on its own. No instruction of the LDOS files on this diskette and of the ROM addresses it.
40AE-41E2
DEFS 309
Not in the file: 40AEH-41E2H, RAM that the ROM and BASIC/CMD use. SYS0/SYS's reset sets its Stack Pointer to 41E3H, so the reset's stack grows down from 41E2H (4E15H).
41E3H - The Reset's Return Word
Two bytes at the top of the stack SYS0/SYS's reset sets (Stack Pointer 41E3H at 4E15H). Then the printer and keyboard drivers SYS0/SYS puts over the ROM's two RS-232 device control blocks (41E5H-41F4H), which LDOS does not use.
41E3-41E4
DEFB 00H x 2 00 x 2
41E3H-41E4H: 0000H. The reset starts with the Stack Pointer at 41E3H, so this is the word a RET would take with nothing pushed: 0000H, the ROM's restart. BASIC/CMD addresses 41E4H (its 559EH).
41E5
The printer driver the reset puts at 4026H: the ROM's device routine comes here with the flags of the request (CARRY for input, Z for output, NZ for a control request). If the CARRY FLAG is set (an input request), jump to 41EAH and the ROM's printer driver.
41E7
If the NZ FLAG is set (a control request), jump to the ROM's printer status test at 044BH, which reads port F8H and returns the Z FLAG when the printer is ready.
41EA
Jump to 03C2H, the ROM's printer driver, to print the character in Register C (an output request, the Z FLAG set). 41E5H comes here for an input request too.
41ED
The keyboard driver the reset puts at 4016H: GOSUB to 4285H, the @KITSK hook, a RET until a module puts a JP there to run a task on every key request.
41F0
Jump to 3024H, the ROM's keyboard driver, which returns the key in Register A (00H when no key is pressed).
41F3-4202
DEFS 16
Not in the file: 41F3H-4202H, the rest of the ROM's RS-232 output block and RAM up to 4202H that the ROM keeps.
4203H - The BREAK Vector, @CKDRV and the Date
4203H is the vector the ROM jumps to when BREAK is pressed while it waits on the cassette or the RS-232 port (3362H, 3677H, 3699H). Then the ROM's interrupt vector at 4206H, the @CKDRV request stub and the date.
4203
Jump to 44FAH, which turns the cassette motor off and ends the program through @ABORT. SYS0/SYS's interrupt routine also sends interrupt bits 0 and 1, the cassette's, here (4475H-4478H); SYS1/SYS makes it a jump to 4206H before every command line it carries out (its 4E5CH-4E65H), and nothing on this diskette puts 44FAH back.
4206-4208
DEFB 00H x 3 00 x 3
4206H-4208H: three bytes of 00H over the ROM's vector of interrupt bit 4 (the ROM's poll jumps here at 35E1H; SYS0/SYS's interrupt routine does not use it). SYS1/SYS stores 4206H at 4204H, making 4203H a jump to these bytes (its 4E5CH-4E65H).
4209
LD A,C4H 3E C4
@CKDRV: load Register A with 0C4H, the request code of SYS2/SYS's function 40H: check that the drive in Register C is ready and holds a diskette. BACKUP/CMD, CMDFILE/CMD, DATECONV/CMD, HELP/CMD, LOG/CMD and SYS7/SYS call 4209H.
420B
RST 28H EF
RST 28H: call the supervisor dispatcher (400CH, 4BCCH) with the request code in Register A (0C4H).
420C-4219
DEFS 14
Not in the file: 420CH-4219H. The reset stores its port ECH value at 4210H (4E26H) and its interrupt mask at 4213H (4E2DH); 4217H-4219H is TIME$, the seconds, minutes and hours, which the ROM's real time clock routine counts and the reset sets from the Time prompt (4FC0H-4FC6H).
421A
DEFB 00H 00
421AH, DATE$ +00H: the year, a number 0-99 (the last two digits), stored by the reset at 4F3AH and displayed by it at 4F81H. SYS3/SYS reads it (its 4E71H).
421B
DEFB 00H 00
421BH, DATE$ +01H: the day of the month (1-31), stored by the reset at 4F14H and displayed by it at 4F76H.
421C
DEFB 00H 00
421CH, DATE$ +02H: the month (1-12), stored by the reset at 4EFFH and displayed by it at 4F6AH. BACKUP/CMD reads it (its 5B36H).
421D
RET C9
@ICNFG: RETurn at once. SYS0/SYS's reset calls 421DH after the configuration file has been loaded (5072H); a configuration that needs to run code at boot leaves a jump here, a JP opcode at 421DH and its address at 421EH-421FH.
421E-421F
DEFB 00H x 2 00 x 2
421EH-421FH: the address of the @ICNFG jump, 0000H while 421DH holds the RET.
4220-4221
DEFB 00H x 2 00 x 2
4220H-4221H, JDCB$: the address of the file or device control block of the current file call, stored by the file prologue (49F9H). SYS4/SYS reads it to name the file in an error message (its 4F6BH).
4222-4227
DEFS 6
Not in the file: 4222H-4224H, which no instruction of the LDOS files on this diskette addresses, and 4225H-4227H, the first bytes of INBUF$, the command line buffer (4225H-4264H). During the reset the date and time parser stores its three fields at 4227H, 4226H and 4225H (4256H-4276H).
4228H - Boot Prompt: Display, Input, Parse
Used only by the reset (4EBDH for the date, 4FADH for the time); once the reset has finished, 4228H-4264H is part of INBUF$ and the AUTO command is copied over it (502BH-5031H). Register Pair HL gives the screen address of the prompt, Register Pair DE the prompt text, Register B the most characters to accept and Register C the limit for a separator. Returns with the CARRY FLAG set when three fields of two digits were read.
4228
LD (4020H),HL 22 20 40
Store Register Pair HL (the screen address of the prompt, 3F17H for the date or 3F57H for the time) at 4020H-4021H, the cursor position of the video's device control block: the prompt is displayed there.
422B
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL now points at the prompt text (50B4H or 50BDH), Register Pair DE holds the screen address.
422C
GOSUB to 4467H (@DSPLY) to display the prompt text at Register Pair HL: 1EH (clear to the end of the line), then Date ? or Time ? and a space, ended by 03H.
422F
LD HL,4E00H 21 00 4E
Point Register Pair HL to 4E00H, the line buffer: the start of the reset code, which has already run.
4232
PUSH BC C5
Save Register Pair BC (Register B = the most characters, Register C = the separator limit) to the stack; the ROM's line input changes Register B.
4233
GOSUB to the ROM's line input at 0040H: it takes up to Register B characters into the buffer at Register Pair HL (4E00H) until ENTER and returns with Register B = the number of characters typed.
4236
XOR A AF
Set Register A to 00H (XOR A), which also clears the CARRY FLAG.
4237
OR B B0
OR Register B (the number of characters typed) into Register A: the Z FLAG is set when nothing was typed. The CARRY FLAG stays clear.
4238
POP BC C1
Restore Register Pair BC (Register B = the most characters, Register C = the separator limit) from the stack. POP does not change the flags.
4239
RET Z C8
If the Z FLAG is set (nothing was typed), RETurn with the CARRY FLAG clear: no fields.
423A
JUMP to 4256H to parse the line at Register Pair HL (4E00H).
423C
LD A,(HL) 7E
Fetch the next character of the line from Register Pair HL into Register A. 425CH and 4267H call this routine.
423D
INC HL 23
INCrement Register Pair HL past the character just fetched.
423E
SUB 30H D6 30
SUBtract 30H (the character 0) from Register A: a digit becomes its value 0-9.
4240
CP 0AH FE 0A
Compare Register A against 0AH. The CARRY FLAG is set when the character was a digit (0-9); a character below 0 wraps to D0H-FFH and does not set it.
4242
RET C9
RETurn with the CARRY FLAG set and Register A = the digit's value, or the CARRY FLAG clear (not a digit).
4243-4244
DEFS 2
Not in the file: 4243H-4244H, two bytes of INBUF$ (4225H-4264H) between the digit fetch and the file specification below.
4245H - The CONFIG/SYS Filespec
The name the reset passes to @LOAD (4430H) to load the configuration that SYSTEM (SYSGEN) saved (504BH-5050H). After the reset these bytes are part of INBUF$; SYS1/SYS addresses 424EH (its 4EE1H).
4245-4254
DEFM "CONFIG/SYS.CCC:0" 43 4F 4E 46 49 47 2F 53 59 53 2E 43 43 43 3A 30
4245H-4254H: the file specification CONFIG/SYS.CCC:0, the file CONFIG/SYS with the password CCC on drive 0, which the reset gives @LOAD in Register Pair DE (504BH).
4255
DEFB 03H 03
4255H: 03H, the byte that ends the file specification CONFIG/SYS.CCC:0 above.
4256H - Parse Three Two Digit Fields
Reads the line at Register Pair HL as three fields of two digits each, separated by any one character below the limit in Register C, and stores them at 4227H, 4226H and 4225H (the first field typed at 4227H). Returns with the CARRY FLAG set when all three were read. A field that is not two digits, a separator not below Register C, or ENTER before the third field returns with the CARRY FLAG clear. 4265H-427FH is reused as JFCB$ after the reset.
4256
LD DE,4227H 11 27 42
Point Register Pair DE to 4227H, where the first field goes.
4259
LD B,03H 06 03
Load Register B with 03H, the number of fields.
425B
PUSH DE D5
Save Register Pair DE (the address for this field) to the stack: Register E is used for the value below. 427EH loops back here.
425C
GOSUB to 423CH to fetch the next character from Register Pair HL: the CARRY FLAG is set and Register A holds its value if it is a digit.
425F
If the NO CARRY FLAG is set (not a digit), JUMP to 4270H to return with the CARRY FLAG clear.
4261
LD E,A 5F
Copy Register A (the first digit) into Register E.
4262
RLCA 07
Rotate Register A left one bit: Register A = the first digit x 2 (a digit is at most 9, so no bit is lost).
4263
RLCA 07
Rotate Register A left one bit again: Register A = the first digit x 4.
4264
ADD A,E 83
ADD Register E (the first digit) to Register A: Register A = the first digit x 5.
4265
RLCA 07
Rotate Register A left one bit: Register A = the first digit x 10.
4266
LD E,A 5F
Copy Register A (the first digit times 10, the tens) into Register E for the addition below.
4267
GOSUB to 423CH to fetch the next character from Register Pair HL: the second digit.
426A
If the NO CARRY FLAG is set (the second character is not a digit), JUMP to 4270H to return with the CARRY FLAG clear.
426C
ADD A,E 83
ADD Register E (the tens) to Register A (the second digit): Register A = the value of the field, 0-99.
426D
LD E,A 5F
Copy Register A (the field's value) into Register E.
426E
SCF 37
Set the CARRY FLAG: the field is two good digits, the value is in Register E.
426F
LD A,E 7B
Copy Register E (the field's value) into Register A.
4270
POP DE D1
Restore Register Pair DE (the address for this field) from the stack. POP does not change the flags.
4271
RET NC D0
If the NO CARRY FLAG is set (the field was not two digits), RETurn with the CARRY FLAG clear.
4272
LD (DE),A 12
Store Register A (the field's value) at Register Pair DE (4227H, 4226H or 4225H).
4273
DEC B 05
DECrement Register B, the fields still to read.
4274
SCF 37
Set the CARRY FLAG (DEC does not change it, so it is set again for the return below).
4275
RET Z C8
If the Z FLAG is set (Register B reached 0: all three fields are stored), RETurn with the CARRY FLAG set.
4276
DEC DE 1B
DECrement Register Pair DE: the next field goes one byte lower.
4277
LD A,(HL) 7E
Fetch the character after the field from Register Pair HL into Register A: the separator.
4278
INC HL 23
INCrement Register Pair HL past the separator.
4279
CP C B9
Compare Register A (the separator) against Register C (the limit: 30H for the date, so any character below 0, or 3BH for the time, so the : too). The NO CARRY FLAG is set when the separator is not below the limit.
427A
RET NC D0
If the NO CARRY FLAG is set (the separator in Register A is not below Register C), RETurn with the CARRY FLAG clear.
427B
CP 0DH FE 0D
Compare Register A (the separator) against 0DH, ENTER. The Z FLAG is set (and the CARRY FLAG cleared) when the line ends here.
427D
RET Z C8
If the Z FLAG is set (the line ended before the third field), RETurn with the CARRY FLAG clear.
427E
JUMP back to 425BH to read the next field at Register Pair HL into the next byte down.
4280-4284
DEFS 5
Not in the file: 4280H-4284H, the last bytes of JFCB$ (4265H-4284H), the control block SYS11/SYS uses for a JCL file.
4285H - @KITSK, the Flags, @LOGOT and Request Stubs
A hook for the keyboard, TIMER$ and DFLAG$, the job log entries, five request stubs, KFLAG$, the port FEH byte and SFCB$.
4285
RET C9
@KITSK: RETurn at once. The keyboard driver at 41EDH calls 4285H on every key request, and BASIC/CMD calls it too (its 5621H, 5C6EH); a module that wants to run on every key request puts a JP here (C3H and the address at 4286H-4287H).
4286-4287
DEFB 00H x 2 00 x 2
4286H-4287H: the address of the @KITSK jump, 0000H while 4285H holds the RET.
4288
DEFB 00H 00
4288H, TIMER$: the tick counter, incremented on every clock interrupt by 4530H; its bits 2-0 pick the task slot run on each tick. BACKUP/CMD, FORMAT/CMD, SYS2/SYS and SYS12/SYS read it to time delays.
4289
DEFB 00H 00
4289H, DFLAG$, the device flags that the modules which install themselves in memory set and test, 00H at boot. LCOMM/CMD, SYS6/SYS, SYS7/SYS and TED/CMD read and set it.
428A
@LOGOT: GOSUB to 4D39H (@DSPLY) to display the text at Register Pair HL on the video, then go on into @LOGER below to send it to the job log. BACKUP/CMD and many other programs call 428AH.
428D
RET C9
@LOGER: RETurn at once: the job log takes nothing while this byte is a RET. SYS1/SYS (its 4E68H) and SYS11/SYS (its 4F33H, 4FD1H) call 428DH.
428E-428F
DEFB 00H x 2 00 x 2
428EH-428FH: two bytes of 00H after @LOGER, the room for an address when a module puts a JP at 428DH. No instruction of the LDOS files on this diskette addresses them.
4290
LD A,9EH 3E 9E
@RAMDIR: load Register A with 9EH, the request code of SYS12/SYS's function 10H: directory information into memory. No instruction of the LDOS files on this diskette calls 4290H.
4292
RST 28H EF
RST 28H: call the supervisor dispatcher (400CH, 4BCCH) with the request code in Register A (9EH).
4293
LD A,A5H 3E A5
@FNAME: load Register A with 0A5H, the request code of SYS3/SYS's function 20H: build the file specification of directory record Register B on drive Register C into the buffer at Register Pair DE. LCOMM/CMD calls 4293H.
4295
RST 28H EF
RST 28H: call the supervisor dispatcher with the request code in Register A (0A5H).
4296
LD A,93H 3E 93
@CMD: load Register A with 93H, the request code of SYS1/SYS's function 10H, the LDOS Ready command loop. The reset pushes 4296H as its last return address when there is no AUTO command (501FH).
4298
RST 28H EF
RST 28H: call the supervisor dispatcher (400CH, 4BCCH) with the request code in Register A (93H). SYS1/SYS does not return.
4299
LD A,B3H 3E B3
@CMNDI: load Register A with 0B3H, the request code of SYS1/SYS's function 30H: carry out the command line at Register Pair HL. The reset pushes 4299H to carry out the AUTO command (5024H); BASIC/CMD and SYS11/SYS call it.
429B
RST 28H EF
RST 28H: call the supervisor dispatcher with the request code in Register A (0B3H).
429C
LD A,A3H 3E A3
Load Register A with 0A3H, the request code of SYS1/SYS's function 20H: carry out the command line at Register Pair HL and return to the caller. LCOMM/CMD calls 429CH.
429E
RST 28H EF
RST 28H: call the supervisor dispatcher with the request code in Register A (0A3H).
429F
DEFB 00H 00
429FH, KFLAG$, the keyboard flags. The keyboard scan of every interrupt (4DBEH) sets bit 0 when BREAK is pressed (unless BREAK is disabled), bit 1 when SHIFT and @ are held (pause) and bit 2 when ENTER is held; BACKUP/CMD, BASIC/CMD and the keyboard drivers test and clear them.
42A0
DEFB 00H 00
42A0H: 00H, the byte the reset writes to port FEH (4E49H-4E4CH). No other instruction of the LDOS files on this diskette addresses it.
42A1H - SFCB$, the Control Block for System Files
A 20 byte file control block the overlay loader uses to read a system file: it stores the directory record number at 42A8H, the flags at 42A2H and a record number of 0 at 42ABH-42ACH, and 47B4H copies the first two extents of the file to 42AFH-42B4H; then the file is loaded through it. Its buffer is SBUFF$, 4300H.
42A1
DEFB 80H 80
42A1H, SFCB$ +00H: 80H, bit 7 set: the block describes an open file, which the file prologue requires. The overlay loader addresses the block at 42A1H (4C3BH).
42A2
DEFB 00H 00
42A2H, SFCB$ +01H: the file flags (bits 2-0 the access granted, bit 5 the buffer must be read first). The overlay loader stores 20H here before every load (4C1FH-4C21H): full access and an empty buffer.
42A3
DEFB 00H 00
42A3H, SFCB$ +02H: 00H. No instruction of the LDOS files on this diskette addresses this byte of the block.
42A4-42A5
DEFW 4300H 00 43
42A4H-42A5H, SFCB$ +03H-+04H: 4300H, SBUFF$, the address of the 256 byte buffer the sectors of a system file are read into.
42A6
DEFB 00H 00
42A6H, SFCB$ +05H: 00H, the position of the next byte in the buffer.
42A7
DEFB 00H 00
42A7H, SFCB$ +06H: 00H, the drive: system files are always read from drive 0.
42A8
DEFB 00H 00
42A8H, SFCB$ +07H: the directory record number of the system file, stored by the overlay loader (4C1BH).
42A9
DEFB 00H 00
42A9H, SFCB$ +08H: 00H, the end of file byte, which a system file does not use.
42AA
DEFB 00H 00
42AAH, SFCB$ +09H: 00H, the record length: 256 bytes.
42AB-42AC
DEFB 00H x 2 00 x 2
42ABH-42ACH, SFCB$ +0AH-+0BH: the next record number, set to 0000H before every load (4C24H-4C26H) so the file is read from its start.
42AD-42AE
DEFB FFH x 2 FF x 2
42ADH-42AEH, SFCB$ +0CH-+0DH: FFFFH, the ending record number, as high as it goes, so a system file never reaches its end of file before its last load record.
42AF-42B0
DEFB 00H x 2 00 x 2
42AFH-42B0H, SFCB$ +0EH-+0FH: the first extent of the system file (cylinder, then the first granule in bits 7-5 and the granules less one in bits 4-0), copied from its directory record by 47B4H. SYS2/SYS and SYS6/SYS read 42B0H.
42B1-42B4
DEFB FFH x 4 FF x 4
42B1H-42B4H, SFCB$ +10H-+13H: the number of granules of the first extent (a word, 47BBH-47C2H) and the second extent from the directory record (47C3H). FFH in the file.
42B5
LD A,CDH 3E CD
@DOKEY: load Register A with 0CDH, the request code of SYS11/SYS's function 40H: take a key for a JCL job. SYS11/SYS addresses 42B5H (its 4E50H).
42B7
RST 28H EF
RST 28H: call the supervisor dispatcher (400CH, 4BCCH) with the request code in Register A (0CDH).
42B8-42C1
DEFS 10
Not in the file: 42B8H-42B9H, KISV$, the keyboard driver address the reset installs (41EDH, 4E54H); 42BAH-42BBH, DOSV$, the video driver address (4E6BH); 42BCH-42BDH, PRSV$, the printer driver address (41E5H, 4E74H); 42BEH-42BFH, KIJCL$, where SYS11/SYS keeps a keyboard driver address (its 4E30H); 42C0H-42C1H, addressed by SYS1/SYS (its 4ED9H).
42C2H - Device Control Blocks of JL, SI and SO
Three more device control blocks, six bytes each: the job log (JL), the standard input (SI) and the standard output (SO). Type 08H with the driver 497CH (XOR A and RET): a request to them returns 00H at once until a device is assigned to them. The four spare blocks after them (42D4H-42EBH) are cleared by the reset, and the table of device names follows.
42C2
DEFB 08H 08
42C2H, JLDCB$ +00H: 08H, the type of a device with nothing assigned (bit 3), the job log.
42C3-42C4
DEFW 497CH 7C 49
42C3H-42C4H, JLDCB$ +01H-+02H: 497CH, the XOR A and RET at the end of the file routines: a request to the job log returns Register A = 00H with the Z FLAG.
42C5-42C7
DEFB 00H x 3 00 x 3
42C5H-42C7H, JLDCB$ +03H-+05H: three bytes of 00H for the driver of the job log.
42C8
DEFB 08H 08
42C8H, SIDCB$ +00H: 08H, the type of a device with nothing assigned (bit 3), the standard input.
42C9-42CA
DEFW 497CH 7C 49
42C9H-42CAH, SIDCB$ +01H-+02H: 497CH, the XOR A and RET at the end of the file routines: a request to the standard input returns Register A = 00H.
42CB-42CD
DEFB 00H x 3 00 x 3
42CBH-42CDH, SIDCB$ +03H-+05H: three bytes of 00H for the driver of the standard input.
42CE
DEFB 08H 08
42CEH, SODCB$ +00H: 08H, the type of a device with nothing assigned (bit 3), the standard output.
42CF-42D0
DEFW 497CH 7C 49
42CFH-42D0H, SODCB$ +01H-+02H: 497CH, the XOR A and RET at the end of the file routines: a request to the standard output returns Register A = 00H.
42D1-42D3
DEFB 00H x 3 00 x 3
42D1H-42D3H, SODCB$ +03H-+05H: three bytes of 00H for the driver of the standard output.
42D4-42EB
DEFS 24
Not in the file: 42D4H-42EBH, the four spare device control blocks of six bytes each, which SYS0/SYS's reset clears to 00H (4E1BH-4E22H). BACKUP/CMD addresses 42E0H (its 5C8CH).
42EC-42F7
DEFM "KIDOPRJLSISO" 4B 49 44 4F 50 52 4A 4C 53 49 53 4F
42ECH-42F7H: the device names, two letters for each device control block in order: KI (4015H), DO (401DH), PR (4025H), JL (42C2H), SI (42C8H) and SO (42CEH). SYS2/SYS (its 4EE2H) and SYS6/SYS search the table.
42F8-42FF
DEFB 00H x 8 00 x 8
42F8H-42FFH: the names of the four spare device control blocks (42D4H-42EBH), 00H while those blocks are not in use.
4300-43FF
DEFS 256
Not in the file: 4300H-43FFH, SBUFF$, the 256 byte buffer for system disk work. The reset reads the system information sector into it (4E91H-4E98H) and then the allocation table of drive 0 (4FD3H-4FD8H); the overlay loader reads system files through it (42A4H), and SYS1/SYS, BACKUP/CMD and FORMAT/CMD use it.
4400H - The Supervisor Call Vectors
The fixed entry points of the system, the same address for every program: each is either a JP to a routine of SYS0/SYS or a request stub, LD A with a request code and RST 28H. A request code names a system file in its low four bits (the file number plus 2: 3 for SYS1/SYS up to 0EH for SYS12/SYS) and a function of that file in bits 6-4. Programs CALL these addresses; the supervisor dispatcher (4BCCH) drops the return address the RST pushes, so the overlay's RET goes straight back to the program. That is why a stub needs no RET, and why the byte after some stubs is free: SYS0/SYS keeps variables there (441FH, 4423H, 4427H, 442BH).
4400-4401
DEFW 4876H 76 48
4400H-4401H: 4876H, the address of an OR A and RET: the hook SYS5/SYS (DEBUG) calls for a command letter it does not know (its 4E95H reads it), which returns with the flags of Register A. SYS6/SYS (its 52EEH), SYS7/SYS (its 5259H) and SYS9/SYS, the extended DEBUG commands (its 4E22H), store other addresses here.
4402
@MSG: jump to 4D3CH to send the text at Register Pair HL to the device whose control block is at Register Pair DE, until 03H (not sent) or 0DH (sent).
4405
RET C9
The BREAK trap switch: RETurn at once. While this byte is C9H BREAK is off; a program that wants BREAK to stop it stores C3H (JP) here, and the interrupt routine then jumps to the address at 4406H-4407H when BREAK is pressed (44EAH-44F9H). The dispatcher turns it off and back on around each request (4BD2H, 4BE9H); BASIC/CMD, FED/CMD, SYS1/SYS and SYS5/SYS store into it.
4406-4407
DEFW 440DH 0D 44
4406H-4407H: the address the BREAK trap goes to, 440DH (enter DEBUG) in the file; the interrupt routine loads it from here (44F3H). SYS5/SYS stores another address (its 4F9BH).
4408
RET Z C8
RETurn if the Z FLAG is set; with the NZ FLAG set, go on into @ERROR at 4409H. SYS6/SYS points Register Pair DE at 4408H (its 520CH) to come here with the result of a request in the flags.
4409
PUSH AF F5
@ERROR: save Register Pair AF to the stack. Register A holds the error number in bits 5-0, bit 6 set for the short message and bit 7 set to return to the caller instead of ending the program; SYS4/SYS takes it back from the stack.
440A
LD A,96H 3E 96
Load Register A with 96H, the request code of SYS4/SYS's function 10H: display the message of the error number pushed above.
440C
RST 28H EF
RST 28H: call the supervisor dispatcher (400CH, 4BCCH) with the request code in Register A (96H). SYS4/SYS either returns to the program that called 4409H (bit 7 of the error byte set) or ends it through @ABORT (4030H); it does not come back to 440DH.
440D
PUSH AF F5
@DEBUG: save Register Pair AF to the stack; SYS5/SYS (DEBUG) shows and restores the program's registers, Register Pair AF first. RST 30H (400FH), the BREAK trap (4406H) and the reset, when D or DOWN ARROW is held at boot (5012H), come here.
440E
LD A,87H 3E 87
Load Register A with 87H, the request code of SYS5/SYS, the DEBUG monitor.
4410
RST 28H EF
RST 28H: call the supervisor dispatcher (400CH, 4BCCH) with the request code in Register A (87H).
4411-4413
DEFS 3
Not in the file: 4411H-4412H, HIGH$, the highest address free for programs, which the reset sets to the top of memory it finds (4E43H) and modules that install themselves in high memory lower; 4413H, the year of the date less 80 (0-31, 1980-2011), stored by the reset's date prompt (4ECFH) and read by it at 4F03H.
4414
DEFB 00H 00
4414H, OVRLY$: the request code of the system file now at 4E00H, 00H when none has been loaded. The dispatcher compares it with a new request (4BE0H) and the overlay loader stores it (4C09H); SYS0/SYS reads it at 4A92H and BASIC/CMD reads and sets it.
4415-4416
DEFB 00H x 2 00 x 2
4415H-4416H: the top of memory found by the reset (4E46H), kept apart from HIGH$ (4411H), which modules lower; SYS10/SYS compares the two (its 4F2CH).
4417
DEFB 00H 00
4417H: the day of the year, its low 8 bits (1-366), stored by the reset at 4F2AH.
4418
DEFB 00H 00
4418H: bit 0 = bit 8 of the day of the year (4F2BH-4F2EH), bits 3-1 = the day of the week, 1 for Sunday to 7 for Saturday (4F53H-4F5AH), bit 7 = a leap year (4ED8H-4EDBH).
4419
LD A,AEH 3E AE
@DODIR: load Register A with 0AEH, the request code of SYS12/SYS's function 20H: a directory display or directory information of the drive in Register C. CMDFILE/CMD, HELP/CMD and TED/CMD call 4419H.
441B
RST 28H EF
RST 28H: call the supervisor dispatcher (400CH, 4BCCH) with the request code in Register A (0AEH).
441C
LD A,C3H 3E C3
@FSPEC: load Register A with 0C3H, the request code of SYS1/SYS's function 40H: take a file specification from the text at Register Pair HL into the control block at Register Pair DE.
441E
RST 28H EF
RST 28H: call the supervisor dispatcher with the request code in Register A (0C3H).
441F
DEFB 53H 53
441FH, OSVER$: 53H, the system version 5.3, the byte after the @FSPEC stub. BASIC/CMD reads it (its 5364H); the manual's zap D02,8F of SYS0/SYS changes this byte (file record 02H, byte 8FH).
4420
LD A,A4H 3E A4
@INIT: load Register A with 0A4H, the request code of SYS2/SYS's function 20H: open the file whose control block is at Register Pair DE, creating it when it does not exist (Register Pair HL = its buffer, Register B = the record length).
4422
RST 28H EF
RST 28H: call the supervisor dispatcher with the request code in Register A (0A4H).
4423
DEFB FFH FF
4423H, PDRV$: the last drive select value the floppy disk driver wrote to port F4H, stored by 45CAH and written again by 46D9H and 46E3H. FFH in the file: no drive selected yet.
4424
LD A,94H 3E 94
@OPEN: load Register A with 94H, the request code of SYS2/SYS's function 10H: open the existing file whose control block is at Register Pair DE (Register Pair HL = its buffer, Register B = the record length). @LOAD uses it.
4426
RST 28H EF
RST 28H: call the supervisor dispatcher with the request code in Register A (94H).
4427
DEFB FFH FF
4427H, LDRV$: the drive number of the last disk primitive call (477CH stores Register C here); 4750H selects that drive again. FFH: no drive yet. BACKUP/CMD stores into it (its 547AH).
4428
LD A,95H 3E 95
@CLOSE: load Register A with 95H, the request code of SYS3/SYS's function 10H: close the file or device whose control block is at Register Pair DE.
442A
RST 28H EF
RST 28H: call the supervisor dispatcher with the request code in Register A (95H).
442B
DEFB 00H 00
442BH, SFLAG$, the system flags: bit 2 an @RUN load in progress (4C5EH), bit 3 FAST (5059H-5068H), bit 4 BREAK disabled (4DE4H, 44E3H), and the bits SYS1/SYS, SYS2/SYS, SYS6/SYS, SYS11/SYS and many programs test. 00H in the file.
442C
LD A,9CH 3E 9C
@KILL: load Register A with 9CH, the request code of SYS10/SYS's function 10H: delete the file whose control block is at Register Pair DE.
442E
RST 28H EF
RST 28H: call the supervisor dispatcher with the request code in Register A (9CH).
442F
DEFS 1
Not in the file, so a reset keeps it: 442FH, the month of the system date OR 50H once a date is set (4EF6H-4EFAH). The reset uses the date again without the prompt when it holds 51H-5CH, and skips the date and the time prompts when it holds 50H (4EA8H-4EB2H).
4430
@LOAD: jump to 4C76H to load the program file named in the control block at Register Pair DE and return its transfer address in Register Pair HL. The reset jumps here to load CONFIG/SYS (5050H).
4433
@RUN: jump to 4C5DH to load the program file named at Register Pair DE and run it.
4436
@READ: jump to 48ADH to read the next record of the file at Register Pair DE (into the record area at Register Pair HL when the record length is not 256).
4439
@WRITE: jump to 48CBH to write the next record of the file at Register Pair DE.
443C
@VER: jump to 48E6H to write the next record of the file at Register Pair DE and read it back to check it.
443F
@REW: jump to 4835H to put the file at Register Pair DE back at its first record.
4442
@POSN: jump to 47CFH to put the file at Register Pair DE at the record number in Register Pair BC.
4445
@BKSP: jump to 4816H to move the file at Register Pair DE back one record.
4448
@PEOF: jump to 483CH to put the file at Register Pair DE at its end, ready to add records.
444B
LD A,D3H 3E D3
@FEXT: load Register A with 0D3H, the request code of SYS1/SYS's function 50H: give the file specification at Register Pair DE the extension at Register Pair HL when it has none.
444D
RST 28H EF
RST 28H: call the supervisor dispatcher (400CH, 4BCCH) with the request code in Register A (0D3H).
444E
@MULT: jump to 4B8EH to multiply Register Pair HL by Register A (the 24 bit product: Register Pair HL the high 16 bits, Register A the low 8 bits). BACKUP/CMD and SYS12/SYS call 444EH.
4451
@DIV: jump to 4BA8H to divide Register Pair HL by Register A (quotient in Register Pair HL, remainder in Register A). The reset uses it for the day of the week (4F4CH calls 4BA8H directly).
4454
LD A,E3H 3E E3
@PARAM: load Register A with 0E3H, the request code of SYS1/SYS's function 60H: read the parameters at Register Pair HL against the parameter table at Register Pair DE.
4456
RST 28H EF
RST 28H: call the supervisor dispatcher (400CH, 4BCCH) with the request code in Register A (0E3H).
4457
DEFS 1
Not in the file, so a reset keeps it: 4457H, the day of the system date, stored by the date prompt (4EEFH) and used by the reset when it takes the date again (4F11H).
4458
@CKEOF: jump to 4A1AH to test whether the file at Register Pair DE is at its end (Register A = 1CH and the NZ FLAG at the end, 1DH beyond it, 00H with the Z FLAG before it).
445B
@WEOF: jump to 4886H to write the end of file of the file at Register Pair DE into its directory record.
445E
@RREAD: jump to 480FH to read the current sector of the file at Register Pair DE again.
4461
@RWRIT: jump to 499EH to write the file's buffer back to the current sector of the file at Register Pair DE.
4464
@SKIP: jump to 47CBH to pass over the next record of the file at Register Pair DE.
4467
@DSPLY: jump to 4D39H to display the text at Register Pair HL, ended by 03H (not displayed) or 0DH (displayed). The reset's prompts (422CH) and its AUTO command display (5027H) use it, as do most programs.
446A
@PRINT: jump to 4D4EH to print the text at Register Pair HL, ended by 03H or 0DH.
446D
@LOC: jump to 484DH to return in Register Pair BC the current record number of the file at Register Pair DE.
4470
@LOF: jump to 4878H to return in Register Pair BC the number of records of the file at Register Pair DE.
4473H - The Interrupt Latch Image, Mask and Vectors
The interrupt service routine (44A5H) reads the interrupt latch (port E0H, whose bits read 0 for a pending interrupt), keeps its complement at 4473H, masks it with 4474H and calls the vector of every bit that is set, bit 0 first.
4473
DEFB 00H 00
4473H, INTIM$: the image of the interrupt latch the interrupt service routine read last (44A7H-44ADH), a set bit for each interrupt pending. CMDFILE/CMD addresses it (its 541BH).
4474
DEFB 7FH 7F
4474H, INTMSK$: 7FH, the mask of the interrupt bits that are served (44AFH): bits 0-6. The reset enables only the real time clock in the latch itself (04H to port E0H, 4E2BH-4E30H).
4475-4476
DEFW 4203H 03 42
4475H-4476H, INTVC$ +00H, the vector of interrupt bit 0 (cassette): 4203H, which jumps to 44FAH to turn the cassette motor off and end the program.
4477-4478
DEFW 4203H 03 42
4477H-4478H, INTVC$ +02H, the vector of interrupt bit 1 (cassette): 4203H, the same cassette exit as bit 0.
4479-447A
DEFW 4518H 18 45
4479H-447AH, INTVC$ +04H, the vector of interrupt bit 2, the real time clock: 4518H, which runs the tasks and then the ROM's real time clock routine.
447B-447C
DEFW 44C2H C2 44
447BH-447CH, INTVC$ +06H, the vector of interrupt bit 3: 44C2H, a RET, so the bit does nothing. QFB/CMD addresses 447BH (its 6214H).
447D-447E
DEFW 44C2H C2 44
447DH-447EH, INTVC$ +08H, the vector of interrupt bit 4: 44C2H, a RET, so the bit does nothing.
447F-4480
DEFW 44C2H C2 44
447FH-4480H, INTVC$ +0AH, the vector of interrupt bit 5: 44C2H, a RET, so the bit does nothing.
4481-4482
DEFW 44C2H C2 44
4481H-4482H, INTVC$ +0CH, the vector of interrupt bit 6: 44C2H, a RET, so the bit does nothing.
4483-4484
DEFW 44C2H C2 44
4483H-4484H, INTVC$ +0EH, the vector of interrupt bit 7: 44C2H, a RET; bit 7 is outside the mask 7FH anyway.
4485-44A4
DEFS 32
Not in the file: 4485H-44A4H, CFCB$, the 32 byte control block that SYS1/SYS fills for the command being run; BASIC/CMD uses it too (its 54AFH, 54D1H, 54EBH).
44A5H - The Interrupt Service Routine
ROM 0038H (RST 38H in interrupt mode 1) jumps to 4012H and so here. It reads the interrupt latch at port E0H (a bit reads 0 while its interrupt is pending), keeps the complement at 4473H, and for every bit that is also set in the mask at 4474H calls the routine whose address is in that bit's vector at 4475H-4484H, bit 0 first. Then it scans the keyboard for BREAK, SHIFT @ and ENTER (4DBEH): SHIFT BREAK selects the drive of the last disk call again, BREAK alone springs the BREAK trap at 4405H. Registers are kept.
44A5
PUSH HL E5
Save Register Pair HL to the stack: the interrupted program's Register Pair HL comes back at 44C0H or through the EX (SP),HL of the BREAK trap.
44A6
PUSH AF F5
Save Register Pair AF to the stack: the interrupted program's Register A and flags.
44A7
IN A,(E0H) DB E0
Read the interrupt latch from port E0H into Register A: a bit is 0 while its interrupt is pending (bit 2 the real time clock).
44A9
CPL 2F
Complement Register A: a set bit now marks a pending interrupt.
44AA
LD HL,4473H 21 73 44
Point Register Pair HL to 4473H, INTIM$, the image of the latch.
44AD
LD (HL),A 77
Store Register A (the pending interrupts) at Register Pair HL, 4473H, INTIM$, the image of the latch other programs can read.
44AE
INC L 2C
INCrement Register L: Register Pair HL = 4474H, INTMSK$, the mask of the bits that are served.
44AF
AND (HL) A6
AND Register A with the mask at Register Pair HL (4474H, 7FH): only the pending bits that are served remain.
44B0
If the Z FLAG is set (no served interrupt is pending), JUMP to 44BAH for the keyboard scan.
44B2
INC L 2C
INCrement Register L: Register Pair HL points at the low byte of the next bit's vector (4475H for bit 0). 44B8H loops back here.
44B3
RRA 1F
Rotate Register A right: the lowest remaining bit goes into the CARRY FLAG.
44B4
If the CARRY FLAG is set (this bit's interrupt is pending), JUMP to 44C3H to call its vector at Register Pair HL.
44B6
INC L 2C
INCrement Register L past the high byte of the vector. The routine called at 44C3H comes back here through 44D8H.
44B7
OR A B7
Test Register A (OR A): the Z FLAG is set when no pending bit is left above this one.
44B8
If the NZ FLAG is set (more bits are pending in Register A), JUMP back to 44B2H for the next vector.
44BA
GOSUB to 4DBEH, the keyboard scan: it sets the bits of KFLAG$ (429FH) and returns the NZ FLAG when BREAK is held and the CARRY FLAG when a SHIFT key is held.
44BD
If the NZ FLAG is set (BREAK is held), JUMP to 44DAH.
44BF
POP AF F1
Restore the interrupted program's Register Pair AF from the stack. The other exits of the routine come back here (44E1H, 44E8H, 44F0H).
44C0
POP HL E1
Restore the interrupted program's Register Pair HL from the stack.
44C1
EI FB
Enable interrupts again (RST 38H entered with them off).
44C2
RET C9
RETurn to the interrupted program. The vectors of the unused interrupt bits (447BH-4484H) point at this RET.
44C3
PUSH AF F5
Save Register Pair AF (Register A = the pending bits still to serve) to the stack.
44C4
PUSH BC C5
Save Register Pair BC to the stack for the interrupt routine of this bit.
44C5
PUSH DE D5
Save Register Pair DE to the stack for the routine of this bit, which may change it.
44C6
PUSH HL E5
Save Register Pair HL (the pointer to this bit's vector) to the stack.
44C7
PUSH IX DD E5
Save Index Register IX to the stack: the clock routine's tasks use it.
44C9
LD DE,44D2H 11 D2 44
Point Register Pair DE to 44D2H, where the routine of this bit returns to.
44CC
PUSH DE D5
Save Register Pair DE (44D2H) to the stack as the return address of the routine.
44CD
LD E,(HL) 5E
Fetch the low byte of the vector at Register Pair HL into Register E.
44CE
INC L 2C
INCrement Register L to the high byte of the vector.
44CF
LD D,(HL) 56
Fetch the high byte of the vector at Register Pair HL into Register D: Register Pair DE = the routine of this bit.
44D0
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the routine.
44D1
JP (HL) E9
Jump to the routine at Register Pair HL (4203H for bits 0-1, 4518H for bit 2, 44C2H for the others); it returns to 44D2H.
44D2
POP IX DD E1
Restore Index Register IX from the stack: the routine of this bit has returned here.
44D4
POP HL E1
Restore Register Pair HL (the pointer to the high byte of this bit's vector) from the stack.
44D5
POP DE D1
Restore Register Pair DE from the stack, as it was before the routine of this bit ran.
44D6
POP BC C1
Restore Register Pair BC from the stack, as it was before the routine of this bit ran.
44D7
POP AF F1
Restore Register Pair AF (Register A = the pending bits) from the stack.
44D8
JUMP back to 44B6H to step past this vector and look at the next pending bit.
44DA
If the NO CARRY FLAG is set (BREAK without SHIFT), JUMP to 44E3H to spring the BREAK trap.
44DC
PUSH BC C5
SHIFT BREAK: save Register Pair BC to the stack, which 4750H changes.
44DD
GOSUB to 4750H to select the drive of the last disk primitive call (LDRV$, 4427H) again.
44E0
POP BC C1
Restore Register Pair BC from the stack after the select of the last drive.
44E1
JUMP to 44BFH to return to the interrupted program.
44E3
LD A,(442BH) 3A 2B 44
BREAK alone: fetch SFLAG$, the system flags, from 442BH into Register A.
44E6
BIT 4,A CB 67
Test bit 4 of Register A: set when BREAK is disabled.
44E8
If the NZ FLAG is set (BREAK is disabled), JUMP to 44BFH to return to the interrupted program.
44EA
LD HL,4405H 21 05 44
Point Register Pair HL to 4405H, the BREAK trap switch.
44ED
LD A,C3H 3E C3
Load Register A with C3H, the JP opcode that marks the trap set.
44EF
SUB (HL) 96
SUBtract the switch at Register Pair HL (4405H) from Register A: Register A = 00H and the Z FLAG set only when the switch holds C3H.
44F0
If the NZ FLAG is set (the trap is not set), JUMP to 44BFH to return to the interrupted program.
44F2
LD (HL),A 77
Store Register A (00H) at Register Pair HL (4405H): the trap is turned off, so it springs once.
44F3
LD HL,(4406H) 2A 06 44
Load Register Pair HL with the address the trap goes to from 4406H-4407H.
44F6
POP AF F1
Restore the interrupted program's Register Pair AF from the stack.
44F7
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer is not changed): the interrupted program's Register Pair HL comes back and the trap's address takes its place, above the interrupted program's address.
44F8
EI FB
Enable interrupts again before the jump to the trap's address.
44F9
RET C9
RETurn to the trap's address with the interrupted program's address on the stack, as though the program had called it.
44FA
The cassette exit the vector at 4203H jumps to: GOSUB to the ROM's 01F8H to turn off the cassette motor.
44FD
Jump to 4030H, @ABORT: the program ends and LDOS Ready follows.
4500H - TCB$, the Task Table
Twelve words, one for each task slot 0-11: the address of the task's block, whose first word is the address of the task's routine (the routine finds its block in Index Register IX and may keep its own bytes after that word). The clock interrupt runs slots 8-11 on every tick and one of slots 0-7 in turn (4518H-4549H). @ADTSK, @RMTSK, @RPTSK and @KLTSK (403DH-4046H) change the entries. In the file every slot holds 455FH, the empty block.
4500-4501
DEFW 455FH 5F 45
4500H-4501H, task slot 0: 455FH, the empty block, whose routine is a RET.
4502-4503
DEFW 455FH 5F 45
4502H-4503H, task slot 1: 455FH, the empty block, whose routine is a RET.
4504-4505
DEFW 455FH 5F 45
4504H-4505H, task slot 2: 455FH, the empty block, whose routine is a RET.
4506-4507
DEFW 455FH 5F 45
4506H-4507H, task slot 3: 455FH, the empty block, whose routine is a RET.
4508-4509
DEFW 455FH 5F 45
4508H-4509H, task slot 4: 455FH, the empty block, whose routine is a RET.
450A-450B
DEFW 455FH 5F 45
450AH-450BH, task slot 5: 455FH, the empty block, whose routine is a RET.
450C-450D
DEFW 455FH 5F 45
450CH-450DH, task slot 6: 455FH, the empty block, whose routine is a RET.
450E-450F
DEFW 455FH 5F 45
450EH-450FH, task slot 7: 455FH, the empty block, whose routine is a RET.
4510-4511
DEFW 455FH 5F 45
4510H-4511H, task slot 8: 455FH, the empty block. Slots 8-11 run on every clock tick.
4512-4513
DEFW 455FH 5F 45
4512H-4513H, task slot 9: 455FH, the empty block, whose routine is a RET.
4514-4515
DEFW 455FH 5F 45
4514H-4515H, task slot 10: 455FH, the empty block, whose routine is a RET.
4516-4517
DEFW 455FH 5F 45
4516H-4517H, task slot 11: 455FH, the empty block, whose routine is a RET.
4518H - The Clock Interrupt: Run the Tasks
The vector of interrupt bit 2 (4479H), the real time clock. 4BBBH decides whether this tick runs the tasks; when it does, the address of the ROM's real time clock routine (3529H, saved at 4BBCH by the reset) is pushed as the return address, the tasks of slots 8, 9, 10 and 11 run, TIMER$ (4288H) counts the tick and the task of the slot 0-7 its bits 2-0 select runs last; its RET goes to the ROM's routine, which blinks the cursor and keeps TIME$.
4518
GOSUB to 4BBBH: it returns here with Register Pair DE = the ROM's real time clock routine (3529H) when this tick runs the tasks; otherwise it ends the interrupt of this bit itself.
451B
PUSH DE D5
Save Register Pair DE (the ROM's real time clock routine) to the stack: the RET of the last task below goes there.
451C
LD A,08H 3E 08
Load Register A with 08H, task slot 8, the first of the four slots run on every tick.
451E
GOSUB to 4537H to run the task in slot Register A (8).
4521
LD A,09H 3E 09
Load Register A with 09H, task slot 9, run on every tick like slot 8.
4523
GOSUB to 4537H to run the task in slot Register A (9).
4526
LD A,0AH 3E 0A
Load Register A with 0AH, task slot 10, run on every tick like slot 8.
4528
GOSUB to 4537H to run the task in slot Register A (10).
452B
LD A,0BH 3E 0B
Load Register A with 0BH, task slot 11, the last slot run on every tick.
452D
GOSUB to 4537H to run the task in slot Register A (11).
4530
LD HL,4288H 21 88 42
Point Register Pair HL to 4288H, TIMER$, the tick counter.
4533
INC (HL) 34
INCrement TIMER$ at Register Pair HL (4288H).
4534
LD A,(HL) 7E
Fetch TIMER$ from Register Pair HL into Register A.
4535
AND 07H E6 07
Mask Register A to bits 2-0: task slot 0-7, a different slot on each tick. The code goes on into 4537H to run it.
4537H - Run the Task in Slot A
Register A = the slot (0-11). Points Index Register IX at the slot's task block and jumps to the routine whose address is the block's first word. The address of the slot's table entry is kept in the operand at 4562H for @RPTSK and @KLTSK.
4537
RLCA 07
Rotate Register A left: the slot times 2, the offset of its word in the task table (the slot is below 80H, so no bit is lost).
4538
LD L,A 6F
Copy Register A (the offset) into Register L.
4539
LD H,45H 26 45
Load Register H with 45H: Register Pair HL = 4500H + the slot x 2, the slot's entry in TCB$.
453B
LD (4562H),HL 22 62 45
Store Register Pair HL (the entry's address) at 4562H, the operand of the LD HL at 4561H that @RPTSK uses, and that @KLTSK reads back.
453E
LD E,(HL) 5E
Fetch the low byte of the task block's address from Register Pair HL into Register E.
453F
INC L 2C
INCrement Register L to the high byte of the entry.
4540
LD D,(HL) 56
Fetch the high byte of the task block's address from Register Pair HL into Register D: Register Pair DE = the task block.
4541
PUSH DE D5
Save Register Pair DE (the task block) to the stack.
4542
POP IX DD E1
Restore it into Index Register IX: the task routine finds its block in Index Register IX.
4544
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the task block.
4545
LD E,(HL) 5E
Fetch the low byte of the routine's address from the block at Register Pair HL into Register E.
4546
INC HL 23
INCrement Register Pair HL to the high byte of the routine's address in the task block.
4547
LD D,(HL) 56
Fetch the high byte of the routine's address from Register Pair HL into Register D: Register Pair DE = the task routine.
4548
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the task routine, Register Pair DE = the block's second byte.
4549
JP (HL) E9
Jump to the task routine at Register Pair HL; its RET goes back to the caller of 4537H (or to the ROM's routine at 3529H for the slot 0-7 task).
454AH - @KLTSK, @RMTSK and @ADTSK
454AH (@KLTSK, the jump at 4046H that the reset installs) is called by a running task to remove itself; 454FH (@RMTSK) removes the task in slot Register A; 4552H (@ADTSK) puts the block at Register Pair DE into slot Register A. Interrupts are off while the two bytes of an entry change. A slot number of 12 or more is ignored.
454A
POP DE D1
@KLTSK: drop the return address into the task routine from the stack into Register Pair DE: the RET below goes straight back to the caller of the task.
454B
LD A,(4562H) 3A 62 45
Fetch the low byte of the running task's table entry from the operand at 4562H into Register A: 00H plus the slot times 2.
454E
RRCA 0F
Rotate Register A right: the slot number of the running task.
454F
LD DE,455FH 11 5F 45
@RMTSK: point Register Pair DE to 455FH, the empty task block.
4552
CP 0CH FE 0C
@ADTSK: compare Register A (the slot) against 0CH. The NO CARRY FLAG is set for a slot of 12 or more.
4554
RET NC D0
If the NO CARRY FLAG is set (no such slot), RETurn without changing anything.
4555
RLCA 07
Rotate Register A left: the slot times 2, the offset of its word in TCB$.
4556
LD L,A 6F
Copy Register A (the offset) into Register L.
4557
LD H,45H 26 45
Load Register H with 45H: Register Pair HL = the slot's entry in TCB$ (4500H + the slot x 2).
4559
DI F3
Disable interrupts, so that the clock does not run the task while its entry is half written. @RPTSK joins here from 4569H.
455A
LD (HL),E 73
Store Register E (the low byte of the block address in Register Pair DE) at Register Pair HL.
455B
INC L 2C
INCrement Register L to the high byte of the entry.
455C
LD (HL),D 72
Store Register D (the high byte of the block address) at Register Pair HL.
455D
EI FB
Enable interrupts again: the entry in TCB$ is complete.
455E
RET C9
RETurn to the caller. This RET is also the routine of the empty task block at 455FH.
455F-4560
DEFW 455EH 5E 45
455FH-4560H: the empty task block, its first word 455EH, the RET above: a slot holding 455FH runs nothing.
4561
LD HL,0000H 21 00 00
@RPTSK: load Register Pair HL with the address of the running task's table entry, the operand at 4562H-4563H that 453BH stores before each task runs (0000H in the file).
4564
LD E,(HL) 5E
Fetch the low byte of the task block's address from the entry at Register Pair HL into Register E.
4565
INC HL 23
INCrement Register Pair HL to the high byte of the task block's address in the entry.
4566
LD D,(HL) 56
Fetch the high byte of the task block's address from Register Pair HL into Register D: Register Pair DE = the task block.
4567
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the task block.
4568
POP DE D1
Restore the return address into the task routine (the instruction after its CALL 4043H) from the stack into Register Pair DE: the task's next run starts there.
4569
JUMP to 4559H to store Register Pair DE as the first word of the block at Register Pair HL, with interrupts off, and return to the caller of the task.
456BH - Change a Drive's Density
Called by the read and write engine (4680H) when the controller reported record not found, with Register A = byte +03H of the drive code table at Index Register IY. It flips bit 6 (double density) and sets bytes +07H and +08H to the geometry of the new density: 10 sectors a track in two granules of five for single density, 18 sectors a track in three granules of six for double density. After a change to double density the head goes back to cylinder 0.
456B
XOR 40H EE 40
Flip bit 6 of Register A (XOR 40H), the double density bit of the drive flags.
456D
LD (IY+03H),A FD 77 03
Store Register A (the drive flags with the new density) at byte +03H of the drive code table at Index Register IY.
4570
LD BC,2409H 01 09 24
Load Register Pair BC with 2409H: Register C = 09H, the highest sector of a single density track (10 sectors), Register B = 24H, two granules a track (bits 7-5 = 1) of five sectors (bits 4-0 = 4).
4573
BIT 6,A CB 77
Test bit 6 of Register A, the new density: the Z FLAG is set for single density.
4575
If the Z FLAG is set (single density), JUMP to 457AH with the single density geometry in Register Pair BC.
4577
LD BC,4511H 01 11 45
Load Register Pair BC with 4511H: Register C = 11H, the highest sector of a double density track (18 sectors), Register B = 45H, three granules a track (bits 7-5 = 2) of six sectors (bits 4-0 = 5).
457A
LD (IY+07H),C FD 71 07
Store Register C (the highest sector) at byte +07H of the drive code table at Index Register IY.
457D
LD (IY+08H),B FD 70 08
Store Register B (the granules and sectors a granule) at byte +08H of the drive code table at Index Register IY.
4580
RET Z C8
If the Z FLAG is set (the drive is now single density), RETurn to the read and write engine.
4581
JUMP to 459EH to restore the head to cylinder 0 on the double density setting.
4583H - The Floppy Disk Driver: Function Dispatch
The address every floppy drive code table jumps to (4700H +00H: JP 4583H). The controller is reached through ports F0H (command and status), F1H (track), F2H (sector), F3H (data) and F4H (drive select, side, density and wait states). Register B = the function: 00H nothing, 01H select, 02H-04H restore to cylinder 0, 05H step in one cylinder, 06H seek, 07H wait until not busy, 08H, 09H and 0BH read a sector, 0AH verify a sector, 0CH and 0DH write a sector, 0EH write a sector with the deleted data mark, 0FH write a track. Register D = the cylinder, Register E = the sector, Register Pair HL = the buffer, Index Register IY = the drive code table. Returns with the Z FLAG set and Register A = 00H when the function succeeded, otherwise Register A = the error number.
4583
LD A,B 78
Copy Register B (the function) into Register A.
4584
AND A A7
Test Register A (AND A): the Z FLAG is set for function 00H.
4585
RET Z C8
If the Z FLAG is set (function 00H), RETurn at once with Register A = 00H.
4586
CP 07H FE 07
Compare Register A (the function) against 07H.
4588
If the Z FLAG is set (function 07H), jump to 46D4H to wait until the controller is not busy.
458B
If the NO CARRY FLAG is set (functions 08H and up, the sector and track transfers), jump to 461AH.
458E
CP 06H FE 06
Compare Register A (the function) against 06H.
4590
If the Z FLAG is set (function 06H), JUMP to 45DEH to seek cylinder Register D for sector Register E.
4592
DEC A 3D
DECrement Register A: the Z FLAG is set for function 01H.
4593
If the Z FLAG is set (function 01H), JUMP to 45A6H to select the drive.
4595
INC (IY+05H) FD 34 05
Functions 02H-05H: INCrement byte +05H of the drive code table at Index Register IY, the cylinder under the head, for a step in.
4598
CP 04H FE 04
Compare Register A (the function less 1) against 04H: the Z FLAG is set for function 05H.
459A
LD B,58H 06 58
Load Register B with 58H, the Step In command with the track register updated (bit 4) and the head loaded (bit 3).
459C
If the Z FLAG is set (function 05H), JUMP to 4609H to select the drive and issue the Step In command in Register B.
459E
LD (IY+05H),00H FD 36 05 00
Functions 02H-04H: store 00H at byte +05H of the drive code table at Index Register IY: the head will be on cylinder 0. The density change comes here too (4581H).
45A2
LD B,09H 06 09
Load Register B with 09H, the Restore command with the head loaded (bit 3) and bit 0 of the step rate set.
45A4
JUMP to 4609H to select the drive and issue the Restore command in Register B.
45A6H - Select the Drive
Waits until the controller is not busy, then writes the drive's select bit, the side bit, the double density bit and, on a double density cylinder above the directory cylinder, the write precompensation bit to port F4H, and keeps the value at PDRV$ (4423H). When the controller reported NOT READY before the select (its motor was off), waits for the motor through the ROM's delay: once when bit 2 of byte +03H of the drive code table is set, twice when it is clear.
45A6
GOSUB to 46D4H to wait until the controller is not busy; Register A returns the status. Functions 01H (4593H) and the command issue (4609H) come here.
45A9
RLCA 07
Rotate Register A left: bit 7 of the status, NOT READY, goes into the CARRY FLAG.
45AA
PUSH AF F5
Save Register Pair AF (the CARRY FLAG = the drive was not ready) to the stack.
45AB
PUSH BC C5
Save Register Pair BC (Register B = the command or function) to the stack.
45AC
LD A,(IY+03H) FD 7E 03
Fetch byte +03H of the drive code table at Index Register IY into Register A, the drive flags.
45AF
RLA 17
Rotate Register A left through the CARRY FLAG: bit 6 (double density) moves to bit 7.
45B0
SRA A CB 2F
Shift Register A right arithmetically: bit 7 (double density) stays and is copied into bit 6, and the other bits go back where they were, bit 4 (side 1) included.
45B2
AND 90H E6 90
Mask Register A with 90H: bit 7 = double density, bit 4 = side 1, the positions of those bits at port F4H.
45B4
LD C,A 4F
Copy Register A (the density and side bits) into Register C.
45B5
BIT 7,A CB 7F
Test bit 7 of Register A, the double density bit for port F4H.
45B7
If the Z FLAG is set (single density), JUMP to 45C1H: no write precompensation.
45B9
LD A,(IY+09H) FD 7E 09
Fetch byte +09H of the drive code table at Index Register IY into Register A, the directory cylinder.
45BC
CP D BA
Compare Register A (the directory cylinder) against Register D (the cylinder): the NO CARRY FLAG is set when Register D is not above it.
45BD
If the NO CARRY FLAG is set (the cylinder is not above the directory cylinder), JUMP to 45C1H.
45BF
SET 5,C CB E9
Set bit 5 of Register C, the write precompensation bit of port F4H, for a double density cylinder above the directory cylinder.
45C1
LD A,(IY+04H) FD 7E 04
Fetch byte +04H of the drive code table at Index Register IY into Register A.
45C4
AND 0FH E6 0F
Mask Register A to bits 3-0, the drive's select bit (01H, 02H, 04H or 08H).
45C6
OR C B1
OR Register C (the density, side and precompensation bits) into Register A.
45C7
POP BC C1
Restore Register Pair BC (Register B = the command or function) from the stack.
45C8
OUT (F4H),A D3 F4
Send Register A to port F4H: the drive is selected and its motor started.
45CA
LD (4423H),A 32 23 44
Store Register A (the drive select value) at 4423H, PDRV$, for the waits that select the drive again (46D9H, 46E3H).
45CD
POP AF F1
Restore Register Pair AF from the stack: the CARRY FLAG is set when the drive was not ready before the select.
45CE
RET NC D0
If the NO CARRY FLAG is set (the drive was ready, its motor running), RETurn.
45CF
BIT 2,(IY+03H) FD CB 03 56
Test bit 2 of byte +03H of the drive code table at Index Register IY: when it is set, one motor wait is enough.
45D3
If the Z FLAG is set (bit 2 is clear), GOSUB to 45D6H for a first motor wait; the code then goes on into 45D6H for the second.
45D6
PUSH BC C5
Save Register Pair BC to the stack: the ROM's delay counts Register Pair BC down.
45D7
LD B,7FH 06 7F
Load Register B with 7FH: the ROM's delay at 0060H counts Register Pair BC (7FxxH) down to 0.
45D9
GOSUB to the ROM's delay at 0060H, which decrements Register Pair BC until it is 0.
45DC
POP BC C1
Restore the caller's Register Pair BC from the stack.
45DD
RET C9
RETurn (once to 45D6H after the first wait, then to the caller of 45A6H).
45DEH - Seek: Cylinder D, Sector E
Function 06H, and the first step of every sector transfer (465FH). The sector number in Register E counts through both sides of a cylinder: a number above the highest sector of a track (byte +07H, bits 4-0) sets bit 4 of byte +03H (side 1) and is reduced by the sectors of a track. The current cylinder goes to the track register, the sector to the sector register and the cylinder Register D to the data register, and the Seek command is issued, with the verify bit when the head has to move.
45DE
GOSUB to 46D4H to wait until the controller is not busy.
45E1
LD A,(IY+05H) FD 7E 05
Fetch byte +05H of the drive code table at Index Register IY into Register A, the cylinder the head is on.
45E4
OUT (F1H),A D3 F1
Send Register A (the current cylinder) to port F1H, the track register.
45E6
LD A,(IY+07H) FD 7E 07
Fetch byte +07H of the drive code table at Index Register IY into Register A.
45E9
AND 1FH E6 1F
Mask Register A to bits 4-0: the highest sector number of a track.
45EB
SUB E 93
SUBtract Register E (the sector) from Register A. The CARRY FLAG is set when the sector is above the highest sector of a track, on side 1.
45EC
CPL 2F
Complement Register A: Register A = Register E less the highest sector less 1, the sector number on side 1. CPL does not change the CARRY FLAG.
45ED
SET 4,(IY+03H) FD CB 03 E6
Set bit 4 of byte +03H of the drive code table at Index Register IY: side 1.
45F1
If the CARRY FLAG is set (the sector is on side 1), JUMP to 45F8H with the side 1 sector number in Register A.
45F3
RES 4,(IY+03H) FD CB 03 A6
Reset bit 4 of byte +03H of the drive code table at Index Register IY: side 0.
45F7
LD A,E 7B
Copy Register E (the sector) into Register A: the sector number on side 0.
45F8
OUT (F2H),A D3 F2
Send Register A (the sector on its side) to port F2H, the sector register.
45FA
LD A,D 7A
Copy Register D (the cylinder wanted) into Register A.
45FB
OUT (F3H),A D3 F3
Send Register A (the cylinder wanted) to port F3H, the data register, for the Seek command.
45FD
CP (IY+05H) FD BE 05
Compare Register A (the cylinder wanted) against byte +05H of the drive code table at Index Register IY: the Z FLAG is set when the head is already there.
4600
LD B,18H 06 18
Load Register B with 18H, the Seek command with the head loaded (bit 3) and no verify.
4602
If the Z FLAG is set (the head is on the cylinder), JUMP to 4609H to issue the Seek command without verify.
4604
LD B,1CH 06 1C
Load Register B with 1CH, the Seek command with the verify bit (bit 2): the head moves and the cylinder is checked.
4606
LD (IY+05H),D FD 72 05
Store Register D (the cylinder wanted) at byte +05H of the drive code table at Index Register IY.
4609
GOSUB to 45A6H to select the drive (and wait for its motor). The restore and step functions come here too (459CH, 45A4H).
460C
LD A,(IY+03H) FD 7E 03
Fetch byte +03H of the drive code table at Index Register IY into Register A.
460F
AND 03H E6 03
Mask Register A to bits 1-0, the drive's step rate.
4611
OR B B0
OR Register B (the command) into Register A: the command with the step rate.
4612
OUT (F0H),A D3 F0
Send Register A (the command) to port F0H, the controller's command register. 46F2H calls here with a read or write command.
4614
LD B,12H 06 12
Load Register B with 12H for the delay that gives the controller time to set BUSY before its status is read.
4616
DECrement Register B and loop back to 4616H until it reaches 0. Register B comes back as 00H, the count of 256 bytes for the transfer loops.
4618
XOR A AF
Set Register A to 00H (XOR A) and the Z FLAG: no error.
4619
RET C9
RETurn to the caller with Register A = 00H and the Z FLAG set: the command has been issued.
461AH - The Read and Write Engine
Functions 08H and up. Register B gets the number of tries (6) and Register C the controller command: 82H Read Sector with the side compared (functions 08H, 09H, 0AH, 0BH), A2H Write Sector (0CH, 0DH), A3H Write Sector with the deleted data mark (0EH) and F0H Write Track (0FH). The three bytes after each CALL 464CH are its parameters, not code: the first error number of the operation and the address of the transfer loop. A write is refused with error 0FH when bit 7 of byte +03H of the drive code table (the software write protect) is set.
461A
BIT 2,B CB 50
Test bit 2 of Register B (the function): set for functions 0CH-0FH, the writes.
461C
LD BC,0682H 01 82 06
Load Register Pair BC with 0682H: Register B = 06H, the tries, Register C = 82H, the Read Sector command with the side compare bit (bit 1).
461F
If the NZ FLAG is set (a write function), JUMP to 4631H.
4621
CP 0AH FE 0A
Compare Register A (the function) against 0AH, verify.
4623
If the Z FLAG is set (function 0AH, verify), JUMP to 462BH.
4625
GOSUB to 464CH with the three parameter bytes at 4628H: the read. 464CH does not return here.
4628
DEFB 01H 01
4628H, the first parameter byte of the CALL 464CH at 4625H: 01H, the error number the read's status bits are counted from (CRC error 04H, record not found 05H, deleted data mark 06H).
4629-462A
DEFW 46C0H C0 46
4629H-462AH, the second and third parameter bytes of the CALL 464CH at 4625H: 46C0H, the read loop that takes the 256 bytes into the buffer at Register Pair HL.
462B
GOSUB to 464CH with the three parameter bytes at 462EH: the verify. 464CH does not return here.
462E
DEFB 01H 01
462EH, the first parameter byte of the CALL 464CH at 462BH: 01H, the error number the verify's status bits are counted from, the same as the read.
462F-4630
DEFW 46BEH BE 46
462FH-4630H, the second and third parameter bytes of the CALL 464CH at 462BH: 46BEH, which points the bytes read at 38xxH, where they are lost, and then runs the read loop.
4631
BIT 7,(IY+03H) FD CB 03 7E
Test bit 7 of byte +03H of the drive code table at Index Register IY, the software write protect.
4635
If the Z FLAG is set (the drive is not write protected), JUMP to 463AH.
4637
LD A,0FH 3E 0F
Load Register A with 0FH, error 15, write protected disk. The NZ FLAG from the BIT above stays.
4639
RET C9
RETurn with the error in Register A and the NZ FLAG.
463A
LD C,A2H 0E A2
Load Register C with A2H, the Write Sector command with the side compare bit (bit 1).
463C
CP 0EH FE 0E
Compare Register A (the function) against 0EH.
463E
If the CARRY FLAG is set (functions 0CH and 0DH), JUMP to 4646H with the Write Sector command.
4640
LD C,A3H 0E A3
Load Register C with A3H, the Write Sector command with the deleted data mark (bit 0) and the side compare bit.
4642
If the Z FLAG is set (function 0EH), JUMP to 4646H with that command.
4644
LD C,F0H 0E F0
Load Register C with F0H, the Write Track command (function 0FH).
4646
GOSUB to 464CH with the three parameter bytes at 4649H: the write. 464CH does not return here.
4649
DEFB 09H 09
4649H, the first parameter byte of the CALL 464CH at 4646H: 09H, the error number the write's status bits are counted from (write fault 0EH, write protected 0FH).
464A-464B
DEFW 4692H 92 46
464AH-464BH, the second and third parameter bytes of the CALL 464CH at 4646H: 4692H, the write loop, ended by the NMI.
464C
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer is not changed): Register Pair HL = the address of the parameter bytes after the CALL, and the caller's buffer address goes onto the stack.
464D
LD A,(HL) 7E
Fetch the first parameter byte at Register Pair HL into Register A: the first error number.
464E
INC HL 23
INCrement Register Pair HL to the address of the transfer loop.
464F
LD (468BH),A 32 8B 46
Store Register A (the first error number) at 468BH, the operand of the LD A at 468AH that counts the error number.
4652
LD A,(HL) 7E
Fetch the low byte of the transfer loop's address at Register Pair HL into Register A.
4653
INC HL 23
INCrement Register Pair HL to the high byte of the transfer loop's address.
4654
LD H,(HL) 66
Fetch the high byte of the transfer loop's address from Register Pair HL into Register H.
4655
LD L,A 6F
Copy Register A (the low byte) into Register L: Register Pair HL = the transfer loop.
4656
LD (4666H),HL 22 66 46
Store Register Pair HL (the transfer loop) at 4666H, the operand of the CALL at 4665H.
4659
POP HL E1
Restore the buffer address from the stack into Register Pair HL. The parameters' return address is not used: the code goes on at 465AH.
465A
PUSH BC C5
Save Register Pair BC (Register B = the tries left, Register C = the command) to the stack. A retry comes back here (4673H, 4685H).
465B
PUSH DE D5
Save Register Pair DE (the cylinder and sector) to the stack.
465C
PUSH HL E5
Save Register Pair HL (the buffer) to the stack.
465D
BIT 4,C CB 61
Test bit 4 of Register C (the command): clear for the sector commands, set for Write Track.
465F
If the Z FLAG is set (a sector command), GOSUB to 45DEH to seek the cylinder in Register D and set the sector register for Register E.
4662
GOSUB to 46D4H to wait until the controller is not busy (the seek has ended).
4665
GOSUB to the transfer loop whose address 4656H stores in the operand at 4666H-4667H (0000H in the file): 46C0H, 46BEH or 4692H.
4668
EI FB
Enable interrupts again (the transfer loops run with them off).
4669
IN A,(F0H) DB F0
Read the controller's status from port F0H into Register A.
466B
AND 7CH E6 7C
Mask Register A with 7CH, the error bits: bit 2 lost data, bit 3 CRC error, bit 4 record not found, bit 5 deleted data mark or write fault, bit 6 write protected.
466D
POP HL E1
Restore Register Pair HL (the buffer) from the stack.
466E
POP DE D1
Restore Register Pair DE (the cylinder and sector) from the stack.
466F
POP BC C1
Restore Register Pair BC (Register B = the tries left, Register C = the command) from the stack.
4670
RET Z C8
If the Z FLAG is set (no error), RETurn with Register A = 00H.
4671
BIT 2,A CB 57
Test bit 2 of Register A, the lost data bit of the controller's status.
4673
If the NZ FLAG is set (lost data), JUMP back to 465AH to try again; this does not count as a try.
4675
PUSH AF F5
Save Register Pair AF (the error bits in Register A) to the stack.
4676
AND 18H E6 18
Mask Register A with 18H: the record not found and CRC error bits.
4678
If the Z FLAG is set (neither), JUMP to 4688H, inside the LD B below, to take the error bits back and count the error number at once.
467A
BIT 4,A CB 67
Test bit 4 of Register A, the record not found bit of the controller's status.
467C
PUSH BC C5
Save Register Pair BC (the tries and the command) to the stack.
467D
LD A,(IY+03H) FD 7E 03
Fetch byte +03H of the drive code table at Index Register IY into Register A, the drive flags.
4680
If the NZ FLAG is set (record not found), GOSUB to 456BH to change the drive's density with Register A, the flags.
4683
POP BC C1
Restore Register Pair BC (Register B = the tries left, Register C = the command) from the stack.
4684
POP AF F1
Restore Register Pair AF (the error bits in Register A) from the stack.
4685
DECrement Register B, the tries left, and JUMP back to 465AH to try again until it reaches 0.
4687
LD B,F1H 06 F1
Load Register B with F1H. The value is not used: 4689H loads Register B again. The byte F1H at 4688H is a POP AF that 4678H jumps to; after the last try the error bits are already in Register A, so the LD B passes over it.
4689
LD B,A 47
Copy Register A (the error bits) into Register B.
468A
LD A,00H 3E 00
Load Register A with the first error number of the operation, the operand at 468BH that 464FH stores (00H in the file).
468C
RRC B CB 08
Rotate Register B right: the next error bit, from bit 0, goes into the CARRY FLAG.
468E
RET C D8
If the CARRY FLAG is set (this is the lowest error bit), RETurn with the error number in Register A and the NZ FLAG.
468F
INC A 3C
INCrement Register A, the error number, for the next bit.
4690
JUMP back to 468CH to test the next bit of Register B.
4692H - The Write Loop
The transfer loop of the write commands (the parameter at 464AH). It issues the command, waits for the first data request, writes the first byte, turns on the NMI for the end of the command (port E4H) and then writes byte after byte with wait states, in a loop that only the NMI ends: the NMI routine at 46F9H drops the loop's address and returns to the engine at 4668H.
4692
GOSUB to 46E0H to issue the command in Register C: Register D comes back as the drive select value with wait states, Register C as F3H, the data port.
4695
LD E,76H 1E 76
Load Register E with 76H, the status bits to wait for: data request (bit 1), lost data (bit 2), record not found (bit 4), write fault (bit 5) and write protected (bit 6).
4697
IN A,(F0H) DB F0
Read the controller's status from port F0H into Register A. 469AH loops back here.
4699
AND E A3
AND Register A with Register E (76H): the Z FLAG is set while none of those bits is set.
469A
If the Z FLAG is set (no data request yet), JUMP back to 4697H.
469C
OUTI ED A3
Send the byte at Register Pair HL to port Register C (F3H) and INCrement Register Pair HL (OUTI; Register B, 00H, counts down to FFH).
469E
DI F3
Disable interrupts for the rest of the write.
469F
IN A,(F0H) DB F0
Read the controller's status from port F0H into Register A.
46A1
RRA 1F
Rotate Register A right: bit 0, BUSY, goes into the CARRY FLAG.
46A2
RET NC D0
If the NO CARRY FLAG is set (the controller is not busy: the command has already ended with an error), RETurn to the engine.
46A3
LD A,C0H 3E C0
Load Register A with C0H: bits 7 and 6 of port E4H.
46A5
OUT (E4H),A D3 E4
Send Register A (C0H) to port E4H: the controller's interrupt request now causes an NMI, which ends the write (46F9H).
46A7
LD B,50H 06 50
Load Register B with 50H for a short delay after the NMI has been turned on.
46A9
DECrement Register B and loop back to 46A9H until it reaches 0.
46AB
LD B,(HL) 46
Fetch the second byte of the buffer at Register Pair HL into Register B.
46AC
INC HL 23
INCrement Register Pair HL to the third byte.
46AD
LD A,D 7A
Copy Register D (the drive select value with wait states) into Register A. 46B3H loops back here.
46AE
OUT (F4H),A D3 F4
Send Register A to port F4H: the drive stays selected and the next data port access waits for the controller.
46B0
IN A,(F0H) DB F0
Read the controller's status from port F0H into Register A.
46B2
AND E A3
AND Register A with Register E (76H): the Z FLAG is set while no data request has come.
46B3
If the Z FLAG is set (no data request has come yet), JUMP back to 46ADH.
46B5
OUT (C),B ED 41
Send Register B (the second byte) to port Register C (F3H).
46B7
LD A,D 7A
Copy Register D (the drive select value with wait states) into Register A. 46BCH loops back here.
46B8
OUT (F4H),A D3 F4
Send Register A to port F4H, so that the next OUTI waits until the controller asks for the byte.
46BA
OUTI ED A3
Send the byte at Register Pair HL to port Register C (F3H) and INCrement Register Pair HL (OUTI).
46BC
JUMP back to 46B8H for the next byte. The loop has no end of its own: the NMI at the end of the command leaves it (46F9H).
46BEH - The Verify and Read Loops
46BEH, the verify, points Register Pair HL at 38xxH, the keyboard addresses, where the bytes read are not kept, and goes on into the read loop at 46C0H. The read loop issues the command, waits for the first data request, then takes the 256 bytes of the sector into the buffer with wait states and returns when the controller is not busy.
46BE
LD H,38H 26 38
Load Register H with 38H: Register Pair HL now points into the keyboard addresses 3800H-38FFH, so the verified sector is read but not stored.
46C0
GOSUB to 46E0H to issue the command in Register C: Register D comes back as the drive select value with wait states, Register C as F3H, the data port.
46C3
LD E,16H 1E 16
Load Register E with 16H, the status bits to wait for: data request (bit 1), lost data (bit 2) and record not found (bit 4).
46C5
IN A,(F0H) DB F0
Read the controller's status from port F0H into Register A. 46C8H loops back here.
46C7
AND E A3
AND Register A with Register E (16H): the Z FLAG is set while none of those bits is set.
46C8
If the Z FLAG is set (no data request yet), JUMP back to 46C5H.
46CA
INI ED A2
Take the first byte from port Register C (F3H) into the buffer at Register Pair HL and INCrement Register Pair HL (INI); Register B goes from 00H to FFH.
46CC
DI F3
Disable interrupts for the rest of the read, so that no byte of the sector is missed.
46CD
LD A,D 7A
Copy Register D (the drive select value with wait states) into Register A. 46D2H loops back here.
46CE
OUT (F4H),A D3 F4
Send Register A to port F4H, so that the next INI waits until the controller has the byte.
46D0
INI ED A2
Take the next byte from port Register C (F3H) into the buffer at Register Pair HL, INCrement Register Pair HL and DECrement Register B (INI).
46D2
If the NZ FLAG is set (Register B has not reached 0: bytes are left), JUMP back to 46CEH. After 256 bytes the code goes on into 46D4H.
46D4H - Wait Until the Controller Is Not Busy
Function 07H and the wait of every command. Returns when bit 0 (BUSY) of the controller's status is clear, with the status in Register A and the Z FLAG set. While it waits it writes the last drive select value (PDRV$, 4423H) to port F4H again, which keeps the drive selected and its motor running.
46D4
IN A,(F0H) DB F0
Read the controller's status from port F0H into Register A.
46D6
BIT 0,A CB 47
Test bit 0 of Register A, BUSY: the Z FLAG is set when the controller is idle.
46D8
RET Z C8
If the Z FLAG is set (not busy), RETurn with the status in Register A.
46D9
LD A,(4423H) 3A 23 44
Fetch PDRV$, the last drive select value, from 4423H into Register A.
46DC
OUT (F4H),A D3 F4
Send Register A to port F4H: the drive stays selected while the controller is busy.
46DE
JUMP back to 46D4H to read the controller's status again.
46E0H - Issue a Read or Write Command
Called by the transfer loops with the command in Register C and the cylinder in Register D. Writes the cylinder to the track register, takes the drive select value of PDRV$ with the wait state bit (bit 6), adds the side compare bit for side 1 when the command has its side compare enable bit, and issues the command. Returns with Register D = the drive select value with wait states, Register C = F3H (the data port) and Register B = 00H.
46E0
LD A,D 7A
Copy Register D (the cylinder) into Register A.
46E1
OUT (F1H),A D3 F1
Send Register A (the cylinder) to port F1H, the track register, which the controller compares with the sector's address.
46E3
LD A,(4423H) 3A 23 44
Fetch PDRV$, the last drive select value, from 4423H into Register A.
46E6
OR 40H F6 40
OR 40H into Register A: bit 6 of port F4H, wait states for the data port.
46E8
LD D,A 57
Copy Register A (the drive select value with wait states) into Register D for the transfer loops.
46E9
AND 10H E6 10
Mask Register A with 10H to keep bit 4, the side 1 bit of the drive select value.
46EB
RRCA 0F
Rotate Register A right: 08H for side 1, the side bit (bit 3) of a sector command.
46EC
BIT 1,C CB 49
Test bit 1 of Register C (the command), the side compare enable bit.
46EE
If the NZ FLAG is set (the command compares the side), JUMP to 46F1H to keep the side bit.
46F0
XOR A AF
Set Register A to 00H (XOR A): Write Track has no side bit.
46F1
OR C B1
OR Register C (the command) into Register A: the command with its side bit.
46F2
GOSUB to 4612H to send the command in Register A to port F0H and wait for BUSY; Register B comes back as 00H.
46F5
LD C,F3H 0E F3
Load Register C with F3H, the data port, for the INI and OUTI of the transfer loops.
46F7
NOP 00
No operation: a spare byte between the load of Register C and the RET.
46F8
RET C9
RETurn to the transfer loop with Register C = F3H and Register D = the select value.
46F9H - The NMI Routine
The reset stores 46F9H at 404AH, the NMI vector (4E07H-4E0CH). The controller's interrupt request at the end of a write causes the NMI (port E4H bits 7-6 set at 46A5H): the NMI pushes the address of the write loop, which this routine drops, so that its RET goes back to the engine at 4668H.
46F9
XOR A AF
Set Register A to 00H (XOR A), the value that turns off the controller's NMIs.
46FA
OUT (E4H),A D3 E4
Send Register A (00H) to port E4H: no more NMIs from the controller.
46FC
POP HL E1
Drop the address the NMI pushed (inside the write loop) from the stack into Register Pair HL.
46FD
RET C9
RETurn to the caller of the write loop (4668H).
46FE
JP (IY) FD E9
Jump to the drive code table at Index Register IY: its first three bytes are a JP to the drive's driver (4583H) or a RET for a drive that is not present. The disk primitives call here (4787H).
4700H - DCT$, the Drive Code Tables
Eight entries of 10 bytes, drives 0-7 (GETDCT, 478FH, points Index Register IY at entry 4700H + the drive x 10). +00H C3H for a drive that is present (a JP) or C9H for one that is not (a RET, so a call returns at once); +01H-+02H the driver address; +03H flags (bits 1-0 the step rate, bit 2 one motor wait, bit 4 side 1, bit 6 double density, bit 7 software write protect); +04H bits 3-0 the drive select bit; +05H the cylinder the head is on; +06H the highest cylinder; +07H bits 4-0 the highest sector of a track; +08H bits 4-0 the sectors in a granule less one, bits 7-5 the granules on a track less one; +09H the directory cylinder. The reset takes the step rate and the directory cylinder of drive 0 from the boot sector (4E77H-4E88H) and drives 1-7 from the system information sector (4FC8H-4FD1H).
4700-4709
DEFB C3H, 83H, 45H, 44H, 41H, 16H, 27H, 11H, 45H, 14H C3 83 45 44 41 16 27 11 45 14
4700H-4709H, drive 0: C3H 83H 45H = JP 4583H, the floppy disk driver; +03H 44H, double density with bit 2 set, step rate 0 (the reset ORs in the boot sector's rate); +04H 41H, select bit 01H and bit 6; +05H 16H, the cylinder in the file (the reset stores the track register); +06H 27H, cylinder 39 the highest; +07H 11H, 18 sectors; +08H 45H, three granules of six sectors; +09H 14H, the directory on cylinder 20.
470A-4713
DEFB C3H, 83H, 45H, 40H, 42H, 00H, 27H, 11H, 45H, 14H C3 83 45 40 42 00 27 11 45 14
470AH-4713H, drive 1: C3H 83H 45H = JP 4583H; +03H 40H, double density, step rate 0; +04H 42H, select bit 02H and bit 6; +05H 00H, cylinder 0; +06H 27H, cylinder 39 the highest; +07H 11H, 18 sectors; +08H 45H, three granules of six; +09H 14H, the directory on cylinder 20. The reset copies drives 1-7 from the system information sector over these bytes (4FCBH).
4714-471D
DEFB C3H, 83H, 45H, 40H, 44H, 00H, 27H, 11H, 45H, 14H C3 83 45 40 44 00 27 11 45 14
4714H-471DH, drive 2: C3H 83H 45H = JP 4583H; +03H 40H, double density, step rate 0; +04H 44H, select bit 04H and bit 6; +05H 00H, cylinder 0; +06H 27H, cylinder 39 the highest; +07H 11H, 18 sectors; +08H 45H, three granules of six; +09H 14H, the directory on cylinder 20.
471E-4727
DEFB C3H, 83H, 45H, 40H, 48H, 00H, 27H, 11H, 45H, 14H C3 83 45 40 48 00 27 11 45 14
471EH-4727H, drive 3: C3H 83H 45H = JP 4583H; +03H 40H, double density, step rate 0; +04H 48H, select bit 08H and bit 6; +05H 00H, cylinder 0; +06H 27H, cylinder 39 the highest; +07H 11H, 18 sectors; +08H 45H, three granules of six; +09H 14H, the directory on cylinder 20.
4728
DEFB C9H C9
4728H, drive 4, +00H: C9H, the opcode of RET: the drive is not present and every request for it returns at once.
4729-4731
DEFB 00H x 9 00 x 9
4729H-4731H, drive 4, +01H-+09H: 00H, no driver address and no geometry.
4732
DEFB C9H C9
4732H, drive 5, +00H: C9H, the opcode of RET: the drive is not present and every request for it returns at once.
4733-473B
DEFB 00H x 9 00 x 9
4733H-473BH, drive 5, +01H-+09H: 00H, no driver address and no geometry.
473C
DEFB C9H C9
473CH, drive 6, +00H: C9H, the opcode of RET: the drive is not present and every request for it returns at once.
473D-4745
DEFB 00H x 9 00 x 9
473DH-4745H, drive 6, +01H-+09H: 00H, no driver address and no geometry.
4746
DEFB C9H C9
4746H, drive 7, +00H: C9H, the opcode of RET: the drive is not present and every request for it returns at once.
4747-474F
DEFB 00H x 9 00 x 9
4747H-474FH, drive 7, +01H-+09H: 00H, no driver address and no geometry.
4750H - The Disk Primitives
The named entry points the system and the utilities use for a sector operation: each loads the driver function into Register A and joins 4779H, which calls the driver of the drive in Register C through its drive code table. Each entry is five bytes, and the fifth byte is a variable. 4750H is the same as SELECT with the drive of the last call (LDRV$, 4427H).
4750
LD A,(4427H) 3A 27 44
Fetch LDRV$, the drive of the last primitive call, from 4427H into Register A. The interrupt routine calls 4750H on SHIFT BREAK (44DDH); BASIC/CMD calls it too (its 5518H).
4753
LD C,A 4F
Copy Register A (the last drive) into Register C, the drive for the select below.
4754
LD A,01H 3E 01
SELECT: load Register A with 01H, the driver's function select the drive.
4756
JUMP to 4779H to call the driver of drive Register C with the function in Register A.
4758
DEFB 00H 00
4758H: the fifth byte of SELECT, a status byte of the command interpreter that SYS1/SYS clears, sets and tests (its 4E22H, 4E44H, 4E9AH, 4EA3H); SYS4/SYS, HITAPE/CMD, LCOMM/CMD and TED/CMD address it too.
4759
LD A,07H 3E 07
TSTBSY: load Register A with 07H, the driver's function wait until the controller is not busy. BACKUP/CMD, SYS2/SYS and SYS12/SYS call 4759H.
475B
JUMP to 4779H to call the driver of drive Register C with the function in Register A.
475D
DEFB 00H 00
475DH: the fifth byte of TSTBSY, flags that SYS2/SYS (its 4EA7H) and SYS3/SYS (its 4E99H) use when they open and close files; BACKUP/CMD reads and sets it too.
475E
LD A,06H 3E 06
SEEK: load Register A with 06H, the driver's function seek cylinder Register D for sector Register E. BACKUP/CMD, SYS2/SYS and SYS12/SYS call 475EH.
4760
JUMP to 4779H to call the driver of drive Register C with the function in Register A.
4762
DEFB FFH FF
4762H: the fifth byte of SEEK, FFH, the pattern 4BBBH rotates on every clock tick: a tick whose rotated bit is set runs the tasks, so with FFH every tick runs them.
4763
LD A,0DH 3E 0D
WRSECT: load Register A with 0DH, the driver's function write the sector at Register Pair HL to cylinder Register D, sector Register E. The file routines call it at 49CAH.
4765
JUMP to 4779H to call the driver of drive Register C with the function in Register A.
4767
DEFB 01H 01
4767H: the fifth byte of WRSECT, 01H, which SYS8/SYS reads (its 4EBFH) for the cylinder where it starts its search for free space.
4768
LD A,0EH 3E 0E
WRPROT: load Register A with 0EH, the driver's function write a sector with the deleted data mark, used for every directory sector (4B25H).
476A
JUMP to 4779H to call the driver of drive Register C with the function in Register A.
476C
DEFB 00H 00
476CH: the fifth byte of WRPROT, 00H. No instruction of the LDOS files on this diskette addresses it.
476D
LD A,0FH 3E 0F
WRTRK: load Register A with 0FH, the driver's function write a track from the buffer at Register Pair HL.
476F
JUMP to 4779H to call the driver of drive Register C with the function in Register A.
4771
DEFB 00H 00
4771H: the fifth byte of WRTRK, 00H. No instruction of the LDOS files on this diskette addresses it.
4772
LD A,0AH 3E 0A
VERSEC: load Register A with 0AH, the driver's function verify cylinder Register D, sector Register E (read without storing the bytes).
4774
JUMP to 4779H to call the driver of drive Register C with the function in Register A.
4776
DEFB 00H 00
4776H: the fifth byte of VERSEC, 00H. No instruction of the LDOS files on this diskette addresses it.
4777
LD A,09H 3E 09
RDSECT: load Register A with 09H, the driver's function read cylinder Register D, sector Register E into the buffer at Register Pair HL. The code goes on into 4779H.
4779
PUSH BC C5
Save Register Pair BC (Register C = the drive) to the stack; the driver gets the function in Register B.
477A
LD B,A 47
Copy Register A (the function) into Register B.
477B
LD A,C 79
Copy Register C (the drive number) into Register A.
477C
LD (4427H),A 32 27 44
Store Register A (the drive) at 4427H, LDRV$, for 4750H.
477F
PUSH IY FD E5
Save Index Register IY to the stack: the caller's Index Register IY comes back.
4781
GOSUB to 478FH to point Index Register IY at the drive code table of drive Register C.
4784
LD A,20H 3E 20
Load Register A with 20H for the driver; SYS0/SYS's own driver takes the function from Register B and does not use it.
4786
OR A B7
Set the flags from Register A (OR A): NZ, the CARRY FLAG clear.
4787
GOSUB to 46FEH, which jumps to the drive code table at Index Register IY: a JP to the drive's driver (4583H) or a RET for a drive that is not present. The driver returns with the Z FLAG set and Register A = 00H on success, else the error number in Register A.
478A
POP IY FD E1
Restore the caller's Index Register IY from the stack.
478C
POP BC C1
Restore the caller's Register Pair BC from the stack.
478D
RET C9
RETurn to the caller with the driver's result in Register A and the flags.
478E
DEFB 00H 00
478EH: 00H, the spare byte after the primitives. No instruction of the LDOS files on this diskette addresses it.
478FH - GETDCT and DCTBYT: Find a Drive's Code Table
478FH (GETDCT) points Index Register IY at the drive code table of drive Register C (bits 2-0). 479CH (DCTBYT) returns in Register A byte Register A (an offset 0-9) of drive Register C's table; 4797H does that for byte +08H of the drive in byte +06H of the file control block at Index Register IX. 47A5H works out the address; FORMAT/CMD calls it too.
478F
PUSH HL E5
GETDCT: save the caller's Register Pair HL to the stack.
4790
GOSUB to 47A5H: Register Pair HL comes back pointing at drive Register C's entry in DCT$ (4700H + the drive x 10).
4793
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer is not changed): the entry's address goes onto the stack and the caller's Register Pair HL comes back.
4794
POP IY FD E1
Restore the entry's address from the stack into Index Register IY.
4796
RET C9
RETurn with Index Register IY pointing at the drive code table.
4797
LD C,(IX+06H) DD 4E 06
Fetch byte +06H of the file control block at Index Register IX into Register C: the file's drive.
479A
LD A,08H 3E 08
Load Register A with 08H, the offset of the byte with the sectors in a granule and the granules on a track.
479C
PUSH HL E5
DCTBYT: save the caller's Register Pair HL to the stack.
479D
LD H,A 67
Copy Register A (the offset in the table) into Register H, for 47A5H to add.
479E
GOSUB to 47A5H: Register A comes back as the low byte of drive Register C's entry plus the offset in Register H.
47A1
LD L,A 6F
Copy Register A (the low byte of the byte's address) into Register L. Register H is 47H from 47A5H: Register Pair HL = the address of the byte.
47A2
LD A,(HL) 7E
Fetch the byte of the drive code table at Register Pair HL into Register A.
47A3
POP HL E1
Restore the caller's Register Pair HL from the stack.
47A4
RET C9
RETurn with the byte of the drive code table in Register A.
47A5
LD A,C 79
Copy Register C (the drive number) into Register A.
47A6
AND 07H E6 07
Mask Register A to bits 2-0: the drive number, 0-7.
47A8
ADD A,A 87
Double Register A (ADD A,A): Register A = the drive x 2.
47A9
LD L,A 6F
Copy Register A (the drive x 2) into Register L.
47AA
ADD A,A 87
Double Register A again: Register A = the drive x 4.
47AB
ADD A,A 87
Double Register A again: Register A = the drive x 8.
47AC
ADD A,L 85
ADD Register L (the drive x 2) to Register A: Register A = the drive x 10, the offset of its entry.
47AD
ADD A,00H C6 00
ADD 00H to Register A: the operand at 47AEH is the low byte of DCT$, 00H for 4700H.
47AF
LD L,A 6F
Copy Register A (the low byte of the entry's address) into Register L.
47B0
ADD A,H 84
ADD Register H (an offset within the entry, from DCTBYT) to Register A: the low byte of that byte's address.
47B1
LD H,47H 26 47
Load Register H with 47H. Register Pair HL = the entry's address (4700H + the drive x 10).
47B3
RET C9
RETurn to the caller with the entry's address in Register Pair HL.
47B4H - Copy a System File's Extents into SFCB$
The overlay loader (4C36H) calls this with Register A = the low byte of the first extent's address in the directory record in the buffer at 4300H (the record + 16H). It copies the first extent (cylinder, granule byte) to 42AFH-42B0H, stores the number of granules of that extent as a word at 42B1H-42B2H, and copies the second extent (record + 18H) to 42B3H-42B4H.
47B4
LD L,A 6F
Copy Register A (the low byte of the extent's address) into Register L. Register H is 43H from the directory read: Register Pair HL = the first extent in the buffer.
47B5
LD DE,42AFH 11 AF 42
Point Register Pair DE to 42AFH, the extent area of SFCB$.
47B8
GOSUB to 47C3H to copy two bytes from Register Pair HL to Register Pair DE: the first extent's cylinder and granule byte. Register A comes back holding the granule byte.
47BB
AND 1FH E6 1F
Mask Register A (the granule byte) to bits 4-0: the granules of the extent less one.
47BD
INC A 3C
INCrement Register A: the number of granules in the first extent.
47BE
LD (DE),A 12
Store Register A (the granules) at Register Pair DE (42B1H), the low byte of the count.
47BF
INC DE 13
INCrement Register Pair DE to 42B2H, the high byte of the count.
47C0
XOR A AF
Set Register A to 00H (XOR A) for the high byte of the count.
47C1
LD (DE),A 12
Store Register A (00H) at Register Pair DE (42B2H), the high byte of the count.
47C2
INC DE 13
INCrement Register Pair DE to 42B3H. The code goes on into 47C3H to copy the second extent.
47C3
GOSUB to 47C6H to copy one byte from Register Pair HL to Register Pair DE; the code then falls into 47C6H for the second byte.
47C6
LD A,(HL) 7E
Fetch the byte at Register Pair HL into Register A.
47C7
LD (DE),A 12
Store Register A (the byte) at Register Pair DE in SFCB$.
47C8
INC HL 23
INCrement Register Pair HL to the next byte of the directory record.
47C9
INC DE 13
INCrement Register Pair DE to the next byte of SFCB$.
47CA
RET C9
RETurn to the caller (once to 47C6H, then to the caller of 47C3H).
47CBH - @SKIP and @POSN: Position a File
47CBH (@SKIP) works out the current record (484DH) and positions to the next one; 47CFH (@POSN) positions to record Register Pair BC. Register Pair DE = the file control block (Index Register IX after the prologue). In byte mode (bit 7 of +01H) with a record length below 256, the record number is turned into a sector and an offset (record x length); otherwise the record is the sector. When the buffer already holds that sector only the offset changes; else the buffer is written if it was changed, the next record number (+0AH-+0BH) becomes the sector and bit 5 of +01H marks the buffer to be read before the next byte. Then the end of file is tested (4A1DH).
47CB
@SKIP: GOSUB to 484DH (@LOC) to work out the current record number into Register Pair BC.
47CE
INC BC 03
INCrement Register Pair BC: the record after the current one.
47CF
@POSN: GOSUB to 49F3H, the file prologue: it checks that the control block at Register Pair DE is open, points Index Register IX at it, saves Register Pairs BC, DE and HL and Index Register IX for the return, and comes back with Register A = 00H.
47D2
SET 6,(IX+01H) DD CB 01 F6
Set bit 6 of byte +01H of the file control block at Index Register IX: the file has been positioned, so a write inside the file does not move its end (49DBH, 493BH).
47D6
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of byte +01H of the file control block at Index Register IX: byte mode, the file used a byte at a time.
47DA
If the Z FLAG is set (not byte mode), JUMP to 47FAH: the record in Register Pair BC is a sector, at offset 0 (Register A = 00H).
47DC
LD H,B 60
Copy Register B (the record number's high byte) into Register H.
47DD
LD L,C 69
Copy Register C (the record number's low byte) into Register L. Register Pair HL = the record number.
47DE
OR (IX+09H) DD B6 09
OR byte +09H of the file control block at Index Register IX (the record length, 0 for 256) into Register A (00H): the Z FLAG is set for 256 byte records.
47E1
If the Z FLAG is set (records of 256 bytes), JUMP to 47FAH: the record is the sector.
47E3
GOSUB to 4B8EH to multiply Register Pair HL (the record number) by Register A (the record length): Register Pair HL = the product's high 16 bits (the sector), Register A = its low 8 bits (the offset in the sector).
47E6
LD B,H 44
Copy Register H (the sector's high byte) into Register B.
47E7
LD C,L 4D
Copy Register L (the sector's low byte) into Register C. Register Pair BC = the sector of the record.
47E8
LD (IX+05H),A DD 77 05
Store Register A (the offset of the record in its sector) into byte +05H of the file control block at Index Register IX, the position in the buffer.
47EB
BIT 5,(IX+01H) DD CB 01 6E
Test bit 5 of byte +01H of the file control block at Index Register IX: set when the buffer does not hold the sector before the next record number.
47EF
If the NZ FLAG is set (the buffer has to be read anyway), JUMP to 47FDH to set the next record number to Register Pair BC.
47F1
GOSUB to 497EH: Register Pair HL = the next record number (+0AH-+0BH) of the file at Index Register IX.
47F4
SCF 37
Set the CARRY FLAG, so the SBC below takes away one more.
47F5
SBC HL,BC ED 42
SUBtract Register Pair BC (the sector wanted) and the CARRY FLAG from Register Pair HL (the next record number): the Z FLAG is set when the sector wanted is the one before the next record number, the sector the buffer holds.
47F7
If the Z FLAG is set (the buffer holds the sector wanted), JUMP to 4A1DH to test the end of file: only the offset changed.
47FA
LD (IX+05H),A DD 77 05
Store Register A (the offset: 00H, or the end of file byte from @PEOF) into byte +05H of the file control block at Index Register IX. @REW, @PEOF and the record mode path come here.
47FD
PUSH BC C5
Save Register Pair BC (the sector wanted) to the stack.
47FE
GOSUB to 4993H to write the buffer back to its sector if the file is in byte mode and the buffer was changed. @BKSP and @RREAD join here with the sector on the stack.
4801
POP BC C1
Restore Register Pair BC (the sector wanted) from the stack.
4802
RET NZ C0
If the NZ FLAG is set (the buffer could not be written), RETurn with the error number in Register A.
4803
LD (IX+0AH),C DD 71 0A
Store Register C (the low byte of the sector wanted) into byte +0AH of the file control block at Index Register IX.
4806
LD (IX+0BH),B DD 70 0B
Store Register B (the high byte of the sector wanted) into byte +0BH of the file control block at Index Register IX: the next record number is now the sector wanted.
4809
GOSUB to 4914H to set bit 5 of byte +01H: the buffer must be read before the next byte is taken.
480C
JUMP to 4A1DH to test the end of file at the new position; its result is the result of the call.
480FH - @RREAD and @BKSP
480FH (@RREAD) marks the sector the buffer holds to be read again; 4816H (@BKSP) moves back one record (in byte mode by the record length within the buffer when it can, else to the sector before). Both end at 47FEH with the new next record number on the stack.
480F
@RREAD: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
4812
LD C,01H 0E 01
Load Register C with 01H, so that 4DA1H counts the position as inside the buffer's sector.
4814
JUMP to 482BH to set the next record number to the buffer's sector and read it again.
4816
@BKSP: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
4819
LD C,A 4F
Copy Register A (00H) into Register C: no count of bytes for 4DA1H.
481A
LD B,(IX+09H) DD 46 09
Fetch byte +09H of the file control block at Index Register IX into Register B: the record length (0 for 256).
481D
OR B B0
OR Register B (the record length) into Register A (00H): the Z FLAG is set for 256 byte records.
481E
If the Z FLAG is set (256 byte records), JUMP to 482BH to step back one sector.
4820
LD A,(IX+05H) DD 7E 05
Fetch byte +05H of the file control block at Index Register IX into Register A: the position in the buffer.
4823
SUB B 90
SUBtract Register B (the record length) from Register A (the position): the CARRY FLAG is set when the record before starts in the sector before.
4824
LD (IX+05H),A DD 77 05
Store Register A (the position one record back, in this sector or the one before) into byte +05H of the file control block at Index Register IX.
4827
If the CARRY FLAG is set (the position went back past the start of the buffer), JUMP to 482BH to step back one sector.
4829
XOR A AF
Set Register A to 00H (XOR A) with the Z FLAG set: done, the buffer still holds the sector.
482A
RET C9
RETurn through the prologue's restore (4A14H).
482B
GOSUB to 497EH: Register Pair HL = the next record number (+0AH-+0BH).
482E
DEC HL 2B
DECrement Register Pair HL: the sector before the next record number.
482F
GOSUB to 4DA1H to adjust Register Pair HL for byte mode: there it adds 1 when Register C is not 0 and takes 1 away when the buffer holds the sector before the next record number (bit 5 clear); in record mode Register Pair HL is left as it is. Register Pair HL ends as the sector to read.
4832
PUSH HL E5
Save Register Pair HL (the sector to read) to the stack, where 47FEH-4801H takes it as Register Pair BC.
4833
JUMP to 47FEH to write the buffer if it changed and make the sector in Register Pair HL the next record number.
4835H - @REW and @PEOF
4835H (@REW) positions the file at its first record; 483CH (@PEOF) at its end of file: the ending record number (+0CH-+0DH), less one when the end of file byte (+08H) is not 0, with the end of file byte as the offset.
4835
@REW: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
4838
LD B,A 47
Copy Register A (00H) into Register B, the high byte of the sector.
4839
LD C,A 4F
Copy Register A (00H) into Register C. Register Pair BC = 0000H, the first sector.
483A
JUMP to 47FAH to make sector 0 the next record number with the offset 00H in Register A.
483C
@PEOF: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
483F
LD C,(IX+0CH) DD 4E 0C
Fetch byte +0CH of the file control block at Index Register IX into Register C: the ending record number's low byte.
4842
LD B,(IX+0DH) DD 46 0D
Fetch byte +0DH of the file control block at Index Register IX into Register B. Register Pair BC = the ending record number, the sectors in the file.
4845
OR (IX+08H) DD B6 08
OR byte +08H of the file control block at Index Register IX (the end of file byte: the bytes used in the last sector, 0 for a full sector) into Register A (00H).
4848
If the Z FLAG is set (the last sector is full), JUMP to 47FAH: the end is at offset 0 of sector Register Pair BC.
484A
DEC BC 0B
DECrement Register Pair BC: the end is inside the last sector of the file.
484B
JUMP to 47FAH with Register A = the end of file byte as the offset in that sector.
484DH - @LOC and @LOF
484DH (@LOC) returns in Register Pair BC the current record number of the file; 4878H (@LOF) the number of records (from the ending record number and the end of file byte). A position in sectors and bytes is divided by the record length; a partial record counts as one. Register A returns the high byte of the sector quotient. The result is put where the prologue's restore (4A14H) takes Register Pair BC from.
484D
@LOC: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
4850
GOSUB to 497EH: Register Pair HL = the next record number (+0AH-+0BH).
4853
GOSUB to 4D9EH: Register C = the position in the buffer (+05H) and Register Pair HL adjusted to the sector of the current position.
4856
LD E,(IX+09H) DD 5E 09
Fetch byte +09H of the file control block at Index Register IX into Register E: the record length (0 for 256). @LOF joins here with Register Pair HL = the ending record number and Register C = the end of file byte.
4859
LD A,E 7B
Copy Register E (the record length) into Register A.
485A
OR A B7
Set the flags from Register A (OR A): the Z FLAG is set for 256 byte records.
485B
If the Z FLAG is set (256 byte records: the record is the sector), JUMP to 4873H with Register Pair HL as the result.
485D
INC C 0C
INCrement Register C (the position in the sector)...
485E
DEC C 0D
...and DECrement it again: the pair only sets the Z FLAG from Register C, set when the position is 0.
485F
If the Z FLAG is set (the position in Register C is 0), JUMP to 4862H.
4861
DEC HL 2B
DECrement Register Pair HL: the bytes of the position are in the sector before.
4862
GOSUB to 4BA8H to divide Register Pair HL (the sector) by Register A (the record length): Register Pair HL = the quotient, Register A = the remainder.
4865
LD B,L 45
Copy Register L (the quotient's low byte) into Register B.
4866
LD D,H 54
Copy Register H (the quotient's high byte) into Register D.
4867
LD H,A 67
Copy Register A (the remainder) into Register H.
4868
LD L,C 69
Copy Register C (the position in the sector) into Register L. Register Pair HL = the remainder x 256 + the position: the bytes left over.
4869
LD A,E 7B
Copy Register E (the record length) into Register A.
486A
GOSUB to 4BA8H to divide Register Pair HL (the bytes left over) by Register A (the record length): Register L = the records in them, Register A = the bytes of a partial record.
486D
LD H,B 60
Copy Register B (the first quotient's low byte) into Register H. Register Pair HL = the record number (the first quotient x 256 + the second).
486E
OR A B7
Set the flags from Register A (OR A): the Z FLAG is set when no partial record is left.
486F
If the Z FLAG is set (no partial record), JUMP to 4872H.
4871
INC HL 23
INCrement Register Pair HL: a partial record counts as one.
4872
LD A,D 7A
Copy Register D (the first quotient's high byte) into Register A.
4873
POP BC C1
Restore the prologue's return address (4A14H) from the stack into Register Pair BC.
4874
EX (SP),HL E3
Exchange Register Pair HL (the result) with the top of the stack (the Stack Pointer is not changed): the result replaces the saved Register Pair BC, and the caller's Register Pair BC comes into Register Pair HL.
4875
PUSH BC C5
Save Register Pair BC (4A14H) back on the stack, so the RET below goes to the prologue's restore, which gives the result in Register Pair BC.
4876
OR A B7
Set the flags from Register A (OR A). SYS5/SYS (DEBUG) calls 4876H through 4400H as the default for an unknown command.
4877
RET C9
RETurn: to 4A14H after @LOC and @LOF, or to SYS5/SYS.
4878
@LOF: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
487B
LD L,(IX+0CH) DD 6E 0C
Fetch byte +0CH of the file control block at Index Register IX into Register L: the ending record number's low byte.
487E
LD H,(IX+0DH) DD 66 0D
Fetch byte +0DH of the file control block at Index Register IX into Register H. Register Pair HL = the ending record number.
4881
LD C,(IX+08H) DD 4E 08
Fetch byte +08H of the file control block at Index Register IX into Register C: the end of file byte.
4884
JUMP to 4856H to turn the end of file in Register Pair HL and Register C into records.
4886H - @WEOF: Write the End of File to the Directory
Writes the buffer if it changed, then reads the file's directory record (drive +06H, record number +07H) and stores the end of file byte (record +03H) and the ending record number (record +14H-+15H) from the file control block. 49EDH enters at 488CH after a write when bit 3 of +01H asks for it.
4886
@WEOF: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
4889
GOSUB to 4993H to write the buffer back if the file is in byte mode and the buffer was changed.
488C
LD B,(IX+07H) DD 46 07
Fetch byte +07H of the file control block at Index Register IX into Register B: the number of the file's directory record.
488F
LD C,(IX+06H) DD 4E 06
Fetch byte +06H of the file control block at Index Register IX into Register C: the file's drive.
4892
GOSUB to 4B10H (DIRRD) to read the directory sector of record Register B on drive Register C into 4300H; Register Pair HL comes back pointing at the record.
4895
RET NZ C0
If the NZ FLAG is set (the directory could not be read), RETurn with the error number in Register A (11H).
4896
INC L 2C
INCrement Register L: Register Pair HL points at record +01H.
4897
INC L 2C
INCrement Register L: Register Pair HL points at record +02H.
4898
INC L 2C
INCrement Register L: record +03H, the end of file byte.
4899
LD A,(IX+08H) DD 7E 08
Fetch byte +08H of the file control block at Index Register IX into Register A: the end of file byte.
489C
LD (HL),A 77
Store Register A (the end of file byte) into the directory record at Register Pair HL (+03H).
489D
LD DE,0011H 11 11 00
Load Register Pair DE with 0011H, the distance from +03H to +14H.
48A0
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL points at record +14H, the ending record number.
48A1
LD A,(IX+0CH) DD 7E 0C
Fetch byte +0CH of the file control block at Index Register IX into Register A: the low byte of the ending record number.
48A4
LD (HL),A 77
Store Register A into the directory record at Register Pair HL (+14H).
48A5
INC HL 23
INCrement Register Pair HL to record +15H, the high byte of the ending record number.
48A6
LD A,(IX+0DH) DD 7E 0D
Fetch byte +0DH of the file control block at Index Register IX into Register A: the high byte of the ending record number.
48A9
LD (HL),A 77
Store Register A into the directory record at Register Pair HL (+15H).
48AA
JUMP to 4B1FH (DIRWR) to write the directory sector back and check it; its result is the result of the call.
48ADH - @READ, @WRITE and @VER
48ADH reads the next record: with 256 byte records the next sector is read into the file's buffer (494FH); with shorter records the record's bytes are taken one by one into the record area at Register Pair HL. 48CBH writes the next record the same way (from the buffer, 49ABH, or byte by byte from Register Pair HL), and 48E6H does the same with the verify switch (49CFH) on.
48AD
@READ: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
48B0
PUSH HL E5
Save Register Pair HL (the caller's record area) to the stack.
48B1
GOSUB to 4993H to write the buffer back if the file is in byte mode and the buffer was changed.
48B4
POP HL E1
Restore Register Pair HL (the record area) from the stack.
48B5
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error number in Register A.
48B6
LD B,(IX+09H) DD 46 09
Fetch byte +09H of the file control block at Index Register IX into Register B: the record length (0 for 256).
48B9
LD A,B 78
Copy Register B (the record length) into Register A.
48BA
OR A B7
Set the flags from Register A (OR A): the Z FLAG is set for 256 byte records.
48BB
If the Z FLAG is set (256 byte records), JUMP to 494FH to read the next sector into the file's buffer.
48BE
PUSH HL E5
Save Register Pair HL (the record area pointer) to the stack: the byte fetch changes it. 48C8H loops back here.
48BF
PUSH BC C5
Save Register Pair BC (Register B = the bytes left in the record) to the stack.
48C0
GOSUB to 48FCH to take the next byte of the file into Register A (reading the next sector when the buffer is used up).
48C3
POP BC C1
Restore Register Pair BC (Register B = the bytes left) from the stack.
48C4
POP HL E1
Restore Register Pair HL (the record area pointer) from the stack.
48C5
RET NZ C0
If the NZ FLAG is set (the end of file or a read error), RETurn with the error number in Register A.
48C6
LD (HL),A 77
Store Register A (the byte) into the record area at Register Pair HL.
48C7
INC HL 23
INCrement Register Pair HL to the next byte of the record area.
48C8
DECrement Register B (the bytes left) and LOOP BACK to 48BEH until the record is complete.
48CA
RET C9
RETurn with Register A from the last fetch (00H) and the Z FLAG set.
48CB
@WRITE: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H). @VER joins at 48CEH with Register A = 01H.
48CE
LD (49CFH),A 32 CF 49
Store Register A (00H, or 01H from @VER) at 49CFH, the operand of the LD A at 49CEH: the switch that makes 49B8H verify each sector it writes.
48D1
LD B,(IX+09H) DD 46 09
Fetch byte +09H of the file control block at Index Register IX into Register B: the record length (0 for 256).
48D4
LD A,B 78
Copy Register B (the record length) into Register A.
48D5
OR A B7
Set the flags from Register A (OR A): the Z FLAG is set for 256 byte records.
48D6
If the Z FLAG is set (256 byte records), JUMP to 49ABH to write the file's buffer as the next sector.
48D9
LD A,(HL) 7E
Fetch the next byte of the record from the record area at Register Pair HL into Register A. 48E3H loops back here.
48DA
INC HL 23
INCrement Register Pair HL to the next byte of the record area.
48DB
PUSH HL E5
Save Register Pair HL (the record area pointer) to the stack.
48DC
PUSH BC C5
Save Register Pair BC (Register B = the bytes left) to the stack.
48DD
GOSUB to 4919H to put the byte in Register A into the file (writing the buffer out when it fills).
48E0
POP BC C1
Restore Register Pair BC (Register B = the bytes left) from the stack.
48E1
POP HL E1
Restore Register Pair HL (the record area pointer) from the stack.
48E2
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error number in Register A.
48E3
DECrement Register B (the bytes left) and LOOP BACK to 48D9H until the record is written.
48E5
RET C9
RETurn with Register A = 00H and the Z FLAG set.
48E6
@VER: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
48E9
INC A 3C
INCrement Register A: Register A = 01H, the verify switch on.
48EA
JUMP to 48CEH to write the record with every sector verified.
48ECH - A File Used as a Device
@DVRHK (4D6FH) comes here when a device's control block is an open file (type above 10H): Index Register IX = the file control block, Register B = the request (01H input, 02H output, 04H control), Register C = the character. The file is put into byte mode (bit 7 of +01H) and one byte is taken from it or put into it. 48FCH, the byte fetch, is also used by @READ.
48EC
PUSH IX DD E5
Save Index Register IX (the file control block) to the stack.
48EE
POP DE D1
Restore it into Register Pair DE: the prologue takes the control block in Register Pair DE.
48EF
GOSUB to 49F3H, the file prologue (checks that the file is open; Index Register IX = the file control block, Register A = 00H).
48F2
SET 7,(IX+01H) DD CB 01 FE
Set bit 7 of byte +01H of the file control block at Index Register IX: the file is now used in byte mode.
48F6
LD A,B 78
Copy Register B (the request) into Register A.
48F7
CP 02H FE 02
Compare Register A (the request) against 02H: the NO CARRY FLAG is set for output (02H) and control (04H).
48F9
LD A,C 79
Copy Register C (the character) into Register A. LD does not change the flags.
48FA
If the NO CARRY FLAG is set (output or control), JUMP to 4919H to put the byte in Register A into the file.
48FC
GOSUB to 4A1DH to test the end of file: the NZ FLAG is set (Register A = 1CH or 1DH) at or past the end. @READ calls 48FCH for each byte.
48FF
RET NZ C0
If the NZ FLAG is set (no more bytes), RETurn with the error number in Register A.
4900
BIT 5,(IX+01H) DD CB 01 6E
Test bit 5 of byte +01H of the file control block at Index Register IX: set when the buffer must be read first.
4904
If the NZ FLAG is set (the buffer must be read), GOSUB to 494FH to read the sector of the next record number into the buffer.
4907
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn with the error number in Register A.
4908
GOSUB to 4985H: Register Pair DE = the address in the buffer of the next byte (the buffer +03H-+04H plus the position +05H).
490B
LD A,(DE) 1A
Fetch the byte at Register Pair DE into Register A: the next byte of the file.
490C
INC (IX+05H) DD 34 05
INCrement byte +05H of the file control block at Index Register IX, the position in the buffer. The Z FLAG is set when it wraps to 00H: the buffer is used up.
490F
If the Z FLAG is set (the last byte of the buffer was taken), GOSUB to 4914H to set bit 5: the next byte comes from the next sector.
4912
CP A BF
Compare Register A with itself: the Z FLAG is set (no error) and Register A keeps the byte.
4913
RET C9
RETurn with the byte in Register A and the Z FLAG set.
4914
SET 5,(IX+01H) DD CB 01 EE
Set bit 5 of byte +01H of the file control block at Index Register IX: the buffer must be read (the sector of the next record number) before the next byte is used.
4918
RET C9
RETurn to the caller with the flags as they were.
4919H - Put a Byte into a File
Puts the byte in Register A at the current position of the file at Index Register IX: reads the sector first if needed, stores the byte, marks the buffer changed (bit 4 of +01H), and moves the end of file (+08H, +0CH-+0DH) when the byte is at or past it, unless the file was positioned inside (bit 6 of +01H). When the buffer fills it is written out (49A1H).
4919
PUSH AF F5
Save Register Pair AF (Register A = the byte to put) to the stack.
491A
BIT 5,(IX+01H) DD CB 01 6E
Test bit 5 of byte +01H of the file control block at Index Register IX: set when the buffer must be read first.
491E
If the NZ FLAG is set (the buffer must be read), GOSUB to 4953H to read the sector of the next record number (without the end of file test). It returns with the Z FLAG set on success.
4921
If the Z FLAG is set (the buffer is ready), JUMP to 4926H to store the byte.
4923
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer is not changed): the saved Register Pair AF goes into Register Pair HL and the caller's Register Pair HL onto the stack.
4924
POP HL E1
Restore the caller's Register Pair HL from the stack. The byte is dropped; Register A keeps the error number.
4925
RET C9
RETurn with the error number in Register A and the NZ FLAG set.
4926
GOSUB to 4985H: Register Pair DE = the address in the buffer for the byte (the buffer +03H-+04H plus the position +05H).
4929
POP AF F1
Restore Register Pair AF (Register A = the byte) from the stack.
492A
LD (DE),A 12
Store Register A (the byte) into the buffer at Register Pair DE.
492B
SET 4,(IX+01H) DD CB 01 E6
Set bit 4 of byte +01H of the file control block at Index Register IX: the buffer has been changed and must be written.
492F
INC (IX+05H) DD 34 05
INCrement byte +05H of the file control block at Index Register IX, the position in the buffer. The Z FLAG is set when it wraps to 00H: the buffer is full.
4932
PUSH AF F5
Save Register Pair AF (the Z FLAG = the buffer is full) to the stack.
4933
If the Z FLAG is set (the buffer is full), GOSUB to 4914H to set bit 5 for the next byte.
4936
GOSUB to 4A1DH to compare the new position with the end of file: the NZ FLAG is set at or past the end, and Register Pair HL comes back as the next record number and Register C as the position in the buffer.
4939
If the NZ FLAG is set (the byte was written at or past the end), JUMP to 4941H to move the end of file to this position.
493B
BIT 6,(IX+01H) DD CB 01 76
Test bit 6 of byte +01H of the file control block at Index Register IX: set when the file has been positioned.
493F
If the NZ FLAG is set (positioned inside the file), JUMP to 494AH, keeping the end of file.
4941
LD (IX+08H),C DD 71 08
Store Register C (the position in the buffer) into byte +08H of the file control block at Index Register IX, the end of file byte.
4944
LD (IX+0CH),L DD 75 0C
Store Register L (the next record number's low byte) into byte +0CH of the file control block at Index Register IX.
4947
LD (IX+0DH),H DD 74 0D
Store Register H (the next record number's high byte) into byte +0DH of the file control block at Index Register IX: the ending record number.
494A
POP AF F1
Restore Register Pair AF (the Z FLAG = the buffer is full) from the stack.
494B
If the Z FLAG is set (the buffer is full), JUMP to 49A1H to write it to its sector.
494D
XOR A AF
Set Register A to 00H (XOR A) with the Z FLAG set: the byte is stored.
494E
RET C9
RETurn to the caller with the byte stored in the buffer.
494FH - Read the Sector of the Next Record Number
494FH tests the end of file first; 4953H does not. The file's access (bits 2-0 of +01H) must allow reading (below 6, else error 25H). The next record number is turned into a cylinder and sector (4A41H, which allocates space when needed), the sector is read into the buffer through RDSECT (4777H), bit 5 is cleared and the next record number goes up by one. A sector with the deleted data mark (error 06H) is accepted.
494F
GOSUB to 4A1DH to test the end of file: the NZ FLAG is set (Register A = 1CH or 1DH) at or past it.
4952
RET NZ C0
If the NZ FLAG is set (at or past the end), RETurn with the error number in Register A.
4953
LD A,(IX+01H) DD 7E 01
Fetch byte +01H of the file control block at Index Register IX into Register A.
4956
AND 07H E6 07
Mask Register A to bits 2-0: the access the file was opened with (0 the most, 7 none).
4958
CP 06H FE 06
Compare Register A (the access) against 06H, the first value that forbids reading.
495A
If the CARRY FLAG is set (the access is below 6: reading is allowed), JUMP to 495EH.
495C
JUMP to 49B4H to return error 25H, illegal access to a protected file.
495E
GOSUB to 4A41H to work out the cylinder (Register D) and sector (Register E) of the next record number on drive Register C, asking SYS8/SYS for space when the file has none there.
4961
RET NZ C0
If the NZ FLAG is set (no such sector), RETurn with the error number in Register A.
4962
RES 5,(IX+01H) DD CB 01 AE
Clear bit 5 of byte +01H of the file control block at Index Register IX: the buffer is being filled.
4966
LD L,(IX+03H) DD 6E 03
Fetch byte +03H of the file control block at Index Register IX into Register L: the buffer address's low byte.
4969
LD H,(IX+04H) DD 66 04
Fetch byte +04H of the file control block at Index Register IX into Register H. Register Pair HL = the file's buffer.
496C
GOSUB to 4777H (RDSECT) to read cylinder Register D, sector Register E of drive Register C into the buffer at Register Pair HL.
496F
If the Z FLAG is set (the sector was read), JUMP to 4974H to count it.
4971
CP 06H FE 06
Compare Register A (the error number) against 06H: a sector with the deleted data mark (a directory or system sector) was read.
4973
RET NZ C0
If the NZ FLAG is set (another error), RETurn with the error number in Register A.
4974
INC (IX+0AH) DD 34 0A
INCrement byte +0AH of the file control block at Index Register IX, the next record number's low byte. 49D5H calls this entry after a write.
4977
If the NZ FLAG is set (no carry out of the low byte), JUMP to 497CH.
4979
INC (IX+0BH) DD 34 0B
INCrement byte +0BH of the file control block at Index Register IX, the next record number's high byte.
497C
XOR A AF
Set Register A to 00H (XOR A) with the Z FLAG set: success.
497D
RET C9
RETurn to the caller with Register A = 00H and the Z FLAG set.
497E
LD L,(IX+0AH) DD 6E 0A
Fetch byte +0AH of the file control block at Index Register IX into Register L: the next record number's low byte.
4981
LD H,(IX+0BH) DD 66 0B
Fetch byte +0BH of the file control block at Index Register IX into Register H. Register Pair HL = the next record number.
4984
RET C9
RETurn with the next record number in Register Pair HL.
4985
LD A,(IX+05H) DD 7E 05
Fetch byte +05H of the file control block at Index Register IX into Register A: the position in the buffer.
4988
ADD A,(IX+03H) DD 86 03
ADD byte +03H of the file control block at Index Register IX (the buffer address's low byte) to Register A.
498B
LD E,A 5F
Copy Register A (the low byte of the byte's address) into Register E.
498C
LD A,(IX+04H) DD 7E 04
Fetch byte +04H of the file control block at Index Register IX into Register A: the buffer address's high byte.
498F
ADC A,00H CE 00
ADD the CARRY FLAG from the addition above to Register A (ADC A,00H).
4991
LD D,A 57
Copy Register A into Register D. Register Pair DE = the buffer + the position: the address of the current byte.
4992
RET C9
RETurn with the byte's address in Register Pair DE.
4993H - Write the Buffer When It Was Changed
4993H writes the buffer to the sector before the next record number only when the file is in byte mode (bit 7 of +01H) and the buffer was changed (bit 4); 499EH (@RWRIT) always writes it, 49A1H writes it after the prologue and 49ABH writes it as the next sector. The access (bits 2-0 of +01H) must allow writing (below 5, else error 25H). After the write (and a verify when 49CFH is 01H) the next record number goes up by one; when the write was at or past the end of file and the file was not positioned inside, the ending record number moves up, and bit 3 of +01H makes the directory record follow at once (488CH).
4993
LD A,(IX+01H) DD 7E 01
Fetch byte +01H of the file control block at Index Register IX into Register A.
4996
AND 90H E6 90
Mask Register A to bits 7 and 4: byte mode and buffer changed.
4998
CP 90H FE 90
Compare Register A against 90H: the Z FLAG is set when both bits are on.
499A
If the Z FLAG is set (a changed buffer of a file in byte mode), JUMP to 49A1H to write it.
499C
JUMP to 497CH to return Register A = 00H and the Z FLAG: nothing to write.
499E
@RWRIT: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
49A1
GOSUB to 497EH: Register Pair HL = the next record number.
49A4
DEC HL 2B
DECrement Register Pair HL: the sector the buffer holds.
49A5
LD (IX+0AH),L DD 75 0A
Store Register L into byte +0AH of the file control block at Index Register IX.
49A8
LD (IX+0BH),H DD 74 0B
Store Register H into byte +0BH of the file control block at Index Register IX: the next record number is now the buffer's sector, which is written below.
49AB
LD A,(IX+01H) DD 7E 01
Fetch byte +01H of the file control block at Index Register IX into Register A. @WRITE joins here for 256 byte records.
49AE
AND 07H E6 07
Mask Register A to bits 2-0: the access the file was opened with.
49B0
CP 05H FE 05
Compare Register A (the access) against 05H, the first value that forbids writing.
49B2
If the CARRY FLAG is set (the access is below 5: writing is allowed), JUMP to 49B8H.
49B4
LD A,25H 3E 25
Load Register A with 25H, error 37: illegal access attempted to protected file. 495CH comes here for a read that is not allowed.
49B6
OR A B7
Set the flags from Register A (OR A): the NZ FLAG is set.
49B7
RET C9
RETurn with the error number in Register A (25H) and the NZ FLAG set.
49B8
GOSUB to 4A41H to work out the cylinder (Register D) and sector (Register E) of the next record number on drive Register C, allocating space through SYS8/SYS when the file has none there.
49BB
RET NZ C0
If the NZ FLAG is set (no space or a read error of the allocation table), RETurn with the error number in Register A.
49BC
LD L,(IX+03H) DD 6E 03
Fetch byte +03H of the file control block at Index Register IX into Register L: the buffer address's low byte.
49BF
LD H,(IX+04H) DD 66 04
Fetch byte +04H of the file control block at Index Register IX into Register H. Register Pair HL = the file's buffer.
49C2
RES 4,(IX+01H) DD CB 01 A6
Clear bit 4 of byte +01H of the file control block at Index Register IX: the buffer is about to be written, so it is no longer changed.
49C6
SET 2,(IX+00H) DD CB 00 D6
Set bit 2 of byte +00H of the file control block at Index Register IX: the file has been written, so SYS3/SYS stamps its date when it is closed.
49CA
GOSUB to 4763H (WRSECT) to write the buffer at Register Pair HL to cylinder Register D, sector Register E of drive Register C.
49CD
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn with the error number in Register A.
49CE
LD A,00H 3E 00
Load Register A with the verify switch: the operand at 49CFH is 00H in the file; @WRITE stores 00H and @VER 01H there (48CEH).
49D0
OR A B7
Set the flags from Register A (OR A): the NZ FLAG is set when the sector is to be verified.
49D1
If the NZ FLAG is set (verify), GOSUB to 4772H (VERSEC) to read the sector just written back without storing it.
49D4
RET NZ C0
If the NZ FLAG is set (the verify failed), RETurn with the error number in Register A.
49D5
GOSUB to 4974H to count the sector: the next record number goes up by one.
49D8
GOSUB to 4A1DH to compare the position with the end of file: Register A = 00H before it, 1CH at it, 1DH past it; Register Pair HL = the next record number.
49DB
DEC A 3D
DECrement Register A: FFH before the end of file, 1BH or 1CH at or past it.
49DC
AND (IX+01H) DD A6 01
AND byte +01H of the file control block at Index Register IX into Register A: before the end, Register A keeps the flags of +01H.
49DF
AND 40H E6 40
Mask Register A to bit 6: the Z FLAG is clear only when the write was before the end of file of a positioned file.
49E1
If the NZ FLAG is set (a positioned file written inside its end), JUMP to 497CH to return success without moving the end.
49E3
LD (IX+0CH),L DD 75 0C
Store Register L (the next record number's low byte) into byte +0CH of the file control block at Index Register IX.
49E6
LD (IX+0DH),H DD 74 0D
Store Register H (its high byte) into byte +0DH of the file control block at Index Register IX: the ending record number is now the next record number.
49E9
BIT 3,(IX+01H) DD CB 01 5E
Test bit 3 of byte +01H of the file control block at Index Register IX: set when the directory must follow every change of the end.
49ED
If the NZ FLAG is set (bit 3 on), GOSUB to 488CH to write the end of file into the directory record now.
49F0
RET C9
RETurn with the result of the write (or of the directory update) in Register A.
49F1H - The File Prologue
Every file routine calls 49F3H first (49F1H skips the open test). Register Pair DE = the file control block. 49F3H loads byte +00H and rotates bit 7 (open) into the CARRY FLAG; 49F1H sets the CARRY FLAG instead (the JP NC that follows it is never taken: its bytes 1AH 07H are the LD A,(DE) / RLCA of 49F3H). The routine notes the caller's address in JRET$ (4BCAH) and the control block in JDCB$ (4220H), returns error 26H (file not open) when bit 7 is clear, and otherwise points Index Register IX at the block, saves Register Pairs BC, DE and HL and Index Register IX under the caller's return address with 4A14H on top, and returns with Register A = 00H. The caller's final RET then goes to 4A14H, which restores them.
49F1
SCF 37
Set the CARRY FLAG: the entry that does not test whether the file is open.
49F2
JP NC,071AH D2 1A 07
Jump to 071AH if the NO CARRY FLAG is set. Never taken from 49F1H, where the CARRY FLAG was just set. Entered at 49F3H, the bytes 1AH 07H are LD A,(DE) (byte +00H of the control block at Register Pair DE into Register A) and RLCA (bit 7, open, into the CARRY FLAG): the normal entry.
49F5
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer is not changed): Register Pair HL = the address the prologue returns to (just after the caller's CALL 49F3H), and the caller's Register Pair HL is kept on the stack.
49F6
LD (4BCAH),HL 22 CA 4B
Store Register Pair HL (the address after the CALL 49F3H in the file routine) at 4BCAH-4BCBH, JRET$, which SYS4/SYS reports for an error.
49F9
LD (4220H),DE ED 53 20 42
Store Register Pair DE (the file control block) at 4220H-4221H, JDCB$, so SYS4/SYS can name the file in an error message.
49FD
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack again (the Stack Pointer is not changed): the caller's Register Pair HL comes back and the return address is on top.
49FE
If the NO CARRY FLAG is set (bit 7 of byte +00H clear: the file is not open), JUMP to 4A0FH to return error 26H.
4A00
POP AF F1
Take the return address off the stack into Register Pair AF: it is put back at 4A0CH above the saved registers.
4A01
PUSH DE D5
Save Register Pair DE (the file control block) to the stack.
4A02
EX (SP),IX DD E3
Exchange Index Register IX with the top of the stack (the Stack Pointer is not changed): Index Register IX = the file control block, and the caller's Index Register IX is kept on the stack.
4A04
PUSH HL E5
Save the caller's Register Pair HL to the stack.
4A05
PUSH DE D5
Save the caller's Register Pair DE to the stack.
4A06
PUSH BC C5
Save the caller's Register Pair BC to the stack.
4A07
PUSH HL E5
Save Register Pair HL to the stack as a place for 4A14H.
4A08
LD HL,4A14H 21 14 4A
Load Register Pair HL with 4A14H, the routine that restores the saved registers.
4A0B
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer is not changed): 4A14H goes on the stack above the saved registers and the caller's Register Pair HL comes back.
4A0C
PUSH AF F5
Save Register Pair AF (the return address taken off at 4A00H) to the stack again, on top.
4A0D
XOR A AF
Set Register A to 00H (XOR A) with the Z FLAG set.
4A0E
RET C9
RETurn into the file routine (after its CALL 49F3H) with Index Register IX = the file control block and Register A = 00H. Its own RET goes to 4A14H.
4A0F
POP AF F1
Discard the return address into Register Pair AF: the file routine is not continued.
4A10
LD A,26H 3E 26
Load Register A with 26H, error 38: file not open.
4A12
OR A B7
Set the flags from Register A (OR A): the NZ FLAG is set.
4A13
RET C9
RETurn with the error number in Register A straight to the program that called the file routine.
4A14
POP BC C1
Restore the caller's Register Pair BC from the stack (@LOC and @LOF have put their result here, 4873H-4875H).
4A15
POP DE D1
Restore the caller's Register Pair DE from the stack.
4A16
POP HL E1
Restore the caller's Register Pair HL from the stack.
4A17
POP IX DD E1
Restore the caller's Index Register IX from the stack.
4A19
RET C9
RETurn to the program that called the file routine, with Register A and the flags from the routine.
4A1AH - @CKEOF: Test the End of File
4A1AH (@CKEOF) runs the prologue first; 4A1DH is called by the file routines. It compares the current position (the sector worked out from the next record number by 4D9BH, and the byte position +05H) with the ending record number (+0CH-+0DH) and the end of file byte (+08H). Returns Register A = 00H with the Z FLAG before the end, 1CH (error 28, end of file encountered) at the end, 1DH (error 29, record number out of range) past it, with the NZ FLAG. Register Pair HL comes back as the next record number and Register C as the position in the buffer.
4A1A
@CKEOF: GOSUB to 49F3H, the file prologue (Index Register IX = the file control block, Register A = 00H).
4A1D
GOSUB to 497EH: Register Pair HL = the next record number (+0AH-+0BH).
4A20
GOSUB to 4D9BH: it saves Register Pair HL (the next record number) on the stack under the return address, loads Register C with the position in the buffer and adjusts Register Pair HL to the sector of the current position.
4A23
LD A,H 7C
Copy Register H (the current sector's high byte) into Register A.
4A24
CP (IX+0DH) DD BE 0D
Compare Register A against byte +0DH of the file control block at Index Register IX, the ending record number's high byte.
4A27
If the NZ FLAG is set (the high bytes differ; the CARRY FLAG says the position is before the end), JUMP to 4A37H.
4A29
LD A,L 7D
Copy Register L (the current sector's low byte) into Register A.
4A2A
CP (IX+0CH) DD BE 0C
Compare Register A against byte +0CH of the file control block at Index Register IX, the ending record number's low byte.
4A2D
If the NZ FLAG is set (the sectors differ; the CARRY FLAG says before the end), JUMP to 4A37H.
4A2F
DEC C 0D
DECrement Register C (the position in the buffer): a position of 00H becomes FFH, the last byte of a full sector.
4A30
LD A,(IX+08H) DD 7E 08
Fetch byte +08H of the file control block at Index Register IX into Register A: the end of file byte.
4A33
DEC A 3D
DECrement Register A in the same way (00H becomes FFH).
4A34
SUB C 91
SUBtract Register C from Register A: the Z FLAG is set when the position is the end of file byte, the CARRY FLAG when the position is past it.
4A35
CCF 3F
Flip the CARRY FLAG (CCF): it is now set when the position is before the end of file byte.
4A36
INC BC 03
INCrement Register Pair BC: Register C holds the position again (INC BC does not change the flags).
4A37
POP HL E1
Restore Register Pair HL from the stack: the next record number saved by 4D9BH.
4A38
LD A,1DH 3E 1D
Load Register A with 1DH, error 29: record number out of range. LD does not change the flags.
4A3A
If the NZ FLAG is set (the position is not the end itself), JUMP to 4A3EH.
4A3C
DEC A 3D
DECrement Register A: 1CH, error 28: end of file encountered (the NZ FLAG is set).
4A3D
RET C9
RETurn with Register A = 1CH: the position is the end of the file.
4A3E
RET NC D0
If the NO CARRY FLAG is set (the position is past the end), RETurn with Register A = 1DH and the NZ FLAG.
4A3F
XOR A AF
Set Register A to 00H (XOR A) with the Z FLAG set: the position is before the end.
4A40
RET C9
RETurn with Register A = 00H and the Z FLAG set: before the end of file.
4A41H - Find the Sector of the Next Record Number
Turns the next record number (+0AH-+0BH) of the file at Index Register IX into a cylinder (Register D) and sector (Register E) on drive Register C. The record number divided by the sectors in a granule gives the file's granule and the sector in it (kept in the operand at 4B0CH). The file's extents are searched in the control block (+0EH-+1FH: the first extent at +0EH-+0FH starting at granule 0, then four entries of a starting granule word, a cylinder and a granule byte); an entry not in use has FFH as its cylinder. When the granule is in none of them, SYS8/SYS (request 9AH, @ALLOC) finds or allocates it and updates the entries. A hit in the third to fifth entry is moved to the second entry. The granule then becomes a cylinder (granules a cylinder from byte +08H and +04H bit 5 of the drive code table) and a sector. Returns with Register A = 00H and the Z FLAG set, or with the error number from SYS8/SYS.
4A41
GOSUB to 497EH: Register Pair HL = the next record number (+0AH-+0BH) of the file at Index Register IX.
4A44
GOSUB to 4797H: Register C = the file's drive (+06H) and Register A = byte +08H of its drive code table (bits 4-0 the sectors in a granule less one).
4A47
AND 1FH E6 1F
Mask Register A to bits 4-0: the sectors in a granule less one.
4A49
INC A 3C
INCrement Register A: the sectors in a granule.
4A4A
GOSUB to 4BA8H to divide Register Pair HL (the record number) by Register A (the sectors in a granule): Register Pair HL = the granule of the file, Register A = the sector within it.
4A4D
LD (4B0CH),A 32 0C 4B
Store Register A (the sector within the granule) at 4B0CH, the operand of the ADD A at 4B0BH.
4A50
PUSH IX DD E5
Save Index Register IX (the file control block) to the stack.
4A52
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer is not changed): Register Pair HL = the file control block, and the granule number goes onto the stack.
4A53
LD BC,000EH 01 0E 00
Load Register Pair BC with 000EH, the offset of the extents in the control block.
4A56
ADD HL,BC 09
ADD Register Pair BC to Register Pair HL: Register Pair HL points at +0EH, the first extent.
4A57
POP BC C1
Restore the granule number from the stack into Register Pair BC: the granule of the file wanted.
4A58
LD A,05H 3E 05
Load Register A with 05H, the five extent slots.
4A5A
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H: the first extent starts at granule 0 of the file.
4A5D
PUSH AF F5
Save Register Pair AF (Register A = the slots left) to the stack. 4A77H loops back here.
4A5E
LD A,(HL) 7E
Fetch the slot's cylinder byte at Register Pair HL into Register A.
4A5F
INC HL 23
INCrement Register Pair HL to the slot's granule byte.
4A60
INC A 3C
INCrement Register A: the Z FLAG is set when the cylinder byte was FFH, a slot not in use.
4A61
If the Z FLAG is set (the slot is not in use), JUMP to 4A6EH to go on to the next slot.
4A63
PUSH HL E5
Save Register Pair HL (the slot's granule byte) to the stack.
4A64
LD H,D 62
Copy Register D (the high byte of the slot's starting granule) into Register H.
4A65
LD L,E 6B
Copy Register E (its low byte) into Register L. Register Pair HL = the granule of the file where this extent starts.
4A66
XOR A AF
Set Register A to 00H (XOR A), which clears the CARRY FLAG for the SBC.
4A67
SBC HL,BC ED 42
SUBtract Register Pair BC (the granule wanted) from Register Pair HL (the extent's start): the CARRY FLAG is set when the wanted granule is at or beyond the start plus one, the Z FLAG when it is the extent's first granule.
4A69
If the CARRY FLAG is set (the wanted granule is past the extent's first), JUMP to 4A79H to see whether it is inside the extent.
4A6B
POP HL E1
Restore Register Pair HL (the slot's granule byte) from the stack.
4A6C
If the Z FLAG is set (the wanted granule is the extent's first: Register A = 00H, its offset), JUMP to 4AB6H.
4A6E
INC HL 23
INCrement Register Pair HL to the next slot's starting granule word. 4A86H and 4A7CH come back here.
4A6F
POP AF F1
Restore Register Pair AF (Register A = the slots left) from the stack.
4A70
DEC A 3D
DECrement Register A, the slots left to search.
4A71
If the Z FLAG is set (all five slots searched), JUMP to 4A8CH to ask SYS8/SYS.
4A73
LD E,(HL) 5E
Fetch the low byte of the next slot's starting granule at Register Pair HL into Register E.
4A74
INC HL 23
INCrement Register Pair HL to the high byte of the starting granule.
4A75
LD D,(HL) 56
Fetch the high byte at Register Pair HL into Register D. Register Pair DE = the granule of the file where the next slot's extent starts.
4A76
INC HL 23
INCrement Register Pair HL to the next slot's cylinder byte.
4A77
LOOP BACK to 4A5DH to look at the next slot at Register Pair HL.
4A79
INC H 24
INCrement Register H: the Z FLAG is set when the difference (the start less the wanted granule) is FF00H-FFFFH, a distance of 1-256.
4A7A
LD A,L 7D
Copy Register L (the low byte of the difference) into Register A.
4A7B
POP HL E1
Restore Register Pair HL (the slot's granule byte) from the stack.
4A7C
If the NZ FLAG is set (the wanted granule is more than 256 past the start), JUMP to 4A6EH for the next slot.
4A7E
PUSH DE D5
Save Register Pair DE (the extent's start) to the stack.
4A7F
LD E,A 5F
Copy Register A (the negative distance) into Register E.
4A80
LD A,(HL) 7E
Fetch the slot's granule byte at Register Pair HL into Register A.
4A81
AND 1FH E6 1F
Mask Register A to bits 4-0: the granules of the extent less one.
4A83
ADD A,E 83
ADD Register E (minus the distance from the start) to Register A: the CARRY FLAG is set when the distance is within the granules of the extent.
4A84
LD A,E 7B
Copy Register E (minus the distance) into Register A. LD does not change the flags.
4A85
POP DE D1
Restore Register Pair DE (the extent's start) from the stack.
4A86
If the NO CARRY FLAG is set (the granule is past this extent), JUMP to 4A6EH for the next slot.
4A88
NEG ED 44
Negate Register A: Register A = the distance, the granule's offset in the extent.
4A8A
JUMP to 4AB6H with the granule's offset in the extent in Register A.
4A8C
LD A,(4B0CH) 3A 0C 4B
Fetch the sector within the granule from 4B0CH into Register A: the SYS8/SYS call below can load a file and change it.
4A8F
LD (4AABH),A 32 AB 4A
Store Register A (the sector within the granule) at 4AABH, the operand of the LD A at 4AAAH, to be put back afterwards.
4A92
LD A,(4414H) 3A 14 44
Fetch OVRLY$ from 4414H into Register A: the request code of the system file now at 4E00H.
4A95
LD (4A9DH),A 32 9D 4A
Store Register A (that request code) at 4A9DH, the operand of the LD A at 4A9CH, to reload the file afterwards.
4A98
GOSUB to 4AB3H, which issues request 9AH: SYS8/SYS (@ALLOC) finds the granule Register Pair BC of the file at Index Register IX, allocating space when needed. It returns Register A = the granule's offset in its extent, Register Pair HL = the extent (Register H the granule byte, Register L the cylinder), and the CARRY FLAG set when it has made room in the first slot (Register Pairs BC and DE to be stored there).
4A9B
PUSH AF F5
Save Register Pair AF (SYS8/SYS's result and flags) to the stack.
4A9C
LD A,00H 3E 00
Load Register A with the request code saved at 4A9DH (00H in the file): the system file that was at 4E00H before SYS8/SYS was loaded over it.
4A9E
AND 8FH E6 8F
Mask Register A (the request code) to bits 7 and 3-0, dropping the function bits 6-4.
4AA0
CP 83H FE 83
Compare Register A against 83H: the Z FLAG is set when the file was SYS1/SYS (request codes 83H-0F3H of file 3).
4AA2
If the Z FLAG is set (SYS1/SYS had been loaded), GOSUB to 4AB5H to issue the RST 28H with the request code in Register A and load SYS1/SYS again, since the command interpreter must still be there when the program returns.
4AA5
POP AF F1
Restore Register Pair AF (SYS8/SYS's result and flags) from the stack.
4AA6
RET NZ C0
If the NZ FLAG is set (SYS8/SYS failed: no space, or the allocation table could not be read), RETurn with the error number in Register A.
4AA7
LD (4AE5H),A 32 E5 4A
Store Register A (the granule's offset in its extent) at 4AE5H, the operand of the ADD A at 4AE4H.
4AAA
LD A,00H 3E 00
Load Register A with the sector within the granule saved at 4AABH (00H in the file).
4AAC
LD (4B0CH),A 32 0C 4B
Store Register A at 4B0CH, the operand of the ADD A at 4B0BH, again.
4AAF
If the NO CARRY FLAG is set (SYS8/SYS updated a slot in place), JUMP to 4ADEH with the extent in Register Pair HL.
4AB1
JUMP to 4AD5H to store Register Pairs BC and DE in the first slot at Register Pair HL.
4AB3
LD A,9AH 3E 9A
Load Register A with 9AH, the request code of SYS8/SYS's function 10H, @ALLOC.
4AB5
RST 28H EF
RST 28H: call the supervisor dispatcher with the request code in Register A (9AH, or the request code of SYS1/SYS from 4AA2H).
4AB6
LD (4AE5H),A 32 E5 4A
Store Register A (the granule's offset in its extent) at 4AE5H, the operand of the ADD A at 4AE4H.
4AB9
LD B,(HL) 46
Fetch the slot's granule byte at Register Pair HL into Register B.
4ABA
DEC HL 2B
DECrement Register Pair HL to the slot's cylinder byte.
4ABB
LD C,(HL) 4E
Fetch the cylinder byte at Register Pair HL into Register C. Register Pair BC = the extent (Register B the granule byte, Register C the cylinder).
4ABC
INC HL 23
INCrement Register Pair HL back to the granule byte.
4ABD
POP AF F1
Restore Register Pair AF (Register A = the slots left when the hit was found: 5 for the first slot, 1 for the fifth) from the stack.
4ABE
CPL 2F
Complement Register A (CPL), the slots left: Register A = minus the slots left, less one.
4ABF
ADD A,04H C6 04
ADD 04H to Register A: Register A = 3 less the slots left. The NO CARRY FLAG is set for the first and second slots.
4AC1
If the NO CARRY FLAG is set (the hit is in the first or second slot), JUMP to 4ADCH, leaving the slots as they are.
4AC3
INC A 3C
INCrement Register A: 1, 2 or 3 for the third, fourth or fifth slot.
4AC4
RLCA 07
Rotate Register A left one bit: the count x 2.
4AC5
RLCA 07
Rotate Register A left one bit again: the count x 4, the bytes of the slots to move down.
4AC6
PUSH BC C5
Save Register Pair BC (the extent) to the stack.
4AC7
PUSH DE D5
Save Register Pair DE (the extent's starting granule) to the stack.
4AC8
LD C,A 4F
Copy Register A (the bytes to move) into Register C.
4AC9
LD B,00H 06 00
Load Register B with 00H. Register Pair BC = the byte count of the LDDR below.
4ACB
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the hit slot's granule byte, the last byte to receive.
4ACC
LD HL,FFFCH 21 FC FF
Load Register Pair HL with FFFCH (minus 4), the size of one slot.
4ACF
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL = the same byte of the slot before, the last byte to copy.
4AD0
LDDR ED B8
Copy Register Pair BC bytes downward from Register Pair HL to Register Pair DE (LDDR): the slots from the second up to the one before the hit move one slot on, over the hit slot.
4AD2
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the second slot's granule byte, now free.
4AD3
POP DE D1
Restore Register Pair DE (the extent's starting granule) from the stack.
4AD4
POP BC C1
Restore Register Pair BC (the extent) from the stack.
4AD5
LD (HL),B 70
Store Register B (the granule byte) at Register Pair HL. 4AB1H joins here with SYS8/SYS's extent in Register Pairs BC and DE.
4AD6
DEC HL 2B
DECrement Register Pair HL to the cylinder byte.
4AD7
LD (HL),C 71
Store Register C (the cylinder) at Register Pair HL.
4AD8
DEC HL 2B
DECrement Register Pair HL to the high byte of the starting granule.
4AD9
LD (HL),D 72
Store Register D (the starting granule's high byte) at Register Pair HL.
4ADA
DEC HL 2B
DECrement Register Pair HL to the low byte of the starting granule.
4ADB
LD (HL),E 73
Store Register E (the starting granule's low byte) at Register Pair HL: the hit extent is now the second slot.
4ADC
LD H,B 60
Copy Register B (the granule byte) into Register H.
4ADD
LD L,C 69
Copy Register C (the cylinder) into Register L. Register Pair HL = the extent.
4ADE
LD A,H 7C
Copy Register H (the extent's granule byte) into Register A.
4ADF
RLCA 07
Rotate Register A left one bit: first of three rotations that bring the first granule from bits 7-5 to bits 2-0.
4AE0
RLCA 07
Rotate Register A left one bit again: second of three rotations.
4AE1
RLCA 07
Rotate Register A left one bit again: bits 7-5 are now bits 2-0.
4AE2
AND 07H E6 07
Mask Register A to bits 2-0: the extent's first granule on its cylinder.
4AE4
ADD A,00H C6 00
ADD the granule's offset in the extent to Register A: the operand at 4AE5H (00H in the file) is stored by 4AA7H or 4AB6H. Register A = the granule counted from the extent's cylinder.
4AE6
LD E,A 5F
Copy Register A (the granule from the extent's cylinder) into Register E.
4AE7
GOSUB to 4797H: Register C = the file's drive, Register A = byte +08H of its drive code table.
4AEA
PUSH AF F5
Save Register Pair AF (byte +08H) to the stack.
4AEB
RLCA 07
Rotate Register A left one bit: first of three rotations that bring bits 7-5 (the granules on a track less one) to bits 2-0.
4AEC
RLCA 07
Rotate Register A left one bit again: second of three rotations.
4AED
RLCA 07
Rotate Register A left one bit again: third rotation.
4AEE
AND 07H E6 07
Mask Register A to bits 2-0: the granules on a track less one.
4AF0
INC A 3C
INCrement Register A: the granules on a track.
4AF1
LD D,A 57
Copy Register A (the granules on a track) into Register D.
4AF2
LD A,04H 3E 04
Load Register A with 04H, the offset of byte +04H in the drive code table.
4AF4
GOSUB to 479CH (DCTBYT): Register A = byte +04H of drive Register C's table.
4AF7
BIT 5,A CB 6F
Test bit 5 of Register A: set for a drive with two sides.
4AF9
LD A,D 7A
Copy Register D (the granules on a track) into Register A. LD does not change the flags.
4AFA
If the Z FLAG is set (one side), JUMP to 4AFDH.
4AFC
RLCA 07
Rotate Register A left one bit: the granules on a cylinder of two sides.
4AFD
GOSUB to 4B7AH (DIVEA) to divide Register E (the granule from the extent's cylinder) by Register A (the granules on a cylinder): Register A = the cylinders to add, Register E = the granule on its cylinder.
4B00
ADD A,L 85
ADD Register L (the extent's cylinder) to Register A: the cylinder of the granule.
4B01
LD D,A 57
Copy Register A (the cylinder) into Register D.
4B02
POP AF F1
Restore Register Pair AF (byte +08H of the drive code table) from the stack.
4B03
AND 1FH E6 1F
Mask Register A to bits 4-0: the sectors in a granule less one.
4B05
INC A 3C
INCrement Register A: the sectors in a granule.
4B06
PUSH DE D5
Save Register Pair DE (Register D = the cylinder) to the stack: MULTEA uses Register D.
4B07
GOSUB to 4B6BH (MULTEA) to multiply Register A (the sectors in a granule) by Register E (the granule on its cylinder): Register A = the granule's first sector.
4B0A
POP DE D1
Restore Register Pair DE (Register D = the cylinder) from the stack.
4B0B
ADD A,00H C6 00
ADD the sector within the granule to Register A: the operand at 4B0CH (00H in the file) is stored by 4A4DH and 4AACH.
4B0D
LD E,A 5F
Copy Register A (the sector) into Register E. Register D = the cylinder, Register E = the sector, Register C = the drive.
4B0E
XOR A AF
Set Register A to 00H (XOR A) with the Z FLAG set: success.
4B0F
RET C9
RETurn with the cylinder and sector in Register Pair DE.
4B10H - DIRRD and DIRWR: Read and Write a Directory Sector
4B10H (DIRRD) reads the directory sector that holds record Register B of drive Register C into 4300H and returns Register Pair HL pointing at the record (error 11H, directory read error, on failure). 4B1FH (DIRWR) writes the sector at 4300H back with the deleted data mark and verifies it (error 12H, directory write error, or 0FH, write protected). Directory record B is the 32 byte slot (B AND E0H) of sector (B AND 1FH) + 2 of the directory cylinder. Register Pair DE is kept.
4B10
PUSH DE D5
DIRRD: Save the caller's Register Pair DE to the stack.
4B11
GOSUB to 4B37H: Register Pair HL = the record's address in the buffer (4300H + (B AND E0H)), Register D = the directory cylinder, Register E = the record's sector.
4B14
PUSH HL E5
Save Register Pair HL (the record's address) to the stack.
4B15
LD L,00H 2E 00
Load Register L with 00H: Register Pair HL = 4300H, the start of the buffer.
4B17
GOSUB to 4B45H (RDSSEC) to read cylinder Register D, sector Register E of drive Register C into the buffer at Register Pair HL. The Z FLAG is set on success.
4B1A
POP HL E1
Restore Register Pair HL (the record's address) from the stack.
4B1B
LD A,11H 3E 11
Load Register A with 11H, error 17: directory read error, in case the read failed. LD does not change the flags.
4B1D
POP DE D1
Restore the caller's Register Pair DE from the stack.
4B1E
RET C9
RETurn: the Z FLAG set and Register Pair HL at the record, or the NZ FLAG with Register A = 11H.
4B1F
PUSH DE D5
DIRWR: Save the caller's Register Pair DE to the stack.
4B20
GOSUB to 4B37H: Register D = the directory cylinder and Register E = the sector of record Register B (Register Pair HL is not needed).
4B23
LD L,00H 2E 00
Load Register L with 00H: Register Pair HL = 4300H, the buffer to write.
4B25
GOSUB to 4768H (WRPROT) to write the buffer to cylinder Register D, sector Register E of drive Register C with the deleted data mark that marks every directory sector.
4B28
If the Z FLAG is set (the write succeeded), GOSUB to 4772H (VERSEC) to read the sector back. A directory sector reads back with error 06H (the deleted data mark), which is the good result.
4B2B
SUB 06H D6 06
SUBtract 06H from Register A (the error number): Register A = 00H with the Z FLAG set when the verify gave 06H.
4B2D
POP DE D1
Restore the caller's Register Pair DE from the stack.
4B2E
RET Z C8
If the Z FLAG is set (written and verified), RETurn with Register A = 00H.
4B2F
CP 09H FE 09
Compare Register A (the error number less 6) against 09H: the Z FLAG is set when the error was 0FH, write protected.
4B31
LD A,12H 3E 12
Load Register A with 12H, error 18: directory write error. LD does not change the flags.
4B33
RET NZ C0
If the NZ FLAG is set (another error), RETurn with Register A = 12H.
4B34
SUB 03H D6 03
SUBtract 03H from Register A: Register A = 0FH, error 15, write protected disk (the NZ FLAG stays set).
4B36
RET C9
RETurn with Register A = 0FH (write protected) and the NZ FLAG.
4B37
GOSUB to 4B64H: Register D = the directory cylinder of drive Register C (byte +09H of its drive code table).
4B3A
LD A,B 78
Copy Register B (the directory record number) into Register A.
4B3B
AND E0H E6 E0
Mask Register A to bits 7-5: the record's slot in its sector times 32, its offset in the buffer.
4B3D
LD L,A 6F
Copy Register A (the offset) into Register L.
4B3E
LD H,43H 26 43
Load Register H with 43H, the high byte of SBUFF$. Register Pair HL = 4300H + the offset: where the record will be in the buffer.
4B40
XOR B A8
Exclusive OR Register B (the record number) into Register A (its bits 7-5): Register A = bits 4-0 of the record number, its sector less 2.
4B41
ADD A,02H C6 02
ADD 02H to Register A: the directory's records start at sector 2 (sector 0 is the allocation table and sector 1 the hash index table).
4B43
LD E,A 5F
Copy Register A (the record's sector) into Register E.
4B44
RET C9
RETurn with Register D = the cylinder, Register E = the sector and Register Pair HL = the record's address.
4B45H - RDSSEC: Read a Directory Sector
Reads cylinder Register D, sector Register E of drive Register C into the buffer at Register Pair HL and accepts it only when it carries the deleted data mark (read error 06H). When it does not, the diskette in the drive may have its directory on another cylinder: the boot sector (cylinder 0, sector 0) is read, byte 2 (the directory cylinder) is stored in the drive's code table (+09H) and the sector is read again from that cylinder. Returns the Z FLAG set on success; Register A = the read result less 6.
4B45
GOSUB to 4B5EH to read the sector and compare the result with 06H: the Z FLAG is set when it is a directory sector.
4B48
RET Z C8
If the Z FLAG is set (a directory sector was read), RETurn.
4B49
PUSH DE D5
Save Register Pair DE (the cylinder and sector wanted) to the stack.
4B4A
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H: cylinder 0, sector 0, the boot sector.
4B4D
GOSUB to 4777H (RDSECT) to read the boot sector of drive Register C into the buffer at Register Pair HL.
4B50
POP DE D1
Restore Register Pair DE (the cylinder and sector wanted) from the stack.
4B51
RET NZ C0
If the NZ FLAG is set (the boot sector could not be read), RETurn with the error number in Register A.
4B52
PUSH HL E5
Save Register Pair HL (the buffer) to the stack.
4B53
INC HL 23
INCrement Register Pair HL to byte 1 of the boot sector.
4B54
INC HL 23
INCrement Register Pair HL to byte 2, the directory cylinder (the operand of the boot sector's CP at 4301H).
4B55
LD D,(HL) 56
Fetch the directory cylinder from Register Pair HL into Register D: the cylinder to read from now.
4B56
LD H,09H 26 09
Load Register H with 09H, the offset of the directory cylinder byte in the drive code table, for 47A5H.
4B58
GOSUB to 47A5H: Register A = the low byte of the address of byte +09H of drive Register C's table.
4B5B
LD L,A 6F
Copy Register A into Register L. Register H is 47H from 47A5H: Register Pair HL = the drive's directory cylinder byte.
4B5C
LD (HL),D 72
Store Register D (the directory cylinder of this diskette) into the drive code table at Register Pair HL (+09H).
4B5D
POP HL E1
Restore Register Pair HL (the buffer) from the stack.
4B5E
GOSUB to 4777H (RDSECT) to read cylinder Register D, sector Register E of drive Register C into the buffer at Register Pair HL.
4B61
SUB 06H D6 06
SUBtract 06H from Register A (the read's error number): the Z FLAG is set when it was 06H, a sector with the deleted data mark.
4B63
RET C9
RETurn with the Z FLAG set for a directory sector.
4B64
LD A,09H 3E 09
DIRCYL: Load Register A with 09H, the offset of the directory cylinder in a drive code table.
4B66
GOSUB to 479CH (DCTBYT): Register A = byte +09H of drive Register C's table, the directory cylinder.
4B69
LD D,A 57
Copy Register A (the directory cylinder) into Register D.
4B6A
RET C9
RETurn with the directory cylinder in Register D.
4B6BH - MULTEA, DIVEA, @MULT and @DIV
Four arithmetic routines. 4B6BH (MULTEA): Register A = Register A x Register E (8 bits). 4B7AH (DIVEA): Register E / Register A, the quotient in Register A and the remainder in Register E. 4B8EH (@MULT, 444EH): Register Pair HL x Register A, a 24 bit product in Register Pair HL (high 16 bits) and Register A (low 8 bits). 4BA8H (@DIV, 4451H): Register Pair HL / Register A, the quotient in Register Pair HL and the remainder in Register A. Register Pair BC is kept by all four.
4B6B
PUSH BC C5
MULTEA: Save Register Pair BC to the stack: Register B is the bit counter.
4B6C
LD D,A 57
Copy Register A (the first factor) into Register D, the value added for each set bit of Register E.
4B6D
XOR A AF
Set Register A to 00H (XOR A): the product so far.
4B6E
LD B,08H 06 08
Load Register B with 08H, one pass for each bit of Register E.
4B70
ADD A,A 87
Double Register A, the product so far (ADD A,A). 4B76H loops back here.
4B71
SLA E CB 23
Shift Register E (the second factor) left one bit: its bit 7 goes into the CARRY FLAG.
4B73
If the NO CARRY FLAG is set (that bit of Register E was 0), JUMP to 4B76H without adding.
4B75
ADD A,D 82
ADD Register D (the first factor) to Register A (the product so far).
4B76
DECrement Register B and LOOP BACK to 4B70H until all 8 bits of Register E are done.
4B78
POP BC C1
Restore the caller's Register Pair BC from the stack.
4B79
RET C9
RETurn with the product in Register A (Register D = the first factor, Register E = 00H).
4B7A
PUSH BC C5
DIVEA: Save the caller's Register Pair BC to the stack.
4B7B
LD C,A 4F
Copy Register A (the divisor) into Register C.
4B7C
LD B,08H 06 08
Load Register B with 08H, one pass for each bit of the dividend in Register E.
4B7E
XOR A AF
Set Register A to 00H (XOR A): the remainder so far.
4B7F
SLA E CB 23
Shift Register E (the dividend, then the quotient bits) left one bit: its bit 7 goes into the CARRY FLAG. 4B87H loops back here.
4B81
RLA 17
Rotate the CARRY FLAG into Register A (the remainder so far) through bit 0 (RLA).
4B82
CP C B9
Compare Register A (the remainder) against Register C (the divisor).
4B83
If the CARRY FLAG is set (the remainder is below the divisor), JUMP to 4B87H.
4B85
SUB C 91
SUBtract Register C (the divisor) from Register A (the remainder).
4B86
INC E 1C
INCrement Register E: a quotient bit of 1 into bit 0.
4B87
DECrement Register B and LOOP BACK to 4B7FH until all 8 bits are done: Register E = the quotient, Register A = the remainder.
4B89
LD C,A 4F
Copy Register A (the remainder) into Register C.
4B8A
LD A,E 7B
Copy Register E (the quotient) into Register A.
4B8B
LD E,C 59
Copy Register C (the remainder) into Register E.
4B8C
POP BC C1
Restore the caller's Register Pair BC from the stack.
4B8D
RET C9
RETurn with the quotient in Register A and the remainder in Register E.
4B8E
PUSH BC C5
@MULT: Save the caller's Register Pair BC to the stack.
4B8F
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the 16 bit factor (Register Pair HL on entry).
4B90
LD C,A 4F
Copy Register A (the 8 bit factor) into Register C.
4B91
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H: the product's low 16 bits so far.
4B94
LD A,L 7D
Copy Register L (00H) into Register A: the product's high 8 bits so far.
4B95
LD B,08H 06 08
Load Register B with 08H, one pass for each bit of Register C.
4B97
ADD HL,HL 29
Double Register Pair HL (ADD HL,HL): the product so far moves up one bit and bit 15 goes into the CARRY FLAG. 4BA0H loops back here.
4B98
RLA 17
Rotate Register A left through the CARRY FLAG (RLA): the bit out of the top of Register Pair HL comes into bit 0 of Register A. While the product is built, Register A is its high byte and Register Pair HL its low 16 bits.
4B99
RLC C CB 01
Rotate Register C (the 8 bit factor) left: its top bit goes into the CARRY FLAG.
4B9B
If the NO CARRY FLAG is set (that bit of Register C was 0), JUMP to 4BA0H without adding.
4B9D
ADD HL,DE 19
ADD Register Pair DE (the 16 bit factor) to Register Pair HL.
4B9E
ADC A,00H CE 00
ADD the CARRY FLAG out of Register Pair HL to Register A (ADC A,00H), the product's high byte.
4BA0
DECrement Register B and LOOP BACK to 4B97H until all 8 bits of Register C are done.
4BA2
LD C,A 4F
Copy Register A (the product's high byte) into Register C.
4BA3
LD A,L 7D
Copy Register L (the product's low byte) into Register A.
4BA4
LD L,H 6C
Copy Register H (the product's middle byte) into Register L.
4BA5
LD H,C 61
Copy Register C into Register H. Register Pair HL and Register A now hold the 24 bit product: Register Pair HL the high 16 bits and Register A the low 8 bits.
4BA6
POP BC C1
Restore the caller's Register Pair BC from the stack.
4BA7
RET C9
RETurn with the product in Register Pair HL and Register A (Register Pair DE = the 16 bit factor).
4BA8
PUSH DE D5
@DIV: Save the caller's Register Pair DE to the stack.
4BA9
LD D,A 57
Copy Register A (the divisor) into Register D.
4BAA
LD E,10H 1E 10
Load Register E with 10H, one pass for each of the 16 bits of Register Pair HL.
4BAC
XOR A AF
Set Register A to 00H (XOR A): the remainder so far.
4BAD
ADD HL,HL 29
Double Register Pair HL (ADD HL,HL): the next bit of the dividend goes into the CARRY FLAG and a 0 comes into bit 0 for the quotient. 4BB7H loops back here.
4BAE
RLA 17
Rotate the CARRY FLAG into Register A, the remainder (RLA).
4BAF
If the CARRY FLAG is set (the remainder overflowed 8 bits), JUMP to 4BB4H to subtract.
4BB1
CP D BA
Compare Register A (the remainder) against Register D (the divisor).
4BB2
If the CARRY FLAG is set (the remainder is below the divisor), JUMP to 4BB6H.
4BB4
SUB D 92
SUBtract Register D (the divisor) from Register A (the remainder).
4BB5
INC L 2C
INCrement Register L: a quotient bit of 1 at bit 0 of Register Pair HL.
4BB6
DEC E 1D
DECrement Register E, the bits of the dividend left to do.
4BB7
If the NZ FLAG is set (bits remain in Register E), LOOP BACK to 4BADH.
4BB9
POP DE D1
Restore the caller's Register Pair DE from the stack.
4BBA
RET C9
RETurn with the quotient in Register Pair HL and the remainder in Register A.
4BBBH - The Clock Tick Divider
Called by the clock interrupt (4518H) on every tick. Register Pair DE gets the address of the ROM's real time clock routine, which the reset copied into the operand at 4BBCH from the ROM's clock vector at 4047H (4E01H-4E04H). The pattern at 4762H is rotated one place; when the bit that comes out is set the tick runs the tasks, otherwise the interrupt of the clock is cleared here and the tasks and the ROM's routine are passed over for this tick. With FFH at 4762H every tick runs them.
4BBB
LD DE,3529H 11 29 35
Load Register Pair DE with 3529H, the ROM's real time clock routine: the operand at 4BBCH-4BBDH that the reset stores from the ROM's vector at 4047H-4048H, which the clock interrupt pushes as the return address of the tasks.
4BBE
LD HL,4762H 21 62 47
Point Register Pair HL to 4762H, the tick pattern, the spare byte of SEEK.
4BC1
RLC (HL) CB 06
Rotate the pattern at Register Pair HL (4762H) left one place: bit 7 goes into the CARRY FLAG and into bit 0.
4BC3
RET C D8
If the CARRY FLAG is set (this tick runs the tasks), RETurn to the clock interrupt at 451BH with Register Pair DE = the ROM's routine.
4BC4
IN A,(ECH) DB EC
Read port ECH into Register A: reading the port clears the real time clock's interrupt, since the ROM's routine that would do it is not run on this tick.
4BC6
POP AF F1
Drop the return address into the clock interrupt (451BH) from the stack into Register Pair AF: the RET below goes back to the interrupt service routine at 44D2H instead.
4BC7
RET C9
RETurn to 44D2H, the end of the vector call in the interrupt service routine, without running the tasks.
4BC8-4BC9
DEFB 00H x 2 00 x 2
4BC8H-4BC9H: every system file SYS1/SYS-SYS12/SYS starts with a load block for these two bytes, the length of the file's part at 4E00H (see each file's page), so they always hold the length of the system file in the overlay area.
4BCA-4BCB
DEFB 00H x 2 00 x 2
4BCAH-4BCBH, JRET$: the return address of the program's call into the file system, stored by the file prologue (49F6H); SYS4/SYS reads it for the address it reports with an error (its 4FFAH).
4BCCH - The Supervisor Dispatcher (RST 28H)
ROM 0028H jumps to 400CH and so here with the request code in Register A. A code below 80H is handled at 4BEEH. For 80H and above, the return address of the RST is dropped (the overlay returns straight to the program that called the request stub), the BREAK trap switch (4405H) is turned off and saved, the system file the code names is loaded when it is not already at 4E00H (4BF4H), and its entry is called with Register A = the request code from OVRLY$ (4414H). Then the BREAK trap switch is put back.
4BCC
OR A B7
Set the flags from Register A (OR A), the request code: the SIGN FLAG is set for 80H and above.
4BCD
If the SIGN FLAG is clear (POSITIVE: the code is below 80H), JUMP to 4BEEH.
4BD0
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer is not changed): Register Pair HL = the return address of the RST 28H (the byte after the request stub) and the caller's Register Pair HL is on the stack.
4BD1
PUSH AF F5
Save Register Pair AF (the request code) to the stack.
4BD2
LD HL,4405H 21 05 44
Point Register Pair HL to 4405H, the BREAK trap switch. The RST's return address in Register Pair HL is dropped here.
4BD5
LD A,(HL) 7E
Fetch the switch at Register Pair HL (C3H on, C9H off) into Register A.
4BD6
LD (4BE8H),A 32 E8 4B
Store Register A (the switch) at 4BE8H, the operand of the LD A at 4BE7H, to be put back after the overlay.
4BD9
LD (HL),C9H 36 C9
Store C9H at Register Pair HL (4405H): the BREAK trap is off while the overlay runs.
4BDB
POP AF F1
Restore Register Pair AF (the request code) from the stack.
4BDC
POP HL E1
Restore the caller's Register Pair HL from the stack. The top of the stack is now the return address into the program that called the request stub.
4BDD
GOSUB to 4BF4H to make sure the system file of request Register A is loaded (and, for 88H and 89H, the library command Register B); it stores the file's entry at 4BE4H.
4BE0
LD A,(4414H) 3A 14 44
Fetch OVRLY$ from 4414H into Register A: the request code (for the libraries, the code of the file already at 4E00H).
4BE3
GOSUB to the system file's entry: the operand at 4BE4H-4BE5H is 0000H in the file; 4C45H stores the entry address there (SYS7/SYS stores one too, its 568EH).
4BE6
PUSH AF F5
Save Register Pair AF (the overlay's result in Register A and the flags) to the stack.
4BE7
LD A,00H 3E 00
Load Register A with the BREAK trap switch saved at 4BE8H (00H in the file; 4BD6H stores the value of 4405H here).
4BE9
LD (4405H),A 32 05 44
Store Register A at 4405H: the BREAK trap switch is as it was before the request.
4BEC
POP AF F1
Restore Register Pair AF (the overlay's result and flags) from the stack.
4BED
RET C9
RETurn to the program that called the request stub.
4BEE
DEC A 3D
A request code below 80H. DECrement Register A: the Z FLAG is set for code 01H.
4BEF
NOP 00
No operation in the file. SYS0/SYS's reset stores C8H (RET Z) here when the AUTO command starts with 2AH (5006H-5008H), and BASIC/CMD (its 57D7H) and SYS7/SYS (its 529EH) store into it too; then code 01H returns at once with Register A = 00H.
4BF0
If the NZ FLAG is set (the code was not 01H), JUMP to 4C4AH to display SYS Error and abort.
4BF2
INC A 3C
INCrement Register A: Register A = 01H (the NZ FLAG is set).
4BF3
RET C9
RETurn with Register A = 01H for request code 01H.
4BF4H - Load the System File of a Request
Register A = the request code, Register B = the library command (for 88H and 89H). A library request (88H, SYS6/SYS, or 89H, SYS7/SYS) always loads, because each command is its own member of the file. For the others nothing is loaded when the file named by the low four bits is already at 4E00H (OVRLY$, 4414H). Otherwise OVRLY$ gets the new code and the file is read through SFCB$ (42A1H): its directory record (3-7, or 20H-26H for the files from 8 on) is read from drive 0, its first extents copied, and the module loader (4C8CH) loads it, returning its entry address. A file missing from the directory or a load error displays SYS Error and aborts.
4BF4
PUSH HL E5
Save the caller's Register Pair HL to the stack.
4BF5
LD H,A 67
Copy Register A (the request code) into Register H.
4BF6
LD A,B 78
Copy Register B (the library command number) into Register A.
4BF7
LD (4C3AH),A 32 3A 4C
Store Register A (the library command) at 4C3AH, the operand of the LD B at 4C39H that tells the module loader which member to load.
4BFA
LD A,H 7C
Copy Register H (the request code) into Register A.
4BFB
OR 01H F6 01
OR 01H into Register A: 88H and 89H both become 89H.
4BFD
CP 89H FE 89
Compare Register A against 89H: the Z FLAG is set for a library request.
4BFF
LD A,H 7C
Copy Register H (the request code) into Register A. LD does not change the flags.
4C00
If the Z FLAG is set (a library request), JUMP to 4C11H to load the command's member.
4C02
LD A,(4414H) 3A 14 44
Fetch OVRLY$ from 4414H into Register A: the request code of the file now at 4E00H.
4C05
XOR H AC
Exclusive OR Register H (the new request code) into Register A.
4C06
AND 0FH E6 0F
Mask Register A to bits 3-0: the Z FLAG is set when both codes name the same system file.
4C08
LD A,H 7C
Copy Register H (the new request code) into Register A. LD does not change the flags.
4C09
LD (4414H),A 32 14 44
Store Register A (the new request code) at 4414H, OVRLY$.
4C0C
LD HL,4E00H 21 00 4E
Load Register Pair HL with 4E00H, the entry of a file already in place.
4C0F
If the Z FLAG is set (the file is already at 4E00H), JUMP to 4C45H to use the entry in Register Pair HL.
4C11
PUSH DE D5
Save the caller's Register Pair DE to the stack.
4C12
PUSH BC C5
Save the caller's Register Pair BC to the stack (Register B = the library command).
4C13
AND 0FH E6 0F
Mask Register A (the request code) to bits 3-0: the system file's number plus 2.
4C15
BIT 3,A CB 5F
Test bit 3 of Register A: set for the files from SYS6/SYS on (8 and up).
4C17
If the Z FLAG is set (SYS1/SYS-SYS5/SYS), JUMP to 4C1BH: their directory records are 3-7.
4C19
ADD A,18H C6 18
ADD 18H to Register A: the records of SYS6/SYS-SYS12/SYS are 20H-26H (the second slot of the directory's sectors 2-8).
4C1B
LD (42A8H),A 32 A8 42
Store Register A (the directory record number) at 42A8H, byte +07H of SFCB$.
4C1E
LD B,A 47
Copy Register A (the directory record number) into Register B, for DIRRD.
4C1F
LD A,20H 3E 20
Load Register A with 20H: full access and bit 5, the buffer must be read first.
4C21
LD (42A2H),A 32 A2 42
Store Register A (20H) at 42A2H, byte +01H of SFCB$.
4C24
SBC HL,HL ED 62
SUBtract Register Pair HL and the CARRY FLAG from Register Pair HL (SBC HL,HL; the CARRY FLAG is clear after the AND above): Register Pair HL = 0000H.
4C26
LD (42ABH),HL 22 AB 42
Store Register Pair HL (0000H) at 42ABH-42ACH, the next record number of SFCB$: read from the start.
4C29
LD C,H 4C
Copy Register H (00H) into Register C: drive 0.
4C2A
GOSUB to 4B10H (DIRRD) to read the directory sector of record Register B on drive Register C into 4300H; Register Pair HL comes back pointing at the record.
4C2D
If the NZ FLAG is set (the directory could not be read), JUMP to 4C4AH: SYS Error.
4C2F
BIT 4,(HL) CB 66
Test bit 4 of byte +00H of the directory record at Register Pair HL: set when the record is in use.
4C31
If the Z FLAG is set (the system file is not on the diskette), JUMP to 4C4AH: SYS Error.
4C33
LD A,L 7D
Copy Register L (the record's low byte in the buffer) into Register A.
4C34
ADD A,16H C6 16
ADD 16H to Register A: the low byte of the record's first extent (+16H).
4C36
GOSUB to 47B4H to copy the first two extents into SFCB$ (42AFH-42B4H).
4C39
LD B,00H 06 00
Load Register B with the library command number: the operand at 4C3AH (00H in the file) is stored by 4BF7H.
4C3B
LD DE,42A1H 11 A1 42
Point Register Pair DE to 42A1H, SFCB$, the system files' control block.
4C3E
GOSUB to 4C8CH to load the module through the control block at Register Pair DE (for a library, member Register B). It returns the entry address in Register Pair HL with the Z FLAG set.
4C41
If the NZ FLAG is set (the load failed), JUMP to 4C4AH: SYS Error.
4C43
POP BC C1
Restore the caller's Register Pair BC from the stack.
4C44
POP DE D1
Restore the caller's Register Pair DE from the stack.
4C45
LD (4BE4H),HL 22 E4 4B
Store Register Pair HL (the entry address: 4E00H, or the one the loader returned) at 4BE4H-4BE5H, the operand of the CALL at 4BE3H.
4C48
POP HL E1
Restore the caller's Register Pair HL from the stack.
4C49
RET C9
RETurn to the dispatcher (4BE0H) with the entry stored.
4C4A
LD HL,4C53H 21 53 4C
Point Register Pair HL to 4C53H, the text SYS Error.
4C4D
GOSUB to 428AH (@LOGOT) to display the text at Register Pair HL (and send it to the job log).
4C50
JUMP to 4030H, @ABORT: the program is ended and LDOS Ready follows.
4C53-4C5B
DEFM "SYS Error" 53 59 53 20 45 72 72 6F 72
4C53H-4C5BH: the message displayed when a request cannot be served: an unknown request code below 80H, or a system file that is missing or cannot be loaded.
4C5C
DEFB 0DH 0D
4C5CH: 0DH, the end of the SYS Error text (displayed: the line ends).
4C5DH - @RUN and @LOAD
4C5DH (@RUN) sets bit 2 of SFLAG$ (442BH), loads the program file named in the control block at Register Pair DE (@LOAD) and runs it at its transfer address; when DEBUG is on (bit 7 of 442BH) and bit 1 is clear, it enters DEBUG at the program's first instruction instead. An error goes to @ERROR (4409H). 4C76H (@LOAD) opens the file with the buffer 4300H and loads it (4C8CH), returning the transfer address in Register Pair HL; a file not found becomes error 1FH (program not found), and bit 6 is set in every error number.
4C5D
PUSH HL E5
@RUN: Save Register Pair HL (the command line pointer) to the stack.
4C5E
LD HL,442BH 21 2B 44
Point Register Pair HL to 442BH, SFLAG$, the system flags.
4C61
SET 2,(HL) CB D6
Set bit 2 of SFLAG$ at Register Pair HL: a program load by @RUN is in progress.
4C63
GOSUB to 4430H (@LOAD) to load the program named in the control block at Register Pair DE; it returns the transfer address in Register Pair HL and the Z FLAG on success.
4C66
If the NZ FLAG is set (the load failed), JUMP to 4409H (@ERROR) with the error number in Register A.
4C69
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (the Stack Pointer is not changed): the transfer address goes on the stack and the command line pointer comes back into Register Pair HL for the program.
4C6A
LD A,(442BH) 3A 2B 44
Fetch SFLAG$, the system flags, from 442BH into Register A.
4C6D
BIT 1,A CB 4F
Test bit 1 of Register A (SFLAG$): when it is set the program runs without DEBUG.
4C6F
RET NZ C0
If the NZ FLAG is set (bit 1 on), RETurn: the RET takes the transfer address and runs the program.
4C70
BIT 7,A CB 7F
Test bit 7 of Register A: set when DEBUG is turned on.
4C72
If the NZ FLAG is set (DEBUG is on), JUMP to 400FH to enter DEBUG with the transfer address on the stack as the program's address.
4C75
RET C9
RETurn: the RET takes the transfer address and runs the program.
4C76H - @LOAD: Load a Program File
Register Pair DE = a file control block with the program's file specification. The file is opened with the buffer 4300H and 256 byte records (@OPEN) and loaded by 4C8CH, which returns the transfer address in Register Pair HL. On failure bit 6 is set in the error number (the short message), and 18H (file not in directory) becomes 1FH (program not found).
4C76
LD B,00H 06 00
@LOAD: Load Register B with 00H, the record length for @OPEN: 256 bytes.
4C78
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the buffer for the file's sectors (the module loader takes its bytes from 4300H-43FFH).
4C7B
GOSUB to 4424H (@OPEN) to open the file named in the control block at Register Pair DE with the buffer at Register Pair HL and the record length in Register B.
4C7E
PUSH DE D5
Save Register Pair DE (the control block) to the stack.
4C7F
If the Z FLAG is set (the file is open), GOSUB to 4C8CH to load it: Register Pair HL = its transfer address.
4C82
POP DE D1
Restore Register Pair DE (the control block) from the stack.
4C83
RET Z C8
If the Z FLAG is set (opened and loaded), RETurn with the transfer address in Register Pair HL.
4C84
SET 6,A CB F7
Set bit 6 of Register A (the error number): SYS4/SYS gives the short message.
4C86
CP 58H FE 58
Compare Register A against 58H (18H, file not in directory, with bit 6).
4C88
RET NZ C0
If the NZ FLAG is set (another error), RETurn with the error number in Register A.
4C89
ADD A,07H C6 07
ADD 07H to Register A: 5FH, error 1FH (program not found) with bit 6.
4C8B
RET C9
RETurn with Register A = 5FH and the NZ FLAG set.
4C8CH - The Module Loader
Loads the load module of the open file whose control block is at Register Pair DE, its sectors read into 4300H. Register B = the library member wanted (for SYS6/SYS and SYS7/SYS). Record types: 01H a load block (length, address, data), 02H the transfer address, 04H the end of a library member, 08H a library member's header (its number, entry address, the record of the file where it starts and the byte in that record), 0AH and 20H-FFH are a load file format error (22H), every other type below 20H is passed over by its length. Each data byte is checked after it is stored: a byte that does not stay is error 23H (memory fault) or 24H (read only memory), with bit 6 set. Returns the Z FLAG and the transfer (or member entry) address in Register Pair HL.
4C8C
LD A,B 78
Copy Register B (the library member wanted) into Register A.
4C8D
LD (4CF8H),A 32 F8 4C
Store Register A at 4CF8H, the operand of the CP at 4CF7H that picks the member.
4C90
PUSH DE D5
Save Register Pair DE (the file control block) to the stack.
4C91
EX (SP),IX DD E3
Exchange Index Register IX with the top of the stack (the Stack Pointer is not changed): Index Register IX = the file control block, and the caller's Index Register IX is kept on the stack.
4C93
LD DE,43FFH 11 FF 43
Load Register Pair DE with 43FFH: the pointer to the byte before the buffer at 4300H, so the first fetch (INC E gives 00H) reads the first sector.
4C96
GOSUB to 4C9CH to load the records of the module, one by one.
4C99
POP IX DD E1
Restore the caller's Index Register IX from the stack.
4C9B
RET C9
RETurn with the result of the load (Register Pair HL, Register A, the flags).
4C9C
GOSUB to 4D1BH to fetch the next byte of the file into Register A: the record type. 4CC4H, 4CE1H and the member search come back here.
4C9F
CP 01H FE 01
Compare Register A (the record type) against 01H, a load block.
4CA1
If the Z FLAG is set (type 01H), JUMP to 4CCDH to load the block.
4CA3
CP 02H FE 02
Compare Register A (the record type) against 02H, the transfer address.
4CA5
If the Z FLAG is set (type 02H), JUMP to 4CC6H to take the transfer address and return.
4CA7
CP 04H FE 04
Compare Register A (the record type) against 04H, the end of a library member.
4CA9
If the Z FLAG is set (type 04H), JUMP to 4CEDH to return the member's entry address.
4CAB
CP 08H FE 08
Compare Register A (the record type) against 08H, a library member's header.
4CAD
If the Z FLAG is set (type 08H), JUMP to 4CEFH to see whether it is the member wanted.
4CAF
CP 0AH FE 0A
Compare Register A (the record type) against 0AH.
4CB1
If the Z FLAG is set (type 0AH, not allowed in a load module), JUMP to 4CB7H: load file format error.
4CB3
CP 20H FE 20
Compare Register A (the record type) against 20H.
4CB5
If the CARRY FLAG is set (another type below 20H: a name, a comment or a copyright record), JUMP to 4CBBH to pass over it.
4CB7
LD A,22H 3E 22
Load Register A with 22H, error 34: load file format error (the file is not a load module).
4CB9
OR A B7
Set the flags from Register A (OR A): the NZ FLAG is set.
4CBA
RET C9
RETurn with Register A = 22H and the NZ FLAG set.
4CBB
GOSUB to 4D1BH to fetch the record's length byte into Register A.
4CBE
LD B,A 47
Copy Register A (the length) into Register B: the bytes to pass over (00H passes over 256).
4CBF
GOSUB to 4D1BH to fetch the next byte of the record into Register A, which is not used. 4CC2H loops back here; 4CF9H joins here for a member that is not wanted.
4CC2
DECrement Register B and LOOP BACK to 4CBFH until the record is passed over.
4CC4
JUMP to 4C9CH for the next record of the module.
4CC6
Type 02H: GOSUB to 4D1BH to fetch the record's length byte (02H), which is not used.
4CC9
GOSUB to 4D2FH to fetch the transfer address into Register Pair HL; it returns with the Z FLAG set.
4CCC
RET C9
RETurn with the transfer address in Register Pair HL and the Z FLAG set: the load is complete.
4CCD
Type 01H: GOSUB to 4D1BH to fetch the record's length byte into Register A.
4CD0
LD B,A 47
Copy Register A (the length: the address and the data) into Register B.
4CD1
GOSUB to 4D2FH to fetch the load address into Register Pair HL.
4CD4
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error number in Register A.
4CD5
DEC B 05
DECrement Register B for the low address byte.
4CD6
DEC B 05
DECrement Register B for the high address byte: Register B = the data bytes (00H counts as 256).
4CD7
GOSUB to 4D1BH to fetch the next data byte into Register A. 4CDFH loops back here.
4CDA
LD (HL),A 77
Store Register A (the data byte) at the load address in Register Pair HL.
4CDB
CP (HL) BE
Compare Register A against the byte at Register Pair HL: the Z FLAG is set when the store took.
4CDC
If the NZ FLAG is set (the memory did not keep the byte), JUMP to 4CE3H to find out why.
4CDE
INC HL 23
INCrement Register Pair HL, the load address.
4CDF
DECrement Register B and LOOP BACK to 4CD7H until the block is loaded.
4CE1
JUMP to 4C9CH for the next record of the module.
4CE3
LD B,(HL) 46
Fetch the byte the memory at Register Pair HL holds into Register B.
4CE4
CPL 2F
Complement Register A (the data byte) to write a different value.
4CE5
LD (HL),A 77
Store Register A (the complement) at Register Pair HL.
4CE6
LD A,(HL) 7E
Fetch the byte at Register Pair HL back into Register A.
4CE7
CP B B8
Compare Register A against Register B (what the memory held before): the Z FLAG is set when the memory did not change at all, read only memory.
4CE8
LD A,63H 3E 63
Load Register A with 63H: error 23H (35, memory fault) with bit 6. LD does not change the flags.
4CEA
RET NZ C0
If the NZ FLAG is set (the memory changes but did not keep the data byte), RETurn with Register A = 63H.
4CEB
INC A 3C
INCrement Register A: 64H, error 24H (36, attempted to load read only memory) with bit 6.
4CEC
RET C9
RETurn with Register A = 64H and the NZ FLAG set.
4CED
POP HL E1
Type 04H, the end of the member: Restore the member's entry address (pushed at 4CFEH) from the stack into Register Pair HL.
4CEE
RET C9
RETurn with the member's entry address in Register Pair HL; the Z FLAG is set (from the CP at 4CA7H).
4CEF
Type 08H: GOSUB to 4D1BH to fetch the record's length byte into Register A.
4CF2
LD B,A 47
Copy Register A (the length) into Register B.
4CF3
GOSUB to 4D1BH to fetch the member number into Register A.
4CF6
DEC B 05
DECrement Register B for the member number just read.
4CF7
CP 00H FE 00
Compare Register A (the member number) against the member wanted: the operand at 4CF8H is 00H in the file; 4C8DH stores Register B there.
4CF9
If the NZ FLAG is set (another member), JUMP to 4CBFH to pass over the rest of the record (Register B bytes).
4CFB
GOSUB to 4D2FH to fetch the member's entry address into Register Pair HL.
4CFE
PUSH HL E5
Save Register Pair HL (the member's entry address) to the stack, for 4CEDH.
4CFF
If the Z FLAG is set (no read error), GOSUB to 4D2FH to fetch the next word into Register Pair HL: the record of the file where the member starts.
4D02
If the NZ FLAG is set (a read error), JUMP to 4D2BH to drop the entry address and return the error.
4D04
GOSUB to 4D1BH to fetch the next byte into Register A: the position of the member's first byte in that record.
4D07
LD E,A 5F
Copy Register A (the byte position) into Register E: the low byte of the fetch pointer in Register Pair DE.
4D08
PUSH BC C5
Save Register Pair BC (Register B = the bytes of the record left) to the stack.
4D09
LD B,H 44
Copy Register H (the record's high byte) into Register B.
4D0A
LD C,L 4D
Copy Register L (the record's low byte) into Register C. Register Pair BC = the record where the member starts.
4D0B
PUSH DE D5
Save Register Pair DE (the fetch pointer) to the stack.
4D0C
PUSH IX DD E5
Save Index Register IX (the file control block) to the stack.
4D0E
POP DE D1
Restore it into Register Pair DE: @POSN takes the control block in Register Pair DE.
4D0F
GOSUB to 4442H (@POSN) to position the file at record Register Pair BC.
4D12
POP DE D1
Restore Register Pair DE (the fetch pointer, Register E = the byte position) from the stack.
4D13
POP BC C1
Restore Register Pair BC (Register B = the bytes left) from the stack.
4D14
If the NZ FLAG is set (the position failed), JUMP to 4D2BH to drop the entry address and return the error.
4D16
GOSUB to 4D20H to read the record into the buffer and fetch the byte at the pointer: Register A = the type of the member's first record.
4D19
JUMP to 4C9FH to act on that record type in Register A.
4D1B
INC E 1C
INCrement Register E, the fetch pointer in the buffer (Register Pair DE, 43xxH). The Z FLAG is set when it wraps to 00H: the buffer is used up.
4D1C
If the Z FLAG is set (the buffer is used up), JUMP to 4D20H to read the next sector.
4D1E
LD A,(DE) 1A
Fetch the byte at Register Pair DE (the buffer) into Register A.
4D1F
RET C9
RETurn with the byte of the file in Register A.
4D20
PUSH HL E5
Save the caller's Register Pair HL to the stack.
4D21
PUSH DE D5
Save Register Pair DE (the fetch pointer) to the stack.
4D22
PUSH BC C5
Save the caller's Register Pair BC to the stack.
4D23
GOSUB to 494FH to read the sector of the file's next record number into its buffer (4300H): the file at Index Register IX.
4D26
POP BC C1
Restore the caller's Register Pair BC from the stack.
4D27
POP DE D1
Restore Register Pair DE (the fetch pointer) from the stack.
4D28
POP HL E1
Restore the caller's Register Pair HL from the stack.
4D29
If the Z FLAG is set (the sector was read), JUMP to 4D1EH to fetch the byte at Register Pair DE.
4D2B
POP BC C1
Drop a word from the stack into Register Pair BC: the return address into the loader (or the member's entry address), so the RET below leaves the loader.
4D2C
OR 40H F6 40
OR 40H into Register A (the error number): bit 6, the short message (the NZ FLAG is set).
4D2E
RET C9
RETurn with the error number in Register A and the NZ FLAG set.
4D2F
GOSUB to 4D1BH to fetch the next byte into Register A: the low byte of a word.
4D32
LD L,A 6F
Copy Register A (the low byte of the word) into Register L.
4D33
GOSUB to 4D1BH to fetch the next byte into Register A: the high byte.
4D36
LD H,A 67
Copy Register A into Register H. Register Pair HL = the word.
4D37
CP A BF
Compare Register A with itself: the Z FLAG is set.
4D38
RET C9
RETurn with the word in Register Pair HL and the Z FLAG set.
4D39H - @DSPLY, @MSG and @PRINT: Send a Text to a Device
4D39H (@DSPLY, 4467H) sends to the video (401DH), 4D4EH (@PRINT, 446AH) to the printer (4025H) and 4D3CH (@MSG, 4402H) to the device control block in Register Pair DE. The text at Register Pair HL ends with 03H (not sent) or 0DH (sent); each byte goes out through the ROM's @PUT at 001BH. Register Pair HL comes back unchanged.
4D39
LD DE,401DH 11 1D 40
@DSPLY: point Register Pair DE to 401DH, DODCB$, the video's device control block. @LOGOT (428AH) and @DSPLY (4467H) come here.
4D3C
PUSH HL E5
@MSG: save Register Pair HL (the start of the text) to the stack, so that it comes back unchanged. @PRINT joins here from 4D51H.
4D3D
LD A,(HL) 7E
Fetch the next byte of the text from Register Pair HL into Register A. 4D4AH loops back here.
4D3E
CP 03H FE 03
Compare Register A against 03H, the byte that ends a text without being sent.
4D40
If the Z FLAG is set (03H, the end), JUMP to 4D4CH to return.
4D42
PUSH AF F5
Save Register Pair AF (Register A = the byte) to the stack: the ROM's @PUT changes Register A.
4D43
GOSUB to the ROM's @PUT at 001BH to send Register A to the device whose control block is at Register Pair DE.
4D46
POP AF F1
Restore Register Pair AF (Register A = the byte sent) from the stack.
4D47
INC HL 23
INCrement Register Pair HL to the next byte of the text.
4D48
CP 0DH FE 0D
Compare Register A (the byte sent) against 0DH, ENTER, which ends a text after it has been sent.
4D4A
If the NZ FLAG is set (not 0DH), JUMP back to 4D3DH for the next byte at Register Pair HL.
4D4C
POP HL E1
Restore Register Pair HL (the start of the text) from the stack.
4D4D
RET C9
RETurn to the caller with Register Pair HL at the start of the text.
4D4E
LD DE,4025H 11 25 40
@PRINT: point Register Pair DE to 4025H, PRDCB$, the printer's device control block. @PRINT (446AH) comes here.
4D51
JUMP to 4D3CH to send the text at Register Pair HL to the printer's block at Register Pair DE.
4D53H - The Route Routines and @DVRHK
4D53H-4D61H are the four route routines: the loads of Register Pair HL at 4D53H, 4D57H, 4D5BH and 4D5FH (the last three are the LD HL after the DDH prefix of an LD IX), each running on into 4D62H. ROUTE (SYS6/SYS, member 13, its 5261H-5294H) stores the control block a device is routed to into the operand of a free one (low byte 00H) and points the device's +01H-+02H at it, so a request to the device goes to the destination's driver or file; KILL, DEVICE, RESET and SPOOL follow a route through the operand, and ROUTE and RESET clear it again. 4D62H takes a device control block in Register Pair HL (SYS2/SYS jumps there, its 4F3AH) and 4D65H, @DVRHK, the jump at 4033H from the ROM's character routine, enters the driver of the block at Index Register IX: an open file (bit 7 of the type byte) goes to 48ECH, any other block to the address in its bytes +01H-+02H with the flags of the request (CARRY input, Z output, NZ control).
4D53
LD HL,0000H 21 00 00
The first route routine: load Register Pair HL with the operand at 4D54H-4D55H (0000H in the file, free), the control block a routed device goes to; ROUTE (SYS6/SYS, its 5261H) stores it and a routed device's +01H-+02H point here.
4D56
LD IX,0000H DD 21 00 00
Load Index Register IX with the operand at 4D58H-4D59H (0000H in the file), a dead load on the way from 4D53H. Entered at 4D57H, the second route routine, the bytes 21H and the operand run as LD HL with the block that ROUTE stored there.
4D5A
LD IX,0000H DD 21 00 00
Load Index Register IX with the operand at 4D5CH-4D5DH (0000H in the file), a dead load on the way from an earlier route routine. Entered at 4D5BH, the third route routine, it runs as LD HL with the block that ROUTE stored there.
4D5E
LD IX,0000H DD 21 00 00
Load Index Register IX with the operand at 4D60H-4D61H (0000H in the file), a dead load on the way from an earlier route routine. Entered at 4D5FH, the fourth route routine, it runs as LD HL with the block that ROUTE stored there.
4D62
PUSH HL E5
Save Register Pair HL (a device control block) to the stack. SYS2/SYS jumps here (its 4F3AH) with the block in Register Pair HL.
4D63
POP IX DD E1
Restore it into Index Register IX: Index Register IX = the device control block.
4D65
LD L,(IX+01H) DD 6E 01
@DVRHK: fetch byte +01H of the device control block at Index Register IX into Register L, the low byte of its driver's address.
4D68
LD H,(IX+02H) DD 66 02
Fetch byte +02H of the device control block at Index Register IX into Register H: Register Pair HL = the driver's address.
4D6B
BIT 7,(IX+00H) DD CB 00 7E
Test bit 7 of byte +00H, the type byte, of the block at Index Register IX: set for an open file control block used as a device.
4D6F
If the NZ FLAG is set (an open file), jump to 48ECH to take the byte from the file or put it in.
4D72
LD A,B 78
Copy Register B (the request: 01H input, 02H output, 04H control) into Register A.
4D73
CP 02H FE 02
Compare Register A (the request) against 02H: the CARRY FLAG is set for input, the Z FLAG for output, neither for a control request.
4D75
JP (HL) E9
Jump to the driver at Register Pair HL with the flags of the request; Register C holds the character.
4D76H - The Program Counter Display Task
4D76H is a task block that SYS7/SYS puts into a task slot (Register Pair DE = 4D76H at its 52D9H): its first word is 4D78H, the routine, which writes the address the interrupted program was at as four hex digits at 3C2EH, row 0 of the screen. 4D87H writes Register A as two hex characters at Register Pair HL; LCOMM/CMD, SYS6/SYS and SYS7/SYS use it too.
4D76-4D77
DEFW 4D78H 78 4D
4D76H-4D77H: the task block of the program counter display, its first word 4D78H, the address of its routine. SYS7/SYS loads Register Pair DE with 4D76H (its 52D9H) to add it as a task.
4D78
LD HL,0014H 21 14 00
Load Register Pair HL with 0014H, the distance up the stack to the interrupted program's address when the task runs in one of slots 8-11.
4D7B
ADD HL,SP 39
ADD the Stack Pointer to Register Pair HL: Register Pair HL = the address of the word the interrupt pushed, 20 bytes up the stack.
4D7C
LD E,(HL) 5E
Fetch the low byte of the interrupted program's address from Register Pair HL into Register E.
4D7D
INC HL 23
INCrement Register Pair HL to the high byte of the address on the stack.
4D7E
LD D,(HL) 56
Fetch the high byte from Register Pair HL into Register D: Register Pair DE = the address the program was at.
4D7F
LD HL,3C2EH 21 2E 3C
Point Register Pair HL to 3C2EH, columns 46-49 of row 0 of the screen, where the address is shown.
4D82
LD A,D 7A
Copy Register D (the high byte of the address) into Register A.
4D83
GOSUB to 4D87H to write Register A as two hex characters at Register Pair HL.
4D86
LD A,E 7B
Copy Register E (the low byte of the address) into Register A. The code goes on into 4D87H for its two characters.
4D87
PUSH AF F5
Save Register Pair AF (Register A = the byte) to the stack, for its low digit. LCOMM/CMD, SYS6/SYS and SYS7/SYS call 4D87H.
4D88
RRA 1F
Rotate Register A right through the CARRY FLAG: first of four rotations that bring the high digit to bits 3-0.
4D89
RRA 1F
Rotate Register A right through the CARRY FLAG again: second of four rotations.
4D8A
RRA 1F
Rotate Register A right through the CARRY FLAG again: third of four rotations.
4D8B
RRA 1F
Rotate Register A right through the CARRY FLAG again: the high digit is now in bits 3-0 of Register A.
4D8C
GOSUB to 4D90H to write the digit in bits 3-0 of Register A as a hex character at Register Pair HL.
4D8F
POP AF F1
Restore Register Pair AF (Register A = the byte, its low digit in bits 3-0) from the stack. The code goes on into 4D90H.
4D90
AND 0FH E6 0F
Mask Register A to bits 3-0: the hex digit 0-15.
4D92
ADD A,90H C6 90
ADD 90H to Register A, the first step of the conversion of a hex digit to its character.
4D94
DAA 27
Decimal adjust Register A (DAA): 90H-99H for 0-9, 00H-05H with the CARRY FLAG for 10-15.
4D95
ADC A,40H CE 40
ADD 40H and the CARRY FLAG to Register A (ADC A,40H).
4D97
DAA 27
Decimal adjust Register A again (DAA): Register A = the character 0-9 (30H-39H) or A-F (41H-46H).
4D98
LD (HL),A 77
Store Register A (the hex character) at Register Pair HL on the screen.
4D99
INC HL 23
INCrement Register Pair HL to the next screen position.
4D9A
RET C9
RETurn with Register Pair HL past the character written.
4D9BH - The Current Sector of a File
4D9BH saves Register Pair HL under the return address and goes on into 4D9EH; 4D9EH loads Register C with the position in the buffer (+05H); 4DA1H (Register C given) adjusts Register Pair HL, the next record number less one or the next record number, to the sector of the current position: in byte mode (bit 7 of +01H) one is added when Register C is not 0, and one is taken away when the buffer holds the sector before the next record number (bit 5 clear). In record mode Register Pair HL is not changed.
4D9B
POP BC C1
Take the return address off the stack into Register Pair BC.
4D9C
PUSH HL E5
Save Register Pair HL (the next record number) to the stack, under the return address.
4D9D
PUSH BC C5
Save Register Pair BC (the return address) back on top.
4D9E
LD C,(IX+05H) DD 4E 05
Fetch byte +05H of the file control block at Index Register IX into Register C: the position in the buffer.
4DA1
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of byte +01H of the file control block at Index Register IX: byte mode.
4DA5
RET Z C8
If the Z FLAG is set (not byte mode), RETurn with Register Pair HL unchanged.
4DA6
LD A,C 79
Copy Register C (the position in the buffer) into Register A.
4DA7
OR A B7
Set the flags from Register A (OR A): the Z FLAG is set when the position is 0.
4DA8
If the Z FLAG is set (the position is 0), JUMP to 4DABH.
4DAA
INC HL 23
INCrement Register Pair HL: the position is inside the sector after.
4DAB
BIT 5,(IX+01H) DD CB 01 6E
Test bit 5 of byte +01H of the file control block at Index Register IX: set when the buffer must be read before the next byte.
4DAF
RET NZ C0
If the NZ FLAG is set (the buffer does not hold the sector), RETurn.
4DB0
DEC HL 2B
DECrement Register Pair HL: the buffer holds the sector before the next record number.
4DB1
RET C9
RETurn with the current sector in Register Pair HL.
4DB2H - The Video Driver with Interrupts On
The reset puts 4DB2H into the video's device control block (401EH) unless RIGHT ARROW is held at boot (4E57H-4E68H). It sets bit 7 of 401CH, the ROM's blink switch, so that the clock interrupt does not blink the cursor while the character is put on the screen, and calls the ROM's video driver at 0474H, after its DI, so interrupts stay on; then it clears the bit. Index Register IX = the video's device control block (401DH).
4DB2
SET 7,(IX-01H) DD CB FF FE
Set bit 7 of the byte at Index Register IX -01H, the byte before the device control block (401CH, the ROM's cursor blink switch): the ROM's real time clock routine does not blink the cursor while it is not 00H.
4DB6
CALL 0474H CD 74 04
GOSUB to the ROM's video driver at 0474H, the instruction after its DI: the character in Register C is displayed with interrupts left on. The reset stores the ROM's address plus 1 in the operand at 4DB7H (4E61H-4E62H).
4DB9
RES 7,(IX-01H) DD CB FF BE
Reset bit 7 of the byte at Index Register IX -01H (401CH, the ROM's blink switch): the cursor blinks again.
4DBD
RET C9
RETurn to the caller with the ROM driver's result in Register A and the flags.
4DBEH - The Keyboard Scan of Every Interrupt
Called by the interrupt routine (44BAH) on every interrupt, and by BACKUP/CMD (its 53F1H, 5414H). It reads the keyboard rows directly: SHIFT (3880H, bits 1-0) with @ (3801H, bit 0) sets bit 1 of KFLAG$ (429FH), the pause; ENTER (3840H, bit 0) sets bit 2; BREAK (3840H, bit 2) without SHIFT sets bit 0 unless BREAK is disabled (bit 4 of 442BH). Returns with the NZ FLAG set when BREAK is held and the CARRY FLAG set when a SHIFT key is held.
4DBE
PUSH HL E5
Save the interrupted program's Register Pair HL to the stack.
4DBF
LD HL,429FH 21 9F 42
Point Register Pair HL to 429FH, KFLAG$, the keyboard flags.
4DC2
LD A,(3880H) 3A 80 38
Fetch keyboard row 7 from 3880H into Register A: bit 0 the left SHIFT, bit 1 the right SHIFT.
4DC5
AND 03H E6 03
Mask Register A to bits 1-0, the two SHIFT keys.
4DC7
NEG ED 44
Negate Register A: the CARRY FLAG is set when a SHIFT key is held (Register A was not 0).
4DC9
LD A,(3801H) 3A 01 38
Fetch keyboard row 0 from 3801H into Register A: bit 0 is the @ key. LD does not change the flags.
4DCC
BIT 0,A CB 47
Test bit 0 of Register A (row 0): the @ key, held or not.
4DCE
If the Z FLAG is set (@ is not held), JUMP to 4DD4H.
4DD0
If the NO CARRY FLAG is set (no SHIFT key), JUMP to 4DD4H.
4DD2
SET 1,(HL) CB CE
Set bit 1 of KFLAG$ at Register Pair HL: SHIFT @, the pause key.
4DD4
LD A,(3840H) 3A 40 38
Fetch keyboard row 6 from 3840H into Register A: bit 0 ENTER, bit 2 BREAK.
4DD7
BIT 0,A CB 47
Test bit 0 of Register A (row 6): the ENTER key.
4DD9
If the Z FLAG is set (ENTER is not held), JUMP to 4DDDH.
4DDB
SET 2,(HL) CB D6
Set bit 2 of KFLAG$ at Register Pair HL: ENTER was held.
4DDD
BIT 2,A CB 57
Test bit 2 of Register A (row 6): BREAK. The Z FLAG is clear when BREAK is held.
4DDF
PUSH AF F5
Save Register Pair AF (the Z FLAG for BREAK and the CARRY FLAG for SHIFT) to the stack, to return them.
4DE0
If the Z FLAG is set (BREAK is not held), JUMP to 4DEDH.
4DE2
If the CARRY FLAG is set (SHIFT BREAK), JUMP to 4DEDH without setting the BREAK bit.
4DE4
LD A,(442BH) 3A 2B 44
Fetch SFLAG$, the system flags, from 442BH into Register A.
4DE7
BIT 4,A CB 67
Test bit 4 of Register A (SFLAG$): BREAK disabled.
4DE9
If the NZ FLAG is set (BREAK is disabled), JUMP to 4DEDH.
4DEB
SET 0,(HL) CB C6
Set bit 0 of KFLAG$ at Register Pair HL: BREAK was pressed.
4DED
POP AF F1
Restore Register Pair AF (the BREAK and SHIFT flags) from the stack.
4DEE
POP HL E1
Restore the interrupted program's Register Pair HL from the stack.
4DEF
RET C9
RETurn to the interrupt routine with the BREAK and SHIFT flags.
4DF0H - Base Cells for Resident Modules
Sixteen bytes before the reset code that the system files do not load over. Members of SYS6/SYS keep values in 4DF0H, 4DF1H, 4DF6H and 4DF7H (its 5216H, 54D6H, 520EH, 5318H, 531CH) and members of SYS7/SYS read 4DF2H and 4DF6H (its 535BH, 5270H).
4DF0-4DFD
DEFB 00H x 14 00 x 14
4DF0H-4DFDH: 14 bytes of 00H, the base cells above, empty at boot.
4DFE-4DFF
DEFW 41F3H F3 41
4DFEH-4DFFH: F3H 41H, the word 41F3H. No instruction of the LDOS files on this diskette addresses these two bytes.
4E00H - The Reset: Vectors, Memory, Video and Drive 0
The transfer address of SYS0/SYS: the boot sector jumps here with interrupts off and the NMI vector at 4049H pointing at its own end of read. The reset takes over the ROM's clock vector and the NMI, clears the spare device control blocks, sets port ECH and the interrupt mask, finds the top of memory, installs its keyboard, video and printer drivers, sets up drive 0 from the boot sector, enables the interrupts and reads the system information sector (cylinder 0, sector 2) into 4300H. All of 4E00H-50FFH is used only here; the system files load over it afterwards.
4E00
DI F3
Disable interrupts (they are already off after the boot sector). The overlay loader also sets Register Pair HL to 4E00H for a file already in place (4C0CH).
4E01
LD HL,(4047H) 2A 47 40
Load Register Pair HL with the address in the ROM's clock vector at 4047H-4048H (the JP 3529H the ROM put at 4046H): the ROM's real time clock routine.
4E04
LD (4BBCH),HL 22 BC 4B
Store Register Pair HL (the ROM's clock routine) at 4BBCH, the operand of the LD DE at 4BBBH: the clock interrupt runs the ROM's routine after the tasks.
4E07
LD HL,46F9H 21 F9 46
Load Register Pair HL with 46F9H, the NMI routine of the floppy disk driver.
4E0A
LD (404AH),HL 22 4A 40
Store Register Pair HL (46F9H) at 404AH, the address of the NMI vector at 4049H: the NMI at the end of a write goes to 46F9H.
4E0D
LD HL,454AH 21 4A 45
Load Register Pair HL with 454AH, @KLTSK, the routine a task calls to remove itself.
4E10
LD (4047H),HL 22 47 40
Store Register Pair HL (454AH) at 4047H: the JP at 4046H becomes @KLTSK, the vector programs call to end a task.
4E13
IM 1 ED 56
Set interrupt mode 1: a maskable interrupt is RST 38H, to 0038H and through 4012H to the interrupt service routine at 44A5H.
4E15
LD SP,41E3H 31 E3 41
Load the Stack Pointer with 41E3H: the reset's stack grows down from 41E2H, under the word 0000H at 41E3H-41E4H.
4E18
XOR A AF
Set Register A to 00H (XOR A) for port E4H and the clear below.
4E19
OUT (E4H),A D3 E4
Send Register A (00H) to port E4H: no NMI from the disk controller until the write loop asks for one.
4E1B
LD HL,42D4H 21 D4 42
Point Register Pair HL to 42D4H, the four spare device control blocks.
4E1E
LD B,18H 06 18
Load Register B with 18H, the 24 bytes of the four blocks of six bytes.
4E20
LD (HL),A 77
Store Register A (00H) at Register Pair HL. 4E22H loops back here.
4E21
INC L 2C
INCrement Register L to the next byte of the spare blocks (42D4H-42EBH lie in one page).
4E22
DECrement Register B and loop back to 4E20H until the 24 bytes at 42D4H-42EBH are cleared.
4E24
LD A,38H 3E 38
Load Register A with 38H: bit 5 (video wait states), bit 4 (the external I/O bus) and bit 3 (the alternate character set) of port ECH.
4E26
LD (4210H),A 32 10 42
Store Register A (38H) at 4210H, the copy of port ECH the ROM keeps; the FAST setting ORs into it later (5059H-5068H).
4E29
OUT (ECH),A D3 EC
Send Register A (38H) to port ECH, the miscellaneous control port.
4E2B
LD A,04H 3E 04
Load Register A with 04H: bit 2 of the interrupt mask, the real time clock.
4E2D
LD (4213H),A 32 13 42
Store Register A (04H) at 4213H, the copy of the interrupt mask the ROM keeps; the end of the reset sends it again (506AH-506DH).
4E30
OUT (E0H),A D3 E0
Send Register A (04H) to port E0H, the interrupt mask: only the real time clock can interrupt.
4E32
LD HL,FFFFH 21 FF FF
Load Register Pair HL with FFFFH, the highest address of a 64K memory, the first one to test.
4E35
LD A,(HL) 7E
Fetch the byte at Register Pair HL into Register A. 4E41H loops back here with the next address 16K lower.
4E36
LD B,A 47
Copy Register A (the byte) into Register B, to put it back.
4E37
CPL 2F
Complement Register A: a value the byte at Register Pair HL did not hold.
4E38
LD (HL),A 77
Store Register A (the complement) at Register Pair HL.
4E39
CP (HL) BE
Compare Register A against the byte at Register Pair HL: the Z FLAG is set when the memory kept the complement, so there is RAM at this address.
4E3A
LD (HL),B 70
Store Register B (the original byte) back at Register Pair HL.
4E3B
If the Z FLAG is set (RAM is there), JUMP to 4E43H with the top of memory in Register Pair HL.
4E3D
LD A,H 7C
Copy Register H (the high byte of the address tested) into Register A.
4E3E
SUB 40H D6 40
SUBtract 40H from Register A: the same address 16K lower in memory.
4E40
LD H,A 67
Copy Register A into Register H: Register Pair HL = the same address 16K lower (BFFFH, 7FFFH, 3FFFH).
4E41
JUMP back to 4E35H to test the next address at Register Pair HL.
4E43
LD (4411H),HL 22 11 44
Store Register Pair HL (the top of memory) at 4411H-4412H, HIGH$, the highest address free for programs.
4E46
LD (4415H),HL 22 15 44
Store Register Pair HL at 4415H-4416H as well, the top of memory kept apart from HIGH$.
4E49
LD A,(42A0H) 3A A0 42
Fetch the byte for port FEH from 42A0H into Register A (00H in the file).
4E4C
OUT (FEH),A D3 FE
Send Register A (the byte from 42A0H) to port FEH.
4E4E
LD HL,41EDH 21 ED 41
Load Register Pair HL with 41EDH, SYS0/SYS's keyboard driver, which calls @KITSK before the ROM's driver.
4E51
LD (4016H),HL 22 16 40
Store Register Pair HL (41EDH) at 4016H-4017H, the driver address of the keyboard's device control block.
4E54
LD (42B8H),HL 22 B8 42
Store Register Pair HL (41EDH) at 42B8H-42B9H, KISV$.
4E57
LD HL,(401EH) 2A 1E 40
Load Register Pair HL with the video driver address from 401EH-401FH: 0473H, the ROM's driver.
4E5A
LD A,(3840H) 3A 40 38
Fetch keyboard row 6 from 3840H into Register A: bit 6 is RIGHT ARROW.
4E5D
BIT 6,A CB 77
Test bit 6 of Register A: the Z FLAG is clear when RIGHT ARROW is held.
4E5F
If the NZ FLAG is set (RIGHT ARROW is held), JUMP to 4E68H to keep the ROM's video driver.
4E61
INC HL 23
INCrement Register Pair HL: 0474H, the ROM's driver after its DI.
4E62
LD (4DB7H),HL 22 B7 4D
Store Register Pair HL (0474H) at 4DB7H, the operand of the CALL at 4DB6H in SYS0/SYS's video driver.
4E65
LD HL,4DB2H 21 B2 4D
Load Register Pair HL with 4DB2H, SYS0/SYS's video driver, which keeps interrupts on and the cursor from blinking while it writes.
4E68
LD (401EH),HL 22 1E 40
Store Register Pair HL (4DB2H, or 0473H when RIGHT ARROW is held) at 401EH-401FH, the driver of the video's device control block.
4E6B
LD (42BAH),HL 22 BA 42
Store Register Pair HL (the video driver) at 42BAH-42BBH, DOSV$.
4E6E
LD HL,41E5H 21 E5 41
Load Register Pair HL with 41E5H, SYS0/SYS's printer driver, which adds the printer status as a control request.
4E71
LD (4026H),HL 22 26 40
Store Register Pair HL (41E5H) at 4026H-4027H, the driver address of the printer's device control block.
4E74
LD (42BCH),HL 22 BC 42
Store Register Pair HL (41E5H) at 42BCH-42BDH, PRSV$.
4E77
LD A,(4395H) 3A 95 43
Fetch byte 95H of the boot sector, still at 4300H-43FFH, from 4395H into Register A: the operand of its Seek command, whose bits 1-0 are the step rate the diskette was formatted for.
4E7A
AND 03H E6 03
Mask Register A to bits 1-0: the boot step rate.
4E7C
LD B,A 47
Copy Register A (the step rate) into Register B.
4E7D
LD HL,4703H 21 03 47
Point Register Pair HL to 4703H, byte +03H of drive 0's drive code table.
4E80
LD A,(HL) 7E
Fetch drive 0's flags from Register Pair HL into Register A.
4E81
AND FCH E6 FC
Mask Register A with FCH, clearing the step rate bits 1-0.
4E83
OR B B0
OR Register B (the boot step rate) into Register A.
4E84
LD (HL),A 77
Store Register A at Register Pair HL (4703H): drive 0 steps at the rate of the boot diskette.
4E85
LD A,(4302H) 3A 02 43
Fetch byte 02H of the boot sector from 4302H into Register A: the directory cylinder of the boot diskette.
4E88
LD (4709H),A 32 09 47
Store Register A (the directory cylinder) at 4709H, byte +09H of drive 0's drive code table.
4E8B
IN A,(F1H) DB F1
Read the track register from port F1H into Register A: the cylinder the boot sector left the head on.
4E8D
LD (4705H),A 32 05 47
Store Register A (the cylinder) at 4705H, byte +05H of drive 0's drive code table, the cylinder under the head.
4E90
EI FB
Enable interrupts: the clock interrupt now runs (its tasks are empty) and the ROM's real time clock routine with it.
4E91
LD DE,0002H 11 02 00
Load Register Pair DE with 0002H: cylinder 0, sector 2, the system information sector.
4E94
LD C,D 4A
Copy Register D (00H) into Register C: drive 0.
4E95
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, SBUFF$, over the boot sector.
4E98
GOSUB to 4777H (RDSECT) to read cylinder Register D, sector Register E of drive Register C into the buffer at Register Pair HL. The result is not tested.
4E9BH - The Reset: The Date
The system information sector is now at 4300H. Its byte 01H is saved on the stack and replaced by 00H. When its date prompt switch (43C2H) is not 00H the date is skipped. When the date was set before a reset (442FH holds a month OR 50H) it is used again without a prompt; 442FH = 50H skips the date and the time. Otherwise Date? is asked at 3F17H until three good fields are typed (MM/DD/YY, years 80-99 for 1980-1999 and 00-11 for 2000-2011).
4E9B
LD L,01H 2E 01
Load Register L with 01H: Register Pair HL = 4301H, byte 01H of the system information sector (RDSECT returns Register Pair HL unchanged).
4E9D
LD A,(HL) 7E
Fetch byte 01H of the system information sector from Register Pair HL into Register A.
4E9E
LD (HL),00H 36 00
Store 00H at Register Pair HL (4301H): the byte before the month lengths becomes 0 for the day of the year sum (4F1AH).
4EA0
PUSH AF F5
Save Register Pair AF (Register A = byte 01H of the sector) to the stack; 501DH takes it back for the CONFIG/SYS test.
4EA1
LD A,(43C2H) 3A C2 43
Fetch the date prompt switch from 43C2H into Register A, byte C2H of the system information sector.
4EA4
OR A B7
Test Register A (OR A): the Z FLAG is set when the date is to be asked.
4EA5
If the NZ FLAG is set (no date prompt), jump to 4F94H for the time.
4EA8
LD A,(442FH) 3A 2F 44
Fetch the month of the date kept over a reset from 442FH into Register A (the month OR 50H once a date has been set).
4EAB
XOR 50H EE 50
Exclusive OR Register A with 50H: Register A = the month 1-12 when a date is kept, 00H when 442FH holds 50H.
4EAD
If the Z FLAG is set (442FH holds 50H), jump to 4FC8H, past the date and the time.
4EB0
CP 0DH FE 0D
Compare Register A against 0DH: the CARRY FLAG is set for a month of 1-12.
4EB2
If the CARRY FLAG is set (a date is kept), JUMP to 4EFFH to use the month in Register A again.
4EB4
LD HL,3F17H 21 17 3F
Point Register Pair HL to 3F17H, row 12, column 23 of the screen, where the date prompt goes. A field out of range comes back here (4EC0H, 4ECDH, 4EE8H, 4EF4H).
4EB7
LD DE,50B4H 11 B4 50
Point Register Pair DE to 50B4H, the text 1EH Date ? 03H.
4EBA
LD BC,0830H 01 30 08
Load Register Pair BC with 0830H: Register B = 8, the most characters, Register C = 30H, the limit for a separator (any character below 0).
4EBD
GOSUB to 4228H to show the prompt at Register Pair HL, take the line and parse three fields into 4227H, 4226H and 4225H.
4EC0
If the NO CARRY FLAG is set (not three fields of two digits), JUMP back to 4EB4H to ask again.
4EC2
LD A,(DE) 1A
Fetch the third field, the year, from Register Pair DE (4225H, where the parser left it) into Register A.
4EC3
CP 0CH FE 0C
Compare Register A (the year) against 0CH: the NO CARRY FLAG is set for 12-99.
4EC5
If the NO CARRY FLAG is set (12-99), JUMP to 4EC9H.
4EC7
ADD A,64H C6 64
ADD 64H to Register A: a year of 00-11 becomes 100-111, the years 2000-2011.
4EC9
SUB 50H D6 50
SUBtract 50H (80) from Register A: Register A = the years since 1980 (0-31 for a good year).
4ECB
CP 20H FE 20
Compare Register A against 20H: the NO CARRY FLAG is set for a year outside 1980-2011.
4ECD
If the NO CARRY FLAG is set (the year is out of range), JUMP back to 4EB4H to ask again.
4ECF
LD (4413H),A 32 13 44
Store Register A (the years since 1980) at 4413H.
4ED2
AND 03H E6 03
Mask Register A to bits 1-0: the Z FLAG is set in a leap year (1980, 1984 ...).
4ED4
LD A,1CH 3E 1C
Load Register A with 1CH, 28 days for February. LD does not change the flags.
4ED6
If the NZ FLAG is set (not a leap year), JUMP to 4EDEH with 28 days.
4ED8
LD HL,4418H 21 18 44
Point Register Pair HL to 4418H, the date flags.
4EDB
SET 7,(HL) CB FE
Set bit 7 of the date flags at Register Pair HL (4418H): a leap year.
4EDD
INC A 3C
INCrement Register A: 1DH, 29 days for February.
4EDE
LD HL,4303H 21 03 43
Point Register Pair HL to 4303H, the days of February in the system information sector (byte 03H).
4EE1
LD (HL),A 77
Store Register A (28 or 29) at Register Pair HL (4303H).
4EE2
LD A,(4227H) 3A 27 42
Fetch the first field, the month, from 4227H into Register A.
4EE5
DEC A 3D
DECrement Register A: the month as 0-11, below 0CH when it is good.
4EE6
CP 0CH FE 0C
Compare Register A against 0CH: the NO CARRY FLAG is set for a month outside 1-12.
4EE8
If the NO CARRY FLAG is set (no such month), JUMP back to 4EB4H to ask again.
4EEA
DEC HL 2B
DECrement Register Pair HL: 4302H, the days of January.
4EEB
ADD A,L 85
ADD Register L to Register A (the month less 1).
4EEC
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the days of the month typed (4302H + the month less 1).
4EED
INC DE 13
INCrement Register Pair DE: 4226H, the second field.
4EEE
LD A,(DE) 1A
Fetch the second field, the day, from Register Pair DE into Register A.
4EEF
LD (4457H),A 32 57 44
Store Register A (the day) at 4457H, the day kept over a reset.
4EF2
DEC A 3D
DECrement Register A: the day as 0-30, for the compare with the month's length.
4EF3
CP (HL) BE
Compare Register A against the days of the month at Register Pair HL: the NO CARRY FLAG is set for a day beyond the month.
4EF4
If the NO CARRY FLAG is set (no such day; a day of 0 wraps too), JUMP back to 4EB4H to ask again.
4EF6
INC DE 13
INCrement Register Pair DE: 4227H, the first field.
4EF7
LD A,(DE) 1A
Fetch the month from Register Pair DE into Register A.
4EF8
OR 50H F6 50
OR 50H into Register A: the month OR 50H, the form kept at 442FH.
4EFA
LD (442FH),A 32 2F 44
Store Register A at 442FH: the date is set, so the next reset can use it again.
4EFD
XOR 50H EE 50
Exclusive OR Register A with 50H: Register A = the month again.
4EFFH - The Reset: Store and Display the Date
Stores the month, the day and the year in DATE$ (421AH-421CH), works out the day of the year (4417H, bit 0 of 4418H) and the day of the week (bits 3-1 of 4418H, from 1 for Sunday), and displays the date at 3F17H as, for example, Tue, Jan 1, 1980.
4EFF
LD (421CH),A 32 1C 42
Store Register A (the month) at 421CH, DATE$ +02H. A kept date comes here from 4EB2H.
4F02
LD B,A 47
Copy Register A (the month) into Register B: the count of month lengths to add for the day of the year.
4F03
LD A,(4413H) 3A 13 44
Fetch the years since 1980 from 4413H into Register A.
4F06
PUSH AF F5
Save Register Pair AF (Register A = the years since 1980) to the stack.
4F07
AND 03H E6 03
Mask Register A to bits 1-0: the Z FLAG is set in a leap year.
4F09
LD HL,4303H 21 03 43
Point Register Pair HL to 4303H, the days of February.
4F0C
LD (HL),1CH 36 1C
Store 1CH (28 days) at Register Pair HL (4303H), February in an ordinary year.
4F0E
If the NZ FLAG is set (not a leap year), JUMP to 4F11H.
4F10
INC (HL) 34
INCrement the days of February at Register Pair HL to 29.
4F11
LD A,(4457H) 3A 57 44
Fetch the day from 4457H into Register A, the day stored by the prompt or kept over a reset.
4F14
LD (421BH),A 32 1B 42
Store Register A (the day) at 421BH, DATE$ +01H.
4F17
LD L,A 6F
Copy Register A (the day) into Register L, the low byte of the day of the year.
4F18
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = the day, the start of the day of the year.
4F1A
LD DE,4301H 11 01 43
Point Register Pair DE to 4301H, the byte of the system information sector set to 00H at 4E9EH, before the month lengths.
4F1D
LD A,(DE) 1A
Fetch the length at Register Pair DE into Register A. 4F24H loops back here.
4F1E
ADD A,L 85
ADD Register L (the low byte of the sum so far) to Register A (the length).
4F1F
LD L,A 6F
Copy Register A into Register L: the low byte of the sum.
4F20
ADC A,H 8C
ADD Register H and the CARRY FLAG to Register A (ADC A,H).
4F21
SUB L 95
SUBtract Register L from Register A: Register A = Register H plus the carry out of the low byte.
4F22
LD H,A 67
Copy Register A into Register H: Register Pair HL = the sum so far.
4F23
INC DE 13
INCrement Register Pair DE to the next month's length.
4F24
DECrement Register B and loop back to 4F1DH: the 00H at 4301H and the lengths of the months before this one are added to the day.
4F26
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the day of the year.
4F27
LD HL,4417H 21 17 44
Point Register Pair HL to 4417H, the day of the year.
4F2A
LD (HL),E 73
Store Register E (the low byte of the day of the year) at Register Pair HL (4417H).
4F2B
INC HL 23
INCrement Register Pair HL to 4418H, the date flags.
4F2C
LD A,D 7A
Copy Register D (bit 8 of the day of the year) into Register A.
4F2D
OR (HL) B6
OR the date flags at Register Pair HL (4418H) into Register A.
4F2E
LD (HL),A 77
Store Register A at Register Pair HL (4418H): bit 0 = bit 8 of the day of the year.
4F2F
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the day of the year again.
4F30
POP AF F1
Restore Register Pair AF (Register A = the years since 1980) from the stack.
4F31
LD E,A 5F
Copy Register A (the years since 1980) into Register E.
4F32
ADD A,50H C6 50
ADD 50H (80) to Register A: the year as a number 80-111.
4F34
CP 64H FE 64
Compare Register A against 64H (100): the CARRY FLAG is set for the years 80-99.
4F36
If the CARRY FLAG is set (80-99), JUMP to 4F3AH.
4F38
SUB 64H D6 64
SUBtract 64H (100) from Register A: 2000-2011 become 0-11.
4F3A
LD (421AH),A 32 1A 42
Store Register A (the year, two digits) at 421AH, DATE$ +00H.
4F3D
LD A,E 7B
Copy Register E (the years since 1980) into Register A.
4F3E
ADD A,03H C6 03
ADD 03H to Register A, for the leap days before this year.
4F40
RRCA 0F
Rotate Register A right: first of two rotations that divide by 4.
4F41
RRCA 0F
Rotate Register A right again: second rotation.
4F42
AND 0FH E6 0F
Mask Register A to bits 3-0: Register A = (the years since 1980 + 3) / 4, the leap days of the years before this one.
4F44
ADD A,E 83
ADD Register E (the years since 1980, a day each) to Register A.
4F45
LD E,A 5F
Copy Register A (the days the week has moved) into Register E.
4F46
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the days the week has moved since 1 January 1980.
4F48
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL (the day of the year).
4F49
INC HL 23
INCrement Register Pair HL: 1 January 1980 was a Tuesday, day 3 of the week counted from Sunday.
4F4A
LD A,07H 3E 07
Load Register A with 07H, the days of a week.
4F4C
GOSUB to 4BA8H (@DIV) to divide Register Pair HL by Register A: Register A = the remainder 0-6.
4F4F
INC A 3C
INCrement Register A: the day of the week, 1 for Sunday to 7 for Saturday.
4F50
LD B,A 47
Copy Register A (the day of the week) into Register B, the name number for 5082H.
4F51
RLCA 07
Rotate Register A left: the day of the week into bits 3-1.
4F52
LD C,A 4F
Copy Register A (the day of the week in bits 3-1) into Register C.
4F53
LD HL,4418H 21 18 44
Point Register Pair HL to 4418H, the date flags.
4F56
LD A,(HL) 7E
Fetch the date flags from Register Pair HL into Register A.
4F57
AND F1H E6 F1
Mask Register A with F1H, clearing bits 3-1 of the date flags for the day of the week.
4F59
OR C B1
OR Register C (the day of the week in bits 3-1) into Register A.
4F5A
LD (HL),A 77
Store Register A at Register Pair HL (4418H).
4F5B
LD HL,3F17H 21 17 3F
Point Register Pair HL to 3F17H, the start of the date prompt line.
4F5E
LD (4020H),HL 22 20 40
Store Register Pair HL (3F17H) at 4020H-4021H, the cursor: the date is displayed over the prompt.
4F61
LD HL,43C7H 21 C7 43
Point Register Pair HL to 43C7H, the names of the days in the system information sector.
4F64
GOSUB to 5082H to display name number Register B (the day of the week) of the table at Register Pair HL.
4F67
GOSUB to 5092H to display a comma and a space.
4F6A
LD A,(421CH) 3A 1C 42
Fetch the month from 421CH, DATE$ +02H, into Register A.
4F6D
LD B,A 47
Copy Register A (the month) into Register B, the name number.
4F6E
LD L,DCH 2E DC
Load Register L with DCH: Register Pair HL = 43DCH, the names of the months.
4F70
GOSUB to 5082H to display name number Register B (the month) of the table at Register Pair HL.
4F73
GOSUB to 5097H to display a space after the name of the month.
4F76
LD A,(421BH) 3A 1B 42
Fetch the day from 421BH, DATE$ +01H, into Register A.
4F79
LD D,00H 16 00
Load Register D with 00H: no tens digit of 0 is displayed.
4F7B
GOSUB to 509CH to display Register A (the day) as one or two digits.
4F7E
GOSUB to 5092H to display a comma and a space.
4F81
LD A,(421AH) 3A 1A 42
Fetch the year from 421AH, DATE$ +00H, into Register A (0-99).
4F84
LD D,14H 16 14
Load Register D with 14H (20), the century of the years 00-11.
4F86
CP 0CH FE 0C
Compare Register A (the year) against 0CH: the CARRY FLAG is set for 00-11.
4F88
If the CARRY FLAG is set (00-11), JUMP to 4F8BH with Register D = 20.
4F8A
DEC D 15
DECrement Register D: 13H (19), the century of the years 80-99.
4F8B
PUSH AF F5
Save Register Pair AF (Register A = the year) to the stack.
4F8C
LD A,D 7A
Copy Register D (19 or 20, the century) into Register A for the display.
4F8D
GOSUB to 509CH to display Register A (19 or 20) as two digits (Register D is not 0).
4F90
POP AF F1
Restore Register Pair AF (Register A = the year) from the stack.
4F91
GOSUB to 509CH to display Register A (the year) as two digits, a leading 0 included (Register D is not 0).
4F94H - The Reset: The Time
When the time prompt switch (43C3H) is 00H, Time? is asked at 3F57H: hours, minutes and seconds, two digits each, separated by any character below 3BH (the : included). Seconds, or minutes and seconds, may be left out (they count as 0). A field out of range asks again; a good time goes into TIME$ (4217H-4219H).
4F94
LD A,(43C3H) 3A C3 43
Fetch the time prompt switch from 43C3H into Register A, byte C3H of the system information sector. 4EA5H jumps here when the date is skipped.
4F97
OR A B7
Test Register A (OR A): the Z FLAG is set when the time is to be asked.
4F98
If the NZ FLAG is set (no time prompt), JUMP to 4FC8H.
4F9A
XOR A AF
Set Register A to 00H (XOR A). A time out of range comes back here (4FB4H, 4FBAH, 4FBEH).
4F9B
LD HL,4225H 21 25 42
Point Register Pair HL to 4225H, the three fields.
4F9E
LD (HL),A 77
Store Register A (00H) at Register Pair HL (4225H): seconds 0 when they are not typed.
4F9F
INC HL 23
INCrement Register Pair HL to 4226H, the field of the minutes.
4FA0
LD (HL),A 77
Store Register A (00H) at Register Pair HL (4226H): minutes 0 when they are not typed.
4FA1
INC HL 23
INCrement Register Pair HL to 4227H, the field of the hours.
4FA2
LD (HL),A 77
Store Register A (00H) at Register Pair HL (4227H).
4FA3
PUSH HL E5
Save Register Pair HL (4227H, the hours) to the stack.
4FA4
LD HL,3F57H 21 57 3F
Point Register Pair HL to 3F57H, row 13, column 23 of the screen, where the time prompt goes.
4FA7
LD DE,50BDH 11 BD 50
Point Register Pair DE to 50BDH, the text 1EH Time ? 03H.
4FAA
LD BC,083BH 01 3B 08
Load Register Pair BC with 083BH: Register B = 8, the most characters, Register C = 3BH, the limit for a separator (the : included).
4FAD
GOSUB to 4228H to show the prompt, take the line and parse up to three fields; fewer fields are accepted, the rest stay 0.
4FB0
POP HL E1
Restore Register Pair HL (4227H, the hours) from the stack.
4FB1
LD A,17H 3E 17
Load Register A with 17H (23), the highest hour.
4FB3
CP (HL) BE
Compare Register A against the hours at Register Pair HL: the CARRY FLAG is set for more than 23.
4FB4
If the CARRY FLAG is set (no such hour), JUMP back to 4F9AH to ask again.
4FB6
DEC HL 2B
DECrement Register Pair HL to 4226H, the minutes.
4FB7
LD A,3BH 3E 3B
Load Register A with 3BH (59), the highest minute and second.
4FB9
CP (HL) BE
Compare Register A against the minutes at Register Pair HL.
4FBA
If the CARRY FLAG is set (more than 59 minutes), JUMP back to 4F9AH to ask again.
4FBC
DEC HL 2B
DECrement Register Pair HL to 4225H, the seconds.
4FBD
CP (HL) BE
Compare Register A (59) against the seconds at Register Pair HL.
4FBE
If the CARRY FLAG is set (more than 59 seconds), JUMP back to 4F9AH to ask again.
4FC0
LD DE,4217H 11 17 42
Point Register Pair DE to 4217H, TIME$, the seconds, minutes and hours.
4FC3
LD BC,0003H 01 03 00
Load Register Pair BC with 0003H, the three bytes.
4FC6
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL (4225H: seconds, minutes, hours) to Register Pair DE (4217H-4219H) (LDIR).
4FC8H - The Reset: Drives and the Diskette
Copies the drive code tables of drives 1-7 from the second block of the system information sector, reads the allocation table of the diskette in drive 0 into 4300H, notes a diskette with two sides in drive 0's table and shows the diskette's name and date on the screen (3CD1H, 3CE5H).
4FC8
LD HL,437AH 21 7A 43
Point Register Pair HL to 437AH, drive 1's entry in the second block of drive code tables of the system information sector. 4EADH and 4F98H jump here.
4FCB
LD DE,470AH 11 0A 47
Point Register Pair DE to 470AH, drive 1's entry in DCT$.
4FCE
LD BC,0046H 01 46 00
Load Register Pair BC with 0046H, the 70 bytes of drives 1-7.
4FD1
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL to Register Pair DE (LDIR): drives 1-7 as the system information sector gives them. Register Pair BC ends as 0000H.
4FD3
GOSUB to 4B64H (DIRCYL): Register D = the directory cylinder of drive Register C (0).
4FD6
LD E,C 59
Copy Register C (00H) into Register E: sector 0, the allocation table.
4FD7
LD L,C 69
Copy Register C (00H) into Register L: Register Pair HL = 4300H (Register H is 43H after the copy).
4FD8
GOSUB to 4B45H (RDSSEC) to read cylinder Register D, sector Register E of drive 0 into the buffer at Register Pair HL, the diskette's allocation table.
4FDB
If the NZ FLAG is set (the allocation table could not be read), jump to 4409H (@ERROR) with the error number in Register A.
4FDE
LD L,CDH 2E CD
Load Register L with CDH: Register Pair HL = 43CDH, byte CDH of the allocation table.
4FE0
LD A,(HL) 7E
Fetch byte CDH of the allocation table from Register Pair HL into Register A.
4FE1
AND 20H E6 20
Mask Register A to bit 5: set for a diskette formatted with two sides.
4FE3
LD B,A 47
Copy Register A (the two sides bit) into Register B.
4FE4
LD A,(4704H) 3A 04 47
Fetch byte +04H of drive 0's drive code table from 4704H into Register A.
4FE7
OR B B0
OR Register B (the two sides bit) into Register A.
4FE8
LD (4704H),A 32 04 47
Store Register A at 4704H: bit 5 marks drive 0 as having two sides when the diskette has them.
4FEB
LD L,D0H 2E D0
Load Register L with D0H: Register Pair HL = 43D0H, the name of the diskette in the allocation table.
4FED
LD DE,3CD1H 11 D1 3C
Point Register Pair DE to 3CD1H, row 3, column 17 of the screen.
4FF0
LD BC,0008H 01 08 00
Load Register Pair BC with 0008H, the eight characters of the name.
4FF3
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL (43D0H) to Register Pair DE (3CD1H) (LDIR): the name is shown.
4FF5
LD C,08H 0E 08
Load Register C with 08H, the eight characters of the date (Register B is 00H).
4FF7
LD E,E5H 1E E5
Load Register E with E5H: Register Pair DE = 3CE5H, row 3, column 37.
4FF9
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL (43D8H) to Register Pair DE (3CE5H) (LDIR): the date of the diskette is shown.
4FFBH - The Reset: AUTO, CONFIG/SYS and the Return to LDOS
Decides what runs after the boot. An AUTO command (the allocation table's 43E0H) is taken unless it is empty (0DH) or ENTER (or @) is held; one that starts with 2AH cannot be stopped that way and runs with BREAK disabled. D (or DOWN ARROW) held enters DEBUG. The AUTO command is copied to INBUF$ (4225H). The end of the reset is copied to 405DH and run there, because loading CONFIG/SYS (through @LOAD, 4430H) loads system files over 4E00H-51FFH. CONFIG/SYS is loaded unless byte 01H of the system information sector has bit 1 or bit 7 set or CLEAR (or 9) or SPACE (or /) is held. The return addresses pushed make the last RET display the AUTO command (4467H) and carry it out (4299H), or go to LDOS Ready (4296H).
4FFB
LD A,(HL) 7E
Fetch the first character of the AUTO command from Register Pair HL (43E0H) into Register A.
4FFC
CP 2AH FE 2A
Compare Register A against 2AH: an AUTO command that starts with 2AH runs with BREAK disabled.
4FFE
If the NZ FLAG is set (an ordinary AUTO command), JUMP to 500DH.
5000
INC HL 23
INCrement Register Pair HL past the 2AH: the command proper starts at 43E1H.
5001
LD A,E6H 3E E6
Load Register A with E6H, the second byte of SET 4,(HL).
5003
LD (5058H),A 32 58 50
Store Register A (E6H) at 5058H: the RES 4,(HL) at 5057H becomes SET 4,(HL), so the copy run at 4060H disables BREAK in SFLAG$.
5006
LD A,C8H 3E C8
Load Register A with C8H, the opcode of RET Z.
5008
LD (4BEFH),A 32 EF 4B
Store Register A (C8H) at 4BEFH: request code 01H now returns at once (the DEC A at 4BEEH leaves the Z FLAG set) instead of going to SYS Error.
500B
JUMP to 501AH, past the key test: the command runs whatever keys are held.
500D
LD A,(3841H) 3A 41 38
Fetch 3841H into Register A: keyboard rows 0 and 6 together (bit 0 @ or ENTER, bit 4 D or DOWN ARROW).
5010
BIT 4,A CB 67
Test bit 4 of Register A: the Z FLAG is clear when D or DOWN ARROW is held.
5012
If the NZ FLAG is set (D or DOWN ARROW is held), GOSUB to 440DH (@DEBUG) to enter DEBUG now.
5015
CPL 2F
Complement Register A (the keyboard rows), so that a held key reads 0.
5016
AND 01H E6 01
Mask Register A to bit 0: the Z FLAG is set when @ or ENTER is held.
5018
If the Z FLAG is set (@ or ENTER is held), JUMP to 501DH with the Z FLAG: no AUTO command.
501A
LD A,(HL) 7E
Fetch the first character of the AUTO command from Register Pair HL into Register A.
501B
CP 0DH FE 0D
Compare Register A against 0DH: the Z FLAG is set when the AUTO command is empty.
501D
POP DE D1
Restore Register Pair DE from the stack: Register D = byte 01H of the system information sector, saved at 4EA0H.
501E
LD A,D 7A
Copy Register D (byte 01H of the sector) into Register A. LD does not change the flags.
501F
LD DE,4296H 11 96 42
Point Register Pair DE to 4296H, @CMD, the LDOS Ready loop.
5022
If the Z FLAG is set (no AUTO command), JUMP to 502AH to push only 4296H.
5024
LD E,99H 1E 99
Load Register E with 99H: Register Pair DE = 4299H, @CMNDI, which carries out the command line at Register Pair HL.
5026
PUSH DE D5
Save Register Pair DE (4299H) to the stack: the second return address of the end of the reset.
5027
LD DE,4467H 11 67 44
Point Register Pair DE to 4467H, @DSPLY, to show the AUTO command first.
502A
PUSH DE D5
Save Register Pair DE (4296H, or 4467H in front of 4299H) to the stack.
502B
LD DE,4225H 11 25 42
Point Register Pair DE to 4225H, INBUF$, the command line buffer.
502E
PUSH DE D5
Save Register Pair DE (4225H) to the stack: the end of the reset takes it into Register Pair HL for @DSPLY and @CMNDI (5080H).
502F
LD C,20H 0E 20
Load Register C with 20H, 32 bytes (Register B is 00H).
5031
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL (the AUTO command) to Register Pair DE (4225H) (LDIR).
5033
LD HL,5054H 21 54 50
Point Register Pair HL to 5054H, the end of the reset.
5036
LD DE,405DH 11 5D 40
Point Register Pair DE to 405DH, where the end of the reset runs.
5039
PUSH DE D5
Save Register Pair DE (405DH) to the stack: the RET at 5053H, or the return from @LOAD, goes there.
503A
LD C,2EH 0E 2E
Load Register C with 2EH, the 46 bytes of 5054H-5081H (Register B is 00H).
503C
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL (5054H) to Register Pair DE (405DH) (LDIR).
503E
LD HL,3860H 21 60 38
Point Register Pair HL to 3860H, keyboard rows 5 and 6 together (bit 1 9 or CLEAR, bit 7 / or SPACE).
5041
OR (HL) B6
OR the keyboard rows at Register Pair HL into Register A (byte 01H of the system information sector).
5042
LD DE,4700H 11 00 47
Point Register Pair DE to 4700H, DCT$, where the end of the reset copies the drive tables CONFIG/SYS loads.
5045
LD HL,4152H 21 52 41
Point Register Pair HL to 4152H, where CONFIG/SYS puts the 80 bytes of drive code tables.
5048
LD C,50H 0E 50
Load Register C with 50H, the 80 bytes (Register B is 00H).
504A
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: the copy waits there until 5070H.
504B
LD DE,4245H 11 45 42
Point Register Pair DE to 4245H, the file specification CONFIG/SYS.CCC:0.
504E
AND 82H E6 82
Mask Register A with 82H, bits 7 and 1: the Z FLAG is set when CONFIG/SYS is to be loaded.
5050
If the Z FLAG is set, jump to 4430H (@LOAD) to load CONFIG/SYS; it returns to 405DH with the Z FLAG when it was loaded.
5053
RET C9
RETurn to 405DH with the NZ FLAG: no CONFIG/SYS.
5054H - The End of the Reset, Run at 405DH
5054H-5081H run as a copy at 405DH-408AH (5033H-503CH). The Z FLAG says whether CONFIG/SYS was loaded. Each comment gives the address the instruction runs at.
5054
LD HL,442BH 21 2B 44
Runs at 405DH. Point Register Pair HL to 442BH, SFLAG$, the system flags.
5057
RES 4,(HL) CB A6
Runs at 4060H. Reset bit 4 of SFLAG$ at Register Pair HL: BREAK enabled. For an AUTO command that starts with 2AH the reset has changed this to SET 4,(HL) (5003H).
5059
Runs at 4062H. If the NZ FLAG is set (CONFIG/SYS was not loaded), JUMP to 5075H, at 407EH in the copy.
505B
BIT 3,(HL) CB 5E
Runs at 4064H. Test bit 3 of SFLAG$ at Register Pair HL, FAST.
505D
Runs at 4066H. If the Z FLAG is set (not FAST), JUMP to 506AH, at 4073H in the copy.
505F
LD BC,78ECH 01 EC 78
Runs at 4068H. Load Register Pair BC with 78ECH: Register B = 78H (the bits 6-3 of port ECH), Register C = ECH, the port.
5062
LD HL,4210H 21 10 42
Runs at 406BH. Point Register Pair HL to 4210H, the copy of port ECH.
5065
LD A,(HL) 7E
Runs at 406EH. Fetch the copy of port ECH from Register Pair HL into Register A.
5066
OR B B0
Runs at 406FH. OR Register B (78H) into Register A: bit 6, the faster CPU clock, is added to the bits set at 4E24H.
5067
LD (HL),A 77
Runs at 4070H. Store Register A at Register Pair HL (4210H).
5068
OUT (C),A ED 79
Runs at 4071H. Send Register A to port Register C (ECH).
506A
LD A,(4213H) 3A 13 42
Runs at 4073H. Fetch the interrupt mask from 4213H into Register A.
506D
OUT (E0H),A D3 E0
Runs at 4076H. Send Register A to port E0H, the interrupt mask, again.
506F
EXX D9
Runs at 4078H. Exchange Register Pairs BC, DE and HL with the alternate set: Register Pair HL = 4152H, Register Pair DE = 4700H, Register Pair BC = 0050H.
5070
LDIR ED B0
Runs at 4079H. Copy Register Pair BC bytes from Register Pair HL (4152H) to Register Pair DE (4700H) (LDIR): the drive code tables of the configuration.
5072
Runs at 407BH. GOSUB to 421DH (@ICNFG), a RET unless the configuration put a jump there.
5075
LD HL,3F40H 21 40 3F
Runs at 407EH. Load Register Pair HL with 3F40H, row 13, column 0 of the screen.
5078
LD (4020H),HL 22 20 40
Runs at 4081H. Store Register Pair HL (3F40H) at 4020H-4021H, the cursor.
507B
LD HL,4012H 21 12 40
Runs at 4084H. Point Register Pair HL to 4012H, the RST 38H vector.
507E
LD (HL),C3H 36 C3
Runs at 4087H. Store C3H (JP) at Register Pair HL (4012H): the interrupt vector is a jump to 44A5H again.
5080
POP HL E1
Runs at 4089H. Restore Register Pair HL from the stack: 4225H, INBUF$ (pushed at 502EH).
5081
RET C9
Runs at 408AH. RETurn to 4467H (@DSPLY, then 4299H, @CMNDI) for an AUTO command, or to 4296H (@CMD), LDOS Ready.
5082H - The Reset's Display Helpers
5082H displays three letter name number Register B of the table at Register Pair HL; 5092H a comma and a space; 5097H a space; 509CH Register A (0-99) as two digits, the tens left out when it is 0 and Register D is 0. All display through the ROM at 0033H.
5082
DEC B 05
DECrement Register B: the name number from 0.
5083
LD A,L 7D
Copy Register L (the low byte of the table) into Register A.
5084
ADD A,B 80
ADD Register B to Register A: first of three additions, the name number times 3.
5085
ADD A,B 80
ADD Register B to Register A again: second addition.
5086
ADD A,B 80
ADD Register B to Register A again: Register A = the low byte of the table + Register B x 3.
5087
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the name (the tables lie in one page).
5088
LD B,03H 06 03
Load Register B with 03H, the three letters of a name.
508A
LD A,(HL) 7E
Fetch the next letter from Register Pair HL into Register A. 508FH loops back here.
508B
INC HL 23
INCrement Register Pair HL to the next letter.
508C
GOSUB to the ROM's 0033H to display the character in Register A at the cursor.
508F
DECrement Register B and loop back to 508AH until the three letters are displayed.
5091
RET C9
RETurn to the caller with the name displayed at the cursor.
5092
LD A,2CH 3E 2C
Load Register A with 2CH, the comma, to display before the space.
5094
GOSUB to the ROM's 0033H to display the comma in Register A.
5097
LD A,20H 3E 20
Load Register A with 20H, the space, which 5092H also comes on to.
5099
Jump to the ROM's 0033H to display the space in Register A; it returns to the caller.
509C
LD E,2FH 1E 2F
Load Register E with 2FH, one below the character 0: the tens digit counts up from here.
509E
INC E 1C
INCrement Register E, the tens digit. 50A1H loops back here.
509F
SUB 0AH D6 0A
SUBtract 0AH (10) from Register A, the value still to count.
50A1
If the NO CARRY FLAG is set (10 more taken away), JUMP back to 509EH.
50A3
PUSH AF F5
Save Register Pair AF (Register A = the units less 10) to the stack.
50A4
LD A,D 7A
Copy Register D (the leading zero switch) into Register A.
50A5
OR A B7
Test Register A (OR A): the Z FLAG is set when a tens digit of 0 is not to be shown.
50A6
LD A,E 7B
Copy Register E (the tens digit) into Register A. LD does not change the flags.
50A7
If the NZ FLAG is set (Register D is not 0), JUMP to 50ABH to display the tens digit whatever it is.
50A9
CP 30H FE 30
Compare Register A (the tens digit) against 30H, the character 0: the Z FLAG is set when the tens are 0.
50AB
If the NZ FLAG is set, GOSUB to the ROM's 0033H to display the tens digit in Register A.
50AE
POP AF F1
Restore Register Pair AF (Register A = the units less 10) from the stack.
50AF
ADD A,3AH C6 3A
ADD 3AH to Register A: the units digit as its character (the 10 taken away too many is added back).
50B1
Jump to the ROM's 0033H to display the units digit in Register A; it returns to the caller.
50B4
DEFB 1EH 1E
50B4H: 1EH, the control code that clears to the end of the line, the start of the date prompt that 4EB7H passes to 4228H.
50B5-50BB
DEFM "Date ? " 44 61 74 65 20 3F 20
50B5H-50BBH: the text Date ? and a space, displayed at 3F17H.
50BC
DEFB 03H 03
50BCH: 03H, the end of the date prompt (not displayed).
50BD
DEFB 1EH 1E
50BDH: 1EH, the control code that clears to the end of the line, the start of the time prompt that 4FA7H passes to 4228H.
50BE-50C4
DEFM "Time ? " 54 69 6D 65 20 3F 20
50BEH-50C4H: the text Time ? and a space, displayed at 3F57H.
50C5
DEFB 03H 03
50C5H: 03H, the end of the time prompt (not displayed).
50C6-50FF
DEFB 00H x 58 00 x 58
50C6H-50FFH: 58 bytes of 00H, the end of SYS0/SYS's last load block. No instruction of SYS0/SYS addresses them.