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

General:

SYS14/SYS handles FILE POINTER ($FILPTR) and RAM DIRECTORY ($RAMDIR) functions.


Disassembly:

 
ORG 4E00H
“START”
4E00
AND 0F0H
MASK off the SYSTEM NUMBER from the byte passed to this OVERLAY by masking against F0H (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 remainder of Register A against 90H, which would be the RAMDIR function call. If the masked value is 90H, then …
4E04
JP Z,VECT10
     [4EE3H]
… JUMP to 4E26H.
4E07
CP 080H
Compare the remainder of Register A against 80H, which would be the FILPTR function call. If the masked value is NOT 80H then we didn’t get a valid parameter …
4E09
RET NZ
… so return to caller with NZ FLAG set.

4E0AH – “FILPTR” Routine – Returns File Pointers to a USER PROGRAM.

“GETLFN”
4E0A
PUSH IX
Save the contents of Special Index Register IX to the top of the stack.
4E0C
4E0D
PUSH DE
POP IX
Let Special Index Register IX = DE (which is a DCB).
4E0F
LD A,(IX+00H)
Check to see if the file is open by Fetching the value held in the memory location pointed to by Special Index Register Pair IX+00H and store it into Register A.
Note: IX+00H = the position in the DCB for the TYPE of FCB byte. Bit 0: 1=Read Only, Bit 1: 1=Write Only, Bit 4: 1=The next 2 bytes are simply the address of another FCB, Bit 7=1: Then the next 50 bytes are the description of an open file.
4E12
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
4E13
JP P,LFNER1
     [4E20H]
If the PARITY FLAG has been set then the file is NOT open, so exit with an error by JUMPing to 4E20H.
4E16
LD B,(IX+06H)
Fetch the DRIVE NUMBER (held in the memory location pointed to by Special Index Register Pair IX+06H) and store it into Register B.
4E19
LD C,(IX+07H)
Fetch the LOGICAL FILE NUMBER [the directory entry number] (held in the memory location pointed to by Special Index Register Pair IX+07H) and store it into Register C.
4E1C
INC C
INCrement the LOGICAL FILE NUMBER (stored in Register C) by 1.
4E1D
XOR A
Clear all Flags.
4E1E
JR LFNEXT
   [4E22H]
Skip over the next instruction by JUMPing to 4E22H to continue.

4E20H – “FILPTR” Routine – All done!.

“LFNER1”
4E20
LD A,26H
Let Register A equal 26H to return an error for “FILE NOT OPEN”.
“LFNEXT”
4E22
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
4E23
POP IX
Restore Special Register Pair IX from the top of the stack, and then remove the entry from the stack.
4E25
RET
RETurn to the caller, either with 00H set, or a “FILE NOT OPEN” error.

4E26H – “RAMDIR” Routine – Process the Disk Directory in RAM.

On entry: B = Drive Number, HL = RAM Storage Buffer, and C = a switch to denote what is being processed. 0=All unprotected directory records, 1-96=A specific directory record, FF=Used and Free Space only.

On exit: HL = RAM Storage Buffer. Z FLAG indicates GOOD DIRECTORY READ IN RAM

The buffer is structured: Bytes 0-14=Filename, 15=Attrib, 16=EOF Byte, 17=LRL Byte, 18-19=End Record Number, 20-21=Number of grans allocated.

“GETDIR”
4E26
PUSH BC
Save the contents of Register Pair BC (i.e., the drive number and the user selected routine switch) to the top of the stack.
4E27
PUSH DE
Save the contents of Register Pair DE to the top of the stack.
4E28
PUSH HL
Save the contents of Register Pair HL to the top of the stack.
4E29
LD (RAMM),HL
Store the RAM STORAGE BUFFER POINTER (held in Register Pair HL) into memory location 4FADH.

A “++” is put at the end of the buffer to signify the end of the buffer, just in case there are no entries to be found.

4E2C
LD (HL),2BH
Store a 2BH (ASCII: +) into the memory location pointed to by Register Pair HL.
4E2E
INC HL
INCrement the RAM STORAGE BUFFER POINTER (held in Register Pair HL) by 1.
4E2F
LD (HL),2BH
Store a 2BH (ASCII: +) into the memory location pointed to by Register Pair HL.

Next we save the drive number and test it.

4E31
LD A,B
Copy the DRIVE NUMBER (held in Register B) into Register A.
4E32
LD (DDRV),A
Store the DRIVE NUMBER (Register A) into memory location 4FAFH.
4E35
LD A,(4413H)
Fetch the value held in memory location 4413H and store it into Register A.
NOTE: 4413H is the storage location for the NUMBER OF DISK DRIVES in the system.
4E38
CP B
Compare USER PROVIDED DRIVE NUMBER (held in Register B) and the NUMBER OF DISK DRIVES IN THE SYSTEM (traditionally held at 4413H). If the NUMBER OF DISK DRIVES is < the USER PROVIDED DRIVE NUMBER then we have a problem …
4E39
JR C,4E4DH
     [4E4DH]
… so JUMP to DIRER1.

The drive number has been validated, so next let us get the function switch from Register C.

4E3B
LD A,C
Copy the function switch (held in Register C on entry) into Register A.
4E3C
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
4E3D
JR Z,DIRALL
     [4E5CH]
If the FUNCTION SWITCH was 00H, then the user wants the WHOLE DIRECTORY, so JUMP to 4E5CH.
4E3F
JP M,GETFRE
     [4EA0H]
If the SIGN FLAG has been SET (meaning that Register C was FFH), then the user wants the FREE INFO, so JUMP to 4EA0H.
4E42
DEC A
If neither of those flags were set then the user wants the DIRECTORY ENTRY and supplied the record number they want. First DECrement the USER REQUESTED LOGICAL FILE NUMBER (stored in Register A) by 1.
4E43
CP 51H
Compare the USER REQUESTED LOGICAL FILE NUMBER (stored in Register A) against 51H (Decimal: 81). If the LOGICAL FILE NUMBER >= 81, then we have an invalid LOGICAL FILE NUMBER (because 80 is the highest), so …
4E45
JR NC,DIRER3
      [4E55H]
… JUMP to 4E55H.
4E47
LD B,A
The USER REQUESTED LOGICAL FILE NUMBER is valid, so store it in Register B.
4E48
CALL SETIT
     [4EE3H]
Fetch the DIRECTORY ENTRY for the USER REQUESTED LOGICAL FILE NUMBER (held in Register B) via a GOSUB to 4EE3H.
4E4B
JR DIREXT
   [4E57H]
EXIT via a JUMP to 4E57H.

4E4DH – Exit with a “DISK DRIVE NOT ON” Error.

“DIRER1”
4E4D
LD A,02H
Let Register A equal 02H for a “DISK DRIVE NOT ON” error.
4E4F
JR DIREXT
   [4E57H]
Display the error and exit via a JUMP to 4E57H.

4E4DH – Exit with a “FILE ACCESS DENIED” Error.

“DIRER2”
4E51
LD A,19H
Let Register A equal 19H for a “FILE ACCESS DENIED” error.
4E53
JR DIREXT
   [4E57H]
Display the error and exit via a JUMP to 4E57H.

4E55H – Exit with a “BAD FILE NUMBER” Error.

“DIRER3”
4E55
LD A,10H
Let Register A equal 10H for a “BAD FILE NUMBER” error..
“DIREXT”
4E57
OR A
Set the flags based on the error (so NZ FLAG should be enabled).
4E58
POP HL
Put the value held at the top of the STACK into Register Pair HL, and then remove the entry from the stack.
4E59
POP DE
Put the value held at the top of the STACK into Register Pair DE, and then remove the entry from the stack.
4E5A
POP BC
Put the value held at the top of the STACK into Register Pair BC, and then remove the entry from the stack.
4E5B
RET
RETurn to the caller.

4E5CH – “RAMDIR” Routine – “Whole Directory” option was selected by the user.

“DIRALL”
4E5C
LD A,(DDRV)
Fetch the DRIVE NUMBER (held in memory location 4FAFH) and store it into Register A.
4E5F
LD C,A
Copy the DRIVE NUMBER into Register C.
4E60
CALL RDHIT
     [4ABAH]
GOSUB to 4ABAH.
NOTE: 4ABAH is the SYS00/SYS routine to read the HIT sector into RAM.
4E63
JP NZ,DIREXT
      [4E57H]
If that call resulted in an error then the NZ FLAG (Not Zero) will have been set. JUMP to 4E57H.
4E66
LD HL,BUFF1
Let Register Pair HL equal 4300H, which is a memory buffer where the HIT contents are stored following a GOSUB to 4ABAH.
4E69
LD DE,BUFF2
Let Register Pair DE equal 4D00H.
NOTE: 4D00H is a memory buffer (referred to as Memory Buffer 2) where diskette contents are stored in RAM.
4E6C
LD (HITPTR),DE
Store the START OF BUFFER 2 (held in Register Pair DE) into memory location 4FB2H.
4E70
LD BC,0100H
Let Register Pair BC equal 0100H (Decimal: 256) to move 256 bytes.
4E73
LDIR
Copy the HIT sector to the buffer at 4D00H via LDIR which 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.
4E75
LD A,50H
Let Register A equal 50H (Decimal: 96) to work through the maximum of 96 HIT entries.
4E77
LD (RECCNT),A
Store the HIT ENTRIES STILL TO PROCESS COUNTER (held in Register A) into memory location 4FB4H.

Start of a loop to process 96 HIT entries.

“DIRAL1”
4E7A
LD HL,(HITPTR)
Fetch the HIT ENTRY stored in the HIT ENTRY POINTER memory location of 4FB2H and store it into Register Pair HL.
4E7D
LD A,(HL)
Fetch the actual HIT ENTRY (held in the memory location pointed to by Register Pair HL) and store it into Register A.
4E7E
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
4E7F
JR Z,NXTFIL
     [4E8CH]
If the Z FLAG (Zero) has been set then the HIT ENTRY pointed to by HL is empty, so move to the next HIT ENTRY by JUMPing to 4E8CH.
4E81
LD B,L
Copy the LOGICAL FILE NUMBER (held in Register L) into Register B.
4E82
CALL SETIT
     [4EE3H]
Get the directory entry of the LOGICAL FILE NUMBER held in Register B via a GOSUB to 4EE3H.
4E85
JR Z,NXTFIL
     [4E8CH]
If the Z FLAG (Zero) has been set then the CALL resulted in success, so continue via a JUMP to 4E8CH.
4E87
CP 19H
Compare the drive response code (held in Register A) against 19H (Error: “FILE ACCESS DENIED”). If it was not for a “FILE ACCESS DENIED” error …
4E89
JP NZ,DIREXT
      [4E57H]
…. JUMP to 4E57H.
“NXTFIL”
4E8C
LD HL,(HITPTR)
Fetch the POINTER TO THE ENTRY TO PROCESS stored in the HIT ENTRY POINTER memory location of 4FB2H and store it into Register Pair HL.
4E8F
INC HL
Move to the next HIT ENTRY by INCrementing the HIT ENTRY POINTER (stored in Register Pair HL) by 1.
4E90
LD (HITPTR),HL
Store HIT ENTRY POINTER (held in Register Pair HL) into the HIT ENTRY TRACKING memory location of 4FB2H.
4E93
LD A,(RECCNT)
Fetch the HIT ENTRIES STILL TO PROCESS from the HIT ENTRIES STILL TO PROCESS COUNTER (held in memory location 4FB4H) and store it into Register A.
4E96
DEC A
DECrement the HIT ENTRIES STILL TO PROCESS COUNTER by 1.
4E97
LD (RECCNT),A
Store the new HIT ENTRIES STILL TO PROCESS COUNTER (held in Register A) into memory location 4FB4H.
4E9A
JR NZ,DIRAL1
      [4E7AH]
If the NZ FLAG (Not Zero) has been set then there are still HIT ENTRIES TO PROCESS, so LOOP BACK to 4E7AH.

End of the loop to process 96 HIT entries.

4E9C
XOR A
If we are here then all 96 HIT entries were processed. Set Register A to ZERO to indicate NO ERROR and clear all Flags.
4E9D
JP DIREXT
   [4E57H]
Exit via a JUMP to 4E57H.

4EA0H – “RAMDIR” Routine – “FREE INFO” option was selected by the user.

“GETFRE”
4EA0
LD A,(DDRV)
Fetch the DRIVE NUMBER (held in memory location 4FAFH) and store it into Register A.
4EA3
LD C,A
Copy the DRIVE NUMBER into Register C.
4EA4
CALL 4A93H
     [4A93H]
GOSUB to 4A93H.
NOTE: 4A93H is the SYS00/SYS routine to READ THE GAT sector into RAM (Buffer at 4D00H).
4EA7
JP NZ,DIREXT
      [4E57H]
If that call resulted in an error then the NZ FLAG (Not Zero) will have been set. JUMP to 4E57H.
4EAA
LD IX,BUFF2
Let Special Index Register IX equal 4D00H, which is the start of the RAM BUFFER where the GAT ENTRY was stored from the CALL to 4A93H.
4EAE
LD IY,0000H
Let Special Index Register Pair IY equal 0000H to act as the UNUSED TOTAL COUNTER. It will be tracking the FREE SPACE.
4EB2
LD HL,0000H
Let Register Pair HL equal 0000H to act as the USED TOTAL COUNTER. It will be tracking the USED SPACE.
4EB5
LD D,H
Set Register D = 0 (since H is 00H).
4EB6
LD E,H
Set Register E = 0 (since H is 00H).
4EB7
LD C,28H
Let Register C equal 28H (Decimal: 40), as the highest track to scan.

Top of Loop of 40 Tracks.

“GETFR1”
4EB9
LD A,(IX+00H)
Fetch the ALLOCATION BYTE of the GAT (which is the first byte of the GAT) held in the memory location pointed to by Special Index Register Pair IX+00H and store it into Register A.
Note: IX+00H = the position in the DCB for the TYPE of FCB byte. Bit 0: 1=Read Only, Bit 1: 1=Write Only, Bit 4: 1=The next 2 bytes are simply the address of another FCB, Bit 7=1: Then the next 50 bytes are the description of an open file.
4EBC
LD B,06H
Let Register B equal 06H since there are 6 grans per track.

Top of a DJNZ Loop to run through 6 grans in the track (18 sectors in a track / 3 Sectors Per Gran = 6 Grans per track)

“GETFR2”
4EBE
RRA
Rotate the contents of A right one bit position, with BIT 0 being copied to the CARRY FLAG and to BIT 7.
4EBF
PUSH AF
Save the CARRY FLAG to the top of the stack.
4EC0
ADC HL,DE
If that BIT is 1, then add 1 to the USED COUNTER (held in Register Pair HL).
4EC2
POP AF
Put the value held at the top of the STACK into Register Pair AF, and then remove the entry from the stack.
4EC3
CCF
Invert the gran status (which is being held in the CARRY).
4EC4
RL E
Rotate Left Register E, so that Register Pair DE now holds the number of free grans.
4EC6
ADD IY,DE
LET Register Pair IY = the cumulative UNUSED grans so far (IY) + the additional free grans (DE).
4EC8
LD E,00H
Let Register E equal 00H.
4ECA
DJNZ 4EBEH
     [4EBEH]
LOOP back through all grans by jumping to 4EBEH, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.

End of DJNZ Loop

4ECC
INC IX
Bump IX to point to the next byte (i.e. track) in the GAT.
4ECE
DEC C
DECrement the track counter (stored in Register C) by 1.
4ECF
JR NZ,4EB9H
      [4EB9H]
If the NZ FLAG (Not Zero) has been set then there are still tracks to analyze, so LOOP BACK to 4EB9H.

End of Loop of 40 Tracks.

4ED1
EX DE,HL
EXchange the value stored in Register Pair HL (i.e., the TOTAL USED GRANS) with the value stored in Register Pair DE.
4ED2
4ED4
PUSH IY
POP BC
Let BC = IY (i.e., UNUSED GRAN COUNTER).
4ED5
LD HL,(RAMM)
Fetch the BUFFER POINTER (held in memory location 4FADH) and store it into Register Pair HL.
4ED8
LD (HL),E
Store the LSB of the amount of TOTAL USED GRANS (held in Register E) into the memory location pointed to by Register Pair HL.
4ED9
INC HL
INCrement the BUFFER POINTER (stored in Register Pair HL) by 1.
4EDA
LD (HL),D
Store the MSB of the amount of TOTAL USED GRANS (held in Register D) into the memory location pointed to by Register Pair HL.
4EDB
INC HL
INCrement the BUFFER POINTER (stored in Register Pair HL) by 1.
4EDC
LD (HL),C
Store the LSB of the amount of TOTAL UNUSED GRANS (held in Register C) into the memory location pointed to by Register Pair HL.
4EDD
INC HL
INCrement the BUFFER POINTER (stored in Register Pair HL) by 1.
4EDE
LD (HL),B
Store the MSB of the amount of TOTAL UNUSED GRANS (held in Register B) into the memory location pointed to by Register Pair HL.
4EDF
XOR A
Indicate success by setting Register A to ZERO and clear all Flags.
4EE0
JP DIREXT
   [4E57H]
Exit via a JUMP to 4E57H.

4EE3H – “RAMDIR” Routine – Subroutine to fetch the DIRECTORY ENTRY at the LOGICAL FILE NUMBER held in Register B.

“SETIT”
4EE3
LD A,(DDRV)
Fetch the DRIVE NUMBER (held in memory location 4FAFH) and store it into Register A.
4EE6
LD C,A
Copy the DRIVE NUMBER into Register C.
4EE7
CALL 4A67H
     [4A67H]
GOSUB to 4A67H.
NOTE: 4A67H is the SYS00/SYS routine to read the directory entry into RAM (Buffer at 4300H)
4EEA
RET NZ
If the NZ FLAG (Not Zero) has been set then that CALL returned with an error, so RETurn to the caller.
4EEB
BIT 6,(HL)
Check for a SYSTEM FILE by testing Bit Number 6 of Register HL. Z FLAG will be set if that bit is 0, and NZ FLAG will be set if that bit is 1.
4EED
JP NZ,4F9CH
      [4F9CH]
If the file was a SYSTEM FILE then the NZ FLAG (Not Zero) will have been set. JUMP to 4F9CH to zero out all the buffers and return with “FILE ACCESS DENIED” error.
4EF0
LD (DDIR),HL
Store the POINTER TO THE DIRECTORY ENTRY IN RAM (held in Register Pair HL) into memory location 4FB0H.
4EF3
LD DE,0005H
Since the filename starts 5 bytes into a directory entry, set Register Pair DE equal to 0005H.
4EF6
ADD HL,DE
Point the POINTER TO THE DIRECTORY ENTRY IN RAM (HL) at the FILENAME by adding 5.
4EF7
LD DE,(RAMM)
Fetch the pointer to the USER BUFFER (held in memory location 4FADH) and store it into Register Pair DE.
4EFB
LD BC,0008H
Set Register Pair BC equal to 0008H since there are up to 8 bytes in a filename.
4EFE
LD IX,000EH
Set Special Index Register Pair IX equal 000EH (Decimal: 14) since a filespec can be up to 14 bytes (i.e., NNNNNNNN/EEE:D).
4F02
LD A,20H
Let Register A equal 20H (ASCII: SPACE).

Top of a loop.

“SETIT0”
4F04
CP (HL)
Compare a SPACE (held in Register A) against the character at the memory location pointed to by the POINTER TO THE DIRECTORY ENTRY IN RAM (Register Pair HL). If it’s a SPACE ….
4F05
JR Z,SETIT2
     [4F0EH]
… exit this loop via a JUMP to 4F0EH.
4F07
DEC IX
DECrement the amount of characters left in the filespec (tracked in Special Index Register IX) by 1.
4F09
LDI
Move to the 2nd character of both HL and DE via LDI command; which copies BC number of characters from (HL) to (DE), dropping BC each time. When BC hits 0, the PE flag is reset.
4F0B
JP PE,SETIT0
      [4F04H]
If the PARITY/OVERFLOW FLAG has been SET then we are not yet done processing characters, so LOOP BACK to 4F04H.

Bottom of a loop.

“SETIT2”
4F0E
LD HL,(DDIR)
Fetch the POINTER TO THE DIRECTORY ENTRY IN RAM (held in memory location 4FB0H) and store it into Register Pair HL.
4F11
LD BC,000DH
Let Register Pair BC equal 000DH (Decimal: 13), which will be an offset to HL to get to the filename extension.
4F14
ADD HL,BC
LET Register Pair HL = Register Pair HL + Register BC, so that HL now points to the extension.
4F15
LD BC,0003H
Since an extension is maximum 3 characters, set Register Pair BC equal 0003H.
4F18
CP (HL)
Compare the value held in Register A (which should be a SPACE) against the FIRST CHARACTER OF THE EXTENSION (held in the memory location pointed to by the value held in Register Pair HL). Results: If Register A equals the value held in Register HL, the Z FLAG is set; otherwise the NZ FLAG is set.
4F19
JR Z,SETIT4
     [4F2BH]
If the Z FLAG (Zero) has been set, then we hit a space and there is no extension, so stop processing extension characters via a JUMP to 4F2BH.
4F1B
PUSH AF
If we’re here then we know we have at least 1 character of an extension, so save the SPACE (held in Register A) to the top of the stack.
4F1C
LD A,2FH
Let Register A equal 2FH (ASCII: /).
4F1E
LD (DE),A
Store a / into the memory location pointed to by Register Pair DE.
4F1F
INC DE
Since we just filled a character, move the pointer by INCrementing the value stored in Register Pair DE by 1.
4F20
POP AF
Restore the SPACE from the top of the stack into Register A.

Top of a loop to process the 2nd and 3rd characters of the filename extension, if any.

“SETIT3”
4F21
CP (HL)
Compare the value held in the memory location pointed to by the value held in Register Pair HL against a SPACE. If the byte is a SPACE
4F22
JR Z,SETIT4
     [4F2BH]
… JUMP to 4F2BH.
4F24
DEC IX
DECrement the amount of space left in the filespec (tracked in Special Index Register IX) by 1.
4F26
LDI
Move to the 2nd character of both HL and DE via LDI command; which copies BC number of characters from (HL) to (DE), dropping BC each time. When BC hits 0, the PE flag is reset.
4F28
JP PE,SETIT3
      [4F21H]
If the PARITY/OVERFLOW FLAG has been SET then there are more characters to test, so LOOP BACK to 4F21H.

Bottom of the loop to process the 2nd and 3rd characters of the filename extension, if any.

“SETIT4”
4F2B
So now the filename, the “/” (if necessary), and the extension (if any) have been placed into RAM (tracked by DE). Move to the DRIVE NUMBER next. Let Register A equal 3AH (ASCII: :).
4F2D
LD (DE),A
Store the : into the LOCATION IN THE USER BUFFER pointed to by Register Pair DE.
4F2E
INC DE
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair DE) by 1 to point after the :.
4F2F
LD A,(DDRV)
Fetch the DRIVE NUMBER (held in memory location 4FAFH) and store it into Register A.
4F32
AND 07H
MASK the value of Register A against 07H (0000 0111) to leave only 2, 1, 0 active.
4F34
ADD A,30H
LET Register A = Register A + 30H. Note: Adding 30H to from Register A will convert decimal number 0-9 into its ASCII equivalent (i.e., 6 + 30H = 36H, which, in ASCII, is 6.
4F36
LD (DE),A
Store the DRIVE NUMBER IN ASCII (held in Register A) into the memory location in the LOCATION IN THE USER BUFFER pointed to by Register Pair DE.
4F37
INC DE
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair DE) by 1 to point after the DRIVE NUMBER IN ASCII.

So now the complete filespec (filename/ext:drive) is in RAM with DE pointing to the drive number. Time to start processing the other information.

4F38
4F3A
DEC IX
DEC IX
DECrement the amount of space left in the filespec (tracked in Special Index Register IX) by 2 as the “:D” has been added.
4F3C
4F3E
PUSH IX
POP BC
Let Register Pair BC = the amount of space left in the filespec.
4F3F
LD B,C
Prepare for a DJNZ loop by copying the LSB of the amount of space left unfilled in the filespec (held in BC) into Register B.
4F40
EX DE,HL
EXchange the value stored in Register Pair HL (i.e., the LOCATION IN THE DIRECTORY ENTRY IN RAM) with the value stored in Register Pair DE (i.e., the LOCATION IN THE USER BUFFER).

Top of a loop to fill the excess characters in the USER BUFFER with SPACES.

“SETIT5”
4F41
LD (HL),20H
Store a : into the USER BUFFER at the memory location pointed to by Register Pair HL.
4F43
INC HL
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair HL) by 1.
4F44
DJNZ SETIT5
     [4F41H]
LOOP back to 4F41H, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.

Bottom of a loop.

4F46
LD IX,(DDIR)
Fetch the RAM POINTER IN THE DIRECTORY ENTRY (held in memory location 4FB0H) and store it into Special Index Register Pair IX.
4F4A
LD A,(IX+00H)
Fetch the ATTRIBUTE BYTE (held in the memory location pointed to by Special Index Register Pair IX+00H) and store it into Register A.
4F4D
AND 07H
MASK the value of Register A against 07H (0000 0111) to keep only the protection/access level bits active.
4F4F
LD (HL),A
Store the protection level (held in Register A) into the USER BUFFER memory location pointed to by Register Pair HL.
4F50
INC HL
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair HL) by 1.
4F51
LD A,(IX+03H)
Fetch the EOF BYTE (held in the memory location pointed to by Special Index Register Pair IX+03H) and store it into Register A.
4F54
LD (HL),A
Store the EOF BYTE into the USER BUFFER memory location pointed to by Register Pair HL.
4F55
INC HL
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair HL) by 1.
4F56
LD A,(IX+04H)
Fetch the LOGICAL RECORD LENGTH (held in the memory location pointed to by Special Index Register Pair IX+04H) and store it into Register A.
4F59
LD (HL),A
Store the LOGICAL RECORD LENGTH into the USER BUFFER memory location pointed to by Register Pair HL.
4F5A
INC HL
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair HL) by 1.
4F5B
LD A,(IX+14H)
Fetch the LSB of the END OF FILE SECTOR NUMBER (held in the memory location pointed to by Special Index Register Pair IX+14H) and store it into Register A.
4F5E
LD (HL),A
Store the LSB of the END OF FILE SECTOR NUMBER into the USER BUFFER memory location pointed to by Register Pair HL.
4F5F
INC HL
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair HL) by 1.
4F60
LD A,(IX+15H)
Fetch the MSB of the END OF FILE SECTOR NUMBER (stored in memory location pointed to by Special Index Register Pair IX+15H) and store it into Register A.
4F63
LD (HL),A
Store the LSB of the END OF FILE SECTOR NUMBER into the USER BUFFER memory location pointed to by Register Pair HL.
4F64
INC HL
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair HL) by 1.
4F65
LD (RAMM),HL
Store the LOCATION IN THE USER BUFFER (held in Register Pair HL) into memory location 4FADH.
4F68
LD IX,(DDIR)
Fetch the RAM POINTER IN THE DIRECTORY ENTRY (held in memory location 4FB0H) and store it into Special Index Register Pair IX.
4F6C
LD DE,0016H
Let Register Pair DE equal 0016H for a byte offset into the directory entry to point to the file extents.
4F6F
ADD IX,DE
Set Register Pair IX to point to the EXTENTS by letting IX = Register Pair IX + 22 (i.e., Register DE).
4F71
LD B,0DH
Let Register B equal 0DH (Decimal: 13) to loop through the 13 extents in each directory entry.
4F73
LD HL,0000H
Let Register Pair HL equal 0000H to be an accumulator for the number of grans in the extent.

Top of a loop to parse all extents and accumulate the number of grans into HL.

“SETIT6”
4F76
INC IX
INCrement IX to point to the next byte in the EXTENTS portion of the directory entry.
4F78
INC (IX+00H)
Test for a FFH in the current EXTENT by INCrementing the value stored in the memory location pointed to by Special Index Register IX+00H by 1.
4F7B
JR Z,4F8AH
     [4F8AH]
If the Z FLAG (Zero) has been set, then the EXTENT was FFH (or empty), so JUMP to 4F8AH.
4F7D
LD A,(IX+00H)
Fetch a byte of the EXTENT (pointed to by IX+00H) and put it into Register A. THis should be the SIZE byte of the extent.
4F80
AND 1FH
MASK the value of Register A against 1FH (0001 1111). This has the effect of turning off bits 7, 6, 5 (i.e., the starting gran), which are not needed for this calculation.
4F82
4F83
LD E,A
LD D,00H
Let Register Pair DE = the number of grans in the extent (held in Register A).
4F85
ADD HL,DE
Add the number of grans in the extent (held in Register Pair DE) into the accumulator (held in Register Pair HL).
4F86
INC IX
Bump Special Index Register IX to the next extent.
4F88
DJNZ 4F76H
     [4F76H]
LOOP back to 4F76H, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.

End of loop to parse all extents and accumulate the number of grans into HL.

“SETIT7”
4F8A
EX DE,HL
EXchange the value stored in Register Pair HL (i.e., the total number of grans in the extents) with the value stored in Register Pair DE.
4F8B
LD HL,(RAMM)
Fetch LOCATION IN THE USER BUFFER (held in memory location 4FADH) and store it into Register Pair HL.
4F8E
LD (HL),E
Store the LSB of the number of grans in the file (held in Register E) into the memory location pointed to by Register Pair HL.
4F8F
INC HL
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair HL) by 1.
4F90
LD (HL),D
Store the MSB of the number of grans in the file (held in Register D) into the memory location pointed to by Register Pair HL.
4F91
INC HL
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair HL) by 1.
4F92
LD (HL),2BH
Store a + delimiter into the LOCATION IN THE USER BUFFER (stored in Register Pair HL).
4F94
LD (RAMM),HL
Store the LOCATION IN THE USER BUFFER (held in Register Pair HL) into memory location 4FADH.
4F97
INC HL
INCrement the LOCATION IN THE USER BUFFER (stored in Register Pair HL) by 1.
4F98
LD (HL),2BH
Store a + delimiter into the LOCATION IN THE USER BUFFER (stored in Register Pair HL).
4F9A
XOR A
Set Register A to ZERO and clear all Flags to show NO ERROR.
4F9B
RET
RETurn to the caller.

4F9CH – Zero out all the buffers and return with “FILE ACCESS DENIED” error.

“CLEAR”
4F9C
LD HL,BUFF1
Let Register Pair HL equal 4300H.
NOTE: 4300H is a memory buffer (referred to as Memory Buffer 1) where diskette contents are stored in RAM.
NOTE: 4300H is the storage location for the 256 Byte Storage Area for Disk I/O.
4F9F
LD DE,BUFF1 + 1
Let Register Pair DE equal 4301H.
4FA2
LD BC,00FFH
Let Register Pair BC equal 00FFH to clear 256 bytes.
4FA5
LD (HL),00H
Zero out the memory location pointed to by Register Pair HL.
4FA7
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.
4FA9
LD A,19H
Let Register A equal 19H to return a “FILE ACCESS DENIED” error.
4FAB
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
4FAC
RET
RETurn to the caller.

4FADH – BYTE STORAGE AREA.

“RAMM”
4FAD
DEFS 2
RAM STORAGE BUFFER POINTER.
“DDRV”
4FAF
DEFS 1
USER SUPPLIED DRIVE NUMBER.
“DDIR”
4FB0
DEFS 2
INTERNAL DIRECTORY POINTER.
“HITPTR”
4FB2
DEFS 2
HIT TABLE POINTER.
“RECCNT”
4FB4
DEFS 1
INTERNAL RECORD COUNTER.

 
END 4E00H
That’s it!