TRS-80 DOS – TRSDOS v1.3 – SYS03/SYS Disassembled

 
ORG 4E00H
4E00
AND 0F0H
MASK the value of Register A against 0F0H (0000 1111 0000). This has the effect of turning off bits 3, 2, 1, 0, leaving only bits 7, 6, 5, 4 active.
4E02
CP 90H
Compare the value held in Register A against 90H, which would be the “CLOSE” function call. Results: If Register A equals 90H, the Z FLAG is set; otherwise the NZ FLAG is set.
4E04
If the Z FLAG (Zero) is set, JUMP to 4E0FH.
4E06
CP 0A0H
Compare the value held in Register A against A0H, which would be the “KILL” function call. Results: If Register A equals 90H, the Z FLAG is set; otherwise the NZ FLAG is set.
4E08
If the Z FLAG (Zero) is set, JUMP to 4F61H.
4E0B
LD A,1AH
LET Register A = 1AH to set up for a ILLEGAL COMMAND PARAMETER error.
4E0D
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A. The NZ Flag will be set because we just put a 26H into Register A, so NZ will be set to indicate an error.
4E0E
RET
RETurn to the caller.

4E0FH – MAIN ROUTINE – “CLOSE” – Close an Open File.

4E0F
GOSUB to 4881H (from SYS00/SYS) to set up for closing a file.
4E12
RET NZ
If the NZ FLAG (Not Zero) is set then the prior CALL wound up with an error, RETurn to the caller.
4E13
GOSUB to 4868H (from SYS00/SYS) to write the buffer out, if necessary.
4E16
If the Z FLAG (Zero) is set then the prior CALL had NO error so JUMP to 4E1FH.
4E18
CP 1EH
Compare the value held in Register A against 1EH (the error code for NO MORE EXTENTS). Results: If Register A equals 1EH, the Z FLAG is set; otherwise the NZ FLAG is set.
4E1A
If the Z FLAG (Zero) is set, meaning that the CALL returned an error code for NO MORE EXTENTS, JUMP to 4E1FH.
4E1C
CP 1BH
Compare the value held in Register A against 1BH (the error code for DISK FULL). Results: If Register A equals 1BH, the Z FLAG is set; otherwise the NZ FLAG is set.
4E1E
RET NZ
If the NZ FLAG (Not Zero) is set then the CALL did not result in a DISK FULL error, so RETurn to the caller.
4E1F
LD B,(IX+07H)
Fetch the value stored at the memory location pointed to by IX+07H (i.e., the position in the DCB for the LOGICAL FILE NUMBER) and put it into Register B.
4E22
LD C,(IX+06H)
Fetch the value stored at the memory location pointed to by IX+06H (i.e., the position in the DCB for the DRIVE NUMBER) and put it into Register C.
4E25
LD A,(IX+0EH)
Fetch the value stored at the memory location pointed to by IX+0EH (i.e., the position in the DCB for the DISK SIDE NUMBER) and put it into Register A.
4E28
LD (4463H),A
Store the value held in Register A (i.e., the DISK SIDE NUMBER) into the memory location 4463H (i.e., the storage location for the old system disk side number).
4E2B
GOSUB to 4A93H.
NOTE: 4A93H is the SYS00/SYS routine to READ THE GAT sector into RAM (Buffer at 4D00H).
4E2E
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4E2F
GOSUB to 4A67H.
NOTE: 4A67H is the SYS00/SYS routine to read the directory entry into RAM (Buffer at 4300H)
4E32
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4E33
LD (4F24H),HL
Store the value held in Register HL (i.e., the position of the entry) into the memory location 4F24H, which is in the middle of a LD HL,nnnn OPCODE.
4E36
BIT 3,(IX+01H)
Test Bit 3 of Register (IX+01H).
4E3A
If the Z FLAG (Zero) is set, the BIT 3 of DCB+01H was off, meaning that we were not requested to trim the file, so JUMP to 4F1BH.
4E3D
LD A,03H
LET Register A = 03H so as to allow us to move HL (i.e., the pointer to the current location in the directory entry) forward 3 bytes.
4E3F
ADD A,L
ADD the value held in Register L to Register A (Results held in Register A).
4E40
LD L,A
LET Register L = Register A so that HL = HL + 3 now.
4E41
PUSH HL
Save Register HL (i.e., the pointer to the current location in the directory entry) to the top of the stack.
4E42
LD A,(IX+08H)
Fetch the value stored at the memory location pointed to by IX+08H (i.e., the position in the DCB for the EOF byte) and put it into Register A.
4E45
CP (HL)
Compare the value held in Register A (i.e., the position in the DCB for the EOF byte) against the value held in the memory location (HL) (i.e., the directory’s EOF byte). Results: If Register A equals (HL), the Z FLAG is set; otherwise the NZ FLAG is set.
4E46
If the NZ FLAG (Not Zero) is set, then the EOF bytes didn’t match, so we need to update the the directory — JUMP to 4E5DH.
4E48
LD A,11H
LET Register A = 11H (Decimal: 20) so as to allow us to move HL (i.e., the pointer to the current location in the directory entry) forward 20 bytes (to the directory sector EOF).
4E4A
ADD A,L
ADD the value held in Register L to Register A (Results held in Register A).
4E4B
LD L,A
LET Register L = Register A.
4E4C
LD A,(IX+0CH)
Fetch the value stored at the memory location pointed to by IX+0CH (i.e., the position in the DCB for the NMSB OF THE LAST RECORD) and put it into Register A.
4E4F
CP (HL)
Compare the value held in Register A (i.e., the DCB sector EOF) against the value held in the memory location (HL) (i.e., the EOF byte in the directory). Results: If Register A equals (HL), the Z FLAG is set; otherwise the NZ FLAG is set.
4E50
If the NZ FLAG (Not Zero) is set then the DCB and directory EOF’s didn’t match, so we need to update the directory by JUMPing to 4E5DH.
4E52
INC L
Bump the value stored in Register L by 1 to point to the next position in the directory entry.
4E53
LD A,(IX+0DH)
Fetch the value stored at the memory location pointed to by IX+0DH (i.e., the position in the DCB for the MSB OF THE LAST RECORD) and put it into Register A.
4E56
CP (HL)
Compare the value held in Register A against the value held in the memory location (HL). Results: If Register A equals (HL), the Z FLAG is set; otherwise the NZ FLAG is set.
4E57
If the NZ FLAG (Not Zero) is set then we need to update the directory, so JUMP to 4E5DH.
4E59
POP AF
Restore Register Pair AF from the top of the STACK.
4E5A
JUMP to 4F07H to continue the routine.

4E5DH – Continuation of the CLOSE routine. This routine will update the the directory.

4E5D
POP HL
Restore Register Pair HL (i.e., the pointer to the current location in the directory entry) from the top of the STACK.
4E5E
LD A,(IX+08H)
Fetch the value stored at the memory location pointed to by IX+08H (i.e., the position in the DCB for the EOF byte) and put it into Register A.
4E61
LD (HL),A
Store the value held in Register A (i.e., EOF byte from the DCB) into the memory location pointed to by Register Pair HL (i.e., the pointer to the EOF byte in the directory entry).
4E62
INC HL
Bump the value stored in Register Pair HL by 1 to point to the next byte in the directory entry.
4E63
LD A,(IX+09H)
Fetch the value stored at the memory location pointed to by IX+09H (i.e., the position in the DCB for the LOGICAL RECORD LENGTH) and put it into Register A.
4E66
LD (HL),A
Store the value held in Register A (i.e., the LOGICAL RECORD LENGTH in the DCB) into the memory location pointed to by Register Pair HL (i.e., the position in the directory entry for the LRL byte).
4E67
LD A,10H
LET Register A = 10H so we can move HL to point to the directory entry for the SECTOR EOF.
4E69
ADD A,L
ADD the value held in Register L to Register A (Results held in Register A).
4E6A
LD L,A
LET Register L = Register A, so now HL points to the directory entry for the SECTOR EOF.
4E6B
LD A,(IX+0CH)
Fetch the value stored at the memory location pointed to by IX+0CH (i.e., the position in the DCB for the NMSB OF THE LAST RECORD) and put it into Register A.
4E6E
LD (HL),A
Store the value held in Register A (i.e., the NMSB OF THE LAST RECORD in the DCB) into the memory location pointed to by Register Pair HL (i.e., the position in the directory entry for the NMSB of the last record).
4E6F
INC L
Bump the value stored in Register L by 1 so that HL now points to the position in the directory entry for the MSB of the last record).
4E70
LD A,(IX+0DH)
Fetch the value stored at the memory location pointed to by IX+0DH (i.e., the position in the DCB for the MSB OF THE LAST RECORD) and put it into Register A.
4E73
LD (HL),A
Store the value held in Register A (i.e., the MSB OF THE LAST RECORD in the DCB) into the memory location pointed to by Register Pair HL (i.e., the position in the DCB for the MSB OF THE LAST RECORD).
4E74
INC L
Bump the value stored in Register L by 1 so that HL now points to the next position in the directory entry.
4E75
LD DE,0010H
LET Register Pair DE = 0010H (Decimal: 16).
4E78
PUSH IX
Save Register IX (i.e., DCB + 00H) to the top of the stack.
4E7A
ADD IX,DE
ADD the value held in Register Pair DE (i.e., 16 bytes) to Register Pair IX, so that IX = IX + 16 bytes (to point to the extents).
4E7C
PUSH IX
Save Register IX (i.e., the pointer in the DCB to the extents) to the top of the stack.
4E7E
POP DE
Restore the pointer in the DCB to the extents into Register Pair DE.
4E7F
POP IX
Restore the DCB + 00H (from the top of the stack) into Register Pair IX.
4E81
EX DE,HL
EXchange the value stored in Register Pair HL (i.e., the current working position in the directory entry) with the value stored in Register Pair DE (i.e., the pointer in the DCB to the extents).
4E82
PUSH DE
Save Register DE (i.e., the current working position in the directory entry) to the top of the stack.
4E83
LD BC,001AH
LET Register Pair BC = 001AH (Decimal: 26) to prepare to move 26 bytes via a LDIR.
4E86
LDIR
Transfers a byte of data from the memory location pointed to by HL to the memory location pointed to by DE. Then HL and DE are incremented and BC is decremented. If BC is not zero, this operation is repeated. Interrupts can trigger while this instruction is processing.
4E88
LD C,(IX+06H)
Fetch the value stored at the memory location pointed to by IX+06H (i.e., the position in the DCB for the DRIVE NUMBER) and put it into Register C.
4E8B
LD B,(IX+07H)
Fetch the value stored at the memory location pointed to by IX+07H (i.e., the position in the DCB for the LOGICAL FILE NUMBER) and put it into Register B.
4E8E
LD A,(IX+0EH)
Fetch the value stored at the memory location pointed to by IX+0EH (i.e., the position in the DCB for the DISK SIDE NUMBER) and put it into Register A.
4E91
LD (4463H),A
Store the value held in Register A (i.e., the DISK SIDE NUMBER from the DCB) into the memory location 4463H.
NOTE: 4463H is the storage location for the old system disk side number.
4E94
GOSUB to 4A7BH (from SYS00/SYS) to write the directory entry from the copy in RAM to the diskette.
4E97
POP HL
Restore the current working position in the directory entry (held at the top of the stack) into Register Pair HL.
4E98
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine (to write the directory from the copy in RAM) returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4E99
DEC L
DECrement the value stored in Register L by 1 so that HL now points to the directory entry byte which is 1 byte before the EXTENTS.
4E9A
INC L
Bump the value stored in Register L by 1 so that HL now points to the directory entry byte for the EXTENTS.
4E9B
EX DE,HL
EXchange the value stored in Register Pair HL (i.e., the pointer in the directory entry for the EXTENTS) with the value stored in Register Pair DE.
4E9C
LD L,(IX+0CH)
Fetch the value stored at the memory location pointed to by IX+0CH (i.e., the position in the DCB for the NMSB OF THE LAST RECORD/EOF) and put it into Register L.
4E9F
LD H,(IX+0DH)
Fetch the value stored at the memory location pointed to by IX+0DH (i.e., the position in the DCB for the MSB OF THE LAST RECORD/EOF) and put it into Register H.
4EA2
INC HL
Bump the value stored in Register Pair HL (i.e., the EOF location) by 1.
4EA3
LD A,03H
LET Register A = 03H to prepare to divide that EOF by 3, so as to calculate the number of GRANs
4EA5
GOSUB to 4451H to divide Register Pair HL by Register A; result in Register A.
4EA8
OR A
Set FLAGS based on the contents of Register A.
4EA9
If the Z FLAG (Zero) is set then there is no remainder, so skip the next instruction and JUMP to 4EACH.
4EAB
INC HL
Bump the value stored in Register Pair HL by 1 so that the gran count includes the remainder as a whole number.
4EAC
LD A,0CH
LET Register A = 0CH (Decimal: 13) in preparation for a loop to skip over all 13 extents.
4EAE
LD (4EC5H),A
Store the value held in Register A (which will be the counter of the extents) into the memory location 4EC5H which is in the middle of a LD A,nn OPCode.
4EB1
INC E
Bump the value stored in Register E by 1 so that Register Pair DE points to the next extent in the directory entry.
4EB2
LD A,(DE)
Fetch the value stored at memory location pointed to by Register Pair DE (i.e., the pointer in the directory entry for the next extent) and put it into Register A.
4EB3
CP 0FEH
Compare the value held in Register A (i.e., the next extent) against 0FEH. Results:
  • If Register A equals 0FEH, the Z FLAG is set.
  • If A < 0FEH, the CARRY FLAG will be set.
  • if A >= 0FEH, the NO CARRY FLAG will be set.
4EB5
If the NC FLAG (No Carry) is set then A >= 0FEH meaning that we reached the end of the extents, so JUMP to 4F07H to avoid continuing to parse the extents.
4EB7
AND 1FH
MASK the value of Register A against 1FH (0001 1111). This has the effect of turning off bits 7, 6, 5, leaving only bits 4, 3, 2, 1, 0 active, which will be the number of GRANS in that extent.
4EB9
LD C,A
LET Register C = Register A (i.e., the number of GRANs in the current extent).
4EBA
LD B,00H
LET Register B = 00H, so now Register Pair BC = the number of GRANs in the current extent.
4EBC
OR A
Set FLAGS based on the contents of Register A, but most notedly, clear the CARRY FLAG as we are about to use it.
4EBD
SBC HL,BC
Subtracts the value stored in Register Pair BC (i.e., the number of GRANs in the current extent) and the carry flag from the value stored in Register Pair HL (i.e., the EOF).
4EBF
If the Z FLAG (Zero) is set then the EOF = 0, so JUMP to 4EF3H.
4EC1
If the C FLAG (Carry) is set then the EOF < 0 so JUMP to 4ECEH.
4EC3
INC E
Bump the value stored in Register E by 1 so that Register Pair DE points to the next extent in the directory entry.
4EC4
LD A,nn
LET Register A = nn (i.e., the value in 4EC5H), which is the current counter of extents left to process.
4EC6
DEC A
DECrement the value stored in Register A by 1 to indicate one less extent to process.
4EC7
LD (4EC5H),A
Store the value held in Register A (i.e., the number of extents left to process) into the memory location 4EC5H.
4ECA
If the NZ FLAG (Not Zero) is set then we still have more extents to process, so LOOP BACK to 4EB1H.
4ECC
JUMP to 4F07H to continue once all 13 extents have been checked.

4ECEH – Continuation from the “CLOSE” routine; jumped to if the EOF < 0.

4ECE
LD A,L
LET Register A = Register L (i.e., the number of extra bytes).
4ECF
NEG
NEGate Register A so now it is the NEGATIVE number of extra bytes.
4ED1
LD L,A
LET Register L = Register A (i.e., the NEGATIVE number of extra bytes).
4ED2
LD A,(DE)
Fetch the value stored at memory location pointed to by Register Pair DE (i.e., the pointer in the directory entry) and put it into Register A.
4ED3
SUB L
SUBtract the value held in Register L from Register A so trim off the extra GRANs from the extent.
4ED4
LD (DE),A
Store the value held in Register A (i.e., the reduced/trimmed GRAN count) into the memory location pointed to by Register Pair DE.
4ED5
PUSH HL
Save Register HL (i.e., the numebr of extra GRANs) to the top of the stack.
4ED6
LD HL,4EF3H
LET Register Pair HL = 4EF3H to set a RETURN address.
4ED9
EX (SP),HL
EXchange the value stored in Register Pair HL (i.e., the return address of 4EF3H) with the value stored in Register Pair (SP).
4EDA
PUSH HL
Save Register HL to the top of the stack.
4EDB
PUSH DE
Save Register DE to the top of the stack.
4EDC
PUSH BC
Save Register BC to the top of the stack.
4EDD
LD C,L
LET Register C = Register L (i.e., the number of extra GRANs).
4EDE
EX DE,HL
EXchange the value stored in Register Pair HL with the value stored in Register Pair DE.
4EDF
LD A,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the extra element) and put it into Register A.
4EE0
PUSH AF
Save Register AF to the top of the stack.
4EE1
AND 1FH
MASK the value of Register A against 1FH (0001 1111) to isolate the number of GRANs. This has the effect of turning off bits 7, 6, 5, leaving only bits 4, 3, 2, 1, 0 active.
4EE3
LD E,A
LET Register E = Register A (i.e., the number of GRANs).
4EE4
POP AF
Restore Register Pair AF (i.e., the extent) from the top of the STACK.
4EE5
AND 0E0H
MASK the value of Register A against E0H (1110 0000) to isolate the offset in the track. This has the effect of turning off bits 4, 3, 2, 1, 0, leaving only bits 7, 6, 5 active.
4EE7
4EE8
4EE9
RLCA
RLCA
RLCA
Rotate the bits in A so that bits 7, 6, and 5, aare now bits 2, 1, and 0.
4EEA
PUSH AF
Save Register AF (which is the offset in the track) to the top of the stack.
4EEB
DEC HL
DECrement the value stored in Register Pair HL by 1 to back up 1 byte to the TRACK NUMBER byte.
4EEC
LD L,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the TRACK NUMBER) and put it into Register L.
4EED
LD H,4DH
LET Register H = 4DH so that Register Pair HL now points to the appropriate GAT ENTRY in RAM.
4EEF
POP AF
Restore Register Pair AF (i.e., the offset) from the top of the STACK.
4EF0
JUMP to 4FDEH to deallocate that GRAN.

4EF3H – Continuation from the “CLOSE” routine; jumped to if the EOF = 0, meaning that no trimming need be done. Just set the appropriate bytes to indicate that we have hit the end of the extents.

4EF3
EX DE,HL
EXchange the value stored in Register Pair HL with the value stored in Register Pair DE (the pointer to the directory entry in RAM).
4EF4
INC HL
Bump the value stored in Register Pair HL by 1 so that HL points to the next extent in the directory entry in RAM.
4EF5
LD A,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the TRACK NUMBER) and put it into Register A.
4EF6
CP 0FEH
Compare the value held in Register A (i.e., the TRACK NUMBER) against 0FEH. Results:
  • If Register A equals 0FEH, the Z FLAG is set.
  • If A < 0FEH, the CARRY FLAG will be set.
  • if A >= 0FEH, the NO CARRY FLAG will be set.
4EF8
If the NC FLAG (No Carry) is set then we have reached the end of the extents so JUMP to 4F07H.
4EFA
LD E,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the TRACK NUMBER) and put it into Register E.
4EFB
LD (HL),0FFH
Store a 0FFH into the memory location pointed to by Register Pair HL to indicate that we have reached the end of the extents.
4EFD
INC HL
Bump the value stored in Register Pair HL by 1.
4EFE
LD D,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the number of GRANs plus the offset) and put it into Register D.
4EFF
LD (HL),0FFH
Store a 0FFH into the memory location pointed to by Register Pair HL to indicate that we have reached the end of the extents.
4F01
INC HL
Bump the value stored in Register Pair HL by 1.
4F02
GOSUB to 4FCEH to deallocate the space.
4F05
LOOP BACK to 4EF5H until all extents have been tested.

4F07H – Continuation from the “CLOSE” routine if the directory did NOT need to be updated.

4F07
LD B,(IX+07H)
Fetch the value stored at the memory location pointed to by IX+07H (i.e., the position in the DCB for the LOGICAL FILE NUMBER) and put it into Register B.
4F0A
LD C,(IX+06H)
Fetch the value stored at the memory location pointed to by IX+06H (i.e., the position in the DCB for the DRIVE NUMBER) and put it into Register C.
4F0D
LD A,(IX+0EH)
Fetch the value stored at the memory location pointed to by IX+0EH (i.e., the position in the DCB for the DISK SIDE NUMBER) and put it into Register A.
4F10
LD (4463H),A
Store the value held in Register A into the memory location 4463H.
NOTE: 4463H is the storage location for the old system disk side number.
4F13
GOSUB to 4A9BH to write the GAT sector from the appropriate RAM buffer.
4F16
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4F17
GOSUB to 4A7BH.
NOTE: 4A7BH is the SYS00/SYS routine to to write the directory entry from the copy in RAM to the diskette.
4F1A
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4F1B
LD A,(IX+06H)
Fetch the value stored at the memory location pointed to by IX+06H (i.e., the position in the DCB for the DRIVE NUMBER) and put it into Register A.
4F1E
ADD A,30H
ADD the value 30H to Register A (Results held in Register A) so as to convert a number in to the ASCII value for that number.
4F20
LD (4F59H),A
Store the value held in Register A (i.e., the ASCII version of the drive number) into the memory location 4F59H which is in the middle of a LD A,nn OPCode.
4F23
LD HL,nnnn
LET Register Pair HL = nnnn, which was placed in 4F24H-4F25H elsewhere.
4F26
LD DE,0005H
LET Register Pair DE = 0005H, which is the offset to HL to then point to the filespec in the directory entry.
4F29
ADD HL,DE
ADD the value held in Register Pair DE to Register Pair HL. The results are held in Register Pair HL, so HL now points to the filespec in the directory entry.
4F2A
PUSH HL
Save Register HL (i.e., the pointer to the filespec in the directory entry) to the top of the stack.
4F2B
PUSH IX
Save Register IX (i.e., the DCB) to the top of the stack.
4F2D
POP DE
Restore Register Pair DE (i.e., the DCB) from the top of the STACK.
4F2E
LD B,08H
LET Register B = 08H to prepare for a DJNZ loop of 8 iterations.
4F30
LD A,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., a character of the filespec in the directory entry) and put it into Register A.
4F31
CP 20H
Compare the value held in Register A against 20H (ASCII: SPACE which would indicate that we have run out of letters in the filespec before 8. Results: If Register A equals 20H, the Z FLAG is set; otherwise the NZ FLAG is set.
4F33
If the Z FLAG (Zero) is set, meaning we hit a space, JUMP to 4F3AH as we do not need to keep parsing filespec characters.
4F35
LD (DE),A
Store the value held in Register A (i.e., the current filespec character) into the memory location pointed to by Register Pair DE.
4F36
INC HL
Bump the value stored in Register Pair HL by 1 so that HL now points to the next character in the filespec in the directory entry.
4F37
INC DE
Bump the value stored in Register Pair DE by 1 so that DE now points to the next space in the DCB.
4F38
DJNZ 4F30H
LOOP back to 4F30H until Register B is ZERO and the entire filespec has been copied from the directory entry in RAM to the DCB.
4F3A
POP HL
Restore the pointer to the filespec in the directory entry from the top of the stack into Register Pair HL.
4F3B
LD A,L
LET Register A = Register L so as to prepare to move 8 characters foward, to leave Register Pair HL pointing to the extension in the filename in the directory.
4F3C
ADD A,08H
ADD the value 08H to Register A (Results held in Register A).
4F3E
LD L,A
LET Register L = Register A, so now Register Pair HL points to the extension in the filename in the directory.
4F3F
LD A,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the first character of the extension in the filename in the directory) and put it into Register A.
4F40
CP 20H
Compare the value held in Register A against 20H (ASCII: SPACE) to see if it is empty. Results: If Register A equals 20H, the Z FLAG is set; otherwise the NZ FLAG is set.
4F42
If the Z FLAG (Zero) is set then there is no extension, so JUMP to 4F54H.
4F44
LD A,2FH
LET Register A = 2FH (ASCII: /).
4F46
LD (DE),A
Store the value held in Register A (i.e., a /) into the memory location pointed to by Register Pair DE (i.e., the space in the DCB following the filespec).
4F47
INC DE
Bump the value stored in Register Pair DE by 1 so that DE now points to the space after the / in the DCB.
4F48
LD B,03H
LET Register B = 08H to prepare for a DJNZ loop of 3 iterations (for the extension).
4F4A
LD A,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., a character of the extension in the directory entry) and put it into Register A.
4F4B
CP 20H
Compare the value held in Register A against 20H (ASCII: SPACE) which would indicate that we have run out of letters in the extension before 3. Results: If Register A equals 20H, the Z FLAG is set; otherwise the NZ FLAG is set.
4F4D
If the Z FLAG (Zero) is set, meaning we hit a space, JUMP to 4F54H as we do not need to keep parsing extension characters.
4F4F
LD (DE),A
Store the value held in Register A (i.e., the current extension character) into the memory location pointed to by Register Pair DE.
4F50
INC HL
Bump the value stored in Register Pair HL by 1 so that HL now points to the next character in the filespec in the directory entry.
4F51
INC DE
Bump the value stored in Register Pair DE by 1 so that DE now points to the next space in the DCB.
4F52
DJNZ 4F4AH
LOOP back to 4F4AH until Register B is ZERO and the entire extension has been copied from the directory entry in RAM to the DCB.
4F54
LD A,3AH
LET Register A = 3AH (ASCII: :).
4F56
LD (DE),A
Store the value held in Register A (i.e., a :) into the memory location pointed to by Register Pair DE (i.e., the space in the DCB following the filespec).
4F57
INC DE
Bump the value stored in Register Pair DE by 1 so that DE now points to the space after the : in the DCB.
4F58
LD A,nn
LET Register A = nn. This is the ASCII value of a DRIVE NUMBER and it was placed in (4F59H) by other instructions.
4F5A
LD (DE),A
Store the value held in Register A (i.e., the ASCII version of the DRIVE NUMBER) into the memory location pointed to by Register Pair DE.
4F5B
INC DE
Bump the value stored in Register Pair DE by 1 so that DE now points to the next space in the DCB.
4F5C
LD A,03H
LET Register A = 03H, which is a terminator character
4F5E
LD (DE),A
Store the value held in Register A (i.e., the terminator character) into the memory location pointed to by Register Pair DE.
4F5F
XOR A
Set Register A to ZERO and clear all Flags to signify NO ERROR.
4F60
RET
RETurn to the caller.

4F61H – MAIN ROUTINE – “KILL” – Delete a file from the directory.

4F61
GOSUB to 4881H (from SYS00/SYS) to set up for closing a file.
4F64
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4F65
LD A,(IX+01H)
Fetch the value stored at the memory location pointed to by IX+01H (i.e., the position in the DCB for the OPTIONS byte) and put it into Register A.
4F68
AND 07H
MASK the value of Register A against 07H (0000 0111) to isolate the access level. This has the effect of turning off bits 7, 6, 5, 4, 3, leaving only bits 2, 1, 0 active.
4F6A
CP 02H
Compare the value held in Register A against 02H to see if we have KILL access (or higher) to the file. Results:
  • If Register A equals 02H, the Z FLAG is set.
  • If A < 02H, the CARRY FLAG will be set.
  • if A >= 02H, the NO CARRY FLAG will be set.
4F6C
If the C FLAG (Carry) is set, then we have KILL acces (or higher), so continue on at 4F72H.
4F6E
LD A,1AH
LET Register A = 19H to set up for a FILE ACCESS DENIED error.
4F70
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A. The NZ Flag will be set because we just put a 26H into Register A, so NZ will be set to indicate an error.
4F71
RET
RETurn to the caller.

4F72H – Continuation of “KILL” Routine. Jumped here if we have access to kill the file.

4F72
LD C,(IX+06H)
Fetch the value stored at the memory location pointed to by IX+06H (i.e., the position in the DCB for the DRIVE NUMBER) and put it into Register C.
4F75
LD B,(IX+07H)
Fetch the value stored at the memory location pointed to by IX+07H (i.e., the position in the DCB for the LOGICAL FILE NUMBER) and put it into Register B.
4F78
LD A,(IX+0EH)
Fetch the value stored at the memory location pointed to by IX+0EH (i.e., the position in the DCB for the DISK SIDE NUMBER) and put it into Register A.
4F7B
LD (4463H),A
Store the value held in Register A into the memory location 4463H.
NOTE: 4463H is the storage location for the old system disk side number.
4F7E
GOSUB to 4ABAH.
NOTE: 4ABAH is the SYS00/SYS routine to read the HIT sector into RAM.
4F81
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4F82
LD L,B
LET Register L = Register B, so that Register Pair HL will now point to the HIT ENTRY for the file to kill.
4F83
LD (HL),00H
Store the value held in Register 00H into the memory location pointed to by Register Pair HL (i.e., the HIT ENTRY for the file to kill).
4F85
GOSUB to 4AC2H.
NOTE: 4AC2H is the SYS00/SYS routine to write the HIT sector from RAM to diskette.
4F88
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4F89
GOSUB to 4A93H.
NOTE: 4A93H is the SYS00/SYS routine to READ THE GAT sector into RAM (Buffer at 4D00H).
4F8C
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4F8D
GOSUB to 4A67H.
NOTE: 4A67H is the SYS00/SYS routine to read the directory entry into RAM (Buffer at 4300H)
4F90
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4F91
LD (4FACH),HL
Store the value held in Register HL (i.e., the pointer to the entry) into the memory location 4FACH (which is in the middle of a LD HL,nnnn OPCODE).
4F94
LD A,16H
LET Register A = 16H (Decimal: 22) for the number of bytes to skip to get to the extents in a directory entry of the file to kill.
4F96
ADD A,L
ADD the value held in Register L to Register A (Results held in Register A).
4F97
LD L,A
LET Register L = Register A so now HL points to the extents in a directory entry of the file to kill.
4F98
PUSH BC
Save Register BC (i.e., the DRIVE NUMBER and LOGICAL FILE NUMBER of the file to kill) to the top of the stack.
4F99
LD B,0DH
LET Register B = 0DH (Decimal: 13) to loop over the 13 extents.
4F9B
LD E,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the TRACK NUMBER of the extent) and put it into Register E.
4F9C
INC HL
Bump the value stored in Register Pair HL by 1 so that HL points to the next byte in the extent.
4F9D
LD D,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the SIZE and OFFSET of the extent) and put it into Register D.
4F9E
LD A,E
LET Register A = Register E so that we can test Register E against 0FEH to determine if we have hit the end of the extents.
4F9F
CP 0FEH
Compare the value held in Register A against 0FEH, which would signify that we have reached the end of the extents. Results:
  • If Register A equals 0FEH, the Z FLAG is set.
  • If A < 0FEH, the CARRY FLAG will be set.
  • if A >= 0FEH, the NO CARRY FLAG will be set.
4FA1
If the NC FLAG (No Carry) is set then we have reached the end of the extents so JUMP to 4FABH since we don’t need to keep looping through the extents..
4FA3
INC L
Bump the value stored in Register L by 1 so that Register Pair HL points to the next byte in the extents.
4FA4
PUSH BC
Save Register BC (i.e., the extent counter) to the top of the stack.
4FA5
GOSUB to 4FCEH to de-allocate the extent.
4FA8
POP BC
Restore the extent counter from the top of the stack into Register Pair BC.
4FA9
DJNZ 4F9BH
LOOP back to 4F9BH until Register B is ZERO and all 13 extents have been handled (or we exited earlier).
4FAB
LD HL,nnnn
LET Register Pair HL = nnnn (i.e., the directory entry of the filespec we want to kill), which was placed in 4FACH elsewhere in the DOS.
4FAE
LD (HL),00H
Store the value held in Register 00H into the memory location pointed to by Register Pair HL (i.e., the directory entry of the filespec we want to kill).
4FB0
PUSH DE
Save Register DE to the top of the stack.
4FB1
4FB2
LD D,H
LD D,H
LET Register Pair DE = Register HL (i.e., the directory entry of the filespec we want to kill).
4FB3
INC DE
Bump the value stored in Register Pair DE by 1 (i.e., the directory entry AFTER the directory entry of the filespec we want to kill).
4FB4
LD BC,002FH
LET Register Pair BC = 002FH (Decimal: 47) so that we zero 47 bytes.
4FB7
LDIR
Transfers a byte of data from the memory location pointed to by HL to the memory location pointed to by DE. Then HL and DE are incremented and BC is decremented. If BC is not zero, this operation is repeated. Interrupts can trigger while this instruction is processing.
4FB9
POP DE
Restore Register Pair DE from the top of the STACK.
4FBA
POP BC
Restore Register Pair BC from the top of the STACK.
4FBB
GOSUB to 4A7BH.
NOTE: 4A7BH is the SYS00/SYS routine to to write the directory entry from the copy in RAM to the diskette.
4FBE
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4FBF
GOSUB to 4A9BH.
NOTE: 4A9BH is the SYS00/SYS routine to to write the GAT sector from RAM to diskette.
4FC2
RET NZ
If the NZ FLAG (Not Zero) is set then that the prior CALL routine returned an ERROR, so RETurn to caller with the NZ FLAG set (to signify an error).
4FC3
4FC5
PUSH IX
POP HL
LET HL = IX (i.e., the DCB).
4FC6
LD B,10H
LET Register B = 10H (Decimal: 16) for a DJNZ loop to clear 16 bytes.
4FC8
XOR A
Set Register A to ZERO and clear all Flags.
4FC9
LD (HL),A
Store the value held in Register A into the memory location pointed to by Register Pair HL (i.e., the DCB).
4FCA
INC HL
Bump the value stored in Register Pair HL by 1 so HL points to the next byte of the DCB.
4FCB
DJNZ 4FC9H
LOOP back to 4FC9H until Register B is ZERO.
4FCD
RET
RETurn to the caller.

4FCEH – SUBroutine to De-Allocate Space.

4FCE
PUSH HL
Save Register HL to the top of the stack.
4FCF
PUSH DE
Save Register DE to the top of the stack.
4FD0
PUSH BC
Save Register BC to the top of the stack.
4FD1
LD L,E
LET Register L = Register E.
4FD2
LD H,4DH
LET Register H = 4DH, so that Register Pair HL now points to the GAT Entry in RAM
4FD4
LD A,D
LET Register A = Register D and …
4FD5
AND 1FH
… MASK the value of Register A against 1FH (0001 1111) to isolate the number of GRANs. This has the effect of turning off bits 7, 6, 5, leaving only bits 4, 3, 2, 1, 0 active.
4FD7
LD C,A
LET Register C = Register A (i.e., the number of GRANs).
4FD8
XOR D
eXclusive OR Register D against Register A which will then put the offset in the track into Register A.
4FD9
4FDA
4FDB
RLCA
RLCA
RLCA
Rotate the bits in A left so that the offset moves into bits 2, 1, and 0.
4FDC
LD E,00H
LET Register E = 00H.
4FDE
PUSH AF
Save Register AF to the top of the stack.
4FDF
PUSH HL
Save Register HL to the top of the stack.
4FE0
ADD A,E
ADD the value held in Register E to Register A (Results held in Register A) to computer the number of grans offset.
4FE1
LD L,A
LET Register L = Register A.
4FE2
LD H,00H
LET Register H = 00H, so that Register Pair HL is the number of tracks to offset
4FE4
LD A,06H
LET Register A = 06H since we are going to need to divide by 6.
4FE6
GOSUB to 4451H to divide the number of grans by 6; Remainder in A.
4FE9
LD D,A
LET Register D = Register A (i.e., the remainder from that division).
4FEA
LD A,L
LET Register A = Register L (i.e., the number of tracks offset).
4FEB
POP HL
Restore Register Pair HL from the top of the STACK.
4FEC
PUSH HL
Save Register HL to the top of the stack.
4FED
ADD A,L
ADD the value held in Register L (i.e., the number of tracks offset) to Register A (Results held in Register A).
4FEE
LD L,A
LET Register L = Register A so that HL now points contains the number of tracks to offset.
4FEF
LD A,D
LET Register A = Register D (i.e., the number of grans).
4FF0
LD B,(HL)
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the GAT Table Entry) and put it into Register B.
4FF1
GOSUB to 4FFFH to de-allocate the granule.
4FF4
LD (HL),B
Store the value held in Register B into the memory location pointed to by Register Pair HL (i.e., the GAT Table Entry).
4FF5
POP HL
Restore Register Pair HL from the top of the STACK.
4FF6
POP AF
Restore Register Pair AF from the top of the STACK.
4FF7
INC E
Bump the value stored in Register E by 1 so as to point to the nexy GRAN.
4FF8
DEC C
DECrement the value stored in Register C by 1 to keep track of the loop.
4FF9
If the NZ FLAG (Not Zero) is set then we have more iterations to go, so JUMP to 4FDEH.
4FFB
POP BC
Restore Register Pair BC from the top of the STACK.
4FFC
POP DE
Restore Register Pair DE from the top of the STACK.
4FFD
POP HL
Restore Register Pair HL from the top of the STACK.
4FFE
RET
RETurn to the caller.

4FFFH – SUBroutine from the SUBroutine to de-allocate space.

This routine does a little bit of bit manipulation to form an OPCODE of RES nn,B

In summary, RES n,B is a set of OPCODES which are 80H (for bit 0), 88H (for bit 1), 90H (for bit 2), 98H (for bit 3), etc. These are conveniently “10xx x000” in binary, so they tick up based on bits 5, 4, and 3.

So if the value was 100 after the AND 07 in 4FFFH, then 3 lefts would make it, 00 100 000. Then the OR 80H makes it 10 100 000. 10100000 in Hex is A8H. The Z-80 OPCODE of CB A8 is RES 5,B. So 101 would be RES 5,B.

For purposes of this, I will track an example. Let’s say Register A is 0DBH and we’ll track that through…

4FFF
AND 07H
MASK the value of Register A against 07H (0000 0111). This has the effect of turning off bits 7, 6, 5, 4, 3, leaving only bits 2, 1, 0 active.

07H is 0000 0111 and Register is 0DBH which is 1101 1011. If you AND them together, only the last 3 bits survive, so Register A becomes 0000 0011.

5001
5002
5003
RLCA
RLCA
RLCA
Rotate the bits in A left so that the offset moves bits 2, 1, and 0 to bits 5, 4, and 3 .

Rotating 0000 0011 left 3 times, gives you 00 011 000.

5004
OR 80H
OR Register A against 80H (Binary: 1000 0000) to convert Register A (which is just bits 5, 4, and 3) into an appropriate RES OPCODE.

80H is 1000 0000, so when you OR Register A (00 011 000) by 80H (1000 0000) you get 10 011 000. 10110000 in Hex is 0B0H.

5006
LD (500AH),A
Store the value held in Register A into the memory location 500AH (i.e., the next opcode).

Memory Location 500AH is in the middle of the next 2 instructions which are 0CB nn. Putting 0B0H in 500AH makes the next instruction 0CBH 0B0H, which is the Z-80 OPCODE for RES 6,B

5009
RES nn,B
RESet (i.e., set as 0) BIT (A) of Register B.
500B
RET
RETurn to the caller.
 
END 4E00H