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

Page Customization

Introduction/Summary

NEWDOS/80 v2.0 SYS3/SYS Disassembly - CLOSE, KILL, Timer Chain and Library Commands (Model I)

SYS3/SYS is a one-granule overlay that loads into the overlay area at 4D00H-51DFH (1,248 bytes in five load records, transfer address 4D00H). The manual (section 5.2) describes it as the overlay that closes FCBs, kills files, and inserts and deletes entries in the 25 ms timer chain, and as the executor of the library commands BLINK, BREAK, CLOCK, DEBUG, JKL, LCDVR, LC, VERIFY and most of PURGE. It is called with LD A,code / RST 28H; the SYS0 dispatcher (4BC2H) loads it when 4317H does not already hold its number, 05H, and calls 4D00H with the caller's registers.

The page shows every byte of the file once, in address order. The file on the system diskette has the mandatory zaps applied (see Zaps).

RST 28H Codes Handled by SYS3

CodeCalled fromFunction
25H4428HCLOSE an FCB (4E25H): write the buffer, write the EOF into the FPDE, release the granules beyond the EOF, turn the FCB back into a filespec.
45H442CHKILL the FCB's file (4E09H): release its granules and directory entries, clear the FCB.
65H4410HPut a timer routine into the 25 ms chain (4D47H).
85H4413HTake a timer routine out of the chain (4D55H).
A5HSYS0 45BFH (J-K-L)Print the screen (5182H).
C5H4451HWrite the FCB's EOF into the directory (5050H).
E5H, C = 1SYS1 (BLINK)Cursor blink on or off (4DABH).
E5H, C = 2SYS1 (CLOCK)Clock display on or off (4D70H).
E5H, C = 3SYS1 (DEBUG)DEBUG before the next program (4DB8H).
E5H, C = 4SYS1 (VERIFY)Verify every sector write (4DC5H).
E5H, C = 5SYS1 (BREAK)BREAK key on or off (4DDBH).
E5H, C = 6SYS7 4D69H (PURGE)The PURGE directory scan and questions (505DH).
E5H, C = 7SYS3 500DH through SYS0 49D7HWrite the FCB's EOF into the FPDE (5018H).
E5H, C = 8SYS1 (LCDVR)Lower case driver on or off (4D82H).
E5H, C = 9SYS1 (LC)Keyboard a-z toggle (4DA2H).
anything elseSYS6 568DH (C = FFH)Error 2AH (4D43H). SYS6 uses this to load SYS3 without running anything, then calls 4E3DH itself (60A9H) with the mode at 4FDBH set to CLOSE, to release the granules beyond a copied file's EOF.

The library command routines take HL pointing to the parameter after the command word and return Register A = 0 with the Z FLAG, or an error code with NZ. The Y/N parameter reader at 4DEFH takes a missing parameter as Y.

How CLOSE and KILL Release Space

CLOSE and KILL share one routine, told apart by the mode byte at 4FDBH (00H CLOSE, 01H KILL):

  1. Granules to keep. CLOSE works out from the EOF how many granules the file needs (4E3DH: sectors rounded up, divided by 5 and rounded up). KILL keeps none.
  2. Granules owned. The extent elements of the FPDE and every FXDE (entry bytes 22-31: lump, then first granule in bits 5-7 and granules minus 1 in bits 0-4; FEH = the next entry's DEC follows, FFH = end) are added up (4E52H). A wrong entry or a link that is not in the fifth element is error 2CH.
  3. Work maps. SYS3 overwrites its own code at 4D00H-4DDFH with two maps and clears the overlay number at 4317H (4E95H): 4D00H-4DBFH is a mask for GAT bytes 00H-BFH, 4DC0H-4DDFH a map with one bit per DEC.
  4. Freeing. Working back from the last element (4EC1H), one granule at a time is cleared in the mask until the excess is gone. CLOSE shortens the elements and turns an emptied element into the end mark FFH FFH; an FXDE left with no elements, and for KILL every entry, is freed by clearing bit 4 of its first byte and marking its DEC in the HIT map (4FE5H).
  5. GAT and HIT. The GAT (4F33H) and the HIT (4F56H) are read, changed and written only if the maps mark anything.
  6. The FCB. CLOSE rewrites the FCB as NAME/EXT:d ended by 03H; KILL sets its 32 bytes to 00H (4F7DH). Neither is done while bit 2 of 436BH is set (SYS6).

CLOSE does not release anything when the file may not be written (access level 5 or more), when bit 6 of FCB+2 (the no-deallocate bit copied from the FPDE) is set, or when the file needs all its granules. When it does have excess granules, it first writes back the directory sector it last read (4EBAH); if that write fails it skips the release, and the error code is not returned.

Zaps

From the official zap list: zap 035 (mandatory, directory clobbering when CLOSE or KILL frees an entry in the first slot of a sector) is applied at 4EC3H-4ECAH. Zap 046 (optional, J-K-L graphics for Epson printers, at 51A5H, 51ABH and 51B4H) is not applied.

SYS6 exchanges nine SYS3 locations with its own values while it copies a diskette whose PDRIVE entry has TI flag M, bit 5 of 430CH (patch list at 5BE1H of SYS6): 4E40H, 4E61H, 4E6CH, 4E72H-4E74H, 4E8BH, 4ECEH, 4EDAH, 4EEFH-4EF0H and 5032H. The page shows the NEWDOS/80 values in the file.

Variables

Memory Used by SYS3

Address
Size
Contents
4D00H-4DBFH
192 bytes
GAT Mask
During CLOSE and KILL only, over the code of SYS3 (4E9EH): FFH = keep, a 0 bit = free that granule. Filled at 4F16H, applied to the GAT at 4F4BH.
4DC0H-4DDFH
32 bytes
HIT Map
During CLOSE and KILL only: one bit per DEC, bit 7 of 4DC0H for DEC 00H. Set at 5009H; a set bit clears the HIT byte of that DEC at 4F72H.
4EC4H
1 byte
Entry Being Worked On (Self-Modifying Code)
Operand of the LD E,nn at 4EC3H, stored at 4E59H and 4ED6H: the offset in 4200H of the directory entry being worked on. Read at 4FE5H.
4FDBH
1 byte
Mode (Self-Modifying Code)
Operand of the LD A,nn at 4FDAH, stored at 4E1FH (KILL, 01H) and 4E29H (CLOSE, 00H), and by SYS6 at 60ADH. Read at 4EB0H, 4EDCH and 4F22H.
5153H
1 byte
FDE Sectors (Self-Modifying Code)
Operand of the CP nn at 5152H, stored at 50B3H: the number of FDE sectors PURGE scans (8 + HIT byte 1FH).
5163H
1 byte
PURGE Options
Bit 0 /ext given, bit 1 USR given. Stored at 50A5H, read at 50CAH.
5164H-5166H
3 bytes
PURGE Extension
The wanted extension, three spaces in the file, filled at 5086H and compared at 50DCH.
3840H
1 byte
Keyboard Row 6
Bit 2 is the BREAK key, tested by the screen print at 5185H.
3C00H-3FFFH
1,024 bytes
Display Memory
Sent to the printer by the J-K-L screen print (5182H).
421FH
1 byte
HIT Byte 1FH
The number of FDE sectors over 8, read by PURGE at 50AEH.
4200H-42FFH
256 bytes
Directory Sector Buffer
The SYS0 directory routines read the GAT, the HIT and FDE sectors here.
4308H
1 byte
Current Drive
The drive of the file, put into the filespec at 4FB7H.
430FH
1 byte
Granules per Lump
IY-71H. Read at 4F01H.
4312H-4314H
3 bytes
BREAK Hook
JP 45B0H or RET, set by BREAK (4DE1H, 4DEAH).
4317H
1 byte
Overlay Number
Cleared at 4E9AH so that SYS3 is reloaded after its code has been used as work space.
4369H
1 byte
DOS Flags
Bit 7, DEBUG enabled, set and reset by DEBUG (4DBEH, 4DC1H).
436BH
1 byte
Temporary Flags
Bit 2 (set by SYS6) skips the FCB rewrite at 4F80H.
4370H
1 byte
Option AX
The highest code the printer can print, read by the screen print at 51A6H.
4480H-449FH
32 bytes
DOS FCB
PURGE kills through it: FCB+0 = 80H (513BH), FCB+7 = the DEC (50F1H).
44A0H
block
Clock Timer Block
Taken out of and put back into the timer chain by CLOCK (4D70H).
4502H
1 byte
Cursor Blink
RET Z (blink) or RET (no blink), set by BLINK (4DB1H, 4DB4H).
4505H
1 byte
Display Driver
JR (18H) or JR C (38H), set by LCDVR (4D93H).
4593H
1 byte
Keyboard Case Handling
RET (C9H) or LD C,A (4FH), set by LCDVR (4D8FH).
45B4H
1 byte
a-z Toggle
NOP (convert to upper case) or RET (accept a-z), set by LC and LCDVR (4D9DH).
461DH-461EH
2 bytes
Timer Chain Head
The operand of the SYS0 LD HL,nnnn at 461CH, changed by the enqueue (4D4BH) and the dequeue (4D57H).
4A88H-4A8AH
3 bytes
Verify Switch
LD A,(IX+01H) or NOP / LD A,0FFH in the SYS0 sector write, set by VERIFY (4DD3H, 4DD6H).

Outside Routines Called

AddressContents
0033HROM: display the character in Register A (5105H, 5125H, 512AH, 515DH).
003BHROM: send the character in Register A to the printer (5196H, 51AFH).
0049HROM: wait for a key (5113H).
4409HSYS0: the error exit that displays the error and returns to DOS READY (4E03H).
4410H, 4413HSYS0: enqueue and dequeue a timer routine, which come back into SYS3 (4D7DH, 4D78H).
4467HSYS0: display a message (5110H).
47ECHSYS0: select a drive and check for a turning diskette (5060H).
490AHSYS0: read directory sector Register A into 4200H (4F42H, 4F62H, 50AAH).
491FHSYS0: write the directory sector in 4200H (4E82H, 4EBAH).
492FH, 4936HSYS0: read the FDE sector of the DEC in Register A, if needed (4E7DH) or always (50B8H, 5142H).
494BHSYS0: read the FPDE of the open FCB at Index Register IX (4E0CH, 5018H).
4980HSYS0: check that the FCB is open and run the rest as a DOS function (4E09H, 4E17H, 4E25H, 5050H).
49B9HSYS0: check the access level of the FCB against Register B (4E12H).
49CDHSYS0: the error exit of a DOS function (4E79H).
49D7HSYS0: the return point that chains to another overlay function, pushed at 5011H.
4A62HSYS0: write the buffer of the FCB if it holds changed data (5015H).
4CB2HSYS0: divide Register Pair HL by 5 (4E42H).
4CD5HSYS0: test for the end of the command line or a separator (4D96H, 4E00H, 5064H).

Disassembly

4D00H - Function Dispatcher

SYS3 is entered here by the SYS0 RST 28H dispatcher (4BC2H) with Register A = the RST 28H code and the caller's Register Pairs BC, DE and HL unchanged. Bits 5-7 of the code are the function number (bits 0-4 = 05H, SYS3's directory slot): 25H CLOSE (4428H), 45H KILL (442CH), 65H enqueue a timer routine (4410H), 85H dequeue a timer routine (4413H), A5H the J-K-L screen print (SYS0 45BFH), C5H write EOF (4451H). Function 7 (E5H) takes a sub-function in Register C: 1 BLINK, 2 CLOCK, 3 DEBUG, 4 VERIFY, 5 BREAK, 6 PURGE (chained from SYS7), 7 EOF to the FPDE (chained from 500DH), 8 LCDVR, 9 LC. Any other code or sub-function returns error 2AH; SYS6 (568DH) relies on this to load SYS3 with Register C = FFH and then use its code. The first 224 bytes (4D00H-4DDFH) are also used as work space by CLOSE and KILL once this code has run (4E9EH).

4D00
CP 25H FE 25
Compare Register A (the RST 28H code) against 25H, function 1: CLOSE (the 4428H vector).
4D02
If the Z FLAG is set (Register A = 25H), JUMP to 4E25H to close the FCB at Register Pair DE.
4D05
CP 45H FE 45
Compare Register A (the RST 28H code) against 45H, function 2: KILL (the 442CH vector).
4D07
If the Z FLAG is set (Register A = 45H), JUMP to 4E09H to kill the file of the FCB at Register Pair DE.
4D0A
CP 65H FE 65
Compare Register A (the RST 28H code) against 65H, function 3: enqueue a timer routine (the 4410H vector).
4D0C
If the Z FLAG is set (Register A = 65H), JUMP to 4D47H to put the block at Register Pair DE into the timer chain.
4D0E
CP 85H FE 85
Compare Register A (the RST 28H code) against 85H, function 4: dequeue a timer routine (the 4413H vector).
4D10
If the Z FLAG is set (Register A = 85H), JUMP to 4D55H to take the block at Register Pair DE out of the timer chain.
4D12
CP A5H FE A5
Compare Register A (the RST 28H code) against A5H, function 5: the J-K-L key combination found by SYS0 at 45BFH.
4D14
If the Z FLAG is set (Register A = A5H), JUMP to 5182H to print the screen.
4D17
CP C5H FE C5
Compare Register A (the RST 28H code) against C5H, function 6: write the EOF (the 4451H vector).
4D19
If the Z FLAG is set (Register A = C5H), JUMP to 5050H to write the EOF of the FCB at Register Pair DE.
4D1C
CP E5H FE E5
Compare Register A (the RST 28H code) against E5H, function 7, whose sub-function is in Register C.
4D1E
If the NZ FLAG is set (any other code), JUMP to 4D43H to return error 2AH.
4D20
DEC C 0D
Function 7: DECrement Register C (the sub-function). The Z FLAG is set for sub-function 1.
4D21
If the Z FLAG is set (Register C was 1, BLINK), JUMP to 4DABH.
4D24
DEC C 0D
DECrement Register C (the sub-function) again. The Z FLAG is set for sub-function 2.
4D25
If the Z FLAG is set (Register C was 2, CLOCK), JUMP to 4D70H.
4D27
DEC C 0D
DECrement Register C (the sub-function) again. The Z FLAG is set for sub-function 3.
4D28
If the Z FLAG is set (Register C was 3, DEBUG), JUMP to 4DB8H.
4D2B
DEC C 0D
DECrement Register C (the sub-function) again. The Z FLAG is set for sub-function 4.
4D2C
If the Z FLAG is set (Register C was 4, VERIFY), JUMP to 4DC5H.
4D2F
DEC C 0D
DECrement Register C (the sub-function) again. The Z FLAG is set for sub-function 5.
4D30
If the Z FLAG is set (Register C was 5, BREAK), JUMP to 4DDBH.
4D33
DEC C 0D
DECrement Register C (the sub-function) again. The Z FLAG is set for sub-function 6.
4D34
If the Z FLAG is set (Register C was 6, PURGE, chained from SYS7 4D69H with Register B = the drive number), JUMP to 505DH.
4D37
DEC C 0D
DECrement Register C (the sub-function) again. The Z FLAG is set for sub-function 7.
4D38
If the Z FLAG is set (Register C was 7, write the EOF of the FCB into its FPDE, chained from 500DH through SYS0 49D7H), JUMP to 5018H.
4D3B
DEC C 0D
DECrement Register C (the sub-function) again. The Z FLAG is set for sub-function 8.
4D3C
If the Z FLAG is set (Register C was 8, LCDVR), JUMP to 4D82H.
4D3F
DEC C 0D
DECrement Register C (the sub-function) again. The Z FLAG is set for sub-function 9.
4D40
If the Z FLAG is set (Register C was 9, LC), JUMP to 4DA2H. Any other sub-function (0, 10 and up, and the FFH that SYS6 uses to load SYS3) goes on into 4D43H.

4D43H - Return Error 2AH

Reached from the dispatcher for an unknown function code or function 7 sub-function.

4D43
LD A,2AH 3E 2A
Load Register A with error code 2AH (ILLEGAL DOS FUNCTION).
4D45
OR A B7
OR Register A (2AH) with itself to set the NZ FLAG, since Register A is not zero.
4D46
RET C9
RETurn to the caller of the RST 28H with error 2AH in Register A and the NZ FLAG set.

4D47H - Function 65H: Enqueue a Timer Routine (4410H)

Manual section 3.8. Register Pair DE points to the caller's timer routine block: bytes 0-1 the forward link (filled in here), byte 2 the interval in 25 ms ticks, byte 3 the countdown, the routine itself from byte 4. The block is put at the head of the chain whose head pointer is the operand of the SYS0 LD HL,nnnn at 461CH (the operand is at 461DH-461EH), which the timer tick (4610H) walks every 25 ms.

4D47
DI F3
Disable interrupts, so that the timer tick at 4610H cannot walk the chain while it is being changed.
4D48
LD HL,(461DH) 2A 1D 46
Fetch the chain head from 461DH-461EH (the operand of the SYS0 LD HL,nnnn at 461CH) into Register Pair HL: the first block in the chain, or 0000H if the chain is empty.
4D4B
LD (461DH),DE ED 53 1D 46
Store Register Pair DE (the caller's new block) at 461DH-461EH: the new block becomes the head of the chain.
4D4F
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the link to set (byte 0 of the new block), Register Pair DE = the value for it (the old chain head). The dequeue (4D6EH) comes here with Register Pair HL = the block after the removed one and Register Pair DE = the link that pointed to the removed block.
4D50
LD (HL),E 73
Store Register E (the low byte of the link value) at Register Pair HL, byte 0 of the link.
4D51
INC HL 23
INCrement Register Pair HL to byte 1 of the link.
4D52
LD (HL),D 72
Store Register D (the high byte of the link value) at Register Pair HL: the link now points to the next block.
4D53
EI FB
Enable interrupts again. 4D61H comes here when the dequeue did not find the block.
4D54
RET C9
RETurn to the caller of the RST 28H. The enqueue and the dequeue give no result; Register A holds whatever was last loaded into it.

4D55H - Function 85H: Dequeue a Timer Routine (4413H)

Manual section 3.9. Register Pair DE points to the block to take out of the timer chain. The links are followed from the chain head at 461DH; when a link points to the block, that link is replaced by the block's own link. A block that is not in the chain is ignored.

4D55
LD B,D 42
Copy Register D (the high byte of the block to remove) into Register B.
4D56
LD C,E 4B
Copy Register E (the low byte) into Register C: Register Pair BC = the block to remove.
4D57
LD HL,461DH 21 1D 46
Point Register Pair HL to 461DH, where the chain head is kept: the first link to examine.
4D5A
DI F3
Disable interrupts, so that the timer tick at 4610H cannot walk the chain while it is being changed.

Chain Loop
Register Pair HL = the low byte of the link being examined.

4D5B
LD E,(HL) 5E
Fetch the low byte of the link at Register Pair HL into Register E.
4D5C
INC HL 23
INCrement Register Pair HL to the high byte of the link.
4D5D
LD D,(HL) 56
Fetch the high byte of the link at Register Pair HL into Register D: Register Pair DE = the block this link points to.
4D5E
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the block the link points to, Register Pair DE = the high byte of the link.
4D5F
LD A,H 7C
Copy Register H (the high byte of the block address) into Register A.
4D60
OR L B5
OR Register L (the low byte) into Register A: the Z FLAG is set if the link is 0000H, the end of the chain.
4D61
If the Z FLAG is set (the end of the chain and the block was not in it), JUMP to 4D53H to enable interrupts and return.
4D63
OR A B7
Clear the CARRY FLAG with OR Register A, ready for the SBC.
4D64
SBC HL,BC ED 42
SUBtract Register Pair BC (the block to remove) from Register Pair HL (the block the link points to): the Z FLAG is set if they are the same.
4D66
ADD HL,BC 09
ADD Register Pair BC back to Register Pair HL: Register Pair HL = the block address again. ADD HL,BC does not change the Z FLAG.
4D67
If the NZ FLAG is set (another block), LOOP BACK to 4D5BH to examine that block's own link (Register Pair HL = its byte 0).
4D69
DEC DE 1B
Found. DECrement Register Pair DE to the low byte of the link that points to the block.
4D6A
LD A,(HL) 7E
Fetch the low byte of the removed block's own link at Register Pair HL into Register A.
4D6B
INC HL 23
INCrement Register Pair HL to the high byte of that link.
4D6C
LD H,(HL) 66
Fetch the high byte at Register Pair HL into Register H.
4D6D
LD L,A 6F
Copy Register A (the low byte) into Register L: Register Pair HL = the block after the removed one, or 0000H.
4D6E
JUMP to 4D4FH to store Register Pair HL into the link at Register Pair DE, enable interrupts and return.

4D70H - Function E5H Sub-function 2: CLOCK

CLOCK[,Y|N] (manual 2.12). The clock display routine is the timer block at 44A0H in SYS0 (its routine at 44A4H shows the time on the top line). It is always dequeued first, so it is never in the chain twice, and enqueued again for Y.

4D70
LD DE,44A0H 11 A0 44
Point Register Pair DE to 44A0H, the SYS0 timer block that displays the clock.
4D73
GOSUB to 4DEFH to read the Y/N parameter at Register Pair HL (the command line after CLOCK). The Z FLAG returns for N, the NZ FLAG for Y or no parameter.
4D76
PUSH DE D5
Save Register Pair DE (44A0H, the clock block) onto the stack.
4D77
PUSH AF F5
Save Register Pair AF (the Y/N answer in the flags) onto the stack.
4D78
GOSUB to 4413H (SYS0) to take the block at Register Pair DE (44A0H) out of the timer chain. The vector does an RST 28H with code 85H back into SYS3 (4D55H).
4D7B
POP AF F1
Restore Register Pair AF from the stack: the Y/N answer in the flags.
4D7C
POP DE D1
Restore Register Pair DE from the stack: 44A0H, the clock block.
4D7D
If the NZ FLAG is set (Y or no parameter), GOSUB to 4410H (SYS0) to put the block at Register Pair DE back into the timer chain (RST 28H code 65H, 4D47H).
4D80
XOR A AF
Set Register A to 0 with XOR, which also sets the Z FLAG: no error.
4D81
RET C9
RETurn to SYS1 with Register A = 00H and the Z FLAG.

4D82H - Function E5H Sub-function 8: LCDVR

LCDVR[,x[,s]] (manual 2.29). The first parameter switches the lower case driver built into SYS0: 4593H is the first byte of the case handling in the keyboard driver (RET = off, LD C,A = on) and 4505H is the first byte of the display driver (JR = straight to the ROM routine at 0458H, JR C = characters 20H-7FH go to ROM 047DH without the upper case conversion). The second parameter sets the a-z toggle like LC; without it the toggle is set to convert to upper case. Option BF does the same at reset.

4D82
GOSUB to 4DF4H to read the first Y/N parameter at Register Pair HL (the command line after LCDVR). The Z FLAG returns for N, the NZ FLAG for Y or no parameter; Register Pair HL is left after the Y or N.
4D85
LD A,C9H 3E C9
Load Register A with C9H (the RET opcode) for the keyboard case handling at 4593H: off.
4D87
LD C,18H 0E 18
Load Register C with 18H (the JR opcode) for the display driver at 4505H: go to the ROM routine unchanged.
4D89
If the Z FLAG is set (N), JUMP to 4D8FH to store the two opcodes in Register A and Register C.
4D8B
LD A,4FH 3E 4F
Y: load Register A with 4FH (the LD C,A opcode) for 4593H, which lets the keyboard case handling run.
4D8D
LD C,38H 0E 38
Load Register C with 38H (the JR C opcode) for 4505H, which sends characters 20H-7FH to ROM 047DH so that lower case is displayed.
4D8F
LD (4593H),A 32 93 45
Store Register A (C9H for N, 4FH for Y) at 4593H in the SYS0 keyboard driver.
4D92
LD A,C 79
Copy Register C (18H for N, 38H for Y) into Register A.
4D93
LD (4505H),A 32 05 45
Store Register A at 4505H, the first byte of the SYS0 display driver.
4D96
GOSUB to 4CD5H (SYS0) to test what follows the first parameter at Register Pair HL: the Z FLAG at the carriage return, the NZ FLAG and NO CARRY after a comma or spaces (Register Pair HL moved past them), the CARRY FLAG for anything else. Register A returns 34H.
4D99
RET C D8
If the CARRY FLAG is set (anything else follows), RETurn with Register A = 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR) and the NZ FLAG.
4D9A
If the NZ FLAG is set (a separator follows), JUMP to 4DA2H to read the second parameter the same way as the LC command.
4D9C
XOR A AF
No second parameter: set Register A to 00H (the NOP opcode) with XOR. LC,N (4DA5H) comes here too.
4D9D
LD (45B4H),A 32 B4 45
Store Register A at 45B4H, the a-z toggle in the SYS0 keyboard driver: 00H (NOP) converts a-z to A-Z, C9H (RET, from 4DA9H) accepts a-z. SHIFT-0 flips this byte.
4DA0
XOR A AF
Set Register A to 0 with XOR, which also sets the Z FLAG: no error.
4DA1
RET C9
RETurn to SYS1 with Register A = 00H and the Z FLAG.

4DA2H - Function E5H Sub-function 9: LC

LC[,Y|N] (manual 2.28), and the second parameter of LCDVR (from 4D9AH). Sets the a-z toggle at 45B4H in the SYS0 keyboard driver.

4DA2
GOSUB to 4DEFH to read the Y/N parameter at Register Pair HL; nothing may follow it. The Z FLAG returns for N, the NZ FLAG for Y or no parameter.
4DA5
If the Z FLAG is set (N), JUMP to 4D9CH to store 00H (NOP, convert a-z to upper case) at 45B4H.
4DA7
LD A,C9H 3E C9
Y: load Register A with C9H (RET, accept a-z unchanged).
4DA9
JUMP to 4D9DH to store Register A (C9H) at 45B4H.

4DABH - Function E5H Sub-function 1: BLINK

BLINK[,Y|N] (manual 2.6). 4502H is the first byte of the cursor timer routine in SYS0 (the 44EBH block): RET Z (C8H) lets the cursor blink, RET (C9H) stops the blinking. Option BH sets it at reset.

4DAB
GOSUB to 4DEFH to read the Y/N parameter at Register Pair HL; nothing may follow it. The Z FLAG and Register A = 00H return for N, the NZ FLAG for Y or no parameter.
4DAE
LD HL,4502H 21 02 45
Point Register Pair HL to 4502H, the byte in the SYS0 cursor timer routine that decides whether the cursor blinks.
4DB1
LD (HL),C9H 36 C9
Store C9H (RET) at Register Pair HL (4502H): no blinking. LD does not change the flags.
4DB3
RET Z C8
If the Z FLAG is set (N), RETurn to SYS1 with Register A = 00H (set by 4DEFH) and the Z FLAG.
4DB4
LD (HL),C8H 36 C8
Y: store C8H (RET Z) at Register Pair HL (4502H) instead: the cursor blinks.
4DB6
XOR A AF
Set Register A to 0 with XOR, which also sets the Z FLAG: no error.
4DB7
RET C9
RETurn to SYS1 with Register A = 00H and the Z FLAG.

4DB8H - Function E5H Sub-function 3: DEBUG

DEBUG[,Y|N] (manual 2.18). Bit 7 of 4369H is the DEBUG enable flag: SYS2 (4D88H) tests it after loading a program with load-and-run and enters DEBUG (440DH) instead of starting the program.

4DB8
GOSUB to 4DEFH to read the Y/N parameter at Register Pair HL; nothing may follow it. The Z FLAG and Register A = 00H return for N, the NZ FLAG for Y or no parameter.
4DBB
LD HL,4369H 21 69 43
Point Register Pair HL to 4369H, the DOS flag byte.
4DBE
RES 7,(HL) CB BE
Reset bit 7 of the byte at Register Pair HL (4369H): DEBUG disabled. RES does not change the flags.
4DC0
RET Z C8
If the Z FLAG is set (N), RETurn to SYS1 with Register A = 00H and the Z FLAG.
4DC1
SET 7,(HL) CB FE
Y: set bit 7 of the byte at Register Pair HL (4369H): DEBUG is entered before the next program started with load-and-run.
4DC3
XOR A AF
Set Register A to 0 with XOR, which also sets the Z FLAG: no error.
4DC4
RET C9
RETurn to SYS1 with Register A = 00H and the Z FLAG.

4DC5H - Function E5H Sub-function 4: VERIFY

VERIFY[,Y|N] (manual 2.48). 4A88H-4A8AH in the SYS0 sector write routine loads the value whose bits 7 and 4 decide whether the write is read back: LD A,(IX+01H) (FCB+1, verify only for record and byte I/O) or NOP / LD A,0FFH (every write through 4439H is verified).

4DC5
GOSUB to 4DEFH to read the Y/N parameter at Register Pair HL; nothing may follow it. The Z FLAG returns for N, the NZ FLAG for Y or no parameter.
4DC8
LD A,DDH 3E DD
Load Register A with DDH, the first byte of LD A,(IX+01H).
4DCA
LD HL,017EH 21 7E 01
Load Register Pair HL with 017EH: the bytes 7EH, 01H, the rest of LD A,(IX+01H) (DD 7E 01).
4DCD
If the Z FLAG is set (N), JUMP to 4DD3H to store LD A,(IX+01H): the verify follows FCB+1.
4DCF
XOR A AF
Y: set Register A to 00H (the NOP opcode) with XOR.
4DD0
LD HL,FF3EH 21 3E FF
Load Register Pair HL with FF3EH: the bytes 3EH, FFH = LD A,0FFH. With the NOP, 4A88H-4A8AH becomes NOP / LD A,0FFH and every write is verified.
4DD3
LD (4A88H),A 32 88 4A
Store Register A (DDH or 00H) at 4A88H in the SYS0 sector write routine.
4DD6
LD (4A89H),HL 22 89 4A
Store Register Pair HL (017EH or FF3EH) at 4A89H-4A8AH.
4DD9
XOR A AF
Set Register A to 0 with XOR, which also sets the Z FLAG: no error.
4DDA
RET C9
RETurn to SYS1 with Register A = 00H and the Z FLAG.

4DDBH - Function E5H Sub-function 5: BREAK

BREAK[,Y|N] (manual 2.8). 4312H-4314H is the SYS0 BREAK hook: the ROM keyboard driver does an RST 28H with Register A = 01H when BREAK is pressed, and the dispatcher sends codes below 20H to 4312H. JP 45B0H throws the key away, RET passes it on as a key with code 01H. DOS READY sets it again from option AG.

4DDB
GOSUB to 4DEFH to read the Y/N parameter at Register Pair HL; nothing may follow it. The Z FLAG returns for N, the NZ FLAG for Y or no parameter.
4DDE
LD HL,45B0H 21 B0 45
Point Register Pair HL to 45B0H, the SYS0 routine that clears Register A (the key is ignored).
4DE1
LD (4313H),HL 22 13 43
Store Register Pair HL (45B0H) at 4313H-4314H, the address of the JP at 4312H.
4DE4
LD A,C3H 3E C3
Load Register A with C3H (the JP opcode). LD does not change the flags.
4DE6
If the Z FLAG is set (N), JUMP to 4DEAH to store JP: BREAK is ignored.
4DE8
LD A,C9H 3E C9
Y: load Register A with C9H (the RET opcode): BREAK is a normal key.
4DEA
LD (4312H),A 32 12 43
Store Register A (C3H or C9H) at 4312H, the first byte of the BREAK hook.
4DED
XOR A AF
Set Register A to 0 with XOR, which also sets the Z FLAG: no error.
4DEE
RET C9
RETurn to SYS1 with Register A = 00H and the Z FLAG.

4DEFH - Read a Y/N Parameter

4DEFH reads the parameter and then requires the end of the command line; 4DF4H only reads it. On entry Register Pair HL points to the parameter (SYS1 has already stepped past the comma or spaces after the command word). Result: the Z FLAG and Register A = 00H for N; the NZ FLAG for Y (Register A = 0BH) or when the line ends there (Register A = BFH). Anything else, or anything after the parameter when 4DEFH is used, goes to the SYS0 error exit 4409H with error 34H.

4DEF
GOSUB to 4DF4H to read Y or N at Register Pair HL into the flags and Register B. 4D73H, 4DA2H, 4DABH, 4DB8H, 4DC5H and 4DDBH call here.
4DF2
JUMP to 4E00H to require the carriage return after the parameter.
4DF4
LD A,(HL) 7E
Fetch the character at Register Pair HL (the parameter) into Register A. 4D82H calls here.
4DF5
SUB 4EH D6 4E
SUBtract 4EH (N) from Register A: Register A = 00H for N, 0BH for Y, BFH for a carriage return (0DH).
4DF7
LD B,A 47
Copy Register A (the result) into Register B, where 4E06H takes it from. LD does not change the flags.
4DF8
INC HL 23
INCrement Register Pair HL past the character. INC HL does not change the flags.
4DF9
If the Z FLAG is set (N), JUMP to 4E06H to return Register A = 00H and the Z FLAG.
4DFB
CP 0BH FE 0B
Compare Register A (the result) against 0BH, the result for Y.
4DFD
If the Z FLAG is set (Y), JUMP to 4E06H to return Register A = 0BH and the NZ FLAG.
4DFF
DEC HL 2B
Neither: DECrement Register Pair HL back to the character, which must be the end of the line.
4E00
GOSUB to 4CD5H (SYS0) to test the character at Register Pair HL: the Z FLAG only at a carriage return (0DH); otherwise the NZ FLAG with Register A = 34H. 4DF2H comes here.
4E03
If the NZ FLAG is set (not the end of the line), JUMP to 4409H, the SYS0 error exit, with Register A = 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR). It does not come back.
4E06
LD A,B 78
Copy Register B (the result) into Register A: 00H for N, 0BH for Y, BFH when the line ended without a parameter. 4DF9H and 4DFDH come here.
4E07
OR A B7
OR Register A with itself: the Z FLAG for N (00H), the NZ FLAG otherwise.
4E08
RET C9
RETurn to the command routine with the answer in Register A and the flags.

4E09H - Function 45H: KILL the File of an FCB (442CH)

Manual section 3.16. Register Pair DE points to an open FCB. The directory entries and granules of the file are released through the same code as CLOSE, with the mode byte at 4FDBH = 01H and a granule target of 0, so every granule is freed; finally the FCB is set to all zeroes (4FD8H).

4E09
GOSUB to 4980H (SYS0): the FCB at Register Pair DE must be open (else error 26H); the rest runs as a DOS function with Index Register IX = the FCB, Index Register IY = 4380H and the Stack Pointer saved for the error exit 49CDH. The caller's registers except AF are restored on return.
4E0C
GOSUB to 494BH (SYS0) to select the drive of the FCB and read the directory sector of its FPDE (the DEC in FCB+7). Register Pair HL returns the FPDE in the buffer at 4200H, or the NZ FLAG with error 2DH if it is not an FPDE in use or its first extent differs from the FCB's.
4E0F
RET NZ C0
If the NZ FLAG is set (Register A = the error), RETurn from the DOS function with it.
4E10
LD B,02H 06 02
Load Register B with 02H: the access level must be below 2 for a kill (0 FULL or 1 KILL).
4E12
GOSUB to 49B9H (SYS0) to compare the access level of the FCB (FCB+1 bits 0-2) against Register B; a level of 2 or more leaves through 49CDH with error 25H (ILLEGAL ACCESS TRIED TO PROTECTED FILE).
4E15
JUMP to 4E1AH to set the KILL mode and the granule target of 0.

4E17H - KILL Entry Used by PURGE

PURGE (5136H) comes here with Register Pair DE = 4480H (the DOS FCB, marked open, with the DEC at 4487H) and Register Pair HL = the FPDE in the directory buffer at 4200H. It skips the FPDE check and the access check of 4E09H.

4E17
GOSUB to 4980H (SYS0): the FCB at Register Pair DE (4480H) is marked open (80H), so the rest runs as a DOS function with Index Register IX = 4480H and Index Register IY = 4380H. Register Pair HL still points to the FPDE.
4E1A
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H: the number of granules the file keeps (none). 4E15H comes here.
4E1D
LD A,01H 3E 01
Load Register A with 01H, the mode byte that marks this run as a KILL.
4E1F
LD (4FDBH),A 32 DB 4F
Store Register A (01H) at 4FDBH, the operand of the LD A,nn at 4FDAH, which the routine reads to tell KILL (01H) from CLOSE (00H).
4E22
PUSH BC C5
Save Register Pair BC (0000H) onto the stack as the granule target for 4E95H.
4E23
JUMP to 4E4AH to count the granules of the file.

4E25H - Function 25H: CLOSE the FCB (4428H)

Manual section 3.15. Register Pair DE points to an open FCB. The buffer is written if it holds changed data, the EOF of the FCB is written into the FPDE, granules beyond the EOF are released unless the no deallocate bit of the file is set, and the FCB is turned back into a filespec (NAME/EXT:d).

4E25
GOSUB to 4980H (SYS0): the FCB at Register Pair DE must be open (else error 26H); the rest runs as a DOS function with Index Register IX = the FCB, Index Register IY = 4380H and the Stack Pointer saved for the error exit 49CDH.
4E28
XOR A AF
Set Register A to 0 with XOR: the mode for CLOSE.
4E29
LD (4FDBH),A 32 DB 4F
Store Register A (00H) at 4FDBH, the operand of the LD A,nn at 4FDAH.
4E2C
GOSUB to 500DH to write the buffer if FCB+1 bit 4 says it holds changed data, then write the EOF of the FCB into the FPDE (sub-function 7, 5018H). It returns the CARRY FLAG with Register Pair HL = the FPDE in 4200H and Register Pair DE = the EOF middle and high bytes as stored in the FPDE; the NO CARRY FLAG if the access level is 5 or more.
4E2F
If the NO CARRY FLAG is set (the file may not be written), JUMP to 4F7DH to put the filespec into the FCB and return. Nothing is deallocated.
4E32
BIT 6,(IX+02H) DD CB 02 76
Test bit 6 of (IX+02H) (Index Register IX = the FCB), FCB+2: the no deallocate bit, a copy of byte 1 of the FPDE (manual 5.7 and 5.9).
4E36
If the NZ FLAG is set (no deallocate), JUMP to 4F7DH to put the filespec into the FCB and return. The excess granules stay with the file.
4E39
PUSH HL E5
Save Register Pair HL (the FPDE in the directory buffer) onto the stack.
4E3A
LD A,(IX+08H) DD 7E 08
Fetch (IX+08H) (Index Register IX = the FCB), FCB+8, the EOF low byte, into Register A.

4E3DH - Granules Needed for the EOF

Also entered from SYS6 (60BCH) with Register Pair HL = an FPDE in 4200H pushed onto the stack, Register A = its EOF low byte and Register Pair DE = its EOF middle and high bytes, to release the granules of a copied file beyond its EOF. Register Pair DE is the number of sectors the EOF reaches into (the FPDE form: the middle and high bytes are one higher when the low byte is not 0).

4E3D
OR A B7
OR Register A (the EOF low byte) with itself: the Z FLAG is set if it is 0.
4E3E
If the Z FLAG is set (the EOF low byte is 0), JUMP to 4E41H.
4E40
NOP 00
NOP. Self-Modifying Code
The SYS6 patch list at 5BE1H puts INC DE (13H) here, and a NOP at 5032H, while SYS6 copies a diskette whose PDRIVE entry has TI flag M (bit 5 of 430CH); the file on the system diskette has the NOP.
4E41
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the number of sectors the EOF reaches into; Register Pair DE gets the old Register Pair HL, which is not used again.
4E42
GOSUB to 4CB2H (SYS0) to divide Register Pair HL by 5 (sectors per granule): Register Pair HL returns the whole granules, Register A the remainder.
4E45
OR A B7
OR Register A (the remainder) with itself: the Z FLAG is set if it is 0.
4E46
If the Z FLAG is set (no remainder), JUMP to 4E49H.
4E48
INC HL 23
Part of a granule is used: INCrement Register Pair HL (the granules needed) to count it.
4E49
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (Stack Pointer): the stack now holds the granules the file needs, Register Pair HL = the FPDE saved at 4E39H.
4E4A
LD D,(IX+07H) DD 56 07
Load Register D with (IX+07H) (Index Register IX = the FCB), FCB+7, the DEC of the FPDE. KILL (4E23H) comes here with 0000H on the stack.
4E4D
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H: the count of granules the file owns.
4E50
LD E,10H 1E 10
Load Register E with 10H: bits 7 and 4 of the first entry must be 0 and 1, an FPDE in use.

4E52H - Count the Granules of the File

Register Pair HL points to a directory entry in the buffer at 4200H, Register D holds its DEC and Register E the value bits 7 and 4 of its first byte must have. The extent elements at bytes 22-31 are added into Register Pair BC. An element with lump FEH links to an FXDE (the DEC in its second byte) and must be the fifth one; FFH ends the list. The offset of the last entry examined is kept at 4EC4H.

Entry Loop
Register Pair HL = the entry, Register D = its DEC, Register E = the flag value it must have.

4E52
LD A,(HL) 7E
Fetch byte 0 of the entry at Register Pair HL (the flags) into Register A.
4E53
AND 90H E6 90
AND Register A with 90H, keeping bit 7 (FXDE) and bit 4 (in use).
4E55
CP E BB
Compare Register A against Register E (10H for the FPDE, 90H for an FXDE).
4E56
If the NZ FLAG is set (the wrong kind of entry), JUMP to 4E75H to leave with error 2CH (BAD DIRECTORY DATA).
4E58
LD A,L 7D
Copy Register L (the offset of the entry in the buffer) into Register A.
4E59
LD (4EC4H),A 32 C4 4E
Store Register A (the offset) at 4EC4H, the operand of the LD E,nn at 4EC3H: the entry the freeing loop starts from.
4E5C
ADD A,16H C6 16
ADD 16H to Register A: the offset of byte 22, the first extent element of the entry.
4E5E
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the first extent element.
4E5F
PUSH DE D5
Save Register Pair DE onto the stack: Register D = the DEC of this entry, Register E = the flag value.
4E60
LD E,05H 1E 05
Load Register E with 05H: five two-byte elements per entry (bytes 22-31). SYS6 changes the operand at 4E61H while it copies a diskette whose PDRIVE entry has TI flag M (bit 5 of 430CH), from its patch list at 5BE1H.

Element Loop
Register Pair HL = the element, Register E = the elements left in the entry, Register Pair BC = the granules counted.

4E62
LD A,(HL) 7E
Fetch the first byte of the element at Register Pair HL (the lump number, or FEH or FFH) into Register A.
4E63
CP FEH FE FE
Compare Register A against FEH: the NO CARRY FLAG for FEH (a link to an FXDE) and FFH (the end of the list).
4E65
INC HL 23
INCrement Register Pair HL to the second byte of the element (bits 5-7 the first granule within the lump, bits 0-4 the number of granules minus 1). INC HL does not change the flags.
4E66
If the NO CARRY FLAG is set (FEH or FFH), JUMP to 4E87H.
4E68
LD A,(HL) 7E
Fetch the second byte of the element at Register Pair HL into Register A.
4E69
AND 1FH E6 1F
AND Register A with 1FH, keeping bits 0-4: the number of granules in the element minus 1.
4E6B
INC HL 23
INCrement Register Pair HL to the next element.
4E6C
INC A 3C
INCrement Register A: the number of granules in this element. SYS6 changes this byte while it copies a diskette whose PDRIVE entry has TI flag M (bit 5 of 430CH), from its patch list at 5BE1H.
4E6D
ADD A,C 81
ADD Register C (the low byte of the count) to Register A.
4E6E
LD C,A 4F
Copy Register A into Register C, the new low byte of the count.
4E6F
If the NO CARRY FLAG is set (no carry out of the low byte), JUMP to 4E72H.
4E71
INC B 04
INCrement Register B, the high byte of the count: Register Pair BC = the granules counted so far.
4E72
DEC E 1D
DECrement Register E (the elements left in this entry). SYS6 changes 4E72H-4E74H while it copies a diskette whose PDRIVE entry has TI flag M (bit 5 of 430CH), from its patch list at 5BE1H.
4E73
If the NZ FLAG is set (more elements), LOOP BACK to 4E62H. After the fifth element the code goes on into 4E75H: five elements without an FEH or FFH are bad data.

4E75H - Error Exit and Directory Helpers

4E75H: five elements without an end mark, or the wrong kind of entry, is error 2CH. 4E7CH: read the directory entry whose DEC is in Register D. 4E82H: write the directory sector in 4200H. Both helpers return only on success (the Z FLAG); an error leaves the DOS function through 49CDH.

4E75
LD A,2CH 3E 2C
Load Register A with error code 2CH (BAD DIRECTORY DATA). 4E56H and 4E8BH come here.
4E77
OR A B7
OR Register A (2CH) with itself to set the NZ FLAG.
4E78
RET Z C8
If the Z FLAG is set (no error), RETurn to the caller. 4E80H and 4E85H come here with the result of a SYS0 call.
4E79
JUMP to 49CDH, the SYS0 error exit, with the error code in Register A: it restores the Stack Pointer saved by 4980H and returns from the DOS function. 501BH comes here too.
4E7C
LD A,D 7A
Copy Register D (the DEC of the entry wanted) into Register A. 4E90H and 4ED3H call here.
4E7D
GOSUB to 492FH (SYS0) to read the directory sector holding the DEC in Register A into 4200H unless it is already there. Register Pair HL returns the entry, Register A its offset in the buffer; the NZ FLAG on a read error. 4F87H calls here with the DEC in Register A.
4E80
JUMP to 4E78H to RETurn, or to leave with the error in Register A.
4E82
GOSUB to 491FH (SYS0) to write the directory sector in 4200H back (its number is at 4930H) with the directory mark and a verify read; the NZ FLAG with error 12H on failure. 4F2DH, 4F52H, 4F7AH, 4FEEH and 504AH call here.
4E85
JUMP to 4E78H to RETurn, or to leave with the error in Register A.

4E87H - End of the Extents of an Entry

Register A holds FEH or FFH from 4E62H and Register Pair HL points to the second byte of the element.

4E87
If the NZ FLAG is set (Register A = FFH, the end of the list), JUMP to 4E95H.
4E89
DEC E 1D
FEH: DECrement Register E (the elements left): it becomes 0 only when this is the fifth element.
4E8A
POP DE D1
Restore Register Pair DE from the stack: Register D = the DEC of the entry just finished, Register E = its flag value. POP does not change the flags.
4E8B
If the NZ FLAG is set (FEH before the fifth element), JUMP to 4E75H to leave with error 2CH. SYS6 changes this byte while it copies a diskette whose PDRIVE entry has TI flag M (bit 5 of 430CH), from its patch list at 5BE1H.
4E8D
LD D,(HL) 56
Fetch the second byte of the element at Register Pair HL into Register D: the DEC of the FXDE that continues the list.
4E8E
LD E,90H 1E 90
Load Register E with 90H: the FXDE must be in use (bit 4) and marked as an FXDE (bit 7).
4E90
GOSUB to 4E7CH to read the entry whose DEC is in Register D. Register Pair HL returns the FXDE, Register A its offset.
4E93
LOOP BACK to 4E52H to count the elements of the FXDE.

4E95H - Prepare the Work Maps

All the entries of the file have been counted: Register Pair BC = the granules the file owns, the stack holds the granules it keeps (what the EOF needs for CLOSE, 0 for KILL) and Register Pair HL points to the second byte of the element with the FFH end mark. From here SYS3 uses its own first 224 bytes as work space: 4D00H-4DBFH becomes a mask for the allocation bytes of the GAT (FFH = keep, a 0 bit = a granule to free) and 4DC0H-4DDFH a 256-bit map of DECs to clear in the HIT. Since that overwrites the code of SYS3, the overlay number at 4317H is cleared so that the next RST 28H for SYS3 reloads it.

4E95
POP DE D1
Restore Register Pair DE from the stack: Register D = the DEC of the last entry of the file, Register E = its flag value.
4E96
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (Stack Pointer): the stack now holds the end mark pointer, Register Pair HL = the granules the file keeps.
4E97
XOR A AF
Set Register A to 0 with XOR, which also clears the CARRY FLAG.
4E98
SBC HL,BC ED 42
SUBtract Register Pair BC (the granules the file owns) from Register Pair HL: Register Pair HL = keep minus own. A negative value is minus the number of excess granules; KILL gives minus all of them.
4E9A
LD (4317H),A 32 17 43
Store Register A (00H) at 4317H, the number of the overlay in 4D00H-51FFH: none, since the code at 4D00H is about to be overwritten.
4E9D
PUSH HL E5
Save Register Pair HL (the difference) onto the stack.
4E9E
LD HL,4D00H 21 00 4D
Point Register Pair HL to 4D00H, the start of the GAT mask.
4EA1
LD B,C0H 06 C0
Load Register B with C0H: 192 bytes, one per allocation byte of the GAT (GAT bytes 00H-BFH).

Mask Fill Loop

4EA3
LD (HL),FFH 36 FF
Store FFH (keep every granule) at Register Pair HL.
4EA5
INC HL 23
INCrement Register Pair HL to the next byte of the mask.
4EA6
DECrement Register B and LOOP BACK to 4EA3H until 4D00H-4DBFH is all FFH.
4EA8
LD B,20H 06 20
Load Register B with 20H: the 32 bytes of the HIT map (4DC0H-4DDFH).

Map Clear Loop

4EAA
LD (HL),A 77
Store Register A (00H, no DEC to clear) at Register Pair HL.
4EAB
INC HL 23
INCrement Register Pair HL to the next byte of the map.
4EAC
DECrement Register B and LOOP BACK to 4EAAH until 4DC0H-4DDFH is all 00H.
4EAE
POP BC C1
Restore Register Pair BC from the stack: keep minus own, saved at 4E9DH.
4EAF
POP HL E1
Restore Register Pair HL from the stack: the second byte of the element with the end mark.
4EB0
LD A,(4FDBH) 3A DB 4F
Fetch the mode from 4FDBH (00H CLOSE, 01H KILL) into Register A.
4EB3
OR A B7
OR Register A (the mode) with itself to set the flags.
4EB4
If the NZ FLAG is set (KILL), JUMP to 4EC1H to free every granule.
4EB6
LD A,B 78
CLOSE: copy Register B (the high byte of the difference) into Register A.
4EB7
CP 80H FE 80
Compare Register A against 80H: the NO CARRY FLAG when the difference is negative (the file owns more granules than its EOF needs), the CARRY FLAG and the NZ FLAG otherwise.
4EB9
PUSH HL E5
Save Register Pair HL (the end mark pointer) onto the stack.
4EBA
If the NO CARRY FLAG is set (excess granules), GOSUB to 491FH (SYS0) to write the directory sector now in 4200H (the one holding the last entry of the file, unchanged since it was read) back to the diskette. A write error returns the NZ FLAG with Register A = 12H.
4EBD
POP HL E1
Restore Register Pair HL from the stack: the end mark pointer.
4EBE
If the NZ FLAG is set (no excess granules, from 4EB7H, or the write failed, from 491FH), JUMP to 4F30H to put the filespec into the FCB and finish without freeing anything. The error code of a failed write is not returned.

4EC1H - Free Granules from the End of the File

Register Pair BC counts up from minus the number of granules to free. Working backwards from the last extent element, each granule is marked in the GAT mask at 4D00H (lump offset, granule bit). CLOSE shortens the element, and an element or an FXDE that becomes empty is replaced by an end mark (FFH FFH). KILL leaves the elements as they are, since the whole entry is released. An FXDE that has been emptied (CLOSE) or passed (KILL) is freed through 4FE5H and the walk goes on in the entry its back link names. The offset of the entry being worked on is at 4EC4H; its DEC is in Register D.

Element Walk Loop
Register Pair HL = the second byte of the element after the one to look at.

4EC1
DEC L 2D
DECrement Register L (the low byte of the element pointer) by one. 4EB4H and 4EE0H come here.
4EC2
DEC L 2D
DECrement Register L again: Register Pair HL = the second byte of the previous element. 4EE6H comes here.
4EC3
LD E,00H 1E 00
Load Register E with the offset of the entry being worked on. Self-Modifying Code
The operand at 4EC4H is stored at 4E59H and 4ED6H.
4EC5
LD A,E 7B
Copy Register E (the offset of the entry) into Register A.
4EC6
ADD A,16H C6 16
ADD 16H to Register A: the offset of byte 22, the first byte of the first element of the entry.
4EC8
CP L BD
Compare Register A against Register L (where Register Pair HL points): the CARRY FLAG is set while Register Pair HL is past byte 22, in one of the elements of this entry (zap 035 turned this into an offset test that works for the first entry of a sector).
4EC9
If the CARRY FLAG is set (Register Pair HL is in an element of this entry), JUMP to 4EE8H to free granules from it.
4ECB
LD L,E 6B
Every element of this entry is done: copy Register E (its offset) into Register L, so that Register Pair HL points to byte 0 of the entry.
4ECC
BIT 7,(HL) CB 7E
Test bit 7 of byte 0 of the entry at Register Pair HL: 1 for an FXDE.
4ECE
If the Z FLAG is set (the FPDE, the first entry of the file), JUMP to 4F22H to finish. SYS6 changes this byte while it copies a diskette whose PDRIVE entry has TI flag M (bit 5 of 430CH), from its patch list at 5BE1H.
4ED0
An FXDE: GOSUB to 4FE5H to free it (clear bit 4, write the sector, mark its DEC in the HIT map). Register D returns the DEC of the entry before it (the back link of the FXDE).
4ED3
GOSUB to 4E7CH to read the entry whose DEC is in Register D. Register Pair HL returns the entry, Register A its offset.
4ED6
LD (4EC4H),A 32 C4 4E
Store Register A (the offset of the entry) at 4EC4H: this entry is now the one being worked on.
4ED9
ADD A,1FH C6 1F
ADD 1FH to Register A: the offset of byte 31, the second byte of the fifth element, the one that linked to the freed FXDE. SYS6 changes the operand at 4EDAH while it copies a diskette whose PDRIVE entry has TI flag M (bit 5 of 430CH), from its patch list at 5BE1H.
4EDB
LD L,A 6F
Copy Register A into Register L: Register Pair HL = byte 31 of the entry.
4EDC
LD A,(4FDBH) 3A DB 4F
Fetch the mode from 4FDBH (00H CLOSE, 01H KILL) into Register A. 4F20H comes here.
4EDF
OR A B7
OR Register A (the mode) with itself to set the flags.
4EE0
If the NZ FLAG is set (KILL), LOOP BACK to 4EC1H to go back one element and leave this one as it is.
4EE2
DEC A 3D
CLOSE: DECrement Register A (the mode) from 00H to FFH, the end mark value.
4EE3
LD (HL),A 77
Store Register A (FFH) at Register Pair HL, the second byte of the element.
4EE4
DEC HL 2B
DECrement Register Pair HL to the first byte of the element.
4EE5
LD (HL),A 77
Store Register A (FFH) at Register Pair HL: the element is now the end mark of the list.
4EE6
LOOP BACK to 4EC2H to go back to the second byte of the previous element.
4EE8
LD E,(HL) 5E
Fetch the second byte of the element at Register Pair HL into Register E, kept to put back if the element becomes empty. 4EC9H comes here.

Granule Free Loop
Register Pair HL = the second byte of the element, Register Pair BC = minus the granules still to free.

4EE9
LD A,B 78
Copy Register B (the high byte of the count) into Register A. 4F1DH comes here.
4EEA
OR C B1
OR Register C (the low byte of the count) into Register A: the Z FLAG when Register Pair BC has counted up to 0.
4EEB
If the Z FLAG is set (all the excess granules are freed), JUMP to 4F22H to finish.
4EED
PUSH DE D5
Save Register Pair DE onto the stack: Register D = the DEC of the entry, Register E = the original second byte of the element.
4EEE
PUSH HL E5
Save Register Pair HL (the second byte of the element) onto the stack.
4EEF
LD D,(HL) 56
Fetch the current second byte of the element at Register Pair HL into Register D. SYS6 changes 4EEFH-4EF0H while it copies a diskette whose PDRIVE entry has TI flag M (bit 5 of 430CH), from its patch list at 5BE1H.
4EF0
DEC (HL) 35
DECrement the second byte of the element at Register Pair HL: the element loses its last granule.
4EF1
DEC HL 2B
DECrement Register Pair HL to the first byte of the element.
4EF2
LD E,(HL) 5E
Fetch the lump number of the element at Register Pair HL into Register E.
4EF3
DEC E 1D
DECrement Register E (the lump number), because the loop at 4F04H adds 1 before it subtracts.
4EF4
PUSH BC C5
Save Register Pair BC (the count) onto the stack.
4EF5
LD A,D 7A
Copy Register D (the second byte of the element) into Register A.
4EF6
AND 1FH E6 1F
AND Register A with 1FH, keeping bits 0-4: the number of granules minus 1, the position of the last granule of the element counted from its first.
4EF8
LD B,A 47
Copy Register A (the position) into Register B. LD does not change the flags.
4EF9
PUSH AF F5
Save Register Pair AF onto the stack: the Z FLAG from 4EF6H is set if the element had only one granule left.
4EFA
LD A,D 7A
Copy Register D (the second byte of the element) into Register A again.
4EFB
RLCA 07
Rotate Register A left (the first of three RLCAs).
4EFC
RLCA 07
Rotate Register A left (the second of three RLCAs).
4EFD
RLCA 07
Rotate Register A left (the third): bits 5-7 (the first granule of the element within its lump) are now bits 0-2.
4EFE
AND 07H E6 07
AND Register A with 07H, keeping bits 0-2: the first granule within the lump.
4F00
ADD A,B 80
ADD Register B (the position of the last granule) to Register A: the last granule counted from the start of the first lump of the element.
4F01
LD B,(IY-71H) FD 46 8F
Load Register B with (IY-71H): Index Register IY = 4380H, so this is 430FH, the granules per lump of the current drive.

Lump Loop

4F04
INC E 1C
INCrement Register E (the lump number) to the next lump of the element.
4F05
SUB B 90
SUBtract Register B (the granules per lump) from Register A (the granule number).
4F06
If the NO CARRY FLAG is set (no borrow), LOOP BACK to 4F04H. Register E ends as the lump that holds the granule.
4F08
ADD A,B 80
ADD Register B (the granules per lump) back to Register A: the granule within that lump.
4F09
LD B,A 47
Copy Register A (the granule within the lump) into Register B.
4F0A
LD A,7FH 3E 7F
Load Register A with 7FH, a mask with only bit 7 clear.
4F0C
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the lump number.
4F0E
INC B 04
INCrement Register B: the number of left rotations needed.

Rotate Loop

4F0F
RLCA 07
Rotate Register A (the mask) left one bit, bit 7 going into bit 0.
4F10
DECrement Register B and LOOP BACK to 4F0FH until it is 0. The clear bit of Register A ends up at the position of the granule.
4F12
LD HL,4D00H 21 00 4D
Point Register Pair HL to 4D00H, the GAT mask.
4F15
ADD HL,DE 19
ADD Register Pair DE (the lump number) to Register Pair HL: the mask byte for this lump.
4F16
AND (HL) A6
AND Register A (the new mask) with the mask byte at Register Pair HL.
4F17
LD (HL),A 77
Store Register A at Register Pair HL: the granule is marked to be freed.
4F18
POP AF F1
Restore Register Pair AF from the stack (saved at 4EF9H): the Z FLAG if the element has no granules left.
4F19
POP BC C1
Restore Register Pair BC from the stack: the count.
4F1A
POP HL E1
Restore Register Pair HL from the stack: the second byte of the element.
4F1B
POP DE D1
Restore Register Pair DE from the stack: Register D = the DEC of the entry, Register E = the original second byte of the element.
4F1C
INC BC 03
INCrement Register Pair BC (the count) towards 0: one granule freed. INC BC does not change the flags.
4F1D
If the NZ FLAG is set (the element still has granules), LOOP BACK to 4EE9H.
4F1F
LD (HL),E 73
The element is empty. Store Register E (its original second byte) back at Register Pair HL, since the DEC at 4EF0H ran through bits 0-4 into bits 5-7.
4F20
JUMP to 4EDCH: CLOSE makes the element the end mark, KILL leaves it.

4F22H - Write the Last Entry and Finish

Reached when the excess granules are freed (4EEBH) or when the walk has come back to the FPDE (4ECEH). Register Pair HL points into the entry whose offset is at 4EC4H.

4F22
LD A,(4FDBH) 3A DB 4F
Fetch the mode from 4FDBH (00H CLOSE, 01H KILL) into Register A.
4F25
OR A B7
OR Register A (the mode) with itself to set the flags.
4F26
If the Z FLAG is set (CLOSE), JUMP to 4F2DH to write the shortened entry.
4F28
KILL: GOSUB to 4FE5H to free the FPDE itself (clear bit 4, write the sector, mark its DEC in the HIT map).
4F2B
JUMP to 4F30H to clear the FCB and apply the GAT mask and HIT map.
4F2D
CLOSE: GOSUB to 4E82H to write the directory sector in 4200H with the shortened entry.
4F30
GOSUB to 4F7DH to put the filespec into the FCB (CLOSE) or clear the FCB (KILL). 4EBEH comes here.

4F33H - Apply the GAT Mask

If any byte of the mask at 4D00H-4DBFH is not FFH, the GAT (directory sector 0) is read, each of its allocation bytes 00H-BFH is ANDed with the mask (a cleared bit frees that granule) and the GAT is written back.

4F33
LD HL,4D00H 21 00 4D
Point Register Pair HL to 4D00H, the GAT mask.
4F36
LD B,C0H 06 C0
Load Register B with C0H: the 192 bytes of the mask.

Mask Test Loop

4F38
LD A,(HL) 7E
Fetch the mask byte at Register Pair HL into Register A.
4F39
INC A 3C
INCrement Register A: the Z FLAG is set only for FFH (nothing to free in this lump).
4F3A
INC HL 23
INCrement Register Pair HL to the next mask byte. INC HL does not change the flags.
4F3B
If the NZ FLAG is set (a granule to free), JUMP to 4F41H.
4F3D
DECrement Register B and LOOP BACK to 4F38H until all 192 mask bytes have been tested.
4F3F
The whole mask is FFH: JUMP to 4F56H to look at the HIT map, with Register Pair HL = 4DC0H.
4F41
XOR A AF
Set Register A to 0 with XOR: directory sector 0, the GAT.
4F42
GOSUB to 490AH (SYS0) to read the GAT into the buffer at 4200H. Register Pair HL returns 4200H; the NZ FLAG and the error code in Register A on a read error.
4F45
RET NZ C0
If the NZ FLAG is set (a read error), RETurn from the DOS function with the error code in Register A.
4F46
LD DE,4D00H 11 00 4D
Point Register Pair DE to 4D00H, the GAT mask.
4F49
LD B,C0H 06 C0
Load Register B with C0H: the 192 allocation bytes of the GAT.

Mask Apply Loop
Register Pair DE = the mask byte, Register Pair HL = the GAT byte.

4F4B
LD A,(DE) 1A
Fetch the mask byte at Register Pair DE into Register A.
4F4C
AND (HL) A6
AND Register A (the mask byte) with the GAT byte at Register Pair HL.
4F4D
LD (HL),A 77
Store Register A at Register Pair HL in the GAT: the marked granules are now free.
4F4E
INC DE 13
INCrement Register Pair DE to the next mask byte.
4F4F
INC HL 23
INCrement Register Pair HL to the next GAT byte.
4F50
DECrement Register B and LOOP BACK to 4F4BH until all 192 bytes are done.
4F52
GOSUB to 4E82H to write the GAT in 4200H back (4930H still holds sector 0).
4F55
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = 4DC0H, where Register Pair DE has run to past the mask, the start of the HIT map.

4F56H - Apply the HIT Map

If any bit of the map at 4DC0H-4DDFH is set, the HIT (directory sector 1) is read and the byte of every marked DEC is set to 00H (entry free), then the HIT is written back. The map holds one bit per DEC, bit 7 of 4DC0H for DEC 00H.

4F56
LD B,20H 06 20
Load Register B with 20H: the 32 map bytes. Register Pair HL = 4DC0H. 4F3FH comes here.

Map Test Loop

4F58
LD A,(HL) 7E
Fetch the map byte at Register Pair HL into Register A.
4F59
OR A B7
OR Register A (the map byte) with itself: the Z FLAG is set if no DEC is marked in it.
4F5A
INC HL 23
INCrement Register Pair HL to the next map byte. INC HL does not change the flags.
4F5B
If the NZ FLAG is set (a DEC is marked), JUMP to 4F60H.
4F5D
DECrement Register B and LOOP BACK to 4F58H until all 32 map bytes have been tested.
4F5F
RET C9
Nothing is marked: RETurn from the DOS function with Register A = 00H and the Z FLAG (no error).
4F60
LD A,01H 3E 01
Load Register A with 01H, directory sector 1, the HIT.
4F62
GOSUB to 490AH (SYS0) to read the HIT into 4200H. Register Pair HL returns 4200H, the HIT byte of DEC 00H; the NZ FLAG and the error code on a read error.
4F65
RET NZ C0
If the NZ FLAG is set (a read error), RETurn from the DOS function with the error code in Register A.
4F66
LD DE,4DBFH 11 BF 4D
Point Register Pair DE to 4DBFH, one byte before the map, because the loop moves on first.
4F69
LD C,20H 0E 20
Load Register C with 20H: the 32 map bytes, 256 DECs in all.

Map Byte Loop
Register Pair HL = the HIT byte of the next DEC, Register C = the map bytes left.

4F6B
INC DE 13
INCrement Register Pair DE to the next map byte.
4F6C
LD B,08H 06 08
Load Register B with 08H: eight bits per map byte.
4F6E
LD A,(DE) 1A
Fetch the map byte at Register Pair DE into Register A.

Map Bit Loop

4F6F
RLCA 07
Rotate Register A (the map byte) left: the next bit, from bit 7 down, goes into the CARRY FLAG.
4F70
If the NO CARRY FLAG is set (this DEC is not marked), JUMP to 4F74H.
4F72
LD (HL),00H 36 00
Marked: store 00H at Register Pair HL, the HIT byte of this DEC: the entry is free.
4F74
INC HL 23
INCrement Register Pair HL to the HIT byte of the next DEC.
4F75
DECrement Register B (the bits left) and LOOP BACK to 4F6FH until all 8 are done.
4F77
DEC C 0D
DECrement Register C (the map bytes left), setting the Z FLAG at 0.
4F78
If the NZ FLAG is set (more map bytes), LOOP BACK to 4F6BH.
4F7A
JUMP to 4E82H to write the HIT back; it RETurns from the DOS function with the Z FLAG, or leaves with the error.

4F7DH - Put the Filespec into the FCB

Manual sections 3.15 and 3.16. The FCB (Index Register IX) is rewritten as NAME/EXT:d with 03H at the end, from the entry whose DEC is in FCB+7 and the drive number at 4308H; for KILL (mode 01H at 4FDBH) its 32 bytes are then cleared. Skipped when bit 2 of 436BH is set (SYS6 sets it while it uses this code during COPY). Reached as a subroutine from 4F30H, or with JP from CLOSE (4E2FH, 4E36H), in which case its RET ends the DOS function.

4F7D
LD A,(436BH) 3A 6B 43
Fetch the temporary flags at 436BH into Register A. 4E2FH, 4E36H and 4F30H come here.
4F80
BIT 2,A CB 57
Test bit 2 of Register A (436BH), set by SYS6 while it uses this code.
4F82
If the NZ FLAG is set (SYS6), JUMP to 4FE3H to RETurn with Register A = 00H.
4F84
LD A,(IX+07H) DD 7E 07
Fetch (IX+07H) (Index Register IX = the FCB), FCB+7, the DEC of the FPDE, into Register A.
4F87
GOSUB to 4E7DH with Register A = the DEC to read its directory sector if needed. Register Pair HL returns the entry.
4F8A
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the entry (its name starts at byte 5).
4F8B
PUSH IX DD E5
Save Index Register IX (the FCB address) onto the stack.
4F8D
POP HL E1
Restore it into Register Pair HL: Register Pair HL = the FCB, where the text is written.
4F8E
LD B,08H 06 08
Load Register B with 08H: up to eight name characters.
4F90
PUSH HL E5
Save Register Pair HL (the FCB address) onto the stack for 4FD7H.
4F91
INC DE 13
INCrement Register Pair DE to byte 1 of the entry.
4F92
INC DE 13
INCrement Register Pair DE to byte 2 of the entry.
4F93
INC DE 13
INCrement Register Pair DE to byte 3 of the entry.
4F94
INC DE 13
INCrement Register Pair DE to byte 4 of the entry, one before the name.

Name Loop
Register Pair DE = the entry, Register Pair HL = the FCB, Register B = the characters left.

4F95
INC DE 13
INCrement Register Pair DE to the next name character (bytes 5-12 of the entry).
4F96
LD A,(DE) 1A
Fetch the name character at Register Pair DE into Register A.
4F97
CP 20H FE 20
Compare Register A against 20H (a space), the padding of the name.
4F99
If the Z FLAG is set (a space), JUMP to 4F9DH without copying it.
4F9B
LD (HL),A 77
Store Register A (the character) at Register Pair HL in the FCB.
4F9C
INC HL 23
INCrement Register Pair HL to the next place in the FCB.
4F9D
DECrement Register B and LOOP BACK to 4F95H until all 8 name characters have been looked at.
4F9F
INC DE 13
INCrement Register Pair DE to byte 13 of the entry, the first extension character.
4FA0
LD A,(DE) 1A
Fetch the first extension character at Register Pair DE into Register A.
4FA1
CP 20H FE 20
Compare Register A (the first extension character) against 20H (a space).
4FA3
If the Z FLAG is set (no extension), JUMP to 4FB4H.
4FA5
LD (HL),2FH 36 2F
Store 2FH (/) at Register Pair HL in the FCB, before the extension.
4FA7
LD B,03H 06 03
Load Register B with 03H: up to three extension characters.
4FA9
INC HL 23
INCrement Register Pair HL past the / in the FCB.

Extension Loop

4FAA
LD A,(DE) 1A
Fetch the extension character at Register Pair DE into Register A.
4FAB
CP 20H FE 20
Compare Register A (the extension character) against 20H (a space).
4FAD
INC DE 13
INCrement Register Pair DE to the next extension character. INC DE does not change the flags.
4FAE
If the Z FLAG is set (a space ends the extension), JUMP to 4FB4H.
4FB0
LD (HL),A 77
Store Register A (the character) at Register Pair HL in the FCB.
4FB1
INC HL 23
INCrement Register Pair HL to the next place in the FCB.
4FB2
DECrement Register B and LOOP BACK to 4FAAH until all 3 extension characters have been looked at.
4FB4
LD (HL),3AH 36 3A
Store 3AH (:) at Register Pair HL in the FCB, after the name and extension. 4FA3H and 4FAEH come here.
4FB6
INC HL 23
INCrement Register Pair HL to the next place in the FCB.
4FB7
LD A,(4308H) 3A 08 43
Fetch the current drive number from 4308H (the drive of the file, selected by 494BH or 492FH) into Register A.
4FBA
LD BC,0264H 01 64 02
Load Register Pair BC with 0264H: Register B = 02H (two digit places to work out), Register C = 64H (100, the first power of ten).

Digit Loop
Register A = the rest of the drive number, Register C = the power of ten.

4FBD
LD D,2FH 16 2F
Load Register D with 2FH, one below the character 0.
4FBF
INC D 14
INCrement Register D, the digit character, once for each subtraction.
4FC0
SUB C 91
SUBtract Register C (the power of ten) from Register A.
4FC1
If the NO CARRY FLAG is set (no borrow), LOOP BACK to 4FBFH.
4FC3
ADD A,C 81
ADD Register C (the power of ten) back to Register A: the remainder.
4FC4
LD E,A 5F
Copy Register A (the remainder) into Register E.
4FC5
LD A,D 7A
Copy Register D (the digit character) into Register A.
4FC6
CP 30H FE 30
Compare Register A against 30H (the character 0).
4FC8
If the Z FLAG is set (a 0 in the hundreds or tens place), JUMP to 4FCCH without storing it.
4FCA
LD (HL),A 77
Store Register A (the digit) at Register Pair HL in the FCB.
4FCB
INC HL 23
INCrement Register Pair HL to the next place in the FCB.
4FCC
LD A,E 7B
Copy Register E (the remainder) back into Register A.
4FCD
LD C,0AH 0E 0A
Load Register C with 0AH (10), the power of ten for the next place.
4FCF
DECrement Register B (the places left) and LOOP BACK to 4FBDH until it is 0.
4FD1
ADD A,30H C6 30
ADD 30H to Register A (the last remainder): the units digit as a character.
4FD3
LD (HL),A 77
Store Register A (the units digit) at Register Pair HL in the FCB.
4FD4
INC HL 23
INCrement Register Pair HL to the next place in the FCB.
4FD5
LD (HL),03H 36 03
Store 03H at Register Pair HL, the end of the filespec.
4FD7
POP HL E1
Restore Register Pair HL from the stack: the FCB address saved at 4F90H.
4FD8
LD B,20H 06 20
Load Register B with 20H: the 32 bytes of the FCB.
4FDA
LD A,00H 3E 00
Load Register A with the mode: 00H CLOSE, 01H KILL. Self-Modifying Code
The operand at 4FDBH is stored at 4E1FH and 4E29H, and by SYS6 at 60ADH.
4FDC
DEC A 3D
DECrement Register A (the mode): 00H for KILL, FFH for CLOSE.
4FDD
If the NZ FLAG is set (CLOSE), JUMP to 4FE3H to RETurn, keeping the filespec in the FCB.

FCB Clear Loop

4FDF
LD (HL),A 77
KILL: store Register A (00H) at Register Pair HL in the FCB.
4FE0
INC HL 23
INCrement Register Pair HL to the next byte of the FCB.
4FE1
DECrement Register B and LOOP BACK to 4FDFH until all 32 bytes of the FCB are 00H.
4FE3
XOR A AF
Set Register A to 0 with XOR, which also sets the Z FLAG: no error. 4F82H, 4FDDH and 5056H come here.
4FE4
RET C9
RETurn to the caller with Register A = 00H and the Z FLAG: no error.

4FE5H - Free a Directory Entry

Frees the entry at the offset stored at 4EC4H (in the buffer at 4200H), whose DEC is in Register D: bit 4 of its first byte is cleared (manual 5.7: the rest of the entry is left as it was), the sector is written, and the DEC is marked in the HIT map at 4DC0H. Returns Register D = the second byte of the entry, which for an FXDE is the DEC of the entry before it.

4FE5
LD A,(4EC4H) 3A C4 4E
Fetch the offset of the entry from 4EC4H (the operand of the LD E,nn at 4EC3H) into Register A. 4ED0H and 4F28H call here.
4FE8
LD L,A 6F
Copy Register A (the offset) into Register L: Register Pair HL = the entry (Register H is 42H, the buffer at 4200H).
4FE9
RES 4,(HL) CB A6
Reset bit 4 of byte 0 of the entry at Register Pair HL: the entry is no longer in use.
4FEB
LD E,D 5A
Copy Register D (the DEC of the entry) into Register E.
4FEC
INC HL 23
INCrement Register Pair HL to byte 1 of the entry.
4FED
LD D,(HL) 56
Fetch byte 1 of the entry at Register Pair HL into Register D: the back link of an FXDE.
4FEE
GOSUB to 4E82H to write the directory sector in 4200H back.
4FF1
LD A,E 7B
Copy Register E (the DEC of the freed entry) into Register A.
4FF2
RRCA 0F
Rotate Register A right (the first of three RRCAs).
4FF3
RRCA 0F
Rotate Register A right (the second of three RRCAs).
4FF4
RRCA 0F
Rotate Register A right (the third): bits 3-7 of the DEC are now bits 0-4.
4FF5
AND 1FH E6 1F
AND Register A with 1FH, keeping bits 0-4: the map byte number (the DEC divided by 8).
4FF7
PUSH BC C5
Save Register Pair BC (the count of the freeing loop) onto the stack.
4FF8
LD HL,4DC0H 21 C0 4D
Point Register Pair HL to 4DC0H, the HIT map.
4FFB
LD C,A 4F
Copy Register A (the map byte number) into Register C.
4FFC
LD B,00H 06 00
Load Register B with 00H: Register Pair BC = the map byte number.
4FFE
ADD HL,BC 09
ADD Register Pair BC to Register Pair HL: Register Pair HL = the map byte for this DEC.
4FFF
LD A,E 7B
Copy Register E (the DEC of the freed entry) into Register A again.
5000
AND 07H E6 07
AND Register A with 07H, keeping bits 0-2: the bit within the map byte, counted from bit 7.
5002
LD B,A 47
Copy Register A (the bit number) into Register B.
5003
LD A,01H 3E 01
Load Register A with 01H, the bit that 5006H rotates into place.
5005
INC B 04
INCrement Register B: the number of right rotations.

Bit Loop

5006
RRCA 0F
Rotate Register A right (01H becomes 80H after one rotation).
5007
DECrement Register B and LOOP BACK to 5006H until it is 0. Register A = the bit of this DEC.
5009
OR (HL) B6
OR the map byte at Register Pair HL into Register A.
500A
LD (HL),A 77
Store Register A at Register Pair HL: the HIT byte of this DEC will be cleared at 4F56H.
500B
POP BC C1
Restore Register Pair BC from the stack: the count of the freeing loop.
500C
RET C9
RETurn with Register D = byte 1 of the freed entry.

500DH - Write the Buffer, Then the EOF

Used by CLOSE (4E2CH) and write EOF (5053H) inside their DOS function. Two words are pushed so that the SYS0 buffer write at 4A62H returns into 49D7H: an error there leaves through 49CDH, otherwise 49D7H pops E507H and does RST 28H with Register A = E5H and Register C = 07H, which runs sub-function 7 (5018H) of this same overlay. Its RET comes back to the caller of 500DH.

500D
LD HL,E507H 21 07 E5
Load Register Pair HL with E507H: E5H = SYS3 function 7, 07H = sub-function 7. 4E2CH and 5053H call here.
5010
PUSH HL E5
Save Register Pair HL (E507H) onto the stack for 49D7H to take into Register A and Register C.
5011
LD HL,49D7H 21 D7 49
Load Register Pair HL with 49D7H, the SYS0 return point that chains to another overlay function.
5014
PUSH HL E5
Save Register Pair HL (49D7H) onto the stack as the return address for 4A62H.
5015
JUMP to 4A62H (SYS0) to write the buffer of the FCB if FCB+1 bit 4 says it holds changed data; it RETurns to 49D7H.

5018H - Function E5H Sub-function 7: Write the EOF of the FCB into the FPDE

Reached only through the chain set up by 500DH, so it runs inside the caller's DOS function (Index Register IX = the FCB). Files whose access level is 5 or more (READ, EXEC, LOCK) are not changed: RETurn with the CARRY FLAG clear. Otherwise the EOF of the FCB is stored in the FPDE (low byte at byte 3, middle and high at bytes 20 and 21 in the FPDE form, one higher when the low byte is not 0) and the directory sector is written only if the value changed. Returns the CARRY FLAG, Register Pair HL = the FPDE and Register Pair DE = the EOF middle and high bytes in the FPDE form.

5018
GOSUB to 494BH (SYS0) to select the drive of the FCB and read the directory sector of its FPDE (the DEC in FCB+7). Register Pair HL returns the FPDE, or the NZ FLAG with error 2DH if it is not the file's FPDE. 4D38H comes here.
501B
If the NZ FLAG is set (an error), JUMP to 4E79H, which leaves the DOS function through 49CDH with the error code in Register A.
501E
LD A,(IX+01H) DD 7E 01
Fetch (IX+01H) (Index Register IX = the FCB), FCB+1, into Register A.
5021
AND 07H E6 07
AND Register A with 07H, keeping bits 0-2: the access level (0 FULL to 4 WRITE, 5 READ, 6 EXEC, 7 LOCK).
5023
CP 05H FE 05
Compare Register A (the access level) against 05H.
5025
RET NC D0
If the NO CARRY FLAG is set (level 5 or more), RETurn with the CARRY FLAG clear; the FPDE is not changed.
5026
LD E,(IX+0CH) DD 5E 0C
Load Register E with (IX+0CH) (Index Register IX = the FCB), FCB+12, the EOF middle byte.
5029
LD D,(IX+0DH) DD 56 0D
Load Register D with (IX+0DH) (Index Register IX = the FCB), FCB+13, the EOF high byte: Register Pair DE = the whole sectors of the EOF.
502C
LD A,(IX+08H) DD 7E 08
Fetch (IX+08H) (Index Register IX = the FCB), FCB+8, the EOF low byte (the position within the last sector), into Register A.
502F
OR A B7
OR Register A (the EOF low byte) with itself: the Z FLAG is set if it is 0.
5030
If the Z FLAG is set (the EOF low byte is 0), JUMP to 5033H.
5032
INC DE 13
A partly used sector counts: INCrement Register Pair DE, the FPDE form of the EOF. Self-Modifying Code
The SYS6 patch list at 5BE1H replaces this INC DE with a NOP, and the NOP at 4E40H with INC DE, while SYS6 copies a diskette whose PDRIVE entry has TI flag M (bit 5 of 430CH).
5033
PUSH HL E5
Save Register Pair HL (the FPDE) onto the stack. 5030H comes here.
5034
INC L 2C
INCrement Register L (the FPDE pointer) to byte 1 of the FPDE.
5035
INC L 2C
INCrement Register L (the FPDE pointer) to byte 2 of the FPDE.
5036
INC L 2C
INCrement Register L to byte 3 of the FPDE, the EOF low byte.
5037
LD C,(HL) 4E
Fetch the old EOF low byte at Register Pair HL into Register C.
5038
LD (HL),A 77
Store Register A (the new EOF low byte) at Register Pair HL.
5039
SUB C 91
SUBtract Register C (the old low byte) from Register A: the Z FLAG is set if the low byte did not change.
503A
LD BC,0011H 01 11 00
Load Register Pair BC with 0011H (17). LD does not change the flags.
503D
ADD HL,BC 09
ADD Register Pair BC to Register Pair HL: Register Pair HL = byte 20 of the FPDE, the EOF middle byte. ADD HL,BC does not change the Z FLAG.
503E
LD C,(HL) 4E
Fetch the old EOF middle byte at Register Pair HL into Register C.
503F
INC HL 23
INCrement Register Pair HL to byte 21 of the FPDE, the EOF high byte.
5040
LD B,(HL) 46
Fetch the old EOF high byte at Register Pair HL into Register B: Register Pair BC = the old EOF sectors.
5041
LD (HL),D 72
Store Register D (the new high byte) at Register Pair HL, byte 21.
5042
DEC HL 2B
DECrement Register Pair HL to byte 20 of the FPDE.
5043
LD (HL),E 73
Store Register E (the new middle byte) at Register Pair HL, byte 20.
5044
If the NZ FLAG is set (the low byte changed), JUMP to 504AH to write the sector.
5046
LD H,D 62
Copy Register D (the new high byte) into Register H.
5047
LD L,E 6B
Copy Register E (the new middle byte) into Register L: Register Pair HL = the new EOF sectors.
5048
SBC HL,BC ED 42
SUBtract Register Pair BC (the old EOF sectors) from Register Pair HL; the CARRY FLAG is clear after the equal SUB at 5039H and the ADD at 503DH. The Z FLAG is set if they are the same.
504A
If the NZ FLAG is set (the EOF changed), GOSUB to 4E82H to write the directory sector with the new EOF. 5044H comes here.
504D
POP HL E1
Restore Register Pair HL from the stack: the FPDE.
504E
SCF 37
Set the CARRY FLAG: the FPDE could be updated.
504F
RET C9
RETurn to the caller of 500DH with the CARRY FLAG, Register Pair HL = the FPDE and Register Pair DE = the EOF in the FPDE form.

5050H - Function C5H: Write the EOF to the Directory (4451H)

Manual section 3.28. Register Pair DE points to an open FCB. The buffer is written if it holds changed data, then the EOF is stored in the FPDE. Returns error 25H if the access level of the file does not allow the change.

5050
GOSUB to 4980H (SYS0): the FCB at Register Pair DE must be open (else error 26H); the rest runs as a DOS function with Index Register IX = the FCB and Index Register IY = 4380H.
5053
GOSUB to 500DH to write the buffer if needed, then the EOF into the FPDE (5018H). The CARRY FLAG returns if it was done.
5056
If the CARRY FLAG is set (done), JUMP to 4FE3H to RETurn with Register A = 00H and the Z FLAG.
5059
LD A,25H 3E 25
Load Register A with error code 25H (ILLEGAL ACCESS TRIED TO PROTECTED FILE).
505B
OR A B7
OR Register A (25H) with itself to set the NZ FLAG.
505C
RET C9
RETurn from the DOS function with error 25H in Register A.

505DH - Function E5H Sub-function 6: PURGE

PURGE,[password:]dn[,/ext][,USR] (manual 2.40). SYS7 (4D69H) handles the start of the command and chains here with RST 28H: Register B = the drive number (from 4308H) and Register Pair HL = the command line after the drive. This part reads the options into Register C: bit 0 = /ext given (the extension at 5164H-5166H), bit 1 = USR (leave out system and invisible files).

505D
LD A,B 78
Copy Register B (the drive number from SYS7) into Register A.
505E
LD C,00H 0E 00
Load Register C with 00H: no PURGE options have been read yet.
5060
GOSUB to 47ECH (SYS0) to select the drive in Register A and wait for the index hole to change. The NZ FLAG returns with error 08H if there is no turning diskette.
5063
RET NZ C0
If the NZ FLAG is set (no diskette), RETurn to SYS7 with the error code in Register A.

Option Loop
Register Pair HL = the command line, Register C = the option bits.

5064
GOSUB to 4CD5H (SYS0) to test the character at Register Pair HL: the Z FLAG at the carriage return; the NZ FLAG and NO CARRY after a comma or spaces (Register Pair HL moved past them); the CARRY FLAG for anything else. Register A returns 34H. 5082H, 508AH, 508EH, 5097H, 509DH and 50A2H come here.
5067
RET C D8
If the CARRY FLAG is set (anything else), RETurn to SYS7 with Register A = 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR).
5068
If the Z FLAG is set (the end of the command line), JUMP to 50A4H to start the directory scan.
506A
LD A,(HL) 7E
Fetch the next character of the command line at Register Pair HL into Register A.
506B
CP 2FH FE 2F
Compare Register A (the option character) against 2FH (/).
506D
If the NZ FLAG is set (not /), JUMP to 508CH to test for USR.
506F
SET 0,C CB C1
Set bit 0 of Register C (the options): an extension is given.
5071
INC HL 23
INCrement Register Pair HL past the / on the command line.
5072
LD DE,5163H 11 63 51
Point Register Pair DE to 5163H, one byte before the extension at 5164H, because the loop moves on first.
5075
LD B,03H 06 03
Load Register B with 03H: up to three extension characters.

Extension Loop
Register Pair HL = the command line, Register Pair DE = the last extension character stored, Register B = the places left.

5077
LD A,(HL) 7E
Fetch the character at Register Pair HL into Register A.
5078
SUB 30H D6 30
SUBtract 30H (the character 0) from Register A.
507A
CP 0AH FE 0A
Compare Register A against 0AH: the CARRY FLAG for a digit 0-9.
507C
If the CARRY FLAG is set (a digit), JUMP to 5084H to store it.
507E
SUB 11H D6 11
SUBtract 11H more from Register A: the letters A-Z become 00H-19H.
5080
CP 1AH FE 1A
Compare Register A against 1AH: the CARRY FLAG for a letter A-Z.
5082
If the NO CARRY FLAG is set (not a letter), the extension ends here: LOOP BACK to 5064H, which needs a separator or the end of the line at this character.
5084
INC DE 13
INCrement Register Pair DE to the next place of the extension.
5085
LD A,(HL) 7E
Fetch the character at Register Pair HL into Register A again.
5086
LD (DE),A 12
Store Register A (the character) at Register Pair DE in the extension at 5164H-5166H.
5087
INC HL 23
INCrement Register Pair HL to the next character of the command line.
5088
DECrement Register B (the places left) and LOOP BACK to 5077H while it is not 0.
508A
Three characters taken: LOOP BACK to 5064H for the next option.
508C
CP 55H FE 55
Compare Register A (the character) against 55H (U).
508E
If the NZ FLAG is set (not U), LOOP BACK to 5064H, which gives error 34H at this character.
5090
LD D,H 54
Copy Register H (the high byte of the command line pointer) into Register D.
5091
LD E,L 5D
Copy Register L into Register E: Register Pair DE = the U on the command line.
5092
INC DE 13
INCrement Register Pair DE to the character after the U.
5093
LD A,(DE) 1A
Fetch the character at Register Pair DE into Register A.
5094
CP 53H FE 53
Compare Register A (the character after the U) against 53H (S).
5096
INC DE 13
INCrement Register Pair DE to the next character. INC DE does not change the flags.
5097
If the NZ FLAG is set (not S), LOOP BACK to 5064H with Register Pair HL still at the U, which gives error 34H.
5099
LD A,(DE) 1A
Fetch the character after the S at Register Pair DE into Register A.
509A
CP 52H FE 52
Compare Register A (the character after the S) against 52H (R).
509C
INC DE 13
INCrement Register Pair DE past it. INC DE does not change the flags.
509D
If the NZ FLAG is set (not R), LOOP BACK to 5064H, which gives error 34H at the U.
509F
SET 1,C CB C9
Set bit 1 of Register C (the options): USR given.
50A1
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the command line after USR.
50A2
LOOP BACK to 5064H to look for the next option or the end of the line.

50A4H - PURGE: Ask About Every File

Every FDE sector of the directory is read in turn (Register C = the FDE sector number, counted from 0, which is also the DEC of its first entry) and each entry that is an FPDE in use is offered, except DEC 00H (BOOT/SYS) and DEC 01H (DIR/SYS). The operator answers Y (kill it), N (keep it) or Q (stop).

50A4
LD A,C 79
Copy Register C (the option bits) into Register A. 5068H comes here.
50A5
LD (5163H),A 32 63 51
Store Register A (the option bits) at 5163H for the entry loop to read.
50A8
LD A,01H 3E 01
Load Register A with 01H, directory sector 1, the HIT.
50AA
GOSUB to 490AH (SYS0) to read the HIT into the buffer at 4200H. The NZ FLAG returns with the error code on a read error.
50AD
RET NZ C0
If the NZ FLAG is set (a read error), RETurn to SYS7 with the error code in Register A.
50AE
LD A,(421FH) 3A 1F 42
Fetch HIT byte 1FH from 421FH into Register A: the number of FDE sectors beyond the first eight.
50B1
ADD A,08H C6 08
ADD 08H to Register A: the number of FDE sectors in this directory.
50B3
LD (5153H),A 32 53 51
Store Register A (the number of FDE sectors) at 5153H, the operand of the CP nn at 5152H: the end of the scan.
50B6
XOR A AF
Set Register A to 0 with XOR: FDE sector 0, the first one to read.

FDE Sector Loop
Register A = the FDE sector number.

50B7
LD C,A 4F
Copy Register A (the FDE sector number) into Register C.
50B8
GOSUB to 4936H (SYS0) with Register A = the DEC of the first entry of that FDE sector, to read the sector into 4200H. Register Pair HL returns its first entry; the NZ FLAG on a read error.
50BB
RET NZ C0
If the NZ FLAG is set (a read error), RETurn to SYS7 with the error code in Register A.

Entry Loop
Register Pair HL = the entry, Register C = the FDE sector number.

50BC
LD A,(HL) 7E
Fetch byte 0 of the entry at Register Pair HL (the flags) into Register A.
50BD
AND 90H E6 90
AND Register A with 90H, keeping bit 7 (FXDE) and bit 4 (in use).
50BF
CP 10H FE 10
Compare Register A against 10H: an FPDE in use.
50C1
If the NZ FLAG is set (anything else), JUMP to 5147H for the next entry.
50C4
LD A,(HL) 7E
Fetch byte 0 of the entry at Register Pair HL into Register A again.
50C5
AND 48H E6 48
AND Register A with 48H, keeping bit 6 (a system file) and bit 3 (an invisible file).
50C7
LD DE,5163H 11 63 51
Point Register Pair DE to 5163H, the option bits. LD does not change the flags.
50CA
LD A,(DE) 1A
Fetch the option bits at Register Pair DE into Register A. LD does not change the flags.
50CB
If the Z FLAG is set (neither a system nor an invisible file), JUMP to 50D1H.
50CD
BIT 1,A CB 4F
Test bit 1 of Register A (the option bits): USR, leave out system and invisible files.
50CF
If the NZ FLAG is set (USR given), JUMP to 5147H to skip this system or invisible file.
50D1
BIT 0,A CB 47
Test bit 0 of Register A (the options): an extension is given. 50CBH comes here.
50D3
If the Z FLAG is set (no extension given), JUMP to 50E7H.
50D5
PUSH HL E5
Save Register Pair HL (the entry) onto the stack.
50D6
LD A,L 7D
Copy Register L (the offset of the entry) into Register A.
50D7
ADD A,0DH C6 0D
ADD 0DH to Register A: the offset of the extension of the entry (byte 13).
50D9
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the extension of the entry.
50DA
LD B,03H 06 03
Load Register B with 03H: three characters to compare.

Extension Compare Loop
Register Pair DE = the wanted extension, Register Pair HL = the extension of the entry.

50DC
INC DE 13
INCrement Register Pair DE to the next wanted character (5164H-5166H).
50DD
LD A,(DE) 1A
Fetch the wanted character at Register Pair DE into Register A.
50DE
CP (HL) BE
Compare Register A against the character of the entry at Register Pair HL.
50DF
INC HL 23
INCrement Register Pair HL to the next character of the entry. INC HL does not change the flags.
50E0
If the NZ FLAG is set (different), JUMP to 50E4H.
50E2
DECrement Register B and LOOP BACK to 50DCH until all 3 characters match.
50E4
POP HL E1
Restore Register Pair HL from the stack: the entry. POP does not change the flags. 50E0H comes here.
50E5
If the NZ FLAG is set (a different extension), JUMP to 5147H for the next entry.
50E7
LD A,C 79
Copy Register C (the FDE sector number) into Register A. 50D3H comes here.
50E8
CP 02H FE 02
Compare Register A against 02H: the NO CARRY FLAG for FDE sector 2 or higher.
50EA
LD A,L 7D
Copy Register L (the offset of the entry: 00H, 20H up to E0H) into Register A. LD does not change the flags.
50EB
If the NO CARRY FLAG is set (FDE sector 2 or higher), JUMP to 50F0H.
50ED
OR A B7
OR Register A (the offset) with itself: the Z FLAG for the first entry of FDE sector 0 or 1.
50EE
If the Z FLAG is set (DEC 00H, BOOT/SYS, or DEC 01H, DIR/SYS), JUMP to 5147H: they are never offered.
50F0
ADD A,C 81
ADD Register C (the FDE sector number) to Register A (the offset): Register A = the DEC of the entry (bits 5-7 the entry, bits 0-4 the sector). 50EBH comes here.
50F1
LD (4487H),A 32 87 44
Store Register A (the DEC) at 4487H, FCB+7 of the DOS FCB at 4480H, for the kill at 513CH.
50F4
PUSH HL E5
Save Register Pair HL (the entry) onto the stack.
50F5
LD A,L 7D
Copy Register L (the offset of the entry) into Register A.
50F6
ADD A,05H C6 05
ADD 05H to Register A: the offset of the name (byte 5).
50F8
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the name of the entry.
50F9
LD B,08H 06 08
Load Register B with 08H: eight name characters.
50FB
GOSUB to 5159H to display the Register B characters at Register Pair HL without spaces. Register Pair HL returns byte 13, the extension.
50FE
LD A,(HL) 7E
Fetch the first extension character at Register Pair HL into Register A.
50FF
CP 20H FE 20
Compare Register A (the first extension character) against 20H (a space).
5101
If the Z FLAG is set (no extension), JUMP to 510DH.
5103
LD A,2FH 3E 2F
Load Register A with 2FH (/), shown between the name and the extension.
5105
GOSUB to 0033H (ROM) to display the character in Register A.
5108
LD B,03H 06 03
Load Register B with 03H: three extension characters.
510A
GOSUB to 5159H to display the extension at Register Pair HL without spaces.
510D
LD HL,5167H 21 67 51
Point Register Pair HL to 5167H, the prompt: eight spaces and KILL IT? (Y/N/Q). 5101H comes here.
5110
GOSUB to 4467H (SYS0) to display the message at Register Pair HL up to the 03H at 5181H.

Key Loop

5113
GOSUB to 0049H (ROM) to wait for a key; Register A returns it.
5116
RES 5,A CB AF
Reset bit 5 of Register A (the key): lower case letters become upper case.
5118
CP 51H FE 51
Compare Register A (the key) against 51H (Q).
511A
If the Z FLAG is set (Q), JUMP to 5124H to show and act on the answer.
511C
CP 4EH FE 4E
Compare Register A (the key) against 4EH (N).
511E
If the Z FLAG is set (N), JUMP to 5124H to show and act on the answer.
5120
CP 59H FE 59
Compare Register A (the key) against 59H (Y).
5122
If the NZ FLAG is set (any other key), LOOP BACK to 5113H to wait for another key.
5124
PUSH AF F5
Save Register Pair AF (Register A = the answer) onto the stack. 511AH and 511EH come here.
5125
GOSUB to 0033H (ROM) to display the answer in Register A.
5128
LD A,0DH 3E 0D
Load Register A with 0DH (carriage return) to end the prompt line.
512A
GOSUB to 0033H (ROM) to display the carriage return in Register A and end the line.
512D
POP AF F1
Restore Register Pair AF from the stack: Register A = the answer.
512E
POP HL E1
Restore Register Pair HL from the stack: the entry, saved at 50F4H.
512F
CP 51H FE 51
Compare Register A (the answer) against 51H (Q).
5131
RET Z C8
If the Z FLAG is set (Q), RETurn to SYS7 with the Z FLAG (no error) and Register A = 51H: the PURGE ends.
5132
CP 4EH FE 4E
Compare Register A (the answer) against 4EH (N).
5134
If the Z FLAG is set (N), JUMP to 5147H for the next entry.
5136
LD DE,4480H 11 80 44
Y: point Register Pair DE to 4480H, the DOS FCB.
5139
LD A,80H 3E 80
Load Register A with 80H, the open bit of FCB+0.
513B
LD (DE),A 12
Store Register A (80H) at Register Pair DE as FCB+0: the FCB counts as open. Its DEC (4487H) was stored at 50F1H.
513C
GOSUB to 4E17H to kill the file through the DOS FCB at Register Pair DE, with Register Pair HL = its FPDE. The registers other than AF come back unchanged; the NZ FLAG with an error code on failure.
513F
RET NZ C0
If the NZ FLAG is set (an error), RETurn to SYS7 with the error code in Register A.
5140
PUSH HL E5
Save Register Pair HL (the entry) onto the stack.
5141
LD A,C 79
Copy Register C (the FDE sector number) into Register A.
5142
GOSUB to 4936H (SYS0) to read the FDE sector again: the kill used the buffer at 4200H for the GAT and the HIT.
5145
POP HL E1
Restore Register Pair HL from the stack: the entry. POP does not change the flags.
5146
RET NZ C0
If the NZ FLAG is set (a read error), RETurn to SYS7 with the error code in Register A.
5147
LD A,L 7D
Copy Register L (the offset of the entry) into Register A. 50C1H, 50CFH, 50E5H, 50EEH and 5134H come here.
5148
AND E0H E6 E0
AND Register A with E0H, keeping bits 5-7: the start of the entry.
514A
ADD A,20H C6 20
ADD 20H to Register A: the next entry. The CARRY FLAG is set after the last entry (E0H).
514C
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the next entry.
514D
If the NO CARRY FLAG is set (still in this sector), JUMP to 50BCH for the next entry.
5150
INC C 0C
INCrement Register C (the FDE sector number).
5151
LD A,C 79
Copy Register C (the next FDE sector) into Register A.
5152
CP 00H FE 00
Compare Register A against the number of FDE sectors (00H in the file). Self-Modifying Code
The operand at 5153H is stored at 50B3H.
5154
If the CARRY FLAG is set (more FDE sectors), JUMP to 50B7H to read the next one.
5157
XOR A AF
Set Register A to 0 with XOR, which also sets the Z FLAG: no error.
5158
RET C9
RETurn to SYS7 with Register A = 00H and the Z FLAG.

5159H - Display Characters Without Spaces

Register Pair HL points to the characters, Register B holds how many. Spaces are skipped; Register Pair HL is left after the last character.

Display Loop

5159
LD A,(HL) 7E
Fetch the character at Register Pair HL into Register A. 50FBH and 510AH call here.
515A
CP 20H FE 20
Compare Register A (the character) against 20H (a space), which is skipped.
515C
INC HL 23
INCrement Register Pair HL to the next character. INC HL does not change the flags.
515D
If the NZ FLAG is set (not a space), GOSUB to 0033H (ROM) to display the character in Register A.
5160
DECrement Register B (the characters left) and LOOP BACK to 5159H until it is 0.
5162
RET C9
RETurn with Register Pair HL after the last character.

5163H - PURGE Data

The option bits, the wanted extension and the prompt. SYS3 is loaded from the diskette for every PURGE (SYS7 runs first in the same overlay area), so the extension starts as three spaces each time.

5163
DEFB 00H 00
The PURGE option bits, stored at 50A5H and read at 50CAH: bit 0 = /ext given, bit 1 = USR given. 5072H points Register Pair DE here, one before the extension.
5164-5166
DEFM " " 20 20 20
The wanted extension, filled from the command line at 5086H and compared at 50DCH. Characters not given stay spaces.
5167-5181
DEFM " KILL IT? (Y/N/Q) ", 03H 20 20 20 20 20 20 20 20 4B 49 4C 4C 20 49 54 3F 20 28 59 2F 4E 2F 51 29 20 20 03
The prompt displayed by 5110H after the name, ended by 03H.

5182H - Function A5H: J-K-L Screen Print

Manual sections 2.26 and 4.5. The SYS0 key combination check (45BFH) does RST 28H with code A5H when J, K and L are held down. The display memory 3C00H-3FFFH is sent to the printer through ROM 003BH, a carriage return before each 64-character line. Characters 00H-1FH are sent as 40H-5FH (what the display shows for them) and anything above the value of option AX (4370H) as a period. BREAK stops the print. Zap 046 (optional, not applied in this file) sends codes 80H-BFH as A0H-DFH for Epson graphics, with its code in 51B4H-51BBH.

5182
LD HL,3C00H 21 00 3C
Point Register Pair HL to 3C00H, the start of the display memory.

Print Loop
Register Pair HL = the next display address.

5185
LD A,(3840H) 3A 40 38
Fetch keyboard row 6 from 3840H into Register A. 518FH and 51B2H come here.
5188
AND 04H E6 04
AND Register A with 04H, keeping bit 2, the BREAK key.
518A
If the Z FLAG is set (BREAK is not pressed), JUMP to 5191H.
518C
LD HL,4000H 21 00 40
BREAK is pressed: point Register Pair HL to 4000H, the end of the display memory.
518F
LOOP BACK to 5185H. While BREAK is held Register Pair HL stays 4000H; when it is let go 5191H sends a carriage return and 519CH ends the print.
5191
LD A,L 7D
Copy Register L (the low byte of the display address) into Register A. 518AH comes here.
5192
AND 3FH E6 3F
AND Register A with 3FH, keeping bits 0-5: the Z FLAG at the start of a 64-character display line.
5194
LD A,0DH 3E 0D
Load Register A with 0DH (carriage return). LD does not change the flags.
5196
If the Z FLAG is set (the start of a line), GOSUB to 003BH (ROM) to send the carriage return in Register A to the printer.
5199
LD A,H 7C
Copy Register H (the high byte of the display address) into Register A.
519A
AND 3FH E6 3F
AND Register A with 3FH, keeping bits 0-5: 00H when Register Pair HL has reached 4000H (3CH-3FH stay above 0).
519C
RET Z C8
If the Z FLAG is set (the end of the display memory, or BREAK), RETurn to the caller of the RST 28H.
519D
LD A,(HL) 7E
Fetch the display character at Register Pair HL into Register A.
519E
CP 20H FE 20
Compare Register A against 20H: the CARRY FLAG for 00H-1FH.
51A0
INC HL 23
INCrement Register Pair HL to the next display address. INC HL does not change the flags.
51A1
If the NO CARRY FLAG is set (20H or higher), JUMP to 51A5H.
51A3
ADD A,40H C6 40
00H-1FH: ADD 40H to Register A, giving @, A-Z and [ \ ] ^ _, the characters the display shows for these codes.
51A5
LD B,A 47
Copy Register A (the character to print) into Register B. 51A1H comes here.
51A6
LD A,(4370H) 3A 70 43
Fetch option AX from 4370H into Register A: the highest code the printer can print.
51A9
CP B B8
Compare Register A (option AX) against Register B (the character): the NO CARRY FLAG if the character is not above option AX.
51AA
LD A,B 78
Copy Register B (the character) back into Register A. LD does not change the flags.
51AB
If the NO CARRY FLAG is set (printable), JUMP to 51AFH. Zap 046 changes this to JR NC,51B4H.
51AD
LD A,2EH 3E 2E
Above option AX: load Register A with 2EH (a period) instead.
51AF
GOSUB to 003BH (ROM) to send the character in Register A to the printer; it waits while the printer is not ready. 51ABH comes here.
51B2
LOOP BACK to 5185H for the next display character.

51B4H - Unused Bytes

The end of the file. Nothing in SYS3 reaches these bytes; the optional zap 046 puts its code in 51B4H-51BBH.

51B4-51DF
NOP x 44 00 x 44
44 bytes of 00H to the end of the file (51DFH). 51E0H-51FFH is not in the file.