4000
4000H is where the Model III ROM jumps when a RST 08H is executed. SYS0 has no load record here.
4003
4003H is where the Model III ROM jumps when a RST 10H is executed. SYS0 has no load record here.
4006
4006H is where the Model III ROM jumps when a RST 18H is executed. SYS0 has no load record here.
4009
4009H is where the Model III ROM jumps when a RST 20H is executed. SYS0 has no load record here.
400CRST28
400CH is the RST 28H Vector (i.e. OVERLAY LOADER) ... this is a JUMP to 4B82H.
400FRST30
400FH is the RST 30H Vector (i.e., DEBUG) ... this is a JUMP to 440DH.
4012
JP 3018H
4012H is the RST 38H Vector (i.e., INTERRUPTS) ... this is a JUMP to 3018H in the ROM.
402DSYS1IN / $JP2DOS
JUMP to 4296H.
This is the $JP2DOS routine and is the common routine to transfer control to TRSDOS READY.
4030ABORT
LD A,A1H 3E A1
ABORT: LET Register A = A1H (1010 0001), the overlay request code for the RST 28H call at 4032H. Bits 6-4 (010) select entry 2 of the overlay (the source writes it as vector 20H) and bits 3-0 (0001) select SYS1. The source calls this entry the ABORT OPERATION RE-ENTRY TO DOS: SYS1 abandons the operation in progress and goes back to TRSDOS READY. The ROM's cassette BREAK key vector at 4204H holds this address.
4032
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4033ROMCIO
JUMP to 44B0H.
NOTE: 44B0H is the INPUT/OUTPUT DISPATCHER.
Keyboard and Interrupt Vectors
4036-403CKBROLT
Keyboard Bit Image
KBROLT: Keyboard Bit Image (7 bytes, 4036H-403CH), one byte for each row of the keyboard matrix, kept by the ROM keyboard driver to detect key changes. SYS0 has no load record for these bytes.
403DIODRVZ
JUMP to 35FAH.
NOTE: This is INTERRUPT VECTOR 3. It isn't used.
4040POL6ZZ
JUMP to 35FAH.
NOTE: This is INTERRUPT VECTOR 6. It isn't used.
4043POL7ZZ
JUMP to 35FAH.
NOTE: This is INTERRUPT VECTOR 7. It isn't used.
4046
JUMP to 3529H.
NOTE: This is the real time clock interrupt vector (the source names it so) and SYS0 loads this JP 3529H itself. 3529H is the Model III ROM's clock routine, which flashes the cursor and updates the clock/calendar. For 50 Hz operation the source says to patch this operand to 42BFH (CPATCH).
4049
NMI vector. The ROM sets 4049H-404BH; SYS0 has no load record here. While a disk read or write is running, BOTNMI (459CH) writes C3H to 4049H and 45ADH (BORNMI) to 404AH-404BH, and BORNMI points 404AH-404BH back at 42BDH (RETX, a RETN) when the NMI arrives.
4203READYY
READYY: the ROM's cassette BREAK key vector, a JP that the ROM sets up as JP 022EH. SYS0 has no load record for the JP opcode at 4203H; it loads 4030H (ABORT) into the address field at 4204H-4205H (next row), so the vector becomes JP 4030H and a BREAK during cassette I/O aborts the operation and returns to TRSDOS READY.
4204-4205
DEFW 4030H 30 40
The address field of the cassette BREAK key vector at 4203H. The source writes ORG READYY+1 and DEFW ABORT: SYS0 loads 4030H (ABORT) here.
4225-4264COMAND
DEFS 64
COMAND (64 bytes): the source's COMMAND LINE BUFFER. GETAN (4F84H) uses it as the input buffer for the date and time, and the AUTO code at 4F54H-4F5DH copies the AUTO command into it. SYS0 has no load record for 4225H-4264H.
4265-426CMIKE1
DEFS 8
MIKE1 (8 bytes): the source's WORK AREA FOR MIKE GRUBBS. MIKE at 4CFEH holds its address. SYS0 has no load record for 4265H-426CH.
426D-426EBASICF
DEFS 2
BASICF (2 bytes): the source calls it ONE OF BASIC'S POINTERS. SYS0 has no load record for 426DH-426EH.
426F-4270PROSAV
DEFS 2
PROSAV (2 bytes): the source calls it the BASIC PROTECTION SAVE. SYS0 has no load record for 426FH-4270H.
4271D10SAV
DEFB 00H 00
D10SAV: the source calls it the DRIVE SAVE AREA FOR SYS10. SYS0 loads 00H.
4272-4279BASIC1
DEFS 8
BASIC1, BASIC2, BASIC3 and BASIC4 (2 bytes each, 4272H, 4274H, 4276H and 4278H): the source's BASIC GENERAL PURPOSE SAVE AREAS. SYS0 has no load record for 4272H-4279H.
427ABASICG
DEFB 0FFH FF
BASICG: the source calls it the FLAG SHOWS BASIC IS RUNNING, which is 00H while BASIC runs. SYS0 loads FFH.
427BH - Start of the Overlay in Earnest
427BSYSS10
LD A,9AH 3E 9A
LET Register A = 9AH (1001 1010).
In the context of setting up Register A for a RST 28H call, x001 is the routine number within the overlay to run (i.e, routine 1) and 1010 is the overlay number being called (i.e., overlay 10). This would be the BASIC Error Routine
427D
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
427ESSYS12
LD A,8CH 3E 8C
LET Register A = 8CH (1000 1100).
In the context of setting up Register A for a RST 28H call, x000 is the routine number within the overlay to run (i.e, routine 0) and 1100 is the overlay number being called (i.e., overlay 12). This would be the BASIC Renumber Routine
4280
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4281SYSS12
LD A,9CH 3E 9C
SYSS12: LET Register A = 9CH (1001 1100), the overlay request code for the RST 28H call at 4283H. Bits 6-4 (001) select entry 1 and bits 3-0 (1100) select SYS12. The source calls this the BASIC 'COMPRESS' FUNCTION.
4283
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4284SSYS13
LD A,8DH 3E 8D
SSYS13: LET Register A = 8DH (1000 1101), the overlay request code for the RST 28H call at 4286H. Bits 6-4 (000) select entry 0 and bits 3-0 (1101) select SYS13. The source calls this the BASIC 'SORT' FUNCTION.
4286
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4287SYSS13
LD A,9DH 3E 9D
SYSS13: LET Register A = 9DH (1001 1101), the overlay request code for the RST 28H call at 4289H. Bits 6-4 (001) select entry 1 and bits 3-0 (1101) select SYS13. The source calls this the BASIC 'JULIAN' DATE FUNCTION.
4289
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
428ASSSY13
LD A,ADH 3E AD
SSSY13: LET Register A = ADH (1010 1101), the overlay request code for the RST 28H call at 428CH. Bits 6-4 (010) select entry 2 and bits 3-0 (1101) select SYS13. The source calls this the BASIC 'CROSS REF' FUNCTION.
428C
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
428DH - Overlay Entry for the $FILPTR Vector
The $FILPTR routine provides information on any user file that is currently open. It enables you to obtain the drive number and the logical file number for any file and should be used in conjunction with $RAMDIR. This operates with user files only.
Entry Conditions
- (DE) = Data Control Block (DCB) defined when file was opened
- CALL $FILPTR
Exit Conditions
- NZ = Error occurred
- Z = No error. The following registers are set up:
- B = Which drive contains the file (0, 1,2, or 3)
- C = Logical file number (1-96)
428DSSYS14
LD A,8EH 3E 8E
LET Register A = 8EH (1000 1110).
In the context of setting up Register A for a RST 28H call, x000 is the routine number within the overlay to run (i.e, routine 0) and 1110 is the overlay number being called (i.e., overlay 14). This will return the file pointers to the user.
428F
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4290H - Overlay Entry for the $RAMDIR Vector
This is the $RAMDIR vector which will allow you to examine a diskette directory (one entry or the entire directory) or the diskette's free space. The information is written into a user specified RAM buffer. Only non-SYSTEM files are included.
On entry:
- HL must point to the RAM buffer
- B must point to the drive number
- C will be the desired function:
- C=0 will get the entire directory
- C=1 to 96 will get the one specified directory record into RAM
- C=255 will get the free space information
On exit:
- Z = No error
- NZ = Error
- (HL) will hold the information sought as follows:
- Bytes 0-14: filename/ext:d (left-justified followed by spaces)
- Byte 15: Protection Level, binary 0-6
- Byte 16: Byte EOF, binary 0-255
- Byte 17: Logical record length, binary 0-255
- Byte 18-19: Last sector number in file, binary LSB, MSB
- Byte 20-21: Number of Granules allocated (LSB,MSB) binary
- Byte 22: '' + '' (marks the end of directory list after entire directory.)
4290SSSY14
LD A,9EH 3E 9E
SSSY14: LET Register A = 9EH (1001 1110), the overlay request code for the RST 28H call at 4292H. Bits 6-4 (001) select entry 1 and bits 3-0 (1110) select SYS14. The source calls this the 'USER' RETURN DIRECTORY TO RAM entry.
4292
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4293SSYS15
LD A,8FH 3E 8F
LET Register A = 8FH (1000 1111).
In the context of setting up Register A for a RST 28H call, x000 is the routine number within the overlay to run (i.e, routine 0) and 1111 is the overlay number being called (i.e., overlay 15). There is no overlay 15.
4295
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4296S1RST1
LD A,91H 3E 91
LET Register A = 91H (1001 0001).
In the context of setting up Register A for a RST 28H call, x001 is the routine number within the overlay to run (i.e, routine 1) and 0001 is the overlay number being called (i.e., overlay 1). This is the normal DOS command processor (DOS READY).
4298
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4299H - Execute a TRSDOS Command - $COMDOS
The $COMDOS routine executes a TRSDOS command and returns to TRSDOS READY.
Entry Conditions
- (HL) = Text of TRSDOS command, terminated by x'00'
- JP $COMDOS
4299S1RST2
LD A,0B1H 3E B1
LET Register A = B1H (1011 0001).
In the context of setting up Register A for a RST 28H call, x011 is the routine number within the overlay to run (i.e, routine 3) and 0001 is the overlay number being called (i.e., overlay 1). This will execute a DOS COMMAND and RETURN to DOS READY.
429B
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
429CH - Execute a TRSDOS Command - $CMDTXT
This is the start address of a buffer containing the last command line entered under TRSDOS READY. Using this buffer, your program may recover parameters that were included in the last command line.
For example, given a program named EDITOR/CMD, we want the operator to select an input file name when the program is loaded and executed from TRSDOS READY:
TRSDOS READY
EDITOR MYFILE
The program, EDITOR, can recover the name of the file in the $CMDTXT buffer.
Note: On entry to a program, (HL) = First non-blank character following the program name.
429CS1RST7
LD A,F1H 3E F1
LET Register A = F1H (1111 0001).
In the context of setting up Register A for a RST 28H call, x111 is the routine number within the overlay to run (i.e, routine 7) and 0001 is the overlay number being called (i.e., overlay 1). This will execute a DOS COMMAND and RETURN to the USER PROGRAM.
429E
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
429FFORMAT
LD A,A7H 3E A7
LET Register A = A7H (1010 0111).
In the context of setting up Register A for a RST 28H call, x010 is the routine number within the overlay to run (i.e, routine 2) and 0111 is the overlay number being called (i.e., overlay 7). This will execute a FORMAT COMMAND.
42A1
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
42A2BACKUP
LD A,97H 3E 97
LET Register A = 97H (1001 0111).
In the context of setting up Register A for a RST 28H call, x001 is the routine number within the overlay to run (i.e, routine 1) and 0111 is the overlay number being called (i.e., overlay 7). This will execute a BACKUP COMMAND.
42A4
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
42A5SSYS8
LD A,98H 3E 98
LET Register A = 98H (1001 1000).
In the context of setting up Register A for a RST 28H call, x001 is the routine number within the overlay to run (i.e, routine 1) and 1000 is the overlay number being called (i.e., overlay 8). This will execute a HELP COMMAND.
42A7
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
42A8SSYS9
LD A,99H 3E 99
LET Register A = 99H (1001 1001).
In the context of setting up Register A for a RST 28H call, x001 is the routine number within the overlay to run (i.e, routine 1) and 1001 is the overlay number being called (i.e., overlay 9). This will process LIBRARY commands.
42AA
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
42ABSSYS11
LD A,9BH 3E 9B
LET Register A = 9BH (1001 1011).
In the context of setting up Register A for a RST 28H call, x001 is the routine number within the overlay to run (i.e, routine 1) and 1011 is the overlay number being called (i.e., overlay 11). This will process MORE LIBRARY commands.
42AD
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
42AEBREAK
BREAK: JUMP to 4B00H (KILBRK). The source labels this vector BREAK with the comment KILL BREAK KEY. KILBRK returns A = 00H, so the BREAK request is ignored; SYSLD (4B85H) sends requests with bit 7 of A clear here. The boot code at 4F51H stores C9H (RET) at 42AEH before it runs an AUTO command.
42B1GOSAVE
DEFB 24H 24
GOSAVE (2 bytes, 42B1H-42B2H), LSB. The source declares GOSAVE as DEFW KEYBDZ, the 'DO' SAVE ADDRESS: 24H here and 30H at 42B2H make 3024H, KEYBDZ, the Model III ROM keyboard driver. The DO command in SYS6 saves the keyboard driver address here and SYS4 reads it back.
42B2
DEFB 30H 30
GOSAVE MSB (30H). Together with 24H at 42B1H this is 3024H, the ROM keyboard driver address KEYBDZ.
42B3DIFULT
DEFB 00H 00
DIFULT: the 'MASTER' drive, the starting default drive that SYS2 reads. 00H at load, so drive 0.
42B4CFLAG
DEFB ...
CFLAG (1 byte): the source calls it the FLAG TO SHOW 'CLEAR MEMORY'. When it is 55H the DOS READY code in SYS1 clears user memory and resets it; FORMAT and BACKUP in SYS7 and several utilities store 55H. SYS0 has no load record for 42B4H.
42B5INITD
DEFB ...
INITD (2 bytes, 42B5H-42B6H), LSB: the flag that shows the DOS has been initialized. The boot code at 4E9EH-4EA9H compares the word at 42B5H with 4455H and skips the date and time prompts when they match; 4EACH stores 4455H here after the first boot. SYS0 has no load record for 42B5H-42B6H, so the word holds whatever was in RAM until the first boot sets it.
42B6
DEFB ...
INITD MSB (see 42B5H). Holds 44H once the boot code has stored 4455H.
42B7DTSAVE
DEFB ...
DTSAVE (3 bytes, 42B7H-42B9H), first byte: the year. The boot code at 4EC9H-4ED2H copies the three converted date bytes here (year, day, month) and START2 at 4F2EH-4F37H copies them on to the clock bytes at 421AH-421CH. SYS0 has no load record for 42B7H-42B9H.
42B8
DEFB ...
DTSAVE second byte: the day of the month.
42B9
DEFB ...
DTSAVE third byte: the month.
42BAUTIL
LD A,86H 3E 86
UTIL: LET Register A = 86H (1000 0110), the overlay request code for the RST 28H call at 42BCH. Bits 6-4 (000) select entry 0 and bits 3-0 (0110) select SYS6. The source calls this the 1ST PART OF LIBRARY COMMANDS.
42BC
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
42BDRETX
RETN ED 45
RETN is used at the end of a NMI service routine. It POPs the value at the top of STACK into PC and copies the value of IFF2 into IFF1 (so that maskable interrupts are allowed to continue).
42BFH - Set the clock heartbeat counter to 25 and JUMP to ROM
42BFCPATCH
LD A,(4216H) 3A 16 42
Fetch the value stored at memory location 4216H and put it into Register A.
NOTE: 4216H is the storage location for the Clock Data: Heartbeat Counter.
42C2
CP 1EH FE 1E
Compare the value held in Register A against 1EH. Results: If Register A equals 1EH, the Z FLAG is set; otherwise the NZ FLAG is set.
42C4
If the NZ FLAG (Not Zero) is set, JUMP to 42CBH.
42C6
LD A,19H 3E 19
LET Register A = 19H (Decimal: 25).
42C8
LD (4216H),A 32 16 42
Store the value held in Register A into the memory location 4216H.
NOTE: 4216H is the storage location for the Clock Data: Heartbeat Counter.
42CBCPATC1
JUMP to 3529H.
NOTE: 3529H is in the Model III ROM. It sets and flashes the cursor and updates the clock/calendar.
42CEH - Execute the KILL command
Source label: KILFIL — Kill File Routine. If the first byte of the filespec shows the file is already open (bit 7 set), jumps directly to KILFI1 to kill it. Otherwise, opens the file first via OPEN, then kills it via DO 20,3.
On entry, DE needs to point to the memory location which states whether a file is currently open or not
42CEKILFIL
LD A,(DE) 1A
Fetch the value stored at memory location pointed to by Register Pair DE and put it into Register A. This should indicate if the file is currently open or not.
42CF
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
42D0
If the SIGN FLAG is set then the file is currently open, JUMP away to 42D9H.
42D3
PUSH DE D5
Preseve Register DE to the top of the STACK.
42D4
GOSUB to 4424H to open the file.
42D7
POP DE D1
Restore Register Pair DE from the top of the STACK.
42D8
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have an error, so RETurn to the caller.
42D9KILFI1
LD A,A3H 3E A3
If we are here then there was no error, so LET Register A = A3H (1010 0011).
In the context of setting up Register A for a RST 28H call, x010 is the routine number within the overlay to run (i.e, routine 2) and 0011 is the overlay number being called (i.e., overlay 3).
42DB
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
42DCH - Reset the FDC (including restore the drive to track 0)
Source label: FIX1 — FDC Error Recovery. Terminates the current FDC operation via TERM. If a sector-not-found error (bit 4) occurred, restores the drive to track 0 by issuing a RESTORE command.
42DCFIX1
FIX1: GOSUB to 4566H (TERM) to send the Force Interrupt command to the FDC and stop the operation in progress. TERM keeps Register A, which holds the FDC status from the failed operation.
42DF
AND 10H E6 10
MASK the value of Register A against 10H (0001 0000). This has the effect of turning off bits 7, 6, 5, 3, 2, 1, 0, leaving only bit 4 active. Bit 4 from Port F0H is the flag for RECORD NOT FOUND.
| Status Register Value: 10H (00010000) | | Type I Status |
| N | W | H | S | C | T | I | B | | Type I Command Status Register N: 1=Not Ready, 0=Ready W: 1=Write Protected, 0=Not Protected H: 1=Head Loaded, 0=Head Not Loaded S: 1=Seek Error a/k/a Record Not Found, 0=No Error C: 1=CRC Error, 0=No Error T: 1=Track 0, 0=Not Track 0 I: 1=Index Mark Detected, 0=No Index B: 1=Busy, 0=Not Busy |
42E1
RET Z C8
If the Z FLAG (Zero) is set then we found the record and have no error so RETurn to the caller.
42E2
PUSH BC C5
PUSH Register BC to the top of the STACK.
42E3
PUSH DE D5
PUSH Register DE to the top of the STACK.
42E4
PUSH HL E5
PUSH Register HL to the top of the STACK.
42E5
LD B,00H 06 00
Register Pair BC needs to be set to be the offset in the track table, so start off by setting Register B = 00H.
42E7
LD HL,445BH 21 5B 44
LET Register Pair HL = 445BH, which is the track table in RAM.
42EA
ADD HL,BC 09
ADD the value held in Register Pair BC to Register Pair HL so that HL now points to the track table as offset by the approriate offset in BC.
42EB
LD (HL),00H 36 00
Store 00H into the memory location pointed to by Register Pair HL, which marks that particular track as track 0.
42ED
LD A,0CH 3E 0C
LET Register A = 0CH (0000 1100).
When this bit pattern in sent to Port F0H (the Floppy Disk Control Port) and bits 7-4 are 0000, this is a RESTORE command and is a Type I command. Bits 0-1 are the stepping rate (00=6ms, 01=12ms, 10=20ms, 11=30ms), Bit 2 is the Track Number Verify Flag (0=No Verify), and Bit 3 is the Head Load Flag (1=Load Head).
When activated, the Track Register is checked, and if its 0 (meaning at Track 0) an interrupt is generated. If it is not 0, stepping pulses are issued until the TR00 goes to 0, and then an interrupt is generated.
42EF
OUTput the value held in Register A to port F0H.
NOTE: Port F0H is the Floppy Disk Command/Status Register. OUTputting to Port F0H cannot be simply summarized as there are more than 11 variables held in the bit pattern.
42F1
POP HL E1
Restore Register Pair HL from the top of the STACK
42F2
POP DE D1
Restore Register Pair DE from the top of the STACK
42F3
POP BC C1
Restore Register Pair BC from the top of the STACK
42F4
RET C9
RETurn to the caller.
42F5-42FE
DEFS 10
SYS0 has no load record for 42F5H-42FEH.
42FFH-43FF - Data Storage Area
42FFSCAFLG
DEFB 00H 00
SCAFLG: the source calls it the SYSTEM FLAG; 00H at load. It is the protection over-ride switch: SYS2 tests bit 0 during OPEN and skips the password check when it is set, then resets it; SYS11 sets it before opening files, and SYS1, SYS6 and SYS11 store 00H here.
4300-43FFBUFF1
00H
256 Byte Storage Area for Disk I/O
4400H - Short Delay Routine to Accomodate the FDC
4400DELLY
PUSH AF F5
PUSH Register AF to the top of the STACK.
4401
POP AF F1
POP the top of the STACK into Register Pair AF. The PUSH and POP pairs at 4400H-4407H do no work; they only use up time (DELLY).
4402
PUSH AF F5
PUSH Register AF to the top of the STACK.
4403
POP AF F1
POP the top of the STACK into Register Pair AF. The PUSH and POP pairs at 4400H-4407H do no work; they only use up time (DELLY).
4404SDELAY
PUSH AF F5
PUSH Register AF to the top of the STACK.
4405
POP AF F1
POP the top of the STACK into Register Pair AF. The PUSH and POP pairs at 4404H-4407H do no work; they only use up time (SDELAY).
4406
PUSH AF F5
PUSH Register AF to the top of the STACK.
4407
POP AF F1
POP the top of the STACK into Register Pair AF. The PUSH and POP pairs at 4404H-4407H do no work; they only use up time (SDELAY).
4408
RET C9
RETurn to the caller.
4409H - Process DOS Errors - $ERRDSP
The $ERRDSP routine displays a TRSDOS error message determined by the contents of the accumulator (A). This register contains an error code (0 = no error) after completion of any system routine.
Entry Conditions
- A = TRSDOS error code. In a TRSDOS error code, bits 6 and 7 are normally reset (off). So $ERRDSP interprets them as controls.
- Bit 7:
- Set - Return to caller upon completion
- Not Set - Return to TRSDOS upon completion
- Bit 6:
- Set - Give detailed error message
- Not Set - Give error number only
4409ERROR
PUSH AF F5
Since an overlay call uses Register A, which is otherwise holding the DOS ERROR CODE, PUSH Register AF to the top of the STACK.
440A
LD A,84H 3E 84
LET Register A = 84H (1000 0100).
In the context of setting up Register A for a RST 28H call, x000 is the routine number within the overlay to run (i.e, routine 0) and 0100 is the overlay number being called (i.e., overlay 4).
440C
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
440DH - Process DEBUG
Source label: DEBUG — Debug Entry Point. Saves A via PUSH AF, then invokes the SYS5 debug overlay via DO 00,5.
440DDEBUG
PUSH AF F5
Since an overlay call uses Register A, PUSH Register AF to the top of the STACK to save Register A.
440E
LD A,85H 3E 85
LET Register A = 85H (1000 0101).
In the context of setting up Register A for a RST 28H call, x000 is the routine number within the overlay to run (i.e, routine 0) and 0101 is the overlay number being called (i.e., overlay 5).
4410
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4411H - Data Storage Area
4411-4412MEMEND
DEFW 7FFFH FF 7F
MEMEND (2 bytes, 4411H-4412H): the source calls it the END OF MEMORY LOCATION. 7FFFH at load; the boot code at 4E37H replaces it with the last RAM address it finds (7FFFH, BFFFH or FFFFH). It is normally the physical end of RAM, but a user can lower it to protect memory above it. LSB first.
4413MAXDRV
DEFB 00H 00
MAXDRV: the source calls it the NUMBER OF DRIVES IN SYSTEM. The boot code at 4E72H-4E74H stores the highest drive number found (the number of drives minus 1), so 00H means only drive 0. CHKDRV (4C6BH) refuses any drive number above it.
4414FLAG1
DEFB 00H 00
FLAG1: the source calls it the FLAG SHOWS LAST SYSTEM OVERLAY LOADED. SYSLD (4B82H) keeps the request code of the last overlay here; it compares the low 4 bits (the overlay number) with each new request and skips the disk read when they match. 00H at load.
4415-4416MEM2
DEFW 7FFFH FF 7F
MEM2 (2 bytes, 4415H-4416H): the source calls it the MIRROR OF END OF MEMORY. 7FFFH at load; the boot code at 4E3DH stores the same end of memory value that goes to 4411H (MEMEND). LSB first.
4417DATA3
DEFW 5200H 00 52
DATA3 (2 bytes, 4417H-4418H): the source calls it the BEGIN OF USER RAM and declares it DEFW SYSHI. 5200H is the first address above the area the high SYS overlays use, so user programs start there. LSB first.
4419H - Routine to display a SHORT DIRECTORY to the screen - $DSPDIR
The $DSPDIR routine displays the directory listing of all non-protected user files in a specified drive
Entry Conditions
- (4271) = ASCII-coded drive number "0," "1," "2," or "3"
- CALL $DSPDIR
4419SSYS10
LD A,8AH 3E 8A
LET Register A = 8AH (1000 1010).
In the context of setting up Register A for a RST 28H call, x000 is the routine number within the overlay to run (i.e, routine 0) and 1010 is the overlay number being called (i.e., overlay 10).
441B
RST 28H with Register A = 8AH: load SYS10 and run its entry 0, the source's CMD "D" (DIRECTORY) FOR BASIC.
441CH - Routine to check the syntax of a filespec before it is used - $SYNTAX
The $SYNTAX routine moves a file specification to DCB. This routine takes a file specification and checks it for validity and moves it to a DCB so that the file may be opened.
Entry Conditions
- (HL) = Filename
- (DE) = DCB
- CALL $SYNTAX
Exit Conditions
- Z = Good file specification
- NZ = Bad file specification
441CSYNTAX
LD A,C1H 3E C1
LET Register A = C1H (1100 0001).
In the context of setting up Register A for a RST 28H call, x100 is the routine number within the overlay to run (i.e, routine 4) and 0001 is the overlay number being called (i.e., overlay 1).
441E
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
441FCURDOS
DEFB 13H 13
CURDOS: 13H, the DOS version 1.3. The source notes that BASIC looks at this byte.
4420H - Routine to INIT a disk file (i.e., create or open)
$INIT is provided as an entry point to TRSDOS which will create a new file entry in the directory and open the DCB for this file. $INIT scans the directory for the filespec name given in the DCB. If the filespec name is found, $INIT simply opens the file for use. If the name is not found, a new file is created with the filespec name.
Entry Conditions
- (HL) = BUFFER
- (DE)= DCB
- B = LRL
- CALL $INIT
Exit Conditions
- IY = changed
- Z = OK
- c carry flag is ON if a new file was created
- A = TRSDOS error code
4420INIT
LD A,A2H 3E A2
LET Register A = A2H (1010 0010).
In the context of setting up Register A for a RST 28H call, x010 is the routine number within the overlay to run (i.e, routine 2) and 0010 is the overlay number being called (i.e., overlay 2).
4422
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4423H - Data Storage Area
4423DRIVE
DEFB 00H 00
DRIVE: the source calls it the DRIVE SELECT BIT PATTERN. DSEL (44D4H) and SEEK (44F9H) store the byte for port F4H here: one bit for the drive (bits 0-3), plus 80H for double density and 20H for write precompensation from track 22 up. DSELCT (44DDH) reads it and sends it to port F4H. 00H at load.
4424H - Routine to OPEN A DISK FILE for use
$OPEN provides a way to open the DCB of a file which already exists in the directory. The DCB must contain the filespec of the file to be opened before entry to $OPEN.
Entry Conditions
- (HL) = BUFFER
- (DE)= DCB
- B = LRL
- CALL $OPEN
Exit Conditions
- Z = OK
- z = 0 if file does not exist
- A = TRSDOS error code
- IY = changed
4424OPEN
LD A,92H 3E 92
LET Register A = 92H (1001 0010).
In the context of setting up Register A for a RST 28H call, x001 is the routine number within the overlay to run (i.e, routine 1) and 0010 is the overlay number being called (i.e., overlay 2).
4426
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4427H - Data Storage Area
4427CURDRV
DEFB 00H 00
CURDRV: the source calls it the CURRENT DRIVE IN USE. SEEK (44E7H) stores the drive number (0-3) from Register C here and SEKOUT (4528H) reads it back to index the track table at 445BH. 00H at load.
4428H - Routine to CLOSE A DISK FILE - $CLOSE
The $CLOSE routine closes a file from the last processing done. It is very important to do a $CLOSE on every file opened before the program ends. If you do not close a file, the directory entry for this file is incorrect if any new records have been written into the file. Other cases are not given here, but it is very important to TRSDOS that all of the "housekeeping" be complete for file management.
Entry Conditions
Exit Conditions
- Z = OK
- A = TRSDOS error code
4428CLOSE
LD A,93H 3E 93
LET Register A = 93H (1001 0011).
In the context of setting up Register A for a RST 28H call, x001 is the routine number within the overlay to run (i.e, routine 1) and 0011 is the overlay number being called (i.e., overlay 3).
442A
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
442BH - Data Storage Area
442BOVLFLG
DEFB 00H 00
OVLFLG: the source calls it the OVERLAY FLAG; 00H at load. Bit 7 is tested by LDPGM at 4BF8H: when it is set the program is only being loaded, which is refused for an execute only file; EXEC (4BD9H) stores 00H here first. The overlays use bit 4 to show that SYS6 is resident.
442CH - Vector for the KILL command - $KILL
The $KILL routine deletes the directory entry for a file and releases the disk storage. The file may be open or closed; $KILL will operate in either case.
Entry Conditions
Exit Conditions
- Z = OK
- A = TRSDOS error code
442CKILL
KILL: JUMP to 42CEH (KILFIL), which opens the file if needed and then kills it through SYS3.
442FH - Data Storage Area
442FDULFLG
DEFB 00H 00
DULFLG: the source calls it the FLAG TO SHOW DUAL IS ON/OFF. 00H means off; BASIC's DUAL ON code makes it FFH.
4430H - Various Jump Vectors
4430LDPGM
JUMP to 4BE6H to LOAD PROGRAM INTO RAM.
4433EXEC
JUMP to 4BD9H to LOAD AND EXECUTE PROGRAM.
4436H - $READ Vector
$READ Vector. If LRLO, $READ transfers the logical record whose number is in the DCB as NRN into the RAM area addressed as UREC for the length LRL as defined at open time. The record comes from "BUFFER" defined at open time. If TRSDOS must read a new physical record to satisfy the request, it will do so. "Spanned" logical records will be re-assembled as necessary. $READ automatically increments NRN by l in the DCB after the transfer is completed. $INIT/OPEN set NRN = x'0000' in order to read the first record with the first READ.
If LRL = 0, $READ transfers one physical record into BUFFER, defined at open time, from the disk file. Registers HL are ignored. $READ increments NRN as above.
Entry Conditions
- (HL) = UREC if LRL is not zero. Unused if LRL = 0.
- (DE) = DCB
- CALL $READ
Exit Conditions
- Z = OK
- A = TRSDOS error code. (EOF= X'1C' or X'1D')
4436READ
JUMP to 4737H which is the READ VECTOR.
4439H - $WRITE Vector
If LRLO, $WRITE transfers the one logical record from the RAM area addressed as UREC for the length LRL as defined at open time. The record goes into the BUFFER which was defined at open time. If TRSDOS must write a physical record in order to satisfy the request, it will do so. "Spanning" will be handled by TRSDOS as necessary. At $INIT/$OPEN time the DCB value of NRN is set to X'0000' so that the first record will be written. After each logical record is transferred, the NRN value in the DCB will be incremented by 1.
If LRL = 0, $WRITE transfers one physical record from BUFFER into the disk file using the NRN in the DCB. BUFFER is defined at $INIT/OPEN time only. The DCB value NRN is updated as above, after the WRITE.
Entry Conditions
- (HL) = UREC if LRL is not zero. Unused if LRL = 0
- DE = DCB
- CALL $WRITE
Exit Conditions
- Z = OK
- A = TRSDOS error code
4439WRITE
JUMP to 47B3H which is the WRITE VECTOR.
443CH - $VERF Vector
The only difference between $VERF and $WRITE is that $VERF writes one physical record to disk and then reads it back into a special TRSDOS RAM area not defined by the user. This special area and the original write buffer are then compared byte by byte to assure that the record was successfully written.
Entry Conditions
- (HL) = Same as $WRITE above
- (DE)= DCB
- CALL $VERF
Exit Conditions
- Z = OK
- A = TRSDOS error code
443CVERF
JUMP to 47B3H which is the VERIFY VECTOR when VERIFY is OFF. When VERIFY is ON, this JUMP is changed in RAM to 47CCH.
443FH - Rewind Vector - $REWIND
The $REWIND routine will point to the beginning of the file. This routine positions the file pointer to the first record in the file. This is useful when the same file must be processed more than once.
Entry Conditions
Exit Conditions
- Z = Good file spec
- NZ = Bad file spec
443FREWIND
JUMP to 4720H which is the REWIND VECTOR.
4442H - Position Vector - $POSN
The $POSN routine positions a file to read or write a randomly selected logical record. Since it deals with logical records, the proper computation is done to locate which physical record(s) contain the data. Following a $POSN with a $READ or $WRITE will transfer the record to/from RAM.
Note that positioning to logical record zero sets the file to read the first logical record in the file. To position to end of file in order to add new records onto the end, use the record number ERN + 1.
Entry Conditions
- (DE) = DCB (must have been opened previously)
- BC = Logical record number to position for
- CALL $POSN
Exit Conditions
- Z = OK
- A = TRSDOS error code
4442POSN
JUMP to 46CFH which is the POSN VECTOR.
4445H - Backspace Vector - $BKSPC
The $BKSPC routine positions the file record pointer to the previous record.
Entry Conditions
Exit Conditions
- Z = Valid position
- NZ = Invalid position
4445BACKSP
JUMP to 4701H which is the BACKSPACE VECTOR.
4448H - Point to End of File Vector - $POSEOF
The $POSEOF routine points to the end of file. This routine positions the file pointer to the last record in the file. This may be used to extend a sequential access file.
Entry Conditions
Exit Conditions
- Z = Good file spec
- NZ = Bad file spec
4448POSEOF
JUMP to 4729H which is the POSEOF VECTOR.
444BH - This routine will add a default extension to a filespec - $PUTEXT
This $PUTEXT routine will add an extension to a filename if an extension does not already exist. An extension to a filename may be useful for identifying the type of data in the file.
Entry Conditions
- (DE) = DCB
- (HL) = The extension to be added to the file
- CALL $PUTEXT
Exit Conditions
444BPUTEXT
LD A,D1H 3E D1
LET Register A = D1H (1101 0001).
In the context of setting up Register A for a RST 28H call, x101 is the routine number within the overlay to run (i.e, routine 5) and 0001 is the overlay number being called (i.e., overlay 1).
444D
RST 28H with Register A = D1H: load SYS1 and run its entry 5, the source's ADD AN EXTENSION TO FILESPEC.
444EH - Multiply Routine - $DMULT
The $DMULT routine uses a 16-bit multiplicand and an eight-bit multiplier. After multiplication takes place, the product replaces the 16-bit multiplicand.
Entry Conditions
- HL = Multiplicand
- A = Multiplier
- CALL $DMULT
Exit Conditions
- H = High order byte
- L = Middle order byte
- A = Low order byte
444EMULT
JUMP to 4B55H which is the DMULT VECTOR - Multiply Register Pair HL by Register A.
4451H - Divide Routine - $DIVIDE
The $DIVIDE routine takes a 16-bit dividend and an eight-bit divisor. After division, the quotient replaces the 16-bit dividend and the remainder replaces the eight-bit divisor.
Entry Conditions
- HL = Dividend
- A = Divisor
- CALL $DIVIDE
Exit Conditions
- HL = Quotient
- A = Remainder (0 if none)
4451DIV
JUMP to 4B6FH which is the DIVIDE VECTOR.
4454H - This routine will parse a parameter string
4454SWITCH
LD A,E1H 3E E1
SWITCH: LET Register A = E1H (1110 0001), the overlay request code for the RST 28H call at 4456H. Bits 6-4 (110) select entry 6 and bits 3-0 (0001) select SYS1. The source calls this the TABLE COMPARISON ROUTINE, which parses a parameter list against a table.
4456
Call RST 28H run a specific routine in a specific DOS OVERLAY, all as held in Register A.
4457H - Data Storage Area
4457-445ADIRTRK
DEFB 11H,11H,11H,11H 11 11 11 11
DIRTRK (4 bytes, 4457H-445AH): the directory track for each of the 4 drives. 11H (track 17) for every drive at load.
445B-4462SEKTRK
DEFB 00H x 8 00 x 8
SEKTRK (8 bytes, 445BH-4462H): the last track used, one byte each. The source lays them out as drive 0 side 0, drive 0 side 1, drive 1 side 0 and so on; SEEK (4505H), SEKOUT (452EH) and FIX1 (42E7H) index the table with the drive number in Register C. SEKOUT stores the FDC track register (port F1H) here after every seek and FIX1 stores 00H after a restore. 00H at load.
4463CSIDE
DEFB 00H 00
CSIDE: the source calls it the CURRENT SIDE TO READ/WRITE FROM/TO. 00H at load.
4464OLDSID
DEFB 00H 00
OLDSID: the source calls it the PREVIOUS SIDE. 00H at load.
4465-447BDCB
DEFM "FILENAME/EXT.PASSWORD:D" 46 49 4C 45 4E 41 4D 45 2F 45 58 54 2E 50 41 53 53 57 4F 52 44 3A 44
DCB (50 bytes, 4465H-4496H): the system DCB. SYS0 loads the text FILENAME/EXT.PASSWORD:D into its first 23 bytes (4465H-447BH); the other 27 bytes are reserved by the source (DEFS DCBSIZ-($-DCB)) and are not in the file. DCBSIZ is the 48 byte directory record size plus 2.
447C-4496
DEFS 27
The rest of the 50 byte system DCB at 4465H. SYS0 has no load record for 447CH-4496H.
4497H - Data Storage Area for the System Overlay File Control Block
4497MDCB
DEFB 80H 80
MDCB (4497H-44A8H) is the internal DCB the system uses to read the SYS files. Offset 00H (MTYPE, the file type byte): 80H, which marks it as a disk file DCB.
4498
DEFB 00H 00
MDCB offset 01H (MPROT, the protection level and status byte). Bits 0-2 = the protection level (access permitted); bit 3 = a write operation has been done; bit 4 = the buffer holds data not yet written; bit 5 = the next sector has to be read before the buffer can be used; bit 6 = the record number must be advanced after the write (the source's carry flag); bit 7 = byte level I/O (the logical record length is not 256). For a character device DCB, offsets 01H-02H hold the driver address instead.
4499
DEFB 00H 00
MDCB offset 02H: unused in a disk DCB. In a character device DCB, offsets 01H-02H hold the driver address.
449A-449BMBUFF
DEFW 4D00H 00 4D
MDCB offsets 03H-04H (MBUFF): the buffer address, 4D00H (BUFF2, the second system disk buffer). LSB first.
449C
DEFB 00H 00
MDCB offset 05H (MOFF): the byte offset inside the sector buffer of the next byte to read or write.
449D
DEFB 00H 00
MDCB offset 06H (MDRV): the drive number of the file.
449E
DEFB 00H 00
MDCB offset 07H (MLFN): the logical file number, the position of the file's record in the directory.
449F
DEFB 00H 00
MDCB offset 08H (MEOF): the end of file byte, the offset of the end of file within the last sector.
44A0
DEFB 00H 00
MDCB offset 09H (MLRL): the logical record length (00H means 256).
44A1-44A2
DEFW 0000H 00 00
MDCB offsets 0AH-0BH (MNRN): the next record number (2 bytes, LSB first).
44A3
DEFB 0FFH FF
MDCB offsets 0CH-0DH (MERN): the ending record number, FFFFH at load (source DEFW -1). This is the LSB.
44A4
DEFB 0FFH FF
MDCB offset 0DH: the MSB of the ending record number that starts at 44A3H.
44A5
DEFB 00H 00
MDCB offset 0EH (MSIDE): the side number.
44A6
DEFB 00H 00
MDCB offset 0FH (MSPAR): a spare byte.
44A7-44A8
DEFW 0000H 00 00
MDCB offsets 10H-11H (MEXT): the start of the segment (extent) descriptors.
44A9H - Data Storage Area
44A9-44AASAVE2
DEFW 0000H 00 00
SAVE2 (2 bytes, 44A9H-44AAH): SAVER (4881H) stores here the return address of the program that called the disk I/O routine.
44AB-44ACSAVE3
DEFW 0000H 00 00
SAVE3 (2 bytes, 44ABH-44ACH): SAVER (4881H) stores here the DCB address from Register Pair DE that the I/O routine works on.
44ADH - Set up Special Index Register Pair IX with the address of the DCB
44ADCIO0
PUSH HL E5
PUSH Register HL (which is holding the NEW DCB) to the top of the STACK.
44AE
POP IX DD E1
Restore the NEW DCB from the top of the STACK into Register Pair IX.
44B0H - Continue the I/O Dispatcher Routine which started in ROM
Source label: CIO1 — Character I/O Linkage (Disk), at 44B0H. Gets the driver address from DCB offsets 01H-02H (DADDL/DADDH) and the device type from offset 00H. Type 10H routes to another DCB (back to CIO0 at 44ADH); a type above 10H is a disk file DCB and goes to CIOF (44C3H); a type below 10H jumps to the driver with JP (HL).
44B0CIO1
LD L,(IX+01H) DD 6E 01
Fetch the value stored at memory location IX+01H and put it into Register L. Set HL to be the device driver OR the new DCB if not diskette.
44B3
LD H,(IX+02H) DD 66 02
Fetch the value stored at memory location IX+02H and put it into Register H.
44B6
LD A,(IX+00H) DD 7E 00
Fetch the value stored at memory location IX+00H and put it into Register A. Fetch the FILE TYPE byte into Register A.
44B9
CP 10H FE 10
Compare the value held in Register A against 10H. Results: If Register A equals 10H, the Z FLAG is set; otherwise the NZ FLAG is set.
44BB
If the Z FLAG (Zero) is set then we are needing to ROUTE to a NEW DCB so JUMP BACK to 44ADH to restore HL into IX and start this routine again.
44BD
If the NC FLAG (Carry) is set then we are needing to ROUTE to a disk file so JUMP to 44C3H.
44BF
LD A,B 78
LET Register A = Register B, which is holding the KIND of I/O needed.
44C0
CP 02H FE 02
Compare the value held in Register A against 02H. This is done with an eye to setting the CARRY FLAG if read. 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.
44C2
JP (HL) E9
JUMP to (HL).
44C3H - Routine to ROUTE to a Disk File
Source label: CIOF — Disk File Character I/O. Sets bit 7 of IX+PROT to indicate not LRL-256 mode. Calls SAVER to set up registers, then dispatches to WRBYTE (write) or RDBYTE (read) based on function code in B.
Register B holds the KIND of I/O needed and Register C holds the byte to be sent.
44C3CIOF
SET 7,(IX+01H) DD CB 01 FE
SET (i.e., set as 1) BIT 7 of Register (IX+01H) which is the OPTIONS byte. This sets the FILE TYPE for BYTE LEVEL I/O.
44C7CIOG
CIOG: GOSUB to 4881H (SAVER), which checks that the DCB at Register Pair DE is open, saves the registers and copies the DCB address into IX.
44CA
LD A,B 78
LET Register A = Register B, which is holding the KIND of I/O needed.
44CB
CP 02H FE 02
Compare the value held in Register A against 02H. This is done with an eye to setting the CARRY FLAG if read. 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.
44CD
LD A,C 79
LET Register A = Register C so that the byte to send is put into Register A.
44CE
If the NC FLAG (Carry) is set then we want to WRITE, so JUMP to 4837H.
44D1
Otherwise, JUMP to 4791H to do a READ.
44D4H - Handle DRIVE SELECT
Source label: DSEL — Select Drive by Number. Entry: C = drive number (0-3). Converts to bit pattern via SITIT, ORs with DOUBLE (80H) density bit, stores result in DRIVE variable.
Source label: DSELCT (44DDH) — Select Drive by Bit Pattern. Reads the DRIVE variable and outputs the bit pattern to port F4H (CDRV drive select latch).
Register C holds the drive number to select.
44D4DSEL
LD A,C 79
LET Register A = Register C (which is the drive number).
44D5
GOSUB to 45E9H to calculate the DRIVE SELECT CODE.
44D8
OR 80H F6 80
OR Register A against 80H (1000 0000). This has the effect of turning on bit 7, thus selecting DOUBLE DENSITY when sent to Port F4H.
44DA
LD (4423H),A 32 23 44
Store the drive select byte (held in Register A) into 4423H (DRIVE).
44DDDSELCT
LD A,(4423H) 3A 23 44
Fetch the value stored at memory location 4423H (which holds the Disk Drive Select Code) and put it into Register A.
44E0DSEL0 / DSEL1
OUTput the value held in Register A to port F4H.
NOTE: Port F4H is the Floppy drive select and options register. For OUTPUT:
- Bit 0: Drive 0 Select
- Bit 1: Drive 1 Select
- Bit 2: Drive 2 Select
- Bit 3: Drive 3 Select
- Bit 4: Side Select (0 = Select Side 0, 1 = Select Side 1)
- Bit 5: Write Precompensation (0 = Disable WP, 1 = Enable WP)
- Bit 6: Wait State Generation (0 = Disable WSG, 1 = Enable WSG)
- Bit 7: Density Select (0 = Single/FM, 1 = Double/MFM)
44E2
RET C9
RETurn to the caller.
44E3H - Position the Disk Read/Write Head to the Proper Track
Source label: SEEK — Seek to Track. Entry: D = desired track, C = drive number. Saves registers (SAV3 macro). Sets write pre-compensation for tracks >= 22. Compares current track position to desired track. Issues RESTORE + re-seek on seek error.
On entry, Register C holds the drive number, and Register D holds the track number.
44E3SEEK
PUSH BC C5
PUSH Register BC to the top of the STACK.
44E4
PUSH DE D5
PUSH Register DE to the top of the STACK.
44E5
PUSH HL E5
PUSH Register HL to the top of the STACK.
44E6
LD A,C 79
LET Register A = Register C (which holds the drive number).
44E7
LD (4427H),A 32 27 44
Store the value held in Register A (the drive number) into the memory location 4427H (which stores the currently selected disk drive number).
44EA
PUSH BC C5
Sve Register BC to the top of the STACK.
44EB
GOSUB to 45E9H to calculate the DRIVE SELECT CODE.
44EE
OR 80H F6 80
OR Register A against 80H (1000 0000). This has the effect of turning on bit 7, thus selecting DOUBLE DENSITY when sent to Port F4H.
44F0
LD C,A 4F
LET Register C = Register A (which is the drive select code, modified to double density).
44F1
LD A,D 7A
LET Register A = Register D (which is the track number we want).
44F2
CP 16H FE 16
Compare the value held in Register A against 16H. Results:
- If Register A equals 16H, the Z FLAG is set.
- If A < 16H, the CARRY FLAG will be set.
- if A >= 16H, the NO CARRY FLAG will be set.
44F4
If the C FLAG (Carry) is set, the track number in Register D is below 16H (track 22), so write precompensation is not needed: skip the next instruction and JUMP to 44F8H.
44F6
SET 5,C CB E9
SET (i.e., set as 1) BIT 5 of Register C to enable WRITE PRECOMPENSATION.
44F8SEEK2
LD A,C 79
LET Register A = Register C (which is the DRIVE SELECT CODE).
44F9
LD (4423H),A 32 23 44
Store the value held in Register A into the memory location 4423H (which holds the Disk Drive Select Code).
44FC
POP BC C1
Restore Register Pair from the top of the STACK into Register Pair BC.
44FD
GOSUB to 4547H to wait for the controller.
4500
If the NZ FLAG (Not Zero) is set then that call returned an error, so JUMP to 4536H.
4502
PUSH BC C5
Save Register BC to the STACK.
4503
LD B,00H 06 00
LET Register B = 00H sso that BC will be the OFFSET on the TRACK TABLE.
4505
LD HL,445BH 21 5B 44
LET Register Pair HL = 445BH (which is the TRACK TABLE).
4508
ADD HL,BC 09
ADD the value held in Register Pair BC to Register Pair HL. The results (he entry in the TRACK TABLE for the track we are on) are held in Register Pair HL.
4509
POP BC C1
Restore Register Pair BC from the STACK.
450A
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL (which is the entry in the TRACK TABLE for the track we are on) and put it into Register A.
450B
CP D BA
Compare the value held in Register A (the current track number) against the value held in Register D (the track number we want). Results:
- If Register A equals D, the Z FLAG is set.
- If A < D, the CARRY FLAG will be set.
- if A >= D, the NO CARRY FLAG will be set.
450C
GOSUB to 453AH (SEEKIT) with Register A holding the track the head is on (from the table) and the flags from the CP D just done. SEEKIT tells the FDC where the head is and issues a seek when the two tracks differ.
450F
If the NZ FLAG (Not Zero) is set, then there was an errior, so JUMP to 4536H to handle the error.
4511
BIT 4,A CB 67
Test Bit 4 of Register A, which would be a SEEK ERROR.
4513
If the Z FLAG (Zero) is set, meaning that we did not get a SEEK ERROR, JUMP to 4527H.
4515
LD A,0CH 3E 0C
LET Register A = 0CH (0000 1100).
When this bit pattern in sent to Port F0H (the Floppy Disk Control Port) and bits 7-4 are 0000, this is a RESTORE command and is a Type I command. Bits 0-1 are the stepping rate (00=6ms, 01=12ms, 10=20ms, 11=30ms), Bit 2 is the Track Number Verify Flag (0=No Verify), and Bit 3 is the Head Load Flag (1=Load Head).
When activated, the Track Register is checked, and if its 0 (meaning at Track 0) an interrupt is generated. If it is not 0, stepping pulses are issued until the TR00 goes to 0, and then an interrupt is generated.
4517
OUTput the value held in Register A to port F0H.
NOTE: Port F0H is the Floppy Disk Command/Status Register. OUTputting to Port F0H cannot be simply summarized as there are more than 11 variables held in the bit pattern.
4519
GOSUB to 4400H (DELLY) for a short fixed delay before reading the FDC status.
451CSEEK4
INput a byte from Port F0H and put it into Register A.
NOTE: Port F0H is the FDC Status port on input.
451E
BIT 2,A CB 57
Test Bit 2 of Register A to see if we are at TRACK 0 yet.
| Status Register Value: 04H (00000100) | | Type I Status |
| N | W | H | S | C | T | I | B | | Type I Command Status Register N: 1=Not Ready, 0=Ready W: 1=Write Protected, 0=Not Protected H: 1=Head Loaded, 0=Head Not Loaded S: 1=Seek Error, 0=No Error C: 1=CRC Error, 0=No Error T: 1=Track 0, 0=Not Track 0 I: 1=Index Mark Detected, 0=No Index B: 1=Busy, 0=Not Busy |
4520
If the Z FLAG (Zero) is set then we are not yet at TRACK 0, so LOOP BACK 2 instructions to 451CH.
4522
GOSUB to 453CH to seek the track.
4525
If the NZ FLAG (Not Zero) is set then we had an error in seeking so JUMP FORWARD to 4536H to deal with the error.
4527SEKOUT
PUSH AF F5
PUSH Register AF to the top of the STACK to save Register A and the FLAGs.
4528
LD A,(4427H) 3A 27 44
Fetch the value stored at memory location 4427H (the currently selected disk drive number) and put it into Register A.
452B
LD C,A 4F
LET Register C = Register A.
452C
LD B,00H 06 00
LET Register B = 00H. This leaves Register Pair BC holding the currently selected disk drive number.
452E
LD HL,445BH 21 5B 44
LET Register Pair HL = 445BH, which is the track table in RAM.
4531
ADD HL,BC 09
ADD the value held in Register Pair BC to Register Pair HL. The results (the table entry for the desired track) are held in Register Pair HL.
4532
Read the actual diskette drive track number from the FDC by doing an INput from Port F1H.
4534
LD (HL),A 77
Store the value held in Register A into the memory location pointed to by Register Pair HL (which is the table entry for the desired track).
4535
POP AF F1
Restore Register A and the FLAGs from the STACK.
4536SEKDON
POP HL E1
Restore Register Register Pair HL from the STACK.
4537
POP DE D1
Restore Register Register Pair DE from the STACK.
4538
POP BC C1
Restore Register Register Pair BC from the STACK.
4539
RET C9
RETurn to the caller.
453AH - Prepare to do a TRACK SEEK
On entry, Register A should hold the current track number and Register D should hold the desired track number.
453ASEEKIT
SEEKIT: OUTput Register A (the track the head is on, from the SEKTRK table) to port F1H, the FDC track register, so the FDC knows where the head is.
453CSEEKI1
LD A,D 7A
LET Register A = Register D (the desired track number).
453D
OUTput the value held in Register A to the FDC Data Register (Port F3H).
The reason this is going to the data register is that the FDC seek command requires that the Track Register contains the track number of the current position of the head and the Data Register contains the desired track number.
453F
If the NZ FLAG (Not Zero) is set, the head is not on the wanted track, so JUMP to 4543H to issue the seek. The flags come from the caller: from CP D at 450BH, or the NZ left by BIT 2,A at 451EH when SEEKI1 is called at 4522H after a restore.
4541
XOR A AF
Set Register A to ZERO and clear all Flags.
4542
RET C9
RETurn to the caller.
4543H - Routine to SEEK a TRACK on the diskette
4543SEEKI2
LD A,1CH 3E 1C
LET Register A = 1CH (0001 1100).
When this bit pattern in sent to Port F0H (the Floppy Disk Control Port) and bits 7-4 are 0001, this is a SEEK command and is a Type I command. Bits 0-1 are the stepping rate, Bit 2 is the Track Number Verify Flag (0=No Verify), and Bit 3 is the Head Load Flag (1=Load Head).
So long as the Track Register holds the current position of the head and the Data Register contains the desired track number, the FDC will update the Track Register and issue stepping pulses in the appropriate direction until the Track Register and Data Register match. An interrupt is generated when done.
4545
OUTput the value held in Register A to port F0H.
NOTE: Port F0H is the Floppy Disk Command/Status Register. OUTputting to Port F0H cannot be simply summarized as there are more than 11 variables held in the bit pattern.
4547H - Wait for the disk drive to finish seeking
4547CHKBSY
GOSUB to 44DDH to re-select the drive.
454A
GOSUB to 4400H to delay a little bit.
454D
PUSH BC C5
PUSH Register BC to the top of the STACK.
454E
LD BC,0000H 01 00 00
LET Register Pair BC = 0000H to set up for a counter.
4551CHKBS2
INput a byte from Port F0H (the FDC Status Port) and put it into Register A.
4553
BIT 0,A CB 47
Test Bit 0 of Register A, which would be the FDC BUSY bit from Port F0H.
| Status Register Value: 01H (00000001) | | Type I Status |
| N | W | H | S | C | T | I | B | | Type I Command Status Register N: 1=Not Ready, 0=Ready W: 1=Write Protected, 0=Not Protected H: 1=Head Loaded, 0=Head Not Loaded S: 1=Seek Error, 0=No Error C: 1=CRC Error, 0=No Error T: 1=Track 0, 0=Not Track 0 I: 1=Index Mark Detected, 0=No Index B: 1=Busy, 0=Not Busy |
4555
If the Z FLAG (Zero) is set, meaning that the FDC is NOT busy, JUMP DOWN to 4564H to continue.
4557
DEC BC 0B
If we're here, we got FDC BUSY, so DECrement Register Pair BC by 1.
4558
LD A,B 78
We need to check the counter, but we can't test Register B, so LET Register A = Register B.
4559
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
455A
If the Z FLAG (Zero) is set, Register B has reached 00H: Register Pair BC was counted down from 0000H to 00FFH (65,281 passes) with the FDC still busy, so JUMP to 4561H to report the time out.
455C
Otherwise, GOSUB to 44DDH to re-select the drive.
455F
LOOP BACK to 4551H (CHKBS2) to poll the FDC again.
4561H - Routine to ERROR OUT
4561CHKBS3
LD A,0CH 3E 0C
CHKBS3: LET Register A = 0CH, error code 12 (ETIME), TIME OUT ON DISK DRIVE.
4563
OR A B7
OR Register A with itself so the NZ FLAG is set (A = 0CH), the error return.
4564CHKBS4
POP BC C1
MOVE the value held at the top of the STACK into Register Pair BC.
4565
RET C9
RETurn to the caller.
4566H - Reset the FDC
Source label: TERM — Terminate FDC Operation. Outputs the force-interrupt command (D0H) to port F0H (CSTAT). This immediately stops any in-progress FDC command.
4566TERM
PUSH AF F5
SAVE Register AF to the STACK.
4567
LD A,0D0H 3E D0
LET Register A = D0H (1101 0000).
When this bit pattern in sent to Port F0H (the Floppy Disk Control Port) and bits 7-4 are 1101, this is a FORCE INTERRUPT command and is a Type IV command. Bit 3 designates IMMEDIATE INTERRUPT. Bit 2 designates INDEX PULSE. Bit 1 designates READY to NOT READY TRANSITION. Bit 0 designates NOT READY to READY TRANSITION.
| Command Code: D0H (11010000) | | Force Interrupt |
| 1 | 1 | 0 | 1 | I3 | I2 | I1 | I0 | | Command=Force Interrupt Bit 7-4: Command Code (1101) I3: 1=Interrupt Immediately I2: 1=Interrupt on the next Index Pulse I1: 1=Interrupt the next time Ready goes to Not Ready I0: 1=Interrupt the next time Not Ready goes to Ready |
4569
OUTput the value held in Register A to port F0H (the Floppy Disk Command/Status Register).
456B
POP AF F1
Restore Register Pair AF from the STACK.
456C
RET C9
RETurn to the caller.
456DH - Routine to WRITE SECTOR TO DISK
Assumes the head is already properly positioned.
456DWRITIT
LD BC,00F3H 01 F3 00
LET Register B = 00H for a counter and LET Register C = the FDC data port F3H.
4570
GOSUB to 44DDH to select the drive.
4573
OR 40H F6 40
OR Register A against 40H (0100 0000). This has the effect of turning on bit 6 which enables the WAIT BIT.
4575
LD D,A 57
LET Register D = Register A (which is holding the modified select code).
4576
GOSUB to 459CH to set the appropriate NMI Vector and clear the FDC status.
4579
LD A,0C0H 3E C0
LET Register A = C0H (1100 0000). When sent to the NMI port of E4H this actives NMI for FDC time-out and Disk Drive time-out
457B
OUTput Register A (C0H) to port E4H, the Non-Maskable Interrupt mask latch, to let the FDC interrupt request and the drive motor time out raise an NMI.
457D
LD E,02H 1E 02
LET Register E = 02H to set up a mask of 0000 0010, which, when applied, would test for CONTROLLER READY.
457F
LD HL,0000H 21 00 00
WHL: LET Register Pair HL = the buffer address. The operand at 4580H-4581H is 0000H in the file; XWRIT2 (4600H) stores the address of the buffer to write there before WRITIT runs.
4582
LD A,A5H 3E A5
DATMRK: LET Register A = A5H, the WRITE SECTOR command for the FDC (the source's CWRITE). The operand at 4583H is changed at run time: on track 17 (the directory) the code at 4621H-4628H clears bit 0 (AND FEH), so the sector is written with the other data address mark, and WRTEXT (4667H) sets bit 0 back.
4584OUTWR
OUTput the value held in Register A to port F0H.
NOTE: Port F0H is the Floppy Disk Command/Status Register. OUTputting to Port F0H cannot be simply summarized as there are more than 11 variables held in the bit pattern.
4586
GOSUB to 4404H for a slight delay.
4589IDFDDQ
INput a byte from Port F0H (the FDC Status Port) and put it into Register A.
| Status Register Value | | Type I Status |
| N | W | H | S | C | T | I | B | | Type I Command Status Register N: 1=Not Ready, 0=Ready W: 1=Write Protected, 0=Not Protected H: 1=Head Loaded, 0=Head Not Loaded S: 1=Seek Error, 0=No Error C: 1=CRC Error, 0=No Error T: 1=Track 0, 0=Not Track 0 I: 1=Index Mark Detected, 0=No Index B: 1=Busy, 0=Not Busy |
458B
AND E A3
MASK the value of Register A against the value held in Register E to check for CONTROLLER READY.
458C
If the Z FLAG (Zero) is set then the FDC is not ready so LOOP BACK 2 instructions to 4589H.
458E
OUTI ED A3
Write a byte from the memory location pointed to by HL to port C. Register B is DECremented and Register Pair HL is INCremented.
4590
LD B,64H 06 64
LET Register B = 64H (0110 0100).
4592MLOOP
LOOP back to this very instruction 64H times for a short delay.
4594
LD A,D 7A
LET Register A = Register D (which was holding the drive select code).
4595WLOP
OUTput the value held in Register A to port F4H.
NOTE: Port F4H is the Floppy drive select and options register. For OUTPUT:
- Bit 0: Drive 0 Select
- Bit 1: Drive 1 Select
- Bit 2: Drive 2 Select
- Bit 3: Drive 3 Select
- Bit 4: Side Select (0 = Select Side 0, 1 = Select Side 1)
- Bit 5: Write Precompensation (0 = Disable WP, 1 = Enable WP)
- Bit 6: Wait State Generation (0 = Disable WSG, 1 = Enable WSG)
- Bit 7: Density Select (0 = Single/FM, 1 = Double/MFM)
4597
OUTI ED A3
Write a byte from the memory location pointed to by HL to port C. Register B is DECremented and Register Pair HL is INCremented.
4599
LOOP back to 4595H to keep writing until a NMI exits the loop.
459CH - BOTNMI: Point the NMI vector at BORNMI (45ADH) and clear the FDC status
Source label: BOTNMI — Set Up NMI for Disk I/O, at 459CH. Saves HL, points the NMI vector address field (404AH) at BORNMI (45ADH), writes C3H (the JP opcode) to 4049H, reads port F0H to clear any pending FDC interrupt and returns with interrupts disabled. The caller then enables the FDC interrupt through port E4H.
459CBOTNMI
PUSH HL E5
SAVE Register HL to the STACK.
459D
LD HL,45ADH 21 AD 45
LET Register Pair HL = 45ADH, the address of BORNMI, the routine the NMI is to run when the FDC finishes the disk operation.
45A0
LD (404AH),HL 22 4A 40
Store Register Pair HL (45ADH, BORNMI) into 404AH-404BH, the address field of the NMI vector JP at 4049H (the source writes it as DOS+1).
45A3
LD A,C3H 3E C3
LET Register A = C3H, the opcode of the JP instruction.
45A5
LD (4049H),A 32 49 40
Store C3H (a JP opcode) into 4049H, the NMI vector (the source's DOS), so an NMI now runs JP 45ADH.
45A8SETNM0
INput a byte from Port F0H and put it into Register A.
NOTE: Port F0H is the FDC Status port on input. Input Results:
- Bit 0: Busy
- Bit 1: Index/DRQ
- Bit 2: Track 0/Data Lost
- Bit 3: CRC error
- Bit 4: Seek error/Record not found
- Bit 5: If Reading, Record Type, if Writing, Write Fault/Head loaded
- Bit 6: Write Protect
- Bit 7: Not ready
45AASETNM1
POP HL E1
SETNM1: Restore the caller's Register Pair HL from the STACK.
45AB
DI F3
Disable Maskable Interrupts.
45AC
RET C9
RETurn to the caller.
45ADH - Routine to clear the NMI vector and disable NMIs
Source label: BORNMI — NMI Handler for Disk I/O Completion. Clears the NMI mask (port E4H), resets the NMI vector to point at RETX (a RETN instruction at 42BDH), then clears any pending FDC interrupts.
45ADBORNMI
XOR A AF
Set Register A to ZERO and clear all Flags.
45AE
OUTput 00H (Register A) to port E4H, the Non-Maskable Interrupt mask latch, so no further disk NMIs are allowed.
45B0
LD HL,42BDH 21 BD 42
LET Register Pair HL = 42BDH, the address of RETX, a RETN instruction for an NMI that arrives when no disk I/O is going on.
45B3
LD (404AH),HL 22 4A 40
Store 42BDH (RETX) into 404AH-404BH, the address field of the NMI vector, so a later NMI just returns.
45B6
JUMP to 45A8H in the prior routine to clear the FDC status and disable Maskable Interrupts, and RETurn.
45B8H - Routine to READ SECTOR FROM DISK
Assumes the head is already properly positioned and that Register A holds the drive select code.
45B8READIT
LD BC,00F3H 01 F3 00
LET Register B = 00H for a counter and LET Register C = the FDC data port F3H.
45BB
GOSUB to 44DDH (a short routine to re-select a selected drive).
45BE
LD D,A 57
Preserve the drive select code (held in Register A) into Register D.
45BF
GOSUB to 459CH to set the appropriate NMI Vector and clear the FDC status.
45C2
LD A,C0H 3E C0
LET Register A = C0H (1100 0000) so that the NMI is programmed for controller and drive time-out when sent to Port E4H.
45C4
OUTput Register A (C0H) to port E4H, the Non-Maskable Interrupt mask latch, to let the FDC interrupt request and the drive motor time out raise an NMI.
45C6
LD E,02H 1E 02
LET Register E = 02H (0000 0010) to mask for CONTROLLER READY.
45C8
LD HL,0000H 21 00 00
RHL: LET Register Pair HL = the buffer address. The operand at 45C9H-45CAH is 0000H in the file; XREAD (4675H) stores the address of the buffer to read into there before READIT runs.
45CB
LD A,84H 3E 84
LET Register A = 84H (1000 0100) for sending to Port F0H (the Floppy Disk Control Port)
| Command Code: 84H (10000100) | | Read Sector |
| 1 | 0 | 0 | m | b | E | 0 | 0 | | Command=Read Sector Bit 7-5: Read Command (100) m: 1=Multiple Records, 0=Single Record b: 1=IBM format, 0=Non-IBM Format E: 1=Enable HLD, HLT, and 10ms Delay, 0=Assume Head Already Engaged, no Delay Remainder: Unused (00) |
45CDOUTRD
OUTput the value held in Register A to port F0H.
NOTE: Port F0H is the Floppy Disk Command/Status Register.
45CF
GOSUB to 4404H.
NOTE: 4404H is the routine which has a slight delay.
45D2FST
INput a byte from Port F0H and put it into Register A.
NOTE: Port F0H is the FDC Status port on input. Input Results:
- Bit 0: Busy
- Bit 1: Index/DRQ
- Bit 2: Track 0/Data Lost
- Bit 3: CRC error
- Bit 4: Seek error/Record not found
- Bit 5: If Reading, Record Type, if Writing, Write Fault/Head loaded
- Bit 6: Write Protect
- Bit 7: Not ready
45D4
AND E A3
MASK the value of Register A against the value held in Register E.
45D5
If the Z FLAG (Zero) is set, meaning CONTROLLER NOT READY, LOOP back 2 entries to poll the FDC again.
45D7
INI ED A2
INI: input a byte from the port in Register C (F3H, the FDC data register) into the memory location pointed to by Register Pair HL, then INCrement HL and DECrement Register B.
45D9
LD A,D 7A
Restore the drive select code (saved to Register D) back into Register A.
45DA
OR 40H F6 40
OR Register A against 40H (0100 0000). This has the effect of turning on bit 6 which is the WAIT STATE ON bit when sent to Port F4H.
45DCRD
OUTput the value held in Register A to port F4H.
NOTE: Port F4H is the Floppy drive select and options register. For OUTPUT:
- Bit 0: Drive 0 Select
- Bit 1: Drive 1 Select
- Bit 2: Drive 2 Select
- Bit 3: Drive 3 Select
- Bit 4: Side Select (0 = Select Side 0, 1 = Select Side 1)
- Bit 5: Write Precompensation (0 = Disable WP, 1 = Enable WP)
- Bit 6: Wait State Generation (0 = Disable WSG, 1 = Enable WSG)
- Bit 7: Density Select (0 = Single/FM, 1 = Double/MFM)
45DE
INI ED A2
INI: input a byte from the port in Register C (F3H, the FDC data register) into the memory location pointed to by Register Pair HL, then INCrement HL and DECrement Register B.
45E0
If the NZ FLAG (Not Zero) is set then the buffer is not yet full so LOOP BACK to 45DCH to keep reading bytes.
45E3
LD HL,0000H 21 00 00
If we are here then buffer IS full, so toss out HL by setting Register Pair HL = 0000H.
45E6
LOOP Back 4 instructions (45DCH). This routine will only exit via an interrupt.
45E9H - Routine to make a disk drive select code
45E9SITIT
AND 07H E6 07
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.
45EB
RLCA 07
Rotate the bits in A left (with Bit 7 going into both the CARRY and Bit 0) three times. This rorates the irrelevant bits and moves the bits we need to bits 3-5.
45EC
RLCA 07
Second RLCA: the drive number moves on toward bits 3-5.
45ED
RLCA 07
Third RLCA: the drive number (0-7) is now in bits 3-5, where a BIT, SET or RES instruction keeps its bit number.
45EE
OR C7H F6 C7
OR Register A against C7H to create an opcode using bits 3-5 from the mask.
45F0
LD (45F5H),A 32 F5 45
Store Register A (C7H plus the drive number in bits 3-5) into 45F5H, the second byte of the SET 0,A instruction at 45F4H (the source's SHERE), so that instruction becomes SET n,A for drive n.
45F3
XOR A AF
Set Register A to ZERO and clear all Flags.
45F4
SET 0,A CB C7
SHERE: SET bit n of Register A, where n is the drive number: the second byte of this instruction (45F5H) was rewritten by 45F0H. Register A was 00H, so it returns with only the drive's select bit set (01H, 02H, 04H or 08H).
45F6
RET C9
RETurn to the caller.
45F7H - Write Sector to Disk
Positions the head first. Register C must be set to ... dunno.
First we need to check for write protect.
45F7XWRITE
LD A,FFH 3E FF
WPD: LET Register A = FFH, the user write protect drive. The operand at 45F8H holds the number of a drive that is to be treated as write protected; FFH at load means no drive.
45F9
CP C B9
Compare the value held in Register A against the value held in Register C. Results: If Register A equals C, the Z FLAG is set; otherwise the NZ FLAG is set.
45FA
If the NZ FLAG (Not Zero) is set, the drive in Register C is not the user write protected drive, so JUMP to 4600H (XWRIT2) to continue the write.
45FCWPROT
LD A,0FH 3E 0F
WPROT: LET Register A = 0FH, error code 15 (EWPROT), WRITE PROTECTED DISK.
45FE
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
45FF
RET C9
RETurn to the caller.
4600H - Write Sector to Disk (Continuation)
Positions the head first (continuation after verification that the disk isn't write protected).
4600XWRIT2
LD (4580H),HL 22 80 45
Store the value held in Register HL (which is the buffer address) into the memory location 4580H.
4603
GOSUB to 4C6BH to start up and the check the disk drive.
4606
RET NZ C0
If the NZ FLAG (Not Zero) is set then there was an error from that routine so, RETurn to the caller.
4607
If the C FLAG (Carry) is set, CHKDRV found the diskette write protected, so JUMP to 45FCH (WPROT).
Start of a BIG loop for 9 iterations. The bottom of the loop is at 464EH.
4609
LD B,09H 06 09
TRY2: LET Register B = 09H, the number of retries (the source's RETRY). The operand at 460AH is changed at run time to set a different retry count.
460BREWRT
GOSUB to 44E3H.
NOTE: 44E3H is the routine which handles positions the READ/WRITE HEAD to the proper track (Register C holds the drive number, and Register D holds the track).
460E
CP 0CH FE 0C
Compare Register A (the status SEEK returned) against 0CH, error code 12 (ETIME), the time out.
4610
If the NZ FLAG (Not Zero) is set then we are good, so JUMP to 4614H.
4612
OR A B7
Prepare to return with error by setting the FLAGS based on the contents of Register A.
4613
RET C9
RETurn to the caller.
4614H - Write Sector to Disk (Continuation)
Positions the head first (continuation after positioning the head successfully.
4614REWRT1
BIT 6,A CB 77
Test Bit 6 of Register A to see if the disk is write protected.
4616
If the NZ FLAG (Not Zero) is set, then it is, so JUMP back a few instructions to the WRITE PROTECT ERROR routine (45FCH).
4618
AND 19H E6 19
MASK the value of Register A against 19H (0001 1001). This has the effect of turning off bits 7, 6, 5, 2, 1, leaving only bits 4 (FDC Seek Error), 3 (FDC CRC Error), 0 (FDC Busy) active.
461A
If the NZ FLAG (Not Zero) is set then one of those things happened, so JUMP to 465CH to reset the FDC and try again.
At this point, we know the disk isnt write protected, that we are on the right track, and that the FDC wasn't busy and didn't have an error ... so we are good to start writing.
461C
LD A,D 7A
LET Register A = Register D (which is holding the track number).
461D
CP 11H FE 11
Compare the value held in Register A against 11H (which is the directory track). Results: If Register A equals 11H, the Z FLAG is set; otherwise the NZ FLAG is set.
461F
If the NZ FLAG (Not Zero) is set, the track is not 17 (the directory track), so skip the change of the write command and JUMP to 4629H (NOMARK).
4621
LD A,(4583H) 3A 83 45
Fetch the value stored at memory location 4583H (which would be the write command) and put it into Register A.
4624
AND FEH E6 FE
AND the write command with FEH (the source's CDTMRK) to clear bit 0, the FDC's data address mark select bit, so the directory track is written with the other data address mark.
4626
LD (4583H),A 32 83 45
Store the changed write command back into 4583H, the operand of LD A,A5H at 4582H (DATMRK).
4629NOMARK
LD A,E 7B
LET Register A = Register E.
462A
OUTput the value held in Register A to Port F2H.
NOTE: Port F2H is the Floppy Disk Controller SECTOR Register.
462C
PUSH BC C5
PUSH Register BC to the top of the STACK.
462D
PUSH DE D5
PUSH Register DE to the top of the STACK.
462E
PUSH HL E5
PUSH Register HL to the top of the STACK.
462F
LD (47D8H),BC ED 43 D8 47
Store Register Pair BC into 47D8H-47D9H, the operand of LD BC,0000H at 47D7H (VER1), for the verify that VERF1 does after the write. Register C holds the drive number; Register B holds the retry counter.
4633
LD (47DBH),DE ED 53 DB 47
Store Register Pair DE (D = track, E = sector) into 47DBH-47DCH, the operand of LD DE,0000H at 47DAH (VER2), for the verify that VERF1 does after the write.
4637
GOSUB to 456DH.
NOTE: 456DH is the routine which to write a sector to diskette after the head is already properly positioned.
463A
POP HL E1
Restore Register Pair HL from the STACK (the source's RST3 macro: POP HL, POP DE, POP BC).
463B
POP DE D1
Restore Register Pair DE from the STACK.
463C
POP BC C1
Restore Register Pair BC from the STACK (Register B is the retry counter again).
463D
INput a byte from Port F0H and put it into Register A.
NOTE: Port F0H is the FDC Status port on input. Input Results:
- Bit 0: Busy
- Bit 1: Index/DRQ
- Bit 2: Track 0/Data Lost
- Bit 3: CRC error
- Bit 4: Seek error/Record not found
- Bit 5: If Reading, Record Type, if Writing, Write Fault/Head loaded
- Bit 6: Write Protect
- Bit 7: Not ready
463F
BIT 7,A CB 7F
Test Bit 7 of Register A (which is the NOT READY flag).
4641
If the NZ FLAG (Not Zero) is set then the DRIVE IS NOT READY, so JUMP to 464BH to reset the FDC and try again.
4643
BIT 6,A CB 77
If we're here, then the drive is ready so test Bit 6 (WRITE PROTECT Flag) of Register A (the FDC status from 463DH).
4645
If the NZ FLAG (Not Zero) is set then the WRITE PROTECT FLAG is set, so we have an error and need to JUMP to the WRITE PROTECT ERROR routine (45FCH).
4647
AND 3DH E6 3D
MASK the value of Register A against 3DH (0011 1101). This has the effect of turning off bits 7, 6, 1, leaving only bits 5 (WRITE FAULT), 4 (RECORD NOT FOUND), 3 (CRC ERROR), 2 (LOST DATA), 0 (BUSY) active.
4649
If the Z FLAG (Zero) is set, the write had no error, so JUMP to 4667H (WRTEXT), which puts bit 0 of the write command back and returns.
464BNOWRIT
NOWRIT: GOSUB to 42DCH (FIX1), which terminates the FDC operation and, after a record not found error, restores the drive to track 0.
464E
LOOP back to 460BH until Register B is ZERO.
End of loop of 9 tries.
4650
GOSUB to 4667H (WRTEXT) to set bit 0 of the write command at 4583H back to its normal value.
4653
LD B,0EH 06 0E
LET Register B = 0EH, error code 14 (EWFLT), WRITE FAULT ON DISK I/O, in case bit 5 is set.
4655
BIT 5,A CB 6F
Test Bit 5 of Register A for a WRITE FAULT.
4657
If the NZ FLAG (Not Zero) is set, the FDC reported a write fault, so JUMP to 46CCH (TSTSE1) to return error code 0EH.
465A
JUMP to 46A9H (TSTDAT) to turn the FDC status in Register A into an error code.
465CH - Reset the FDC, Try Again, Disable Read-Protect, and JUMP to the error routine
465CNOWRIE
NOWRIE: GOSUB to 4566H (TERM) to send the Force Interrupt command to the FDC.
465F
LOOP back to 460BH until Register B is ZERO.
4661
GOSUB to 4667H (WRTEXT) to set bit 0 of the write command at 4583H back to its normal value.
4664
JUMP to 46C4H (TSTSEK) to return a seek or CRC error code.
4667H - Disable the READ-PROTECT bit
4667WRTEXT
PUSH AF F5
WRTEXT: Save Register Pair AF (the status) on the STACK.
4668
LD A,(4583H) 3A 83 45
Fetch the write command from 4583H (DATMRK, the operand of the LD A at 4582H) into Register A.
466B
OR 01H F6 01
OR Register A with 01H to set bit 0, the data address mark select bit, back to the value used for normal sectors.
466D
LD (4583H),A 32 83 45
Store the write command back into 4583H (DATMRK).
4670
POP AF F1
Restore Register Pair AF from the top of the STACK.
4671
RET C9
RETurn to the caller.
4672H/4675H - Position the Head and Read Requested Sector
Source label: XREAD — Sector Read with Retries. Entry: D=track, E=sector, C=drive, HL=>buffer. Saves buffer pointer in RHL, calls CHKDRV to verify drive exists. Retries RETRY (9) times. Classifies errors: EHFLT (hardware fault/motor off), ELOSTD (lost data), ECRC (CRC error), ERNF (record not found), ESKER (seek error).
This has 2 entry points. The first empties HL (to toss away any data held there) one one leaves it alone.
4672DVER
LD HL,0000H 21 00 00
DVER: LET Register Pair HL = 0000H. The verify reads the sector into the ROM address space, so the data is thrown away and only the FDC's CRC and error status count.
4675XREAD
LD (45C9H),HL 22 C9 45
XREAD: Store Register Pair HL (the buffer address) into 45C9H-45CAH, the operand of LD HL at 45C8H (RHL), for READIT.
4678
GOSUB to 4C6BH to start up the disk drive.
467B
RET NZ C0
If the NZ FLAG (Not Zero) is set, meaning we received an error from that call, RETurn to the caller.
Start of a BIG loop for 9 iterations. The bottom of the loop is at 46A7H.
467C
LD B,09H 06 09
TRY1: LET Register B = 09H, the number of retries (the source's RETRY). The operand at 467DH is changed at run time to set a different retry count.
467ERERED
GOSUB to 44E3H.
NOTE: 44E3H is the routine which handles positions the READ/WRITE HEAD to the proper track (Register C holds the drive number, and Register D holds the track).
4681
CP 0CH FE 0C
Test for a time-out by comparing the value held in Register A against 0CH. Results: If Register A equals 0CH, the Z FLAG is set; otherwise the NZ FLAG is set.
4683
If the NZ FLAG (Not Zero) is set then we did not get a time-out so continue the routine by a JUMP to 4687H.
4685
OR A B7
Set FLAGS based on the contents of Register A in preparation to error out.
4686
RET C9
RETurn to the caller.
4687RERED1
AND 19H E6 19
MASK the value of Register A against 19H (0001 1001). This has the effect of turning off bits 7, 6, 5, 2, 1, leaving only bits 4 (SEEK ERROR), 3 (CRC ERROR), 0 (BUSY) active.
4689
If the NZ FLAG (Not Zero) is set then we have one of those so JUMP to 46BFH to deal with the error.
468B
LD A,E 7B
LET Register A = Register E (which is holding the SECTOR TO READ).
468C
OUTput the value held in Register A to Port F2H.
NOTE: Port F2H is the Floppy Disk Controller SECTOR Register.
468E
PUSH BC C5
SAV3: Preserve Register Pairs BC, DE and HL on the STACK.
468F
PUSH DE D5
PUSH Register Pair DE onto the STACK (second instruction of SAV3).
4690
PUSH HL E5
PUSH Register Pair HL onto the STACK (third instruction of SAV3).
4691
GOSUB to 45B8H to READ SECTOR FROM DISK (routine assumes the head is already properly positioned and that Register A holds the drive select code).
4694
POP HL E1
RST3: Restore Register Pairs HL, DE and BC from the STACK.
4695
POP DE D1
Restore Register Pair DE from the STACK (second instruction of RST3).
4696
POP BC C1
Restore Register Pair BC from the STACK (third instruction of RST3).
4697
INput a byte from Port F0H and put it into Register A.
NOTE: Port F0H is the FDC Status port on input. Input Results:
- Bit 0: Busy
- Bit 1: Index/DRQ
- Bit 2: Track 0/Data Lost
- Bit 3: CRC error
- Bit 4: Seek error/Record not found
- Bit 5: If Reading, Record Type, if Writing, Write Fault/Head loaded
- Bit 6: Write Protect
- Bit 7: Not ready
4699
EI FB
Enable Interrupts.
469A
LD (4B12H),A 32 12 4B
Store the byte read from the FDC status (held in Register A) into the memory location 4B12H - which is in the middle of a LD A,nnH instruction inside the READ DIRECTORY SECTOR routine at 4B0DH.
469D
BIT 7,A CB 7F
Test Bit 7 (NOT READY) of the FDC status (held in Register A).
469F
If the NZ FLAG (Not Zero) is set, then the FDC returned NOT READY, so JUMP to 46A4H.
46A1
AND 1DH E6 1D
MASK the value of Register A against 1DH (0001 1101). This has the effect of turning off bits 7, 6, 5, 1, leaving only bits 4 (RECORD NOT FOUND), 3 (CRC ERROR), 2 (LOST DATA), 0 (BUSY) active.
46A3
RET Z C8
If the Z FLAG (Zero) is set then we have no error so RETurn to the caller.
If we are here, then we need to deal with a NOT READY FDC error from 469FH.
46A4NOREAD
NOREAD: GOSUB to 42DCH (FIX1), which terminates the FDC operation and, after a record not found error, restores the drive to track 0.
46A7
LOOP back to 467EH to try again until Register B is ZERO.
46A9H - Error Processing Routine
46A9TSTDAT
LD B,06H 06 06
TSTDAT: LET Register B = 06H, error code 6 (EHFLT), DISK DRIVE HARDWARE FAULT.
46AB
BIT 7,A CB 7F
Test Bit 7 of Register A (NOT READY).
46AD
If the NZ FLAG (Not Zero) is set, the drive is not ready (motor off), so JUMP to 46CCH (TSTSE1) to return error code 06H.
46AF
LD B,03H 06 03
LET Register B = 03H, error code 3 (ELOSTD), LOST DATA DURING DISK I/O.
46B1
BIT 2,A CB 57
Test Bit 2 (LOST DATA) of Register A.
46B3
If the NZ FLAG (Not Zero) is set, data was lost, so JUMP to 46CCH (TSTSE1) to return error code 03H.
46B5
LD B,01H 06 01
LET Register B = 01H, error code 1 (ECRC), CRC ERROR DURING DISK I/O.
46B7
BIT 3,A CB 5F
Test Bit 3 (CRC ERROR) of Register A.
46B9
If the NZ FLAG (Not Zero) is set, the FDC reported a CRC error, so JUMP to 46CCH (TSTSE1) to return error code 01H.
46BB
LD B,05H 06 05
LET Register B = 05H, error code 5 (ERNF), DISK SECTOR NOT FOUND.
46BD
JUMP to 46CCH (TSTSE1) to return error code 05H.
46BFH - Deal with SEEK ERROR, CRC ERROR or BUSY FDC code
Jumped here from 4689H to deal with a SEEK ERROR, CRC ERROR or BUSY FDC code.
46BFNOREA1
NOREA1: GOSUB to 4566H (TERM) to send the Force Interrupt command to the FDC.
46C2
LOOP back to 467EH until Register B is ZERO.
46C4TSTSEK
LD B,04H 06 04
TSTSEK: LET Register B = 04H, error code 4 (ESKER), the seek error.
46C6
BIT 4,A CB 67
Test Bit 4 (SEEK ERROR) of Register A.
46C8
If the NZ FLAG (Not Zero) is set, the FDC reported a seek error, so JUMP to 46CCH (TSTSE1) to return error code 04H.
46CA
LD B,01H 06 01
LET Register B = 01H, error code 1 (ECRC): the source says it had to be a CRC error.
46CCH - Set up to return with an error code
46CCTSTSE1
LD A,B 78
TSTSE1: LET Register A = Register B, the error code.
46CD
OR A B7
OR Register A with itself so the NZ FLAG is set, the error return.
46CE
RET C9
RETurn to the caller.
46CFH - POSN Vector - Position a File for Access
This is the VECTOR call for POSN - Position a File for Access.
46CFPOSN1
GOSUB to 4881H to set up for I/O. SAVER requires Register Pair DE to point to the DCB.
46D2
BIT 7,(IX+01H) DD CB 01 7E
Test Bit 7 of Register (IX+01H), which is the OPTIONS byte, to see if we were set up for SECTOR I/O.
46D6
If the Z FLAG (Zero) is set then we are looking for SECTOR I/O so JUMP to 46E2H.
46D8
LD H,B 60
LET Register Pair HL = Register BC (the record number).
46D9
LD L,C 69
LET Register L = Register C: Register Pair HL now holds the requested logical record number from BC.
46DA
LD A,(IX+09H) DD 7E 09
Fetch the value stored at memory location IX+09H (Record Length) and put it into Register A.
46DD
GOSUB to 4B55H (DMULT) to multiply Register Pair HL (the logical record number) by Register A (the logical record length). The product is the byte position in the file: Register Pair HL comes back as its high 16 bits (the sector, that is the physical record number) and Register A as its low 8 bits (the offset inside the sector).
46E0
LD B,H 44
LET Register Pair BC = Register Pair HL (the new record number).
46E1
LD C,L 4D
LET Register C = Register L: Register Pair BC now holds the physical record number (the high 16 bits of the product).
46E2POSN2
LD (46F2H),A 32 F2 46
POSN2: Store Register A (the byte offset inside the sector) into 46F2H, the operand of LD A,00H at 46F1H (POSN8).
46E5
LD (46F7H),BC ED 43 F7 46
Store Register Pair BC (the physical record number) into 46F7H-46F8H, the operand of LD BC,0000H at 46F6H (POSN9).
46E9
GOSUB to 4868H to write the buffer (if necessary).
46EC
RET NZ C0
If the NZ FLAG (Not Zero) is set then there was an error, so RETurn to the caller.
46ED
SET 5,(IX+01H) DD CB 01 EE
SET (i.e., set as 1) BIT 5 of Register (IX+01H), which is the OPTIONS byte, to indicate that the sector is not loaded.
46F1
LD A,00H 3E 00
POSN8: LET Register A = the requested byte offset. The operand at 46F2H is 00H in the file and is stored by 46E2H.
46F3
LD (IX+05H),A DD 77 05
Store the value held in Register A into the memory location IX+05H (which is the BYTE POSITION FOR NEXT).
46F6
LD BC,0000H 01 00 00
POSN9: LET Register Pair BC = the requested record number. The operand at 46F7H-46F8H is 0000H in the file and is stored by 46E5H.
46F9
LD (IX+0AH),C DD 71 0A
Store Register C (the LSB of the requested record number) into IX+0AH, the LSB of the next record number (NRN) in the DCB.
46FC
LD (IX+0BH),B DD 70 0B
Store Register B (the MSB of the requested record number) into IX+0BH, the MSB of the next record number (NRN) in the DCB.
46FF
XOR A AF
Set Register A to ZERO and clear all Flags to indicate NO ERROR.
4700
RET C9
RETurn to the caller.
4701H - BACKSPACE Vector - Back Up To the Previous Record
This is the VECTOR call for BACKSPACE - Back Up To the Previous Record in a File.
4701BKSP
GOSUB to 4881H to set up for I/O. SAVER requires Register Pair DE to point to the DCB.
4704
LD C,(IX+0AH) DD 4E 0A
Fetch IX+0AH, the LSB of the next record number (NRN), into Register C.
4707
LD B,(IX+0BH) DD 46 0B
Fetch IX+0BH, the MSB of the next record number (NRN), into Register B.
470A
BIT 7,(IX+01H) DD CB 01 7E
Test Bit 7 of Register (IX+01H), which is the OPTIONS byte, to see if we were set up for SECTOR I/O.
470E
If the Z FLAG (Zero) is set then we were set up for SECTOR I/O so JUMP to 471DH.
4710
LD A,(IX+09H) DD 7E 09
Fetch the value stored at memory location IX+09H (Logical Record Length) and put it into Register A.
4713
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
4714
If the Z FLAG (Zero) is set then we were set for FULL sector records so JUMP to 471DH.
4716
NEG ED 44
NEGate Register A so that it is -LRL
4718
ADD A,(IX+05H) DD 86 05
Apply the -LRL to (IX+05H) (which is the BYTE POSITION FOR NEXT) to adjust the "NEXT" value
471B
If the C FLAG (Carry) is set, the previous logical record starts inside the current sector (the offset minus the LRL did not go below 0), so JUMP to 46E2H (POSN2) with Register A = the new offset and Register Pair BC = the same sector.
471DPOSI2
DEC BC 0B
DECrement Register Pair BC by 1 to go to the prior sector.
471E
JUMP to 46E2H to finish up and RETurn.
4720H - REWIND Vector - Position to the Start of a File
Source label: REW — Rewind File. Calls SAVER, sets BC=0 (record 0) and A=0 (offset 0), then falls through to POSN2 for positioning.
This is the VECTOR call for REWIND - Position to the Start of a File.
4720REW
GOSUB to 4881H to set up for I/O. SAVER requires Register Pair DE to point to the DCB.
4723
LD BC,0000H 01 00 00
LET Register Pair BC = 0000H so that the NEXT sector will be 0.
4726
XOR A AF
Set Register A to ZERO and clear all Flags so that the NEXT byte will be 0.
4727
JUMP to 46E2H to finish up and RETurn.
4729H - POSEOF Vector - Position to the End of a File
Source label: PEOF — Position to End of File. Calls SAVER, reads ERN (ending record number) into BC and EOF byte into A from DCB, then falls through to POSN2.
This is the VECTOR call for POSEOF - Position to the End of a File.
4729PEOF
GOSUB to 4881H to set up for I/O. SAVER requires Register Pair DE to point to the DCB.
472C
LD C,(IX+0CH) DD 4E 0C
Fetch IX+0CH, the LSB of the ending record number (ERN), into Register C.
472F
LD B,(IX+0DH) DD 46 0D
Fetch IX+0DH, the MSB of the ending record number (ERN), into Register B.
4732
LD A,(IX+08H) DD 7E 08
Fetch the value stored at memory location IX+08H (the Byte Position of the EOF) and put it into Register A.
4735
JUMP to 46E2H to finish up and RETurn.
4737H - READ Vector - Read the Logical Record at the "NEXT" Position
This is the VECTOR call for READ - Read the Logical Record at the "NEXT" Position.
4737READ1
GOSUB to 4881H to set up for I/O. SAVER requires Register Pair DE to point to the DCB.
473A
GOSUB to 4868H to write the buffer (if necessary).
473D
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have an error so RETurn to the caller.
473E
RES 6,(IX+01H) DD CB 01 B6
RESet bit 6 of IX+01H (the protection and status byte), the source's carry bit, which says the record number is to be advanced after a write.
4742
BIT 7,(IX+01H) DD CB 01 7E
Test Bit 7 of Register (IX+01H), which is the OPTIONS byte, to see if we were set up for SECTOR I/O.
4746
If the Z FLAG (Zero) is set then we were set up for SECTOR I/O so JUMP to 4772H to check the file security settings.
4748
LD B,(IX+09H) DD 46 09
Fetch the value stored at memory location IX+09H (Logical Record Length) and put it into Register B. This will serve as a DJNZ loop to read that number of bytes.
474BREAD2
PUSH HL E5
Preserve Register Pairs HL and BC to the STACK because the next routine uses them both.
474C
PUSH BC C5
PUSH Register Pair BC (Register B = the bytes of the record still to read) onto the STACK.
474D
GOSUB to 4791H to read a byte.
4750
POP BC C1
RESTORE Register Pairs BC and HL from the STACK.
4751
POP HL E1
Restore Register Pair HL (the user buffer pointer) from the STACK.
4752
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have an error so RETurn to the caller.
4753
LD (HL),A 77
Store the byte read from disk (held in Register A) into the memory buffer (pointed to by Register Pair HL).
4754
INC HL 23
Bump Register Pair HL by 1 to point to the next byte in the memory buffer.
4755
LOOP back to 474BH until Register B is ZERO.
4757
XOR A AF
Set Register A to ZERO and clear all Flags so as to indicate NO ERROR.
4758
RET C9
RETurn to the caller.
4759H - Verify READ ACCESS or Higher
SUBROUTINE to first verify that READ ACCESS or higher is permitted, and then continue at 476CH. Called from 4772 and 4797.
4759RDREC1
LD A,(IX+01H) DD 7E 01
Fetch the value stored at memory location IX+01H, which is the OPTIONS byte, and put it into Register A.
475C
AND 07H E6 07
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 (the ACCESS LEVEL) active.
475E
CP 06H FE 06
Compare the value held in Register A against 06H to check for READ LEVEL ACCESS or higher. Results:
- If Register A equals 06H, the Z FLAG is set.
- If A < 06H, the CARRY FLAG will be set.
- if A >= 06H, the NO CARRY FLAG will be set.
4760
If the C FLAG (Carry) is set, the protection level is below 6 (PEXEC, execute only), so reading is allowed: JUMP to 476CH (RDRECX).
4762PROTCT
LD A,19H 3E 19
PROTCT: LET Register A = 19H, error code 25 (EFAD), FILE ACCESS DENIED.
4764
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
4765
RET C9
RETurn to the caller.
4766H - Read the Sector / Return With Error or Continue
Called from 4C58.
4766RDREC2
GOSUB to 476CH to read a sector from the file.
4769
RET NZ C0
If the NZ FLAG (Not Zero) is set then there is an error, so RETurn to the caller.
476A
JUMP to 4776H to update "NEXT" and RETURN.
476CH - Check If Past EOF / Return With Error or Continue
476CRDRECX
GOSUB to 4A2EH to Check to see if we are past the EOF.
476F
RET NZ C0
If the NZ FLAG (Not Zero) is set then there is an error, so RETurn to the caller.
4770
JUMP to 4780H (RDSEC) to read the sector into the DCB's buffer.
4772H - Check File Security and Increase IX Next Sector
4772RDREC
GOSUB to 4759H to check the file security settings.
4775
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have an error, so RETurn to the caller.
4776INCREC
INC (IX+0AH) DD 34 0A
INCREC: INCrement IX+0AH, the LSB of the next record number (NRN) in the DCB.
4779
If the NZ FLAG (Not Zero) is set then don't have an overflow (i.e., no need to update the MSB), so skip the next instruction.
477B
INC (IX+0BH) DD 34 0B
INCrement IX+0BH, the MSB of the next record number (NRN), because the LSB wrapped from FFH to 00H.
477EINCRE1
XOR A AF
Set Register A to ZERO and clear all Flags.
477F
RET C9
RETurn to the caller.
4780H - Set Up HL for Re-entry into Position Head and Read Sector
Source label: RDSEC — Read Sector into Buffer. Calls GETPDA to get the physical disk address (track/sector), clears bit 5 of PROT to show record has been read, loads buffer address from DCB, then calls XREAD.
Continues from routine at 476CH (which makes sure we are not past EOF). Sets up HL for re-entry into the position head and read sector routine.
4780RDSEC
GOSUB to 49D4H to find the physical track and sector number of the "NEXT" sector.
4783
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have an error, so RETurn to the caller.
4784
RES 5,(IX+01H) DD CB 01 AE
RESet (i.e., set as 0) BIT 5 of Register (IX+01H), which is the OPTIONS byte, to indicate sector IS loaded.
4788
LD L,(IX+03H) DD 6E 03
Fetch the value stored at memory location IX+03H (the LSB of the 2 byte BUFFER ADDRESS) and put it into Register L.
478B
LD H,(IX+04H) DD 66 04
Fetch the value stored at memory location IX+04H (the MSB of the 2 byte BUFFER ADDRESS) and put it into Register H.
478E
JUMP to 4675H (the Position the Head and Read Requested Sector routine; although THIS time witH HL set).
4791H - Continue READ LOGICAL RECORD Routine
Source label: RDBYTE — Read Byte from File. If bit 5 of PROT is set, reads next record first via RDREC1. Calls GETPRN to verify record is in range. Calls CALCBA to get buffer address. Returns byte in A. Increments OFFSET; when OFFSET wraps to 0, sets bit 5 of PROT and increments NRN.
4791RDBYTE
BIT 5,(IX+01H) DD CB 01 6E
Test Bit 5 of Register (IX+01H), which is the OPTIONS byte, to see if the current sector is loaded.
4795
If the Z FLAG (Zero) is set then the current sector is already loaded so JUMP to 479BH.
4797
GOSUB to 4759H to check the file's security.
479A
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have an error, so RETurn to the caller.
479BRDTOB0
GOSUB to 4A2EH to check to see if we are past the EOF.
479E
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have an error, so RETurn to the caller.
479F
GOSUB to 4872H to determine the applicable byte position in the buffer (by adding the offset to the base buffer address, and then loading Register Pair DE to point to the buffer address of that specific byte).
47A2
XOR A AF
Set Register A to ZERO and clear all Flags.
47A3
LD A,(DE) 1A
Fetch the value stored at memory location pointed to by Register Pair DE (which is the byte from the buffer) and put it into Register A.
47A4
PUSH AF F5
Preserve Register AF (which includes the byte from the buffer) to the top of the STACK.
47A5
INC (IX+05H) DD 34 05
IX+05H is the BYTE POSITION FOR NEXT, so we need to bump that to the next byte
47A8
If the NZ FLAG (Not Zero) is set then we don't have a new sector, so skip the next 2 bytes and JUMP to 47B1H.
47AA
SET 5,(IX+01H) DD CB 01 EE
SET (i.e., set as 1) BIT 5 of Register (IX+01H), which is the OPTIONS byte, to signify that the current sector is NOT loaded.
47AE
GOSUB to 4776H to update the "NEXT" sector.
47B1RDTOB1
POP AF F1
Restore Register Pair AF (including the byte read, which is held in Register A) from the STACK.
47B2
RET C9
RETurn to the caller.
47B3H - WRITE VECTOR - Write File Sector WITHOUT Verify
47B3WRITE1
GOSUB to 4881H to prepare for the write. SAVER requires Register Pair DE to point to the DCB.
47B6H - Start of a loop for the entire LRL of the sector.
47B6WRITE2
BIT 7,(IX+01H) DD CB 01 7E
Test Bit 7 of Register (IX+01H), which is the OPTIONS byte, to see if we are looking for SECTOR I/O.
47BA
If the Z FLAG (Zero) is set then we are looking for SECTOR I/O so JUMP to 47E9H.
47BC
LD B,(IX+09H) DD 46 09
Fetch the value stored at memory location IX+09H, which is the LRL, and put it into Register B since Register B will be the counter for the DJNZ write loop.
47BFWRITE3
LD A,(HL) 7E
Fetch the byte to write (which is the value stored at memory location pointed to by Register Pair HL) and put it into Register A.
47C0
INC HL 23
Bump the pointer (held in Register Pair HL) by 1.
47C1
PUSH HL E5
PUSH Register HL to the top of the STACK.
47C2
PUSH BC C5
PUSH Register BC to the top of the STACK.
47C3
GOSUB to 4837H to write the byte to diskette.
47C6
POP BC C1
MOVE the value held at the top of the STACK into Register Pair BC.
47C7
POP HL E1
MOVE the value held at the top of the STACK into Register Pair HL.
47C8
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have an error, so RETurn to the caller.
47C9
LOOP back to 47BFH until Register B (which was the LRL) is ZERO.
47CB
RET C9
RETurn to the caller.
47CCH - WRITE VECTOR - Write File Sector WITH Verify
47CCVERF1
GOSUB to 4881H to prepare for the write. SAVER requires Register Pair DE to point to the DCB.
47CF
LD B,03H 06 03
LET Register B = 03H for a write of up to three tries.
47D1VERF2
PUSH BC C5
PUSH Register BC (i.e., save the counter held in Register B) to the top of the STACK because the B is used for the LRL counter in 47B6H.
47D2
GOSUB to 47B6H in the prior routine to loop the write of the sector.
47D5
If the NZ FLAG (Not Zero) is set then we have an error, so JUMP to 47E7H (to restore BC from the STACK and RETurn).
47D7
LD BC,0000H 01 00 00
VER1: LET Register Pair BC = the values 462FH stored here during the write. The operand at 47D8H-47D9H is 0000H in the file; Register C becomes the drive number for the verify read.
47DA
LD DE,0000H 11 00 00
VER2: LET Register Pair DE = the track (D) and sector (E) that 4633H stored here during the write. The operand at 47DBH-47DCH is 0000H in the file.
47DD
GOSUB to 4672H (DVER), which reads the sector just written into the ROM address space so only the CRC and error status are checked.
47E0
If the Z FLAG (Zero) is set then we got a good read, so JUMP to 47E7H (to restore BC from the STACK and RETurn).
47E2
POP BC C1
Restore Register Pair BC from the top of the STACK to get the "3 try" counter back into Register B.
47E3
LOOP back to 47D1H until Register B is ZERO (for a total of 3 tries).
47E5
OR A B7
Set FLAGS based on the contents of Register A.
47E6
RET C9
RETurn to the caller.
47E7H - Restore BC and Return
This little routine is called both when there is an error, or when there isn't, in the above routine.
47E7VERF3
POP BC C1
MOVE the value held at the top of the STACK into Register Pair BC.
47E8
RET C9
RETurn to the caller.
47E9H - SECTOR I/O Processing
Source label: WRRECX — Write Physical Record. Sets carry flag (bit 6 of PROT). Checks protection level: if >= PREAD (5), returns EFAD (access denied) error. Calls GETPDA for physical address, ALLOC if record out of range, then XWRITE. Updates ERN if record exceeds current end.
Called from 47B3H (the WRITE VECTOR) if it was determined that SECTOR I/O was required.
47E9WRRECX
SET 6,(IX+01H) DD CB 01 F6
WRRECX: SET bit 6 of IX+01H (the protection and status byte), the source's carry flag, so the next record number is advanced after this write.
47EDWRREC
LD A,(IX+01H) DD 7E 01
Fetch the value stored at memory location IX+01H (the OPTIONS byte) and put it into Register A.
47F0
AND 07H E6 07
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. Those bits are the ACCESS CODE.
47F2
CP 05H FE 05
Compare the protection level against 05H (PREAD, read and execute only). A level below 5 allows writing (C FLAG set).
47F4
If the NC FLAG (Carry) is set then we do not have WRITE access so JUMP to 4762H.
47F7WRIBUF
GOSUB to 49D4H to find the physical location of the track and sector for the I/O.
47FA
If the Z FLAG (Zero) is set then we had no errors in that CALL so JUMP to 4803H.
If we are here then we have an error, so we need to figure out which error and waht to do about it.
47FC
CP 1DH FE 1D
Compare Register A against 1DH, error code 29 (ENRF), RECORD OUT OF RANGE, which means the record is past the space allocated to the file.
47FE
RET NZ C0
If the NZ FLAG (Not Zero) is set, it was some other disk error, so RETurn to the caller with it.
47FFWRIBU0
GOSUB to 48ACH to allocate filespace and expand the file.
4802
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have an error from that CALL so RETurn to the caller.
4803WRIBU1
LD L,(IX+03H) DD 6E 03
Fetch the value stored at memory location IX+03H (the LSB of the 2 byte BUFFER ADDRESS) and put it into Register L.
4806
LD H,(IX+04H) DD 66 04
Fetch the value stored at memory location IX+04H (the MSB of the 2 byte BUFFER ADDRESS) and put it into Register H.
4809
GOSUB to 45F7H (XWRITE) to write the buffer at Register Pair HL to the sector in Register D (track) and Register E (sector) on the drive in Register C.
480C
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have an error from that CALL so RETurn to the caller.
480D
SET 3,(IX+01H) DD CB 01 DE
SET bit 3 of IX+01H (the protection and status byte) to show a write operation has been done on the file.
4811
RES 4,(IX+01H) DD CB 01 A6
RESet bit 4 of IX+01H to show the buffer has been written.
4815
GOSUB to 4A2EH to see if we have past the EOF.
4818
If the Z FLAG (Zero) is set then we have NOT gone past the EOF so JUMP to 482AH.
481A
BIT 6,(IX+01H) DD CB 01 76
Test bit 6 of IX+01H, the source's carry flag.
481E
If the Z FLAG (Zero) is set, the carry flag is off, so the ending record number is stored without adding 1: JUMP to 4821H (WRIBU2).
4820
INC HL 23
INCrement Register Pair HL (the record number from GETPRN) by 1, the source's EVEN BOUNDARY.
4821WRIBU2
LD (IX+0CH),L DD 75 0C
WRIBU2: Store Register L into IX+0CH, the LSB of the ending record number (ERN).
4824
LD (IX+0DH),H DD 74 0D
Store Register H into IX+0DH, the MSB of the ending record number (ERN).
4827
LD (IX+08H),C DD 71 08
Store Register C (the byte offset from GETPRN) into IX+08H, the end of file byte (EOF).
482AWRIBU3
BIT 6,(IX+01H) DD CB 01 76
WRIBU3: Test bit 6 of IX+01H, the source's carry flag.
482E
If the NZ FLAG (Not Zero) is set, the carry flag is on, so GOSUB to 4776H (INCREC) to advance the next record number.
4831
RES 6,(IX+01H) DD CB 01 B6
RESet bit 6 of IX+01H, the carry flag, to show the record number has been taken care of.
4835
XOR A AF
Set Register A to ZERO and clear all Flags.
4836
RET C9
RETurn to the caller.
4837H - Write a Byte at the "Next" Position
Source label: WRBYTE — Write Byte to File Buffer. If sector not yet read (bit 5 of PROT set), reads it first via RDSEC. Calculates buffer address via CALCBA. Stores byte, sets bit 4 of PROT (record needs writing). When OFFSET wraps to 0, sets bit 5 and writes the full buffer via WRRECX.
4837WRBYTE
PUSH AF F5
PUSH Register Pair AF (which contains the byte to write) to the top of the STACK.
4838
SET 3,(IX+01H) DD CB 01 DE
SET (i.e., set as 1) BIT 3 of Register (IX+01H), which is the OPTIONS byte.
483C
BIT 5,(IX+01H) DD CB 01 6E
Test Bit 5 of Register (IX+01H), which is the OPTIONS byte to test to see if the current sector is loaded.
4840
If the Z FLAG (Zero) is set then the current sector is loaded so JUMP to 4850H.
4842
GOSUB to 4780H to load the current sector.
4845
If the Z FLAG (Zero) is set then we had no errors so continue at 4850H.
4847
AND FEH E6 FE
AND the error code in Register A with FEH to force bit 0 off, so error codes 1CH (EEOF) and 1DH (ENRF) both become 1CH.
4849
CP 1CH FE 1C
Compare Register A against 1CH, error code 28 (EEOF), ATTEMPT TO READ PAST EOF (or 29, ENRF, after the AND).
484B
If the Z FLAG (Zero) is set, the sector is past the end of the file, which is allowed for a write, so JUMP to 4850H (WRFMB1).
484D
EX (SP),HL E3
EXchange Register Pair HL with the top of the STACK: HL goes onto the STACK and the pushed AF (the character) comes into HL.
484E
POP HL E1
POP the caller's Register Pair HL back off the STACK. The character that was pushed is discarded and Register A keeps the error code.
484F
RET C9
RETurn to the caller.
4850H - Write Byte When Current Sector Already Loaded
Called from the prior WRITE A BYTE AT NEXT POSITION routine if the current sector is already loaded.
4850WRFMB1
GOSUB to 4872H to compute the applicable position in the buffer (by adding the offset to the base buffer address, and then loading Register Pair DE to point to the buffer address of that specific byte).
4853
POP AF F1
Restore the byte to be written from the top into Register A.
4854
LD (DE),A 12
Store the byte to be written (held in Register A) into the buffer (the memory location pointed to by Register Pair DE).
4855
INC DE 13
Move to the next buffer location by bumping Register Pair DE (which is the pointer) by 1.
4856
SET 4,(IX+01H) DD CB 01 E6
SET (i.e., set as 1) BIT 4 of Register (IX+01H), which is the OPTIONS byte, to indicate that there is unwritten data in the buffer.
485A
INC (IX+05H) DD 34 05
IX+05H is the BYTE POSITION FOR NEXT in the FCB, so bump that as well.
485D
If the Z FLAG (Zero) is set then we have pushed from 256 bytes to 0, so it is time to actually write the buffer. To do so JUMP to 4861H.
485F
XOR A AF
Set Register A to ZERO and clear all Flags to indicate no error.
4860
RET C9
RETurn to the caller.
4861H - Write Buffer Out to Diskette
Jumped to from the prior routine when it is time to write the buffer out to diskette because the buffer is full.
4861WRFMB4
SET 5,(IX+01H) DD CB 01 EE
SET (i.e., set as 1) BIT 5 of Register (IX+01H), which is the OPTIONS byte, to indicate that the sector is NOT loaded.
4865
JUMP to 47E9H (WRRECX) to write the full buffer out to the disk.
4868H - Write the Buffer to Disk (if necessary)
Source label: DBLOCK — Check/Write Pending Buffer. Checks bits 4 (write pending) and 6 (carry flag) of PROT. If either is set, writes the buffer via WRREC. Otherwise returns Z (no action needed).
4868DBLOCK
LD A,(IX+01H) DD 7E 01
Fetch the value stored at memory location IX+01H (which is the OPTIONS byte) and put it into Register A.
486B
AND 50H E6 50
AND Register A with 50H to keep bit 6 (the carry flag) and bit 4 (the buffer holds data not yet written).
486D
If the NZ FLAG (Not Zero) is set, the buffer still has to be written, so JUMP to 47EDH (WRREC).
4870
XOR A AF
Set Register A to ZERO and clear all Flags to indicate no error.
4871
RET C9
RETurn to the caller.
4872H - Compute the Applicable Position in the Buffer
Source label: CALCBA — Calculate Buffer Address. Reads OFFSET from DCB, adds to BUFL/BUFH to compute DE => next available byte in buffer. Returns C = byte offset.
4872CALCBA
LD A,(IX+05H) DD 7E 05
Fetch the value stored at memory location IX+05H (which is the BYTE POSITION FOR NEXT) and put it into Register A. This will act as an offset value.
4875
LD C,A 4F
Save the offset value in Register C.
4876
ADD A,(IX+03H) DD 86 03
IX+03H holds the LSB of the 2 byte BUFFER ADDRESS, so this adds the OFFSET to the BASE buffer address
4879
LD E,A 5F
Put the Offset + Base address into Register E (so that Register Pair DE will point to the actual offset byte in the buffer).
487A
LD A,(IX+04H) DD 7E 04
Fetch the value stored at memory location IX+04H (MSB of the 2 byte BUFFER ADDRESS) and put it into Register A.
487D
ADC 00H CE 00
This is cute. If the offset is such that it would have caused an overflow (i.e., CARRY) when added to the buffer, the CARRY FLAG will be set to 1. By doing an ADD WITH CARRY for a value of 00H, this will increase the MSB by 1 if there was a carry, and increase the MSB by 0 if there wasn't!
487F
LD D,A 57
To round out having the MSB and LSB of the BUFFER which points to the OFFSET byte held in Register Pair DE, let Register D = Register A.
4880
RET C9
RETurn to the caller.
4881H - Prepare for Actual Diskette Write
Source label: SAVER — Save Registers for DCB Operations. Checks bit 7 of first DCB byte to verify file is open. Saves caller return address in SAVE2, DCB pointer in SAVE3. Moves DE to IX for indexed addressing. Pushes HL, DE, BC, IY. Sets up RET6 as cleanup address. Returns to caller with Z flag set.
This routine is called a LOT and prepares for an actual diskette write.
4881SAVER
LD A,(DE) 1A
SAVER: Fetch the first byte of the DCB pointed to by Register Pair DE (the file type byte) into Register A. Bit 7 is set when the file is open.
4882
RLCA 07
Rotate the bits in A left (with Bit 7 going into both the CARRY and Bit 0). This will have the effect of checking to see if the file is open by putting that indicator bit into the CARRY FLAG.
4883
If the NC FLAG (Carry) is set, bit 7 was clear and the file is not open, so JUMP to 48A7H (NOTOPN) to return error 26H.
4885SAVERN
POP AF F1
Get the return address by moving the value held at the top of the STACK into Register Pair AF.
4886
EX (SP),HL E3
Save the calling address (which is at the top of the STACK) by putting it into Register Pair HL.
4887
LD (44A9H),HL 22 A9 44
Store the value held in Register HL into the memory location 44A9H.
NOTE: 44A9H is the storage location for the Saved Caller Address for DOS functions (2 Bytes).
488A
LD (44ABH),DE ED 53 AB 44
Store the value held in Register DE into the memory location 44ABH.
NOTE: 44ABH is the storage location for the Saved FCB Address for DOS functions (2 Bytes).
488E
EX (SP),HL E3
EXchange Register Pair HL with the top of the STACK again: the caller's return address goes back onto the STACK and Register Pair HL gets its own value back.
488F
PUSH DE D5
PUSH Register Pair DE (the DCB address) onto the STACK.
4890
EX (SP),IX DD E3
EXchange Index Register IX with the top of the STACK: IX now holds the DCB address and the caller's IX is saved on the STACK, where RET6 (489FH) will restore it.
4892
PUSH HL E5
PUSH Register HL to the top of the STACK.
4893
PUSH DE D5
PUSH Register DE to the top of the STACK.
4894
PUSH BC C5
PUSH Register BC to the top of the STACK.
4895
PUSH IY FD E5
PUSH Register IY to the top of the STACK.
4897
PUSH HL E5
PUSH Register HL to the top of the STACK. Why push it again? This is to set up a for a routine return via 489FH.
4898
LD HL,489FH 21 9F 48
LET Register Pair HL = 489FH.
489B
EX (SP),HL E3
Put 489FH at the top of the STACK
489C
PUSH AF F5
PUSH Register Pair AF, which holds the return address into the I/O routine that called SAVER, so the RET below goes back into that routine. When that routine returns, it lands on RET6 (489FH).
489D
XOR A AF
Set Register A to ZERO and clear all Flags to signify no error.
489E
RET C9
RETurn to the caller.
489FH - Finish Diskette Write and RETURN
This routine will finish up the diskette write and RETURN. It was set in 489BH.
489FRET6
POP IY FD E1
MOVE the value held at the top of the STACK into Register Pair IY.
48A1
POP BC C1
MOVE the value held at the top of the STACK into Register Pair BC.
48A2
POP DE D1
MOVE the value held at the top of the STACK into Register Pair DE.
48A3
POP HL E1
MOVE the value held at the top of the STACK into Register Pair HL.
48A4
POP IX DD E1
MOVE the value held at the top of the STACK into Register Pair IX.
48A6
RET C9
RETurn to the caller.
48A7H - File Not Open Error Handler
This routine is JUMPed to from 4883H if the file we wanted to do I/O upon was not open.
48A7NOTOPN
POP AF F1
NOTOPN: POP the return address into the I/O routine off the STACK, so the RET below goes straight back to the program that called the I/O routine.
48A8
LD A,26H 3E 26
LET Register A = 26H, error code 38 (EFNYO), I/O ATTEMPT TO UNOPEN FILE.
48AA
OR A B7
Since a LD command does not set any FLAGS, set FLAGS based on the contents of Register A, which will be NZ for sure to signify an error.
48AB
RET C9
RETurn to the caller.
48ACH - Allocate Filespace and/or Expand
This subroutine is called from 47FF to allocate filespace (and/or expand if we hit the EOF).
48AC
LD A,(IX+07H) DD 7E 07
Fetch the value stored at memory location IX+07H (which is the LOGICAL FILE NUMBER IN THE DIRECTORY) and put it into Register A.
48AF
LD B,A 47
Preserve that file number into Register B.
48B0
LD C,(IX+06H) DD 4E 06
Fetch the value stored at memory location IX+06H (which is the DRIVE NUMBER OF THE FILE) and put it into Register C.
48B3
GOSUB to 4A93H (RDGAT) to read the GAT sector of the drive in Register C into BUFF2 at 4D00H.
48B6
RET NZ C0
If the NZ FLAG (Not Zero) is set, then we have an error, so RETurn to the caller.
48B7
GOSUB to 4A67H to read the directory entry directly to Buffer # 1.
48BA
RET NZ C0
If the NZ FLAG (Not Zero) is set, then we have an error, so RETurn to the caller.
48BB
LD (4955H),HL 22 55 49
Store the directory entry pointer (held in Register HL) into the memory location 4955H (which is actually the middle of an OPCODE for LD HL,xxxx).
48BE
LD L,(IX+0AH) DD 6E 0A
Fetch IX+0AH, the LSB of the next record number (NRN), into Register L.
48C1
LD H,(IX+0BH) DD 66 0B
Fetch IX+0BH, the MSB of the next record number (NRN), into Register H.
48C4
LD E,(IX+0CH) DD 5E 0C
Fetch IX+0CH, the LSB of the ending record number (ERN), into Register E.
48C7
LD D,(IX+0DH) DD 56 0D
Fetch IX+0DH, the MSB of the ending record number (ERN), into Register D.
48CA
OR A B7
Set FLAGS based on the contents of Register A which is really just trying to clear the CARRY FLAG as we are about to use it.
48CB
SBC HL,DE ED 52
HL = HL - DE (with Carry), so this way HL = the NEXT - the EOF.
48CD
If the NC FLAG (Carry) is set, the next record number is at or past the ending record number, so Register Pair HL keeps the difference: JUMP to 48D2H.
48CF
LD HL,0001H 21 01 00
The next record number is below the ending record number, so LET Register Pair HL = 0001H (one sector).
48D2
LD A,03H 3E 03
To prepare for a division routine, set Register A = 03H.
48D4
GOSUB to 4B6FH (DIVIDE) to divide Register Pair HL by 3 (the sectors in a gran). HL comes back as the quotient and Register A as the remainder.
48D7
INC HL 23
No matter what, HL needs to be higher than ZERO, so bump Register Pair HL by 1 so we have at least 1 gran. This leaves Register Pair HL holding the number of grans to allocate.
48D8
LD (4942H),HL 22 42 49
Store the value held in Register HL (the number of grans to allocate) into the memory location 4942H (which is actually the middle of an OPCODE for LD HL,xxxx).
The next 4 instructions are designed to set Register Pair HL to be the extent elements by setting HL as a base of 10, putting the DCB into Register Pair DE, and then adding DE to HL.
48DB
LD HL,0010H 21 10 00
LET Register Pair HL = 0010H as a base value
48DE
PUSH IX DD E5
PUSH Register IX to the top of the STACK.
48E0
POP DE D1
Restore Register IX from the top of the STACK into Register Pair DE.
48E1
ADD HL,DE 19
ADD the value held in Register Pair DE to Register Pair HL. The results are held in Register Pair HL.
48E2
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL (which is the first element) and put it into Register A.
48E3
CP FFH FE FF
Compare the value held in Register A against FFH to see if it is free. If Register A equals FFH, the Z FLAG is set; otherwise the NZ FLAG is set.
48E5
DEC HL 2B
DECrement Register Pair HL by 1 to back one one byte because the JP in the next instruction starts with an INC HL.
48E6
If the Z FLAG (Zero) is set, meaning that the element is free, JUMP to 4985H (to search for a free gran and if none found, return DISK FULL).
48E9
LD B,1AH 06 1A
LET Register B = 1AH as a counter to go through 26 bytes.
48EB
INC HL 23
Bump Register Pair HL by 1 to get to the next byte.
48EC
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL (which is the next element) and put it into Register A.
48ED
CP FFH FE FF
Compare the value held in Register A against FFH to see if it is free. If Register A equals FFH, the Z FLAG is set; otherwise the NZ FLAG is set.
48EF
If the Z FLAG (Zero) is set then the element is free so stop looking and JUMP to 48F7H.
48F1
LOOP back to 48EBH until Register B is ZERO.
48F3
LD A,1EH 3E 1E
LET Register A = 1EH to signify NO MORE EXTENTS AVAILABLE
48F5
OR A B7
Since a LD command does not set any FLAGS, set FLAGS based on the contents of Register A, which will be NZ for sure to signify an error.
48F6
RET C9
RETurn to the caller.
48F7H - Check for Free Extents
48F7
DEC HL 2B
DECrement Register Pair HL by 2 so as to back up to the start of the last extent.
48F8
DEC HL 2B
DECrement Register Pair HL again, so it points to the first byte (the track) of the last extent in use.
48F9
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL (which would be the track number) and put it into Register A.
48FA
LD DE,4D00H 11 00 4D
LET Register Pair DE = 4D00H so as to point to the GAT table.
48FD
ADD A,E 83
ADD the value held in Register E to Register A (Results held in Register A) to point to the entry for the given track.
48FE
LD E,A 5F
Preserve the entry for the given track into Register E.
48FF
INC HL 23
Bump Register Pair HL by 1 to point to the storage location for the number of grans in the selected extent.
4900
LD A,(HL) 7E
Fetch the second byte of the extent (bits 0-4 = the number of grans in it) into Register A.
4901
AND 1FH E6 1F
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.
4903
CP 1FH FE 1F
Compare the value held in Register A against 1FH to see if the extent is full. Results: If Register A equals 1FH (= the extent is full), the Z FLAG is set; otherwise the NZ FLAG (= not full) is set.
4905
If the NZ FLAG (Not Zero) is set, then the extent is not full, so JUMP to 490AH.
4907
INC HL 23
If we are here, then Z was set and the extent is full, so we need to bump Register Pair HL by 1 to check for the next extent.
490AH - Process Open Extent Found
This routine is JUMPed to from 4905H if an open extent is found.
490A
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL (the extent data) and put it into Register A.
490B
PUSH AF F5
PUSH Register AF to the top of the STACK.
The next few instructions basically set Register C to be the number of grans offset from the start of the track.
490C
AND E0H E6 E0
MASK Register A with E0H to keep bits 5-7, the starting gran of the extent within its track.
490E
RLCA 07
Move bits 7,6,5 to 0,7,6 by rotating the bits in A left (with Bit 7 going into both the CARRY and Bit 0).
490F
RLCA 07
Move bits 0,7,6 to 1,0,7 by rotating the bits in A left (with Bit 7 going into both the CARRY and Bit 0).
4910
RLCA 07
Move bits 1,0,7 to 2,1,0 by rotating the bits in A left (with Bit 7 going into both the CARRY and Bit 0).
4911
LD C,A 4F
LET Register C = Register A.
The next few instructions basically set Register A to be the number of grans in the extent.
4912
POP AF F1
Restore Register Pair AF (the second byte of the extent) from the STACK.
4913
AND 1FH E6 1F
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.
So now C holds the number of grans offset from the start of the track, and A holds the grans in the extent.
4915
ADD A,C 81
ADD the value held in Register C to Register A (Results held in Register A) so that Register A now equals the number of grans in total from the start.
4916
PUSH HL E5
Preserve Register Pair HL by pushing it to the top of the STACK.
4917
LD L,A 6F
Set Register Pair HL to be the number of grans total from the start of the track.
4918
LD H,00H 26 00
LET Register H = 00H, so Register Pair HL holds the gran count from Register A.
491A
LD A,06H 3E 06
Since TRSDOS v1.3 has 6 grans per track, set up Register A with a 6.
491C
GOSUB to 4B6FH (DIVIDE) to divide Register Pair HL by 6 (the grans in a track): HL comes back as the number of tracks and Register A as the gran within the track.
491F
PUSH AF F5
PUSH Register Pair AF (Register A = the gran within the track) onto the STACK.
There aren't a lot of variables in the Z-80 so the next 3 instructions simply set DE to point to the GAT Table, by setting A=L, A=A+E, E=A.
4920
LD A,L 7D
LET Register A = Register L.
4921
ADD A,E 83
ADD the value held in Register E to Register A (Results held in Register A).
4922
LD E,A 5F
LET Register E = Register A.
4923
POP BC C1
MOVE the value held at the top of the STACK (the number of grans into the track) into Register Pair BC.
4924
POP HL E1
Restore Register Pair HL from the top of the STACK.
4925
CP 28H FE 28
Test Register A against 40 (which is the highest number of tracks). Results:
- If Register A equals 28H, the Z FLAG is set.
- If A < 28H, the CARRY FLAG will be set.
- if A >= 28H, the NO CARRY FLAG will be set.
4927
If the NC FLAG (Carry) is set then we have exceeded track 40, which is a problem, so JUMP to 4985H (to search for a free gran and if none found, return DISK FULL).
492A
LD A,(DE) 1A
Fetch the value stored at memory location pointed to by Register Pair DE (the GAT entry) and put it into Register A.
492B
CP 3FH FE 3F
Compare the value held in Register A against 3FH to see if the track is completely allocated or not. Results: If Register A equals 3FH then the track is completely allocated and the Z FLAG is set; otherwise the NZ FLAG is set.
492D
If the Z FLAG (Zero) is set then the track is completely allocated so JUMP to 4985H (to search for a free gran and if none found, return DISK FULL).
492F
LD C,B 48
If we are here, then the track has room so we continue by setting Register C = the gran offset (held in Register B).
4930
LD B,A 47
LET Register B = the GAT entry (held in Register A).
4931
LD A,C 79
LET Register A = Register C (the gran offset).
4932
GOSUB to 4B48H to test to see if the gran is allocated.
4935
If the NZ FLAG (Not Zero) is set then the gran IS allocated, so create a new extent by JUMPing to 4985H.
4938
LD A,C 79
If we are here, then the gran is not allocated. LET Register A = Register C (the gran offset).
4939
GOSUB to 45E9H (SITIT), which turns the gran number in Register A (0-5) into a byte with only that bit set.
493C
EX DE,HL EB
Swap Register Pair DE (the GAT table) and Register Pair HL (the extent element).
493D
OR (HL) B6
OR the value stored at (HL) against Register A to allocate the gran. The results are stored in Register A.
493E
LD (HL),A 77
Store the value held in Register A into the GAT table (i.e., the memory location pointed to by Register Pair HL).
493F
EX DE,HL EB
Swap Register Pair De and Register Pair HL back. Now HL will contain the extent element.
4940
INC (HL) 34
Since HL points to the extent element, bump it by 1 to allocate another gran in the extent
The next bunch of instructions set that there is now one less gran on the disk to allocate.
4941
LD HL,0000H 21 00 00
LET Register Pair HL = 0000H. Note: This 0000H is replaced at 48D8H and at 4945H with other values, and is supposed to be the number of grans to allocate.
4944
DEC HL 2B
Reduce the number of grans remaining available by (held in Register Pair HL) by 1.
4945
LD (4942H),HL 22 42 49
Store the value held in Register HL (the newly reduced number of available grans) into the memory location 4942H (which is actually the middle of an OPCODE for LD HL,xxxx).
4948
LD A,H 7C
LET Register A = Register H and OR it with Register L: the Z FLAG is set only when Register Pair HL is 0000H.
4949
OR L B5
OR Register L into Register A: the Z FLAG is set only when Register Pair HL is 0000H.
494A
If the NZ FLAG (Not Zero) is set, meaning that HL was not zero, LOOP BACK to 48DBH.
4950
RET NZ C0
If the NZ FLAG (Not Zero) is set then there was an error from that routine, so RETurn to the caller.
4951
JUMP to 49D4H to continue the routine.
4954H - Continue File Space Allocation
This subroutine is called from 494DH to continue with the file space allocation.
The first part of this routine figures out what the EOF data is in the buffer and then saves the new EOF in the directory.
4954
LD HL,0000H 21 00 00
LET Register Pair HL = 0000H. This value gets repopulated at 48BBH to be the applicable directory entry pointer.
4957
LD DE,0014H 11 14 00
LET Register Pair DE = 0014H, the offset of the ending record number (DERN, 20) in a directory record.
495A
ADD HL,DE 19
ADD the value held in Register Pair DE (the EOF data in the entry) to Register Pair HL (the directory entry). The results, which should be the EOF data in the buffer) are held in Register Pair HL.
495B
LD A,(IX+0AH) DD 7E 0A
Fetch IX+0AH, the LSB of the next record number (NRN), into Register A.
495E
LD (HL),A 77
Store the value held in Register A into the memory location pointed to by Register Pair HL.
495F
INC HL 23
Bump Register Pair HL by 1 to point to the next location.
4960
LD A,(IX+0BH) DD 7E 0B
Fetch IX+0BH, the MSB of the next record number (NRN), into Register A.
4963
LD (HL),A 77
Store the value held in Register A into the memory location pointed to by Register Pair HL.
4964
INC HL 23
Bump Register Pair HL by 1.
Now that the new EOF has ben saved, need to deal with the extents.
4965
PUSH IX DD E5
PUSH Register IX (which is the point to the DCB in RAM) to the top of the STACK.
4967
LD DE,0010H 11 10 00
LET Register Pair DE = 0010H, which is the offset for the extent information.
496A
ADD IX,DE DD 19
ADD the value held in Register Pair DE (the offset) to Register Pair IX (the DCB). The results are held in Register Pair IX.
496C
PUSH IX DD E5
Copy IX to DE via a PUSH and a POP.
496E
POP DE D1
POP that value into Register Pair DE, so DE = IX + 10H, the extents in the DCB.
496F
POP IX DD E1
Restore the DCB to Register Pair IX.
4971
EX DE,HL EB
Swap Register Pair DE and Register Pair HL (so now HL will hold the extent information)
4972
LD BC,001AH 01 1A 00
LET Register Pair BC = 001AH to set up a LDIR to move 26 bytes from the DCB to the directory.
4975
LDIR ED B0
Do that loop
4977
LD C,(IX+06H) DD 4E 06
Fetch the value stored at memory location IX+06H (which is the DRIVE NUMBER OF THE FILE) and put it into Register C.
497A
LD B,(IX+07H) DD 46 07
Fetch the value stored at memory location IX+07H (which is the LOGICAL FILE NUMBER IN THE DIRECTORY) and put it into Register B.
497D
GOSUB to 4A9BH to write the new GAT sector.
4980
RET NZ C0
If the NZ FLAG (Not Zero) is set then there was an error from that routine, so RETurn to the caller.
4981
GOSUB to 4A7BH to write the directory entry.
4984
RET C9
RETurn to the caller.
4985H - Search for Available Gran
Routine to search for an available gran and if none, error out.
4985
INC HL 23
Bump Register Pair HL by 1 so that it points to the next extent element.
4986
PUSH HL E5
Preserve Register Pair HL by PUSHing Register HL to the top of the STACK.
4987
LD (49C9H),HL 22 C9 49
Store Register Pair HL (the next extent pointer) into 49C9H-49CAH, the operand of LD DE,0000H at 49C8H.
498A
Search for a free gran by GOSUBing to 4997H. That routine should return a Z FLAG if a free gran has been found.
498D
POP HL E1
Restore HL from the top of the STACK.
498E
If the Z FLAG (Zero) is set then a free gran was found so JUMP to 4941H.
4990
GOSUB to 4954H to preserve the new allocation information.
4993
LD A,1BH 3E 1B
LET Register A = 1BH, error code 27 (EDSFL), DISK SPACE FULL.
4995
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A and, based on A, it will definitely be NZ FLAG.
4996
RET C9
RETurn to the caller.
4997H - Find Free Gran on Diskette
SUBROUTINE called from 4997H to find a free gran on a diskette and either JUMP to 49A7H if there is one or error out if there isn't.
4997
LD HL,4D00H 21 00 4D
LET Register Pair HL = 4D00H which is the buffer address of the GAT.
499A
LD B,28H 06 28
LET Register B = 28H (Decimal: 40) to set a loop for 40 tracks to search.
499C
LD A,(HL) 7E
Fetch the status of the current gran (which is the value stored at memory location pointed to by Register Pair HL) and put it into Register A.
499D
CP 3FH FE 3F
Compare the value held in Register A against 3FH to test if that gran is full. Results: If Register A equals 3FH (the gran is full), the Z FLAG is set; otherwise the NZ FLAG is set.
499F
If the NZ FLAG (Not Zero) is set then the gran is NOT full, so JUMP to 49A7H.
49A1
INC L 2C
Bump Register L by 1 so that HL will point to the next entry.
49A2
LOOP back to 499CH until Register B is ZERO (i.e., all 40 tracks have been checked).
49A4
OR FFH F6 FF
OR Register A against FFH to set the flags and otherwise prepare for a GRAN NOT FOUND.
49A6
RET C9
RETurn to the caller.
49A7H - Search for Free Gran
49A7
PUSH HL E5
PUSH Register HL (the element pointer) to the top of the STACK.
49A8
LD DE,0060H 11 60 00
LET Register Pair DE = 0060H, the offset of the flaw table in the GAT sector (the source's FLAW, 96). A track marked FFH there is flawed.
49AB
ADD HL,DE 19
ADD the value held in Register Pair DE to Register Pair HL so that HL now points to the appropriate element in the table.
49AC
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL and put it into Register A.
49AD
POP HL E1
Restore the element pointer back into HL from the top of the STACK.
49AE
CP FFH FE FF
Compare the value held in Register A against FFH to see if the track is bad. Results: If Register A equals FFH then the track is bad and the Z FLAG is set; otherwise the NZ FLAG is set.
49B0
If the Z FLAG (Zero) is set then the track was marked bad so JUMP BACK to 49A1H to keep searching.
49B2
LD C,00H 0E 00
The track is not flawed, so LET Register C = 00H, the first gran of the track.
49B4
LD B,(HL) 46
Fetch the value stored at memory location pointed to by Register Pair HL (the GAT entry)and put it into Register B.
49B5
LD A,C 79
LET Register A = Register C.
49B6
Test to see if the gran is allocated by GOSUBing to 4B48H.
49B9
If the Z FLAG (Zero) is set then the gran is NOT allocated so JUMP to 49BEH.
49BB
INC C 0C
If we're here then the gran was allocated so to move to the next one Bump Register C by 1.
49BC
LOOP BACK to 49B5H until a free gran is found.
49BEH - Update GAT Entry and Number of Free Grans
49BE
LD A,C 79
LET Register A = Register C (the gran number in the track).
49BF
GOSUB to 45E9H (SITIT), which turns the gran number in Register A into a byte with only that bit set.
49C2
OR (HL) B6
OR the value stored at (HL) against Register A to combine the gran number in track with the GAT entry. The results are stored in Register A.
49C3
LD (HL),A 77
Store the new GAT entry (held in Register A) into the memory location pointed to by Register Pair HL.
49C4
LD A,C 79
LET Register A = Register C (the gran number in the track).
49C5
RRCA 0F
Rotate the gran offset into bits 5-7 by doing three RRCA's (which rotates the contents of A right one bit position; so that, for example, the contents of bit 0 are copied bit 7).
49C7
RRCA 0F
Third RRCA: the gran number is now in bits 5-7 of Register A, where the extent byte keeps the starting gran.
49C8
LD DE,0000H 11 00 00
LET Register Pair DE = 0000H. This 0000H is filled in dynamically from 4987H to be the next extent element pointer.
49CB
PUSH AF F5
PUSH Register AF (the gran offset) to the top of the STACK.
49CC
LD A,L 7D
LET Register A = Register L (which is the track number).
49CD
LD (DE),A 12
Store the track number (held in Register A) into the DCB (the memory location pointed to by Register Pair DE).
49CE
INC DE 13
Bump Register Pair DE by 1 to point to the next byte.
49CF
POP AF F1
Restore the gran offset from the top of the STACK into Register Pair AF.
49D0
INC A 3C
Bump Register A by 1 to indicate that one gran has been allocated.
49D1
LD (DE),A 12
Save the updated extent byte by storing the value held in Register A into the memory location pointed to by Register Pair DE.
49D2
XOR A AF
Set Register A to ZERO and clear all Flags to indicate NO ERROR.
49D3
RET C9
RETurn to the caller.
49D4H - Scan All Extents for Availability
49D4GETPDA
PUSH HL E5
PUSH Register HL to the top of the STACK.
49D5
PUSH BC C5
PUSH Register BC to the top of the STACK.
49D6
PUSH IX DD E5
PUSH Register IX to the top of the STACK.
49D8
POP HL E1
MOVE the value held at the top of the STACK (which was Index Register IX) into Register Pair HL.
49D9
LD DE,0010H 11 10 00
LET Register Pair DE = 0010H.
49DC
ADD HL,DE 19
ADD the value held in Register Pair DE (10H) to Register Pair HL, so that HL points to the extent elements in the DCB.
49DD
LD E,(IX+0AH) DD 5E 0A
Fetch IX+0AH and IX+0BH, the next record number (NRN), into Register Pair DE.
49E0
LD D,(IX+0BH) DD 56 0B
Fetch IX+0BH, the MSB of the next record number (NRN), into Register D.
49E3
LD B,0DH 06 0D
LET Register B = 0DH (Decimal: 13) to scan up to 13 elements.
49E5
LD A,(HL) 7E
Fetch the extent element (which is thg value stored at memory location pointed to by Register Pair HL) and put it into Register A.
49E6
INC A 3C
Bump Register A by 1 to see if it is unused.
49E7
If the Z FLAG (Zero) is set, the extent byte was FFH, the end of the extent list, so the record is beyond the space allocated to the file: JUMP to 4A05H to return error 1DH.
49E9
INC HL 23
Bump Register Pair HL by 1 so that it will point to the number of grans in the extent in the DCB.
49EA
LD A,(HL) 7E
Fetch the second byte of the extent into Register A.
49EB
AND 1FH E6 1F
MASK Register A with 1FH to keep bits 0-4, the number of grans in the extent.
49ED
GOSUB to 4A28H to convert that masked value into the number of sectors in the extent.
49F0
NEG ED 44
Negate Register A so that A = - sectors in the extent
49F2
PUSH DE D5
PUSH Register DE to the top of the STACK.
The next bunch of instructions only serves to set DE = DE - number of sectors in the extent and put that into Register A (with the CARRY FLAG set if the result is negative).
49F3
ADD A,E 83
ADD the value held in Register E to Register A (Results held in Register A).
49F4
LD E,A 5F
LET Register E = Register A.
49F5
CCF 3F
Invert the CARRY FLAG so it is a borrow for the SBC below.
49F6
LD A,D 7A
LET Register A = Register D.
49F7
SBC 00H DE 00
Subtract 00H and the CARRY FLAG from Register A.
49F9
LD D,A 57
LET Register D = Register A.
DE now holds the number of sectors in the extent.
49FA
If the C FLAG (Carry) is set, Register Pair DE went below zero, so the record lies inside this extent: JUMP to 4A0AH.
49FC
POP AF F1
POP the saved record number off the STACK and throw it away; Register Pair DE keeps the record number less the sectors of this extent.
49FD
INC HL 23
Bump Register Pair HL by 1 so HL points to the next element.
49FE
LOOP back to 49E5H until Register B is ZERO and all the extents have been checked.
If we are here then every extent has been checked and all extents have been used. This is bad.
4A00
POP BC C1
Restore Register Pair BC from the STACK.
4A01
POP HL E1
Restore Register Pair HL from the STACK.
4A02
JUMP to 48F3H to return error 1EH, error code 30 (ENMEX), NO MORE EXTENTS.
4A05H - Return PAST END OF FILE Error
4A05
OR 1DH F6 1D
OR Register A (00H after the INC of FFH) with 1DH: Register A = 1DH, error code 29 (ENRF), RECORD OUT OF RANGE, with the NZ FLAG set.
4A07
POP BC C1
Restore Register Pair BC from the STACK.
4A08
POP HL E1
Restore Register Pair HL from the STACK.
4A09
RET C9
RETurn to the caller.
4A0AH - Calculate Offset in Grans for Track of Extent
4A0A
POP DE D1
Restore Register Pair DE from the STACK.
4A0B
POP BC C1
Restore Register Pair BC from the STACK.
The next few instructions get the offset (in grans) into the track of the extent.
4A0C
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL and put it into Register A.
4A0D
AND E0H E6 E0
MASK the value of Register A against E0H (1110 0000). This has the effect of turning off bits 4, 3, 2, 1, 0, leaving only bits 7, 6, 5 active.
4A0F
RLCA 07
Rotate the bits in A left 3 times (with Bit 7 going into both the CARRY and Bit 0), thus moving bits 7, 6, and 5 to bits 2, 1, and 0.
4A11
RLCA 07
Third RLCA: bits 5-7 (the starting gran of the extent) are now in bits 0-2 of Register A.
Now that the offset (in grans) is in Register A, prepare to calculate it and write it.
4A12
GOSUB to 4A28H to convert that masked value (which is grans) into the sectors (by multipling them by 3).
4A15
ADD A,E 83
Calculate the ofset into the track by ADDing the value held in Register E to Register A (Results held in Register A).
4A16
DEC HL 2B
DECrement Register Pair HL by 1 to point to where the track of the extent is stored.
4A17
LD D,(HL) 56
Fetch the value stored at memory location pointed to by Register Pair HL (whcih is the track of the extent) and put it into Register D.
4A18
LD E,A 5F
LET Register E = Register A (the sector offset in the track).
4A19
SUB 12H D6 12
SUBtract the value 12H (Decimal: 18) from Register A to set up for a 1 track offset.
4A1B
If the C FLAG (Carry) is set, the sector offset is below 18, so it is in this track: JUMP to 4A20H.
4A1D
INC D 14
Bump Register D by 1 to point to the next track.
4A1E
LOOP BACK to 4A18H until we are at the proper track.
4A20H - Handle Negative Offset
Jumped here from 4A1BH if the offset is negative.
4A20
INC E 1C
Bump Register E by 1, because sectors on the disk are numbered from 1.
4A21
LD A,(IX+06H) DD 7E 06
Fetch the value stored at memory location IX+06H (which is the DRIVE NUMBER OF THE FILE) and put it into Register A.
4A24
LD C,A 4F
LET Register C = Register A (the DRIVE NUMBER OF THE FILE).
4A25
XOR A AF
Set Register A to ZERO and clear all Flags to indicate no error.
4A26
POP HL E1
Restore Register Pair HL from the top of the STACK.
4A27
RET C9
RETurn to the caller.
4A28H - Convert Grans to Sectors
SUBROUTINE to convert the Grans (which was the masked value) into a sector.
4A28
PUSH BC C5
PUSH Register BC to the top of the STACK.
4A29
LD B,A 47
LET Register B = Register A (to preserve A).
4A2A
RLCA 07
Rotate the bits in A left, which effectively doubles Register A.
4A2B
ADD A,B 80
ADD the value held in Register B (which is Register A before it was doubled) to Register A. This results in A * 3.
4A2C
POP BC C1
Restore Register Pair BC from the top of the STACK.
4A2D
RET C9
RETurn to the caller.
4A2EH - Check if Sector is After EOF
Subroutine to check if the sought after sector is after the EOF. Called from 476CH, 479BH, and 4815H.
4A2EGETPRN
PUSH DE D5
PUSH Register DE to the top of the STACK.
The combination of IX+08H, IX+0CH, and IX+0DH is the relative byte address of the EOF.
4A2F
LD D,(IX+0DH) DD 56 0D
Fetch IX+0DH, the MSB of the ending record number (ERN), into Register D.
4A32
LD E,(IX+0CH) DD 5E 0C
Fetch IX+0CH, the LSB of the ending record number (ERN), into Register E.
4A35
LD A,(IX+08H) DD 7E 08
Fetch the value stored at memory location IX+08H (the Byte Position of the EOF) and put it into Register A.
4A38
OR D B2
Check D vs A to see if they are empty by ORing Register D against Register A. The results are stored in Register A.
4A39
OR E B3
Check E vs A to see if they are empty by ORing Register E against Register A. The results are stored in Register A.
4A3A
If the Z FLAG (Zero) is set then D, E, and A are all zero meaning that the file is empty, so JUMP to 4A57H.
4A3C
LD H,(IX+0BH) DD 66 0B
Fetch IX+0BH, the MSB of the next record number (NRN), into Register H.
4A3F
LD L,(IX+0AH) DD 6E 0A
Fetch IX+0AH, the LSB of the next record number (NRN), into Register L.
4A42
OR A B7
Since we are about to do a routine which checks the CARRY FLAG, we need to clear the CARRY FLAG.
4A43
SBC HL,DE ED 52
Subtract Register Pair DE (the ending record number) from Register Pair HL (the next record number).
4A45
If the C FLAG (Carry) is set, the next record is before the ending record, so the record is inside the file: JUMP to 4A5AH.
4A47
If the NZ FLAG (Not Zero) is set, the next record is after the ending record, so JUMP to 4A57H to return error 1CH.
4A49
BIT 6,(IX+01H) DD CB 01 76
The next record is the ending record. Test bit 6 of IX+01H, the source's carry flag.
4A4D
If the NZ FLAG (Not Zero) is set, the carry flag is on, so JUMP to 4A57H to return error 1CH.
4A4F
LD A,(IX+05H) DD 7E 05
Fetch IX+05H, the byte offset of the next byte, into Register A.
4A52
CP (IX+08H) DD BE 08
Compare the EOF Byte Number (held in Register A) against the the Byte Position of the EOF (held in the memory location (IX+08H)). Results:
- If Register A equals (IX+08H), the Z FLAG is set.
- If A < (IX+08H), the CARRY FLAG will be set.
- if A >= (IX+08H), the NO CARRY FLAG will be set.
4A55
If the C FLAG (Carry) is set, the offset is below the end of file byte, so the position is inside the file: JUMP to 4A5AH.
4A57
LD A,1CH 3E 1C
LET Register A = 1CH, error code 28 (EEOF), ATTEMPT TO READ PAST EOF.
4A59
DEFB 0EH 0E
When execution falls through from 4A57H, this 0EH and the AFH at 4A5AH form the instruction LD C,0AFH, which skips the XOR A, so Register A keeps 1CH. A JUMP to 4A5AH runs the XOR A instead.
4A5A
XOR A AF
XOR A: Register A = 00H, the good return.
4A5B
OR A B7
OR Register A with itself: the Z FLAG is set for 00H (no error) and the NZ FLAG for 1CH.
The combination of IX+05H, IX+0AH, and IX+0BH is the relative byte address of the "NEXT" sector.
4A5C
LD H,(IX+0BH) DD 66 0B
Fetch IX+0BH, the MSB of the next record number (NRN), into Register H.
4A5F
LD L,(IX+0AH) DD 6E 0A
Fetch IX+0AH, the LSB of the next record number (NRN), into Register L.
4A62
LD C,(IX+05H) DD 4E 05
Fetch the value stored at memory location IX+05H (which is the BYTE POSITION FOR NEXT) and put it into Register C.
4A65
POP DE D1
Restore Register Pair DE from the top of the STACK.
4A66
RET C9
RETurn to the caller.
4A67H - READ Directory Entry into Buffer #1
4A67RDDIR
PUSH BC C5
Preserve Register Pair BC by PUSHing it to the top of the STACK.
4A68
PUSH DE D5
Preserve Register Pair DE by PUSHing it to the top of the STACK.
4A69
GOSUB to 4AD8H (LFNDIR) to work out the directory sector (Register E) and the address in BUFF1 (Register Pair HL) of the record for the logical file number in Register B.
4A6C
If the NZ FLAG (Not Zero) is set then the prior subroutine exited with an error, so JUMP to 4A76H.
4A6E
PUSH HL E5
Preserve Register Pair HL by PUSHing it to the top of the STACK.
4A6F
LD L,00H 2E 00
LET Register L = 00H. This will form HL as pointing to Buffer # 1.
4A71
GOSUB to 4B0DH to read the sector.
4A74
POP HL E1
Restore Register Pair HL from the top of the STACK.
4A75
DEFB 01H 01
When execution falls through from 4A74H, this 01H and the 3EH 11H at 4A76H form LD BC,113EH, which skips the LD A,11H, so Register A keeps the result of the read. A JUMP to 4A76H runs the LD A,11H instead.
4A76
LD A, 11H 3E 11
LET Register A = 11H, error code 17 (EDRE), DIRECTORY READ ERROR. The flags are still NZ from the failed call.
4A78
POP DE D1
Restore Register Pair DE from the top of the STACK.
4A79
POP BC C1
Restore Register Pair BC from the top of the STACK.
4A7A
RET C9
RETurn to the caller.
4A7BH - WRITE Directory Entry from Buffer #1
Subroutine to WRITE the Directory Entry from Buffer # 1. Called from 4981H.
4A7BWRDIR
PUSH BC C5
Preserve Register Pair BC by PUSHing it to the top of the STACK.
4A7C
PUSH DE D5
Preserve Register Pair DE by PUSHing it to the top of the STACK.
4A7D
GOSUB to 4AD8H to position for a write.
4A80
If the NZ FLAG (Not Zero) is set, LFNDIR returned an error, so JUMP to 4A89H.
4A82
LD L,00H 2E 00
LET Register L = 00H. This will form HL as pointing to Buffer # 1.
4A84
GOSUB to 45F7H to write the sector.
4A87
If the Z FLAG (Zero) is set then the prior routine had NO error, so JUMP to 4A90H.
4A89
CP 0FH FE 0F
If we're here then there was an error, so we need to deal with that. First, compare the value held in Register A against 0FH to check for a WRITE PROTECT ERROR. Results: If Register A equals 0FH, the Z FLAG is set; otherwise the NZ FLAG is set.
4A8B
If the Z FLAG (Zero) is set then we had a WRITE PROTECT ERROR so skip the next instruction that changes the error to DIRECTORY WRITE ERROR and JUMP to 4A8FH.
4A8D
LD A,12H 3E 12
LET Register A = 12H, error code 18 (EDWE), DIRECTORY WRITE ERROR.
4A8F
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
4A90
POP DE D1
Restore Register Pair DE from the top of the STACK.
4A91
POP BC C1
Restore Register Pair BC from the top of the STACK.
4A92
RET C9
RETurn to the caller.
4A93H - Read GAT TABLE into Buffer
Jumped to from 48B3H.
4A93RDGAT
GOSUB to 4AADH to set Register D to the directory track, Register E to 01H (the GAT sector) and Register Pair HL to 4D00H (BUFF2).
4A96
GOSUB to 4B0DH to read the GAT TABLE into the Buffer.
4A99
JUMP to 4AAAH to continue.
4A9BH - WRITE GAT TABLE from Buffer
Subroutine to WRITE the GAT TABLE from the Buffer. Called from 497DH.
4A9BWRGAT
GOSUB to 4AADH to set up to read/write the GAT TABLE into the Buffer.
4A9E
GOSUB to 45F7H to write the GAT TABLE from the Buffer.
4AA1
If the Z FLAG (Zero) is set then the prior routine had NO error, so JUMP to 4AAAH.
4AA3
CP 0FH FE 0F
If we're here then there was an error, so we need to deal with that. First, compare the value held in Register A against 0FH to check for a WRITE PROTECT ERROR. Results: If Register A equals 0FH, the Z FLAG is set; otherwise the NZ FLAG is set.
4AA5
If the Z FLAG (Zero) is set then we had a WRITE PROTECT ERROR so skip the next instruction that changes the error to GAT WRITE ERROR and JUMP to 4AA9H.
4AA7
LD A,15H 3E 15
LET Register A = 15H, error code 21 (EADWE), GAT WRITE ERROR.
4AA9
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
4AAA
POP BC C1
Restore Register Pair BC from the top of the STACK.
4AAB
POP DE D1
Restore Register Pair DE from the top of the STACK.
4AAC
RET C9
RETurn to the caller.
4AADH - Set Up for Read/Write GAT Table
4AAD
POP HL E1
Restore the RETURN ADDRESS from the top of the STACK into Register Pair HL.
4AAE
PUSH DE D5
Preserve Register Pair DE by PUSHing it to the top of the STACK.
4AAF
PUSH BC C5
Preserve Register Pair BC by PUSHing it to the top of the STACK.
4AB0
PUSH HL E5
Preserve Register Pair HL by PUSHing it to the top of the STACK.
4AB1
GOSUB to 4B3EH (TRKGET), which returns the directory track of the drive in Register C in Register D.
4AB4
LD E,01H 1E 01
LET Register E = 01H to point to the GAT sector in the directory track.
4AB6
LD HL,4D00H 21 00 4D
LET Register Pair HL = 4D00H as the base address of BUFFER # 2
4AB9
RET C9
RETurn to the caller.
4ABAH - Read HASH INDEX TABLE and Continue
4ABARDHIT
GOSUB to 4ACBH to set up to read/write the HASH INDEX TABLE.
4ABD
GOSUB to 4B0DH to read the HASH INDEX TABLE.
4AC0
Continue on by POPing BC and DE and RETurning.
4AC2H - Write HASH INDEX TABLE and Continue
4AC2WRHIT
GOSUB to 4ACBH to set up to read/write the HASH INDEX TABLE.
4AC5
GOSUB to 45F7H to write the HASH INDEX TABLE to diskette.
4AC8
POP BC C1
Restore Register Pair BC from the top of the STACK.
4AC9
POP DE D1
Restore Register Pair DE from the top of the STACK.
4ACA
RET C9
RETurn to the caller.
4ACBH - Set Up to Read/Write HASH INDEX TABLE
4ACB
POP HL E1
Restore the RETURN ADDRESS from the top of the STACK into Register Pair HL.
4ACC
PUSH DE D5
Preserve Register Pair DE by PUSHing it to the top of the STACK.
4ACD
PUSH BC C5
Preserve Register Pair BC by PUSHing it to the top of the STACK.
4ACE
PUSH HL E5
Preserve Register Pair HL by PUSHing it to the top of the STACK.
4ACF
GOSUB to 4B3EH (TRKGET), which returns the directory track of the drive in Register C in Register D.
4AD2
LD E,02H 1E 02
LET Register E = 02H to point to the HIT sector in the directory track.
4AD4
LD HL,4300H 21 00 43
LET Register Pair HL = 4300H as the base address of BUFFER # 1.
4AD7
RET C9
RETurn to the caller.
4AD8H - Compute Directory Entry Location
This routine is called to position for a READ (called from 4A69H and 4A7DH) or for a wRITE (called from 4A7DH). Register L will hold the results
4AD8LFNDIR
GOSUB to 4B3EH (TRKGET), which returns the directory track of the drive in Register C in Register D.
4ADB
LD A,B 78
LET Register A = Register B (the logical file number).
4ADC
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
4ADD
If the Z FLAG (Zero) is set then the logical file number is zero, and we can skip a lot of hard work, so JUMP to 4B06H.
4ADF
CP 50H FE 50
Compare the value held in Register A against 50H (Decimal: 80). Results:
- If Register A equals 50H, the Z FLAG is set.
- If A < 50H, the CARRY FLAG will be set.
- if A >= 50H, the NO CARRY FLAG will be set.
4AE1
If the NC FLAG (Carry) is set then it is simply too large so JUMP to 4B02H to set up for an ILLEGAL LOGICAL FILE NUMBER error and RETurn.
4AE3
PUSH BC C5
Preserve Register Pair BC by PUSHing it to the top of the STACK.
4AE4
LD L,B 68
Set up for HL to point to the logical file number by first setting Register L to be Register B (the logical file number).
4AE5
LD H,00H 26 00
Continue that by setting Register H to 0.
4AE7
LD A,05H 3E 05
LET Register A = 05H as the divisor.
4AE9
GOSUB to 4B6FH (DIVIDE) to divide Register Pair HL (the logical file number) by 5, the directory records in a sector. HL comes back as the quotient and Register A as the remainder.
4AEC
PUSH AF F5
Preserve the remainder (held in Register A) by PUSHing it to the top of the STACK.
The next 3 instructions set Register A to be the appropriate directory sector by setting Register E = Register L + 3.
4AED
LD A,L 7D
LET Register A = Register L.
4AEE
ADD 03H C6 03
ADD 03H to Register A, because the directory records start in sector 3 (the source's DIRSEC).
4AF0
LD E,A 5F
LET Register E = Register A.
4AF1
POP BC C1
Restore the remainder (held in Register Pair AF) from the top of the STACK into Register Pair BC.
4AF2
LD HL,4300H 21 00 43
LET Register Pair HL = 4300H as the base address of BUFFER # 1.
We next want to test Register B (the remainder) to see if it is ZERO or not, but we don't necessarily want to mess with other registers, so the simplest way to do that is to increase and decrease Register B.
4AF5
INC B 04
Bump Register B by 1.
4AF6
DEC B 05
DECrement Register B by 1.
4AF7
If the Z FLAG (Zero) is set, meaning the remainder was 0, JUMP to 4AFFH.
If we are here, then the remainder was NOT zero, so we need to do some math, via a LOOP set to B interations.
4AF9
LD A,L 7D
LET Register A = Register L. Register L was set to 00H at 4AF2H.
4AFA
ADD 30H C6 30
ADD 30H (48, the size of a directory record) to Register A.
4AFC
LOOP back to the prior instruction until Register B is ZERO.
4AFE
LD L,A 6F
Put that calculated Register A into Register L.
4AFF
POP BC C1
Restore Register BC from the top of the STACK.
4B00KILBRK
XOR A AF
KILBRK: XOR A to set Register A to 00H with the Z FLAG set. The BREAK vector at 42AEH jumps here, so a BREAK request comes back with A = 00H and is ignored. LFNDIR also ends here with its good return.
4B01RETBRK
RET C9
RETBRK: RETurn to the caller.
4B02H - ILLEGAL LOGICAL FILE NUMBER Error
Set up for an ILLEGAL LOGICAL FILE NUMBER error and RETurn.
4B02
LD A,10H 3E 10
LET Register A = 10H, error code 16 (ELFN), ILLEGAL LOGICAL FILE NUMBER.
4B04
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A. Since A was just loaded with 10H, it will be NZ - the signal for an error.
4B05
RET C9
RETurn to the caller.
4B06H - Handle Remainder Zero
This is the jump point from the routine to compute where the directory entry for a file is located when the remainder is zero (meaning, no offset calculation was required).
4B06
LD E,03H 1E 03
LET Register E = 03H, the first directory record sector (the source's DIRSEC).
4B08
LD HL,4300H 21 00 43
LET Register Pair HL = 4300H as the base address of BUFFER # 1.
4B0B
XOR A AF
Set Register A to ZERO and clear all Flags to indicate NO ERROR.
4B0C
RET C9
RETurn to the caller.
4B0DH - Read a Directory Sector
Called from 4A71, 4A96, and 4ABD
4B0DSREAD
GOSUB to 4675H to read the sector.
4B10
RET NZ C0
If the NZ FLAG (Not Zero) is set then the prior subroutine exited with an error, so RETurn to the caller.
4B11
LD A,00H 3E 00
SAVSTA: LET Register A = the FDC status of the last read. The operand at 4B12H is 00H in the file; XREAD stores the status there at 469AH.
4B13
BIT 5,A CB 6F
Test bit 5 of the read status, the record type bit. It is set when the sector was read with the data address mark used for sectors outside the directory track.
4B15
RET Z C8
If the Z FLAG (Zero) is set, the sector has the directory track's data address mark, so the directory is where DIRTRK says: RETurn.
4B16
PUSH DE D5
Preserve Register Pair DE to the top of the STACK.
4B17
LD DE,0001H 11 01 00
LET Register Pair DE = 0001H: Register D = track 0 and Register E = sector 1, the boot sector.
4B1A
GOSUB to 4675H to read Sector 1, Track 0..
4B1D
POP DE D1
Restore Register Pair DE from the top of the STACK.
4B1E
RET NZ C0
If the NZ FLAG (Not Zero) is set then the prior subroutine exited with an error, so RETurn to the caller.
4B1F
PUSH HL E5
Presever Register HL (which holds the Buffer Pointer) to the top of the STACK.
4B20
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL (i.e., the first byte of the BOOT SECTOR) and put it into Register A.
4B21
CP FEH FE FE
Compare the value held in Register A against FEH. Results: If Register A equals FEH, the Z FLAG is set; otherwise the NZ FLAG is set.
4B23
If the NZ FLAG (Not Zero) is set, the first byte of the boot sector is not FEH, so this is not a system disk: JUMP to 4B39H.
4B25
INC HL 23
Bump Register Pair HL by 1 to point to the next byte of the BOOT SECTOR.
4B26
LD D,(HL) 56
Fetch the second byte of the boot sector, the directory track of the disk, into Register D.
4B27
LD A,D 7A
LET Register A = Register D (the location of the directory track on the disk).
4B28
CP 29H FE 29
Compare Register A against 29H (41).
4B2A
If the NC FLAG (Carry) is set, the directory track is 41 or higher, which cannot be right: JUMP to 4B39H.
4B2C
LD HL,4457H 21 57 44
LET Register Pair HL = 4457H (DIRTRK), the directory track table.
4B2F
PUSH BC C5
Preserve Register BC to the top of the STACK.
4B30
LD B,00H 06 00
LET Register B = 00H so Register Pair BC = the drive number in Register C.
4B32
ADD HL,BC 09
ADD the drive number to Register Pair HL so it points to the drive's entry in DIRTRK.
4B33
POP BC C1
Restore Register Pair BC from the top of the STACK.
4B34
LD (HL),D 72
Store the directory track from the boot sector (Register D) into the drive's DIRTRK entry.
4B35
POP HL E1
Restore the buffer pointer from the STACK into Register Pair HL.
4B36
JUMP to 4675H (XREAD) to read the sector again from the directory track now in Register D, and return.
4B39H - NON-SYSTEM DISK Error
This routine is JUMPed to from 4B23H if it didn't find 0FEH as the first byte on the disk, meaning that there is no system!
4B39
POP HL E1
POP the saved buffer pointer off the STACK.
4B3A
LD A,0DH 3E 0D
LET Register A = 0DH, error code 13 (ENSD), I/O ATTEMPT TO NON SYSTEM DISK.
4B3C
OR A B7
Since A is not zero, ORing A sets the NZ flag to signify an error.
4B3D
RET C9
RETurn to the caller.
4B3EH - Get Directory Track Number
Routine exits with the director track number in Register D.
4B3ETRKGET
PUSH BC C5
Preserve Register BC to the top of the STACK.
4B3F
LD B,00H 06 00
LET Register B = 00H so Register Pair BC = the drive number in Register C.
4B41
LD HL,4457H 21 57 44
LET Register Pair HL = 4457H to point to the directory track table
4B44
ADD HL,BC 09
ADD the value held in Register Pair BC (an offset) to Register Pair HL (the directory track table). The results are held in Register Pair HL.
4B45
POP BC C1
Restore Register Pair BC from the STACK.
4B46
LD D,(HL) 56
Fetch the value stored at memory location pointed to by Register Pair HL (the directory track number) and put it into Register D.
4B47
RET C9
RETurn to the caller.
4B48H - Test if Gran is Allocated
The next few instructions create an OPCODE along the lines of BIT nn of Register B.
4B48BYTBI0
AND 07H E6 07
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.
4B4A
RLCA 07
Rotate the bits in A left 3 times so that Bits 2, 1, 0 move to bits 5, 4, 3.
4B4C
RLCA 07
Third RLCA: the bit number (0-7) is now in bits 3-5 of Register A, where the BIT instruction keeps it.
4B4D
OR 40H F6 40
OR Register A against 40H (0100 0000). This has the effect of turning on bits 6.
Put the generated OPCODE into 4B53H. If tthe value is 40H then it tests Bit 0; 48H tests Bit 1, 50H tests Bit 2, 58H tests Bit 3, and so on.
4B4F
LD (4B53H),A 32 53 4B
Store Register A (40H plus the bit number times 8, the second byte of a BIT n,B instruction) into 4B53H, the second byte of the BIT 0,B at 4B52H.
4B52
BIT 0,B CB 40
Test bit n of Register B (the GAT byte), where n is the gran number written into this instruction by 4B4FH. Z FLAG set = the gran is free.
4B54
RET C9
RETurn to the caller.
4B55H - Multiply Register Pair HL by Register A
On exit, Register A = Overflow and Register Pair HL = the result of the multiplication.
4B55DMULT
PUSH BC C5
Preserve Register BC to the top of the STACK.
4B56
EX DE,HL EB
Swap Register Pair DE and HL, so that Register Pair DE holds the multiplicand.
4B57
LD C,A 4F
LET Register C = Register A, so that Register C holds the multiplier.
4B58
LD HL,0000H 21 00 00
LET Register Pair HL = 0000H to clear the accumulator.
4B5B
LD A,L 7D
LET Register A = Register L to clear the overflow.
4B5C
LD B,08H 06 08
LET Register B = 08H to set up for 8 bits of LOOP.
Start of an 8 bit loop.
4B5E
ADD HL,HL 29
ADD the value held in Register Pair HL to Register Pair HL. The results are held in Register Pair HL.
4B5F
RLA 17
Shift the OVERFLOW to the left by rotating the bits in Register A left one bit, with the contents of BIT 7 being put into the CARRY FLAG and the CARRY FLAG being put into BIT 0.
4B60
RLC C CB 01
Shift the multiplier into the CARRY FLAG
4B62
If the NC FLAG (Carry) is set, this bit of the multiplier is 0, so skip the add: JUMP to 4B67H.
4B64
ADD HL,DE 19
ADD the value held in Register Pair DE (multiplicand) to Register Pair HL (the current result). The results are held in Register Pair HL.
4B65
ADC 00H CE 00
ADD the CARRY out of Register Pair HL into Register A, the high byte of the 24 bit product.
4B67
LOOP back to 4B5EH until Register B is ZERO (i.e., all 8 bits).
End of an 8 bit loop. The next bunch of varliable exchanges are to set Register A = Overflow and Register Pair HL = the result of the multiplication
4B69
LD C,A 4F
LET Register C = Register A, the high byte of the product.
4B6A
LD A,L 7D
LET Register A = Register L, the low byte of the product.
4B6B
LD L,H 6C
LET Register L = Register H, the middle byte of the product.
4B6C
LD H,C 61
LET Register H = Register C: Register Pair HL now holds the high 16 bits of the product and Register A the low 8 bits.
4B6D
POP BC C1
Restore Register Pair BC from the STACK.
4B6E
RET C9
RETurn to the caller.
4B6FH - Divide Register Pair HL by Register A
4B6F
PUSH DE D5
DIVIDE: Preserve Register Pair DE on the STACK.
4B70
LD D,A 57
LET Register D = Register A (the divisor).
4B71
LD E,10H 1E 10
LET Register E = 10H to cover 16 bits of action.
4B73
XOR A AF
Set Register A to ZERO and clear all Flags.
Start of a loop.
4B74
ADD HL,HL 29
LET HL = HL * 2.
4B75
RLA 17
Put the remainder, if any, into the CARRY bit by rotating the bits in Register A left one bit, with the contents of BIT 7 being put into the CARRY FLAG and the CARRY FLAG being put into BIT 0.
4B76
If the C FLAG (Carry) is set, the remainder overflowed 8 bits, so it is certainly larger than the divisor: JUMP to 4B7BH.
4B78
CP D BA
Compare the value held in Register A against the value held in Register D. Results:
- If Register A equals D, the Z FLAG is set.
- If A < D, the CARRY FLAG will be set.
- if A >= D, the NO CARRY FLAG will be set.
4B79
If the C FLAG (Carry) is set, the remainder is below the divisor, so this quotient bit is 0: JUMP to 4B7DH.
4B7B
SUB D 92
The remainder is at least the divisor, so SUBtract the divisor (Register D) from it.
4B7C
INC L 2C
Bump Register L by 1 to set this bit of the quotient.
4B7D
DEC E 1D
DECrement Register E by 1 as we have 1 less subtraction to do.
4B7E
If the NZ FLAG (Not Zero) is set then we have more bits to process so JUMP BACK to 4B74H.
End of the loop.
4B80
POP DE D1
Restore Register Pair DE from the top of the STACK.
4B81
RET C9
RETurn to the caller.
4B82H - RST 28H - DOS Overlay Loader
Register A to hold the requested overlay on entry.
4B82SYSLD
EX (SP),HL E3
SYSLD: EXchange Register Pair HL with the top of the STACK: the RST 28H return address goes into HL and the caller's HL goes onto the STACK.
4B83
POP HL E1
POP the caller's HL back. The RST 28H return address is thrown away, so the overlay returns straight to the program that called the vector.
4B84SYSLOD
OR A B7
Set FLAGS based on the contents of Register A.
4B85
If the P FLAG is set, bit 7 of Register A is clear, so this is not an overlay request: JUMP to 42AEH, the BREAK vector.
4B88
PUSH HL E5
Preserve Register Pair HL to the top of the STACK.
4B89
LD H,A 67
LET Register H = Register A (the requested overlay).
4B8A
LD A,(4414H) 3A 14 44
Fetch 4414H (FLAG1, the request code of the last overlay loaded) into Register A.
4B8D
XOR H AC
We want to see if the requested overlay is the one currently in memory, and we do that with the following 2 instructions. First, eXclusive OR Register H against Register A. The results are stored in Register A.
4B8E
AND 0FH E6 0F
MASK the value of Register A against 0FH (0000 1111). This has the effect of turning off bits 7, 6, 5, 4, leaving only bits 3, 2, 1, 0 active.
4B90
LD A,H 7C
LET Register A = Register H (the new overlay number).
4B91
LD (4414H),A 32 14 44
Store the new request code into 4414H (FLAG1).
4B94
If the Z FLAG (Zero) is set then the requested overlay is the same one which is already in memory so there is no need to load it. Instead, JUMP to 4BD2H.
4B96
PUSH DE D5
Preserve Register DE to the top of the STACK.
4B97
PUSH BC C5
Preserve Register BC to the top of the STACK.
4B98
AND 0FH E6 0F
MASK the value of Register A against 0FH (0000 1111) to isolate the overlay number. This has the effect of turning off bits 7, 6, 5, 4, leaving only bits 3, 2, 1, 0 active.
4B9A
LD B,A 47
LET Register B = the overlay number (0-15).
4B9B
LD (449EH),A 32 9E 44
Store the overlay number into 449EH (MLFN, offset 07H of the system DCB at 4497H).
4B9E
XOR A AF
Set Register A to ZERO and clear all Flags.
4B9F
LD (4498H),A 32 98 44
Store 00H into 4498H (MPROT, offset 01H of the system DCB).
4BA2
LD (449DH),A 32 9D 44
Store 00H into 449DH (MDRV): the overlays are read from drive 0.
4BA5
SBC HL,HL ED 62
Clear HL
4BA7
LD (44A1H),HL 22 A1 44
Store 0000H into 44A1H-44A2H (MNRN), so the overlay is read from its first record.
4BAA
LD C,A 4F
LET Register C = 00H, drive 0.
4BAB
GOSUB to 4ABAH (RDHIT) to read the HIT sector (sector 2 of the directory track) of drive 0 into BUFF1 at 4300H.
4BAE
If the NZ FLAG (Not Zero) is set then the prior subroutine exited with an error, so JUMP to 4409H.
The next 3 instructions set B = Logical File Number * 2 + 0E0H.
4BB1
LD A,B 78
LET Register A = Register B.
4BB2
RLCA 07
Rotate the bits in A left (with Bit 7 going into both the CARRY and Bit 0).
4BB3
ADD E0H C6 E0
ADD E0H: the system file pointers are the last 32 bytes of the HIT sector (the source's SYSOFF, 224), two bytes for each overlay.
The next 2 instructions set HL = 4300H + B.
4BB5
LD L,A 6F
LET Register L = Register A.
4BB6
LD H,43H 26 43
LET Register H = 43H, so Register Pair HL points to the overlay's two byte entry at 43E0H plus twice the overlay number.
The next 4 instructions set DE = the First Overlay Extent Element.
4BB8
LD D,(HL) 56
Fetch the first byte of the entry (the track of the overlay's extent) into Register D.
4BB9
INC HL 23
Bump Register Pair HL by 1.
4BBA
LD E,(HL) 5E
Fetch the second byte of the entry (the gran byte of the extent) into Register E.
4BBB
INC E 1C
Bump Register E by 1 to test it for FFH.
4BBC
If the Z FLAG (Zero) is set, the entry was FFH, so the overlay is not on the disk: JUMP to 4CC0H.
4BBF
DEC E 1D
DECrement Register E back to the gran byte.
4BC0
LD (44A7H),DE ED 53 A7 44
Store Register Pair DE (the overlay's extent) into 44A7H-44A8H (MEXT), the first extent of the system DCB.
4BC4
LD DE,4497H 11 97 44
LET Register Pair DE = 4497H to point to the overlay DCB.
4BC7
GOSUB to 4BFFH to load the overlay pointed to by Register Pair DE.
4BCA
If the NZ FLAG (Not Zero) is set then the prior subroutine exited with an error, so JUMP to 4409H.
4BCD
LD (4BD7H),HL 22 D7 4B
Store the value held in Register HL (the execution address of the overlay) into the memory location 4BD7H, which is a JP nnnnH.
4BD0
POP BC C1
Restore Register Pair BC from the STACK
4BD1
POP DE D1
Restore Register Pair DE from the STACK
4BD2
POP HL E1
Restore Register Pair HL from the STACK
4BD3
LD A,(4414H) 3A 14 44
Fetch 4414H (FLAG1, the request code) into Register A, so the overlay knows which entry was asked for.
4BD6
JUMP to nnnnH. nnnnH was set at 4BCDH
4BD9H - Load and Execute a Program
4BD9
PUSH HL E5
Preserve Register HL to the top of the STACK.
4BDA
XOR A AF
Set Register A to ZERO and clear all Flags.
4BDB
LD (442BH),A 32 2B 44
EXEC: Store 00H into 442BH (OVLFLG), so bit 7 is clear. LDPGM at 4BF8H tests bit 7 to decide whether an execute only file may be loaded.
4BDE
GOSUB to 4430H.
NOTE: 4430H is DOS PROGRAM LOADER routine and does the same as the DOS LIBRARY command of LOAD. Requires Register Pair DE to contain the applicable FCB. All Registers are modified.
4BE1
If the NZ FLAG (Not Zero) is set then the prior subroutine exited with an error, so JUMP to 4409H.
4BE4
EX (SP),HL E3
EXchange Register Pair HL with the top of the STACK: HL gets back the value saved at 4BD9H and the transfer address of the program goes onto the STACK.
4BE5
RET C9
RETurn (which in this case, will execute the program).
4BE6H - Load a Program
4BE6
LD B,00H 06 00
LET Register B = 00H, which is the same as 256. This is to be a LRL of a full sector.
4BE8
LD HL,4D00H 21 00 4D
LET Register Pair HL = 4D00H as a buffer.
4BEB
GOSUB to 4424H to open the file (which just calls RST 28H with A loaded).
4BEE
RET NZ C0
If the NZ FLAG (Not Zero) is set then the prior subroutine exited with an error, so RETurn to the caller.
4BEF
INC DE 13
Bump Register Pair DE by 1 to point to offset 01H of the DCB, the protection level byte.
4BF0
LD A,(DE) 1A
Fetch the protection byte into Register A.
4BF1
DEC DE 1B
DECrement Register Pair DE by 1, so now DE points back to the DCB for the file.
4BF2
AND 07H E6 07
Isolate the ACCESS CODE by MASKing 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.
4BF4
CP 06H FE 06
Compare the protection level against 06H (PEXEC, execute only).
4BF6
If the C FLAG (Carry) is set, the level is below 6 and the file may be read, so JUMP to 4BFFH to load it.
4BF8
LD A,(442BH) 3A 2B 44
The file is execute only. Fetch 442BH (OVLFLG) into Register A.
4BFB
RLCA 07
Rotate bit 7 of OVLFLG into the CARRY FLAG.
4BFC
LD A,19H 3E 19
LET Register A = 19H, error code 25 (EFAD), FILE ACCESS DENIED.
4BFE
RET C D8
If the C FLAG (Carry) is set, bit 7 of OVLFLG was set (load without execute), which is not allowed for an execute only file: RETurn with the error.
4BFF
LD BC,4DFFH 01 FF 4D
LET Register Pair BC = 4DFFH, the last byte of BUFF2, so the first byte fetched (4C4FH) moves Register C to 00H and reads the first sector.
4C02
GOSUB to 4C4FH to get the byte.
4C05
CP 01H FE 01
Compare the value held in Register A against 01H (program code). Results: If Register A equals 01H, the Z FLAG is set; otherwise the NZ FLAG is set.
4C07
If the Z FLAG (Zero) is set, JUMP to 4C32H.
4C09
CP 02H FE 02
Compare the value held in Register A against 02H (execution address). Results: If Register A equals 02H, the Z FLAG is set; otherwise the NZ FLAG is set.
4C0B
If the Z FLAG (Zero) is set, JUMP to 4C25H to put the execution/transfer address into Register Pair HL and RETurn.
4C0D
CP 03H FE 03
Compare the record type against 03H.
4C0F
If the Z FLAG (Zero) is set, JUMP to 402DH (SYS1IN), the return to TRSDOS READY.
4C12
CP 20H FE 20
Compare the record type against 20H.
4C14
If the C FLAG (Carry) is set, the record type is below 20H, so it is a record to skip: JUMP to 4C1AH to read its length and pass over it.
4C16
LD A,22H 3E 22
LET Register A = 22H, error code 34 (ELFFE), LOAD FILE FORMAT ERROR.
4C18
OR A B7
Since Register A is not ZERO, this will set the NZ flag to indicate that there is an error.
4C19
RET C9
RETurn to the caller.
4C1AH - Read Number of Bytes in LENGTH BYTE
4C1A
GOSUB to 4C4FH to get the LENGTH BYTE into Register A.
4C1D
LD B,A 47
Save the LENGTH BYTE into Register B.
4C1E
GOSUB to 4C4FH to read more bytes and ...
4C21
... keep reading bytes until Register B (which was the length byte) is ZERO.
4C23
JUMP to 4C02H to continue the loop.
4C25H - Read Execution/Transfer Address into HL
4C25
GOSUB to 4C4FH to get the LENGTH BYTE into Register A.
4C28
GOSUB to 4C4FH to read the next byte which the LSB and store it in Register A.
4C2B
LD L,A 6F
LET Register L = Register A (the LSB).
4C2C
GOSUB to 4C4FH to read the next byte which the MSB and store it in Register A.
4C2F
LD H,A 67
LET Register H = Register A (the MSB).
4C30
XOR A AF
Set Register A to ZERO and clear all Flags to indicate no error.
4C31
RET C9
RETurn to the caller.
4C32H - Read Data and Store in Buffer
4C32
GOSUB to 4C4FH to read the next byte (which the LENGTH OF DATA BLOCK + 2) and store it in Register A.
4C35
LD B,A 47
Put the LENGTH OF DATA BLOCK + 2 into Register B.
4C36
GOSUB to 4C4FH to read the next byte (which the LSB of the LOADING ADDRESS) and store it in Register A.
4C39
LD L,A 6F
Put the LSB of the LOADING ADDRESS into Register L.
4C3A
DEC B 05
DECrement Register B by 1 so that it now holds LENGTH OF DATA BLOCK + 1.
4C3B
GOSUB to 4C4FH to read the next byte (which the MSB of the LOADING ADDRESS) and store it in Register A.
4C3E
LD H,A 67
Put the MSB of the LOADING ADDRESS into Register H.
4C3F
DEC B 05
DECrement Register B by 1 so that it now holds LENGTH OF DATA BLOCK.
4C40
GOSUB to 4C4FH to read the next byte (which data) and store it in Register A.
4C43
LD (HL),A 77
Store the data held in Register A into the memory location pointed to by Register Pair HL.
4C44
CP (HL) BE
Check to make sure it was really stored by comparing 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.
4C45
If the NZ FLAG (Not Zero) is set then it didn't store properly so JUMP to 4C4CH to set up for a MEMORY FAULT.
4C47
INC HL 23
Bump Register Pair HL by 1 to point to the next spot in the buffer.
4C48
LOOP back to 4C40H until Register B is ZERO.
4C4A
JUMP to the main loop at 4C02H.
4C4CH - Process MEMORY FAULT Error
4C4C
LD A,23H 3E 23
LET Register A = 23H, error code 35 (EMFLT), MEMORY FAULT DURING PGM LOAD. The NZ FLAG from CP (HL) at 4C44H is still set.
4C4E
RET C9
RETurn to the caller.
4C4FH - Read a Sector
4C4F
INC C 0C
Bump Register C by 1 to point to the next location.
4C50
If the NZ FLAG (Not Zero) is set then this is not a new sector so JUMP to 4C65H.
4C52
PUSH DE D5
PUSH Register DE to the top of the STACK.
4C53
EX (SP),IX DD E3
Let Index Register IX = DE and put Register IX at the top of the STACK
4C55
PUSH HL E5
PUSH Register HL to the top of the STACK.
4C56
PUSH DE D5
PUSH Register DE to the top of the STACK.
4C57
PUSH BC C5
PUSH Register BC to the top of the STACK.
4C58
GOSUB to 4766H to read a Sector and Return With Error or Continue.
4C5B
POP BC C1
MOVE the value held at the top of the STACK into Register Pair BC.
4C5C
POP DE D1
MOVE the value held at the top of the STACK into Register Pair DE.
4C5D
POP HL E1
MOVE the value held at the top of the STACK into Register Pair HL.
4C5E
POP IX DD E1
MOVE the value held at the top of the STACK into Register Pair IX.
4C60
If the Z FLAG (Zero) is set then there was no error, so JUMP to 4C65H.
4C62
INC SP 33
Bump Register Pair SP by 2 to clear the most recent RETURN address.
4C63
INC SP 33
Bump the STACK POINTER by 1 again: the two INC SP drop the return address into the loader loop, so the RET below returns the error to the loader's caller.
4C64
RET C9
RETurn to the caller.
4C65H - Continuation When Not at New Sector
4C65
PUSH BC C5
PUSH Register BC to the top of the STACK.
4C66
LD B,4DH 06 4D
LET Register B = 4DH so Register Pair BC points to the byte in BUFF2 at 4D00H plus Register C.
4C68
LD A,(BC) 0A
Fetch the value stored at memory location pointed to by Register Pair BC (i.e., the data byte) and put it into Register A.
4C69
POP BC C1
Restore Register Pair BC from the top of the STACK.
4C6A
RET C9
RETurn to the caller.
4C6BH - Start Up and Check Drive
Register C holds the drive being sought.
4C6BCHKDRV
LD A,(4413H) 3A 13 44
CHKDRV: Fetch 4413H (MAXDRV, the highest drive number in the system) into Register A.
4C6E
CP C B9
Compare the value held in Register A against the value held in Register C. Results:
- If Register A equals C, the Z FLAG is set.
- If A < C, the CARRY FLAG will be set.
- if A >= C, the NO CARRY FLAG will be set.
4C6F
If the NC FLAG (Carry) is set, the drive number in Register C is not above the highest drive, so the drive exists: JUMP to 4C75H.
4C71
LD A,02H 3E 02
LET Register A = 02H, error code 2 (EDNS), DISK DRIVE NOT IN SYSTEM.
4C73
OR A B7
Since Register A is not 00H, this sets the NZ FLAG to signify that an error occurred.
4C74
RET C9
RETurn to the caller.
4C75H - Drive is on System
The prior routine jumps here if the requested drive id on the system.
4C75
INput a byte from Port F0H and put it into Register A.
NOTE: Port F0H is the FDC Status port on input. Input Results:
- Bit 0: Busy
- Bit 1: Index/DRQ
- Bit 2: Track 0/Data Lost
- Bit 3: CRC error
- Bit 4: Seek error/Record not found
- Bit 5: If Reading, Record Type, if Writing, Write Fault/Head loaded
- Bit 6: Write Protect
- Bit 7: Not ready
4C77
AND 80H E6 80
MASK the value of Register A against 80H (1000 0000). This has the effect of turning off bits 6, 5, 4, 3, 2, 1, 0, leaving only bit 7 (DRIVE NOT READY) active.
4C79
GOSUB to 4566H (TERM) to send the Force Interrupt command to the FDC. TERM keeps Register A and the flags.
4C7C
If the Z FLAG (Zero) is set then the disk is good to go so JUMP to 4C89H.
4C7E
GOSUB to 44D4H.
NOTE: 44D4H is the routine which handles DRIVE SELECT (Register C holds the drive number to be used).
4C81
PUSH BC C5
Preserve Register Pair BC to the top of the STACK.
4C82
LD BC,9000H 01 00 90
LET Register Pair BC = 9000H, the delay count for the ROM's delay routine, to give the drive motor time to come up to speed.
4C85
GOSUB to 0060H, the ROM delay routine, which loops Register Pair BC times.
4C88
POP BC C1
Restore Register Pair BC from the top of the STACK.
4C89
GOSUB to 44D4H.
NOTE: 44D4H is the routine which handles DRIVE SELECT (Register C holds the drive number to be used).
4C8C
GOSUB to 4566H.
NOTE: 4566H is the routine which resets the FDC.
4C8F
LD A,(4427H) 3A 27 44
Fetch 4427H (CURDRV, the drive used last) into Register A.
4C92
CP C B9
Compare the value held in Register A against the value held in Register C. Results: If Register A equals C, the Z FLAG is set; otherwise the NZ FLAG is set.
4C93
If the NZ FLAG (Not Zero) is set, this is a different drive from the last one, so JUMP to 4C97H to watch its index pulses.
4C95
XOR A AF
Set Register A to ZERO and clear all Flags to indicate no error.
4C96
RET C9
RETurn to the caller.
4C97H - Read Until INDEX LOW, INDEX HIGH, INDEX LOW
Then set CARRY FLAG if WRITE PROTECT is enabled.
4C97
PUSH BC C5
Preserve Register BC to the top of the STACK.
4C98
LD BC,62AAH 01 AA 62
LET Register Pair BC = 62AAH to set up a counter.
4C9B
GOSUB to 4CB0H to check to see if the BC counter is zero and, if so, exit, and if not get the disk status and look for an index hole. Returns NZ if the index hole was found.
4C9E
If the NZ FLAG (Not Zero) is set, the index hole is under the sensor, so keep waiting for it to pass: LOOP to 4C9BH.
4CA0
GOSUB to 4CB0H to check to see if the BC counter is zero and, if so, exit, and if not get the disk status and look for an index hole. Returns NZ if the index hole was found.
4CA3
If the Z FLAG (Zero) is set, no index pulse yet, so keep waiting: LOOP to 4CA0H.
4CA5
GOSUB to 4CB0H to check to see if the BC counter is zero and, if so, exit, and if not get the disk status and look for an index hole. Returns NZ if the index hole was found.
4CA8
If the NZ FLAG (Not Zero) is set, the index pulse is still present, so keep waiting for its end: LOOP to 4CA5H.
4CAA
POP BC C1
Restore Register Pair BC from the STACK.
4CAB
RLCA 07
Rotate the bits in A left (with Bit 7 going into both the CARRY and Bit 0). This moves Bit 6 from the FDC (Write Protect) to Bit 7.
4CAC
AND 80H E6 80
MASK the value of Register A against 80H (1000 0000). This has the effect of turning off bits 6, 5, 4, 3, 2, 1, 0, leaving only bit 7 active.
4CAE
ADD A,A 87
ADD Register A to itself: 80H becomes 00H with the CARRY FLAG set. Register A is 00H either way, so the Z FLAG is set (good return) and the C FLAG reports a write protected diskette.
4CAF
RET C9
RETurn to the caller.
4CB0H - Check BC Counter and Look for Index Hole
Subroutine to check to see if the BC counter is zero and, if so, exit, and if not get the disk status and look for an index hole. Returns NZ if the index hole was found.
4CB0
DEC BC 0B
DECrement Register Pair BC by 1 to decrease the counter.
4CB1
LD A,B 78
Since there is no way to directly check BC for 0, a common way to handle this is to set Register A = Register B.
4CB2
OR C B1
and then OR Register C against Register A. The results are stored in Register A.
4CB3
If the Z FLAG (Zero) is set, then both B and C were zero, so JUMP to 4CBAH.
4CB5
INput a byte from Port F0H and put it into Register A.
NOTE: Port F0H is the FDC Status port on input. Input Results:
- Bit 0: Busy
- Bit 1: Index/DRQ
- Bit 2: Track 0/Data Lost
- Bit 3: CRC error
- Bit 4: Seek error/Record not found
- Bit 5: If Reading, Record Type, if Writing, Write Fault/Head loaded
- Bit 6: Write Protect
- Bit 7: Not ready
4CB7
BIT 1,A CB 4F
Check the INDEX FOUND by testing Bit 1 of Register A.
4CB9
RET C9
RETurn to the caller.
4CBAH - DISK TIME OUT Error
Clear the stack, set up for a DISK TIME OUT error, and return.
4CBA
POP BC C1
POP twice: the return address of the CALL to 4CB0H and the Register Pair BC saved at 4C97H. The RET below goes back to the caller of CHKDRV.
4CBB
POP BC C1
POP the Register Pair BC that 4C97H saved off the STACK.
4CBC
LD A,08H 3E 08
LET Register A = 08H, error code 8 (EDOOR), DISK DRIVE NOT READY.
4CBE
OR A B7
Since Register A is not 00H, this sets the NZ FLAG to signify that an error occurred.
4CBF
RET C9
RETurn to the caller.
4CC0H - Display Error and Return to DOS PROMPT
4CC0
LD HL,4CCCH 21 CC 4C
LET Register Pair HL = 4CCCH, the no system message.
4CC3
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
4CC6
GOSUB to 0049H, the ROM routine that waits for a key.
4CC9
JUMP to 4030H (ABORT), which loads SYS1 and goes back to TRSDOS READY.
4CCCH - NO SYSTEM ERROR Storage Location
4CCC-4CCF
DEFB 1CH,1FH,17H,0C7H 1C 1F 17 C7
The no system message printed by 4CC0H with the ROM's 021BH: 1CH (cursor home), 1FH (clear to the end of the screen), 17H (32 characters per line) and C7H (a space compression code for 7 spaces).
4CD0-4CD3
DEFM "0 NS" 30 20 4E 53
The text of the no system message.
4CD4
DEFB 0DH 0D
0DH, which ends the message for 021BH.
4CD5-4CE0
DEFS 12
SYS0 has no load record for 4CD5H-4CE0H.
4CE1H - "Dual" Driver
4CE1DUALIT
PUSH BC C5
DUALIT: Preserve Register Pair BC on the STACK. Register C holds the character to send to the screen and the printer.
4CE2
LD IX,401DH DD 21 1D 40
LET Register Pair IX = 401DH (the VIDEO DCB).
4CE6
GOSUB to 0473H in the ROM to send the character in Register C through the video DCB at IX.
4CE9
POP BC C1
Restore Register Pair BC from the top of the STACK.
4CEA
LD A,C 79
LET Register A = Register C (the character to display).
4CEB
CP 0DH FE 0D
Compare the value held in Register A against 0DH. Results: If Register A equals 0DH, the Z FLAG is set; otherwise the NZ FLAG is set.
4CED
If the Z FLAG (Zero) is set then we have a CARRIAGE RETURN, so JUMP to 4CF2H.
4CEF
CP 20H FE 20
Compare the value held in Register A against 20H looking for a CONTROL CHARACTER. Results:
- If Register A equals 20H, the Z FLAG is set.
- If A < 20H, the CARRY FLAG will be set.
- if A >= 20H, the NO CARRY FLAG will be set.
4CF1
RET C D8
If the C FLAG (Carry) is set, it is a control character other than 0DH, so it is not printed: RETurn.
4CF2
PUSH BC C5
PUSH Register BC (the character to display) to the top of the STACK.
4CF3
LD IX,4025H DD 21 25 40
LET Register Pair IX = 4025H (the PRINTER DCB).
4CF7
GOSUB to 03C2H to print the character held in Register C and return.
4CFA
POP BC C1
Restore Register Pair BC from the top of the STACK.
4CFB
LD A,C 79
LET Register A = Register C (the character).
4CFC
RET C9
RETurn to the caller.
4CFDH - DATA STORAGE LOCATION
4CFDDOFLAG
DEFB 00H 00
DOFLAG: the 'DO FILE' flag. 00H means no DO file is running; the DO command in SYS6 sets it while it feeds a DO file to the keyboard and SYS4 checks and clears it.
4CFE-4CFFMIKE
DEFW 4265H 65 42
MIKE (2 bytes): 4265H, the address of MIKE1, the 8 byte WORK AREA FOR MIKE GRUBBS at 4265H-426CH.
4D00-4DFFBUFF2
DEFS 256
BUFF2: the second system disk buffer. The GAT is read here (4A93H), the system DCB at 4497H uses it, and the program loader reads the load file through it. SYS0 has no load record for 4D00H-4DFFH.
4E00H - OVERLAY 0 - DOS Initialization
First we need to set up the interrupts
4E00START
DI F3
Disable Interrupts.
4E01
IM 1 ED 56
Set Interrupt Mode to 1
4E03
LD SP,409FH 31 9F 40
Set the System STACK to start at 409FH.
4E06
XOR A AF
Set Register A to ZERO and clear all Flags.
4E07
OUTput 00H (Register A) to port E4H, the Non-Maskable Interrupt mask latch, so no disk NMIs are allowed.
4E09
LD A,20H 3E 20
LET Register A = 20H (0010 0000).
4E0B
OUTput 20H to port ECH, the Model III control port: bit 5 on turns on the video wait states (the source's VIDEO WAIT); every other control bit is off.
4E0D
LD A,04H 3E 04
LET Register A = 04H (0000 0100).
4E0F
OUTput 04H to port E0H, the maskable interrupt mask: bit 2 allows the real time clock interrupt, which the ROM runs through the vector at 4046H.
Decode the TRSDOS v1.3 disk serial number from Binary Coded Decimal to Text
4E11ST0
LD HL,43F4H 21 F4 43
ST0: LET Register Pair HL = 43F4H, offset F3H (the source's SERIAL) into the boot sector, which is still in BUFF1 at 4300H. The serial number is kept there as 8 bytes of packed decimal digits.
4E14
LD IX,5079H DD 21 79 50
LET Register Pair IX = 5079H, which is the location of the serial number text.
Start of a loop to convert 8 bytes of Binary Coded Decimal into Text
4E18
LD B,08H 06 08
LET Register B = 08H, the number of serial number bytes (the source's SERLTH), two digits each.
4E1A
LD D,00H 16 00
LET Register D = 00H: bit 0 of Register D is the flag that a non zero digit has been stored, so leading zeros are dropped.
4E1CST00X
ST00X: GOSUB to 4FF8H (MOVDIG) to turn the two digits of the byte at (HL) into ASCII at (IX).
4E1F
INC HL 23
Bump Register Pair HL by 1 to point to the next character.
4E20
LOOP back to 4E1CH until Register B is ZERO.
End of loop
4E22
LD (IX+00H),0DH DD 36 00 0D
Store 0DH into the memory location pointed to by Index Register IX, the byte after the last serial digit, to end the serial number text.
4E26H - Determine System Memory Size
4E26
LD HL,FFFFH 21 FF FF
LET Register Pair HL = FFFFH, the last address of a 48K system, the first place to test for RAM.
4E29START0
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL and put it into Register A.
4E2A
LD B,A 47
LET Register B = Register A.
4E2B
CPL 2F
Invert Register A
4E2C
LD (HL),A 77
Store the value held in Register A (i.e., the inverted value) into the memory location pointed to by Register Pair HL.
4E2D
CP (HL) BE
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.
- If A < (HL), the CARRY FLAG will be set.
- if A >= (HL), the NO CARRY FLAG will be set.
4E2E
LD (HL),B 70
Store the value held in Register B (i.e., the original value) into the memory location pointed to by Register Pair HL.
4E2F
If the Z FLAG (Zero) is set then we were able to write to that memory location, so JUMP to 4E37H. This is t he routine exit.
4E31
LD A,H 7C
The byte did not change, so there is no RAM here. Put the MSB of the address into Register A to step down 16K (FFFFH, then BFFFH, then 7FFFH).
4E32
SUB 40H D6 40
SUBtract the value 40H from Register A to drop down 16K.
4E34
LD H,A 67
LET Register H = Register A (which is the new MSB of the memory location to test).
4E37H - Continue Memory Size and Set Up Display
4E37START1
LD (4411H),HL 22 11 44
START1: Store the end of memory (Register Pair HL) into 4411H-4412H (MEMEND).
4E3A
LD (40A0H),HL 22 A0 40
Store the end of memory into 40A0H-40A1H (MEM1), where Disk BASIC gets its end of memory.
4E3D
LD (4415H),HL 22 15 44
Store the end of memory into 4415H-4416H (MEM2).
4E40
GOSUB to 01C9H to clear the screen.
4E43
LD A,(4412H) 3A 12 44
Fetch the value stored at memory location 4412H (i.e., the MSB of the memory size) and put it into Register A.
4E46
LD HL,5010H 21 10 50
LET Register Pair HL = 5010H to point to the message storage area of 48.
4E49
AND F0H E6 F0
MASK the value of Register A (the MSB of the memory size) against F0H (1111 0000) to test for 48K. This has the effect of turning off bits 3, 2, 1, 0, leaving only bits 7, 6, 5, 4 active.
4E4B
CP F0H FE F0
Compare the value held in Register A against F0H. Results: If Register A equals F0H, the Z FLAG is set; otherwise the NZ FLAG is set.
4E4D
If the Z FLAG (Zero) is set then the memory size is 48K so stop testing by JUMPing to 4E59H.
4E4F
LD HL,5012H 21 12 50
LET Register Pair HL = 5012H to point to the message storage area of 32.
4E52
CP B0H FE B0
Compare the value held in Register A against B0H to test for 32K. Results: If Register A equals B0H, the Z FLAG is set; otherwise the NZ FLAG is set.
4E54
If the Z FLAG (Zero) is set then the memory size is 32K so stop testing by JUMPing to 4E59H.
4E56
LD HL,5014H 21 14 50
No more testing; assume its 16K. LET Register Pair HL = 5014H to point to the message storage area of 16.
4E59GO
LD DE,504CH 11 4C 50
GO: LET Register Pair DE = 504CH (MEM), the two digits in front of K System in the sign on message.
4E5C
LD BC,0002H 01 02 00
LET Register Pair BC = 0002H to set up for a 2 byte move under a LDIR instruction.
4E5F
LDIR ED B0
Transfer 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.
4E61H - Determine Number of Disk Drives
Set Up to Display that Number.
4E61
LD C,00H 0E 00
LET Register C = 00H for drive 0.
4E63
LD B,04H 06 04
LET Register B = 04H to signify a maximum of 4 drives.
4E65DRVLOP
GOSUB to 44D4H.
NOTE: 44D4H is the routine which handles DRIVE SELECT (Register C holds the drive number to be used).
4E68
PUSH BC C5
PUSH Register Pair BC (Register B = the drives left to try, Register C = the drive number) onto the STACK.
4E69
GOSUB to 4FDAH to test to see if the disk drive (stored in Register C) is present on the system.
4E6C
POP BC C1
Restore Register Pair BC (the counter and the drive number) from the STACK.
4E6D
If the Z FLAG (Zero) is set then the drive was NOT on the system, so JUMP to 4E72H to deal with that.
4E6F
INC C 0C
Bump Register C by 1 to point to the next disk drive.
4E70
LOOP BACK to 4E65H until Register B is ZERO and 4 drives were tested.
4E72DRVLP1
LD A,C 79
DRVLP1: LET Register A = Register C, the number of drives found.
4E73
DEC A 3D
DECrement Register A by 1 to make it the highest drive number.
4E74
LD (4413H),A 32 13 44
Store the highest drive number into 4413H (MAXDRV).
4E77
INC A 3C
Bump Register A by 1 to prepare to turn it into an ASCII code for that drive number.
4E78
ADD 30H C6 30
ADD the value 30H to Register A (Results held in Register A) to turn Register A into an ASCII rendition of the number that was in Register A.
4E7A
LD (506BH),A 32 6B 50
Store the value held in Register A (the ASCII rendition of the number of disk drives in the system) into the memory location 506BH.
4E7DH - Display Model III Logo and Copyright
4E7D
LD C,00H 0E 00
LET Register C = 00H to point to drive 0
4E7F
GOSUB to 4566H (TERM) to send the Force Interrupt command to the FDC.
4E82
GOSUB to 44D4H.
NOTE: 44D4H is the routine which handles DRIVE SELECT (Register C holds the drive number to be used).
4E85
LD HL,516CH 21 6C 51
LET Register Pair HL = 516CH which is the message storage area for the Model III logo.
4E88
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
4E8B
LD A,(38FFH) 3A FF 38
Fetch the value stored at memory location 38FFH (which is the keyboard) and put it into Register A.
4E8E
LD (4F3AH),A 32 3A 4F
KEYFLG: Store the keyboard byte into 4F3AH, the operand of LD A,00H at 4F39H. Any key held down during the boot makes it non zero.
4E91
LD HL,5016H 21 16 50
LET Register Pair HL = 5016H which is the message storage area for the DOS version
4E94
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
4E97
LD HL,508AH 21 8A 50
LET Register Pair HL = 508AH which is the message storage area for the copyright notice.
4E9A
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
4E9D
EI FB
Enable Interrupts.
4E9E
LD HL,(42B5H) 2A B5 42
Fetch the word at 42B5H-42B6H (INITD) into Register Pair HL.
4EA1
LD DE,4455H 11 55 44
LET Register Pair DE = 4455H, the value INITD holds once the DOS has been initialized.
4EA4
PUSH HL E5
PUSH Register HL (the date flag) to the top of the STACK.
4EA5
OR A B7
Set FLAGS based on the contents of Register A; but really just to clear the CARRY FLAG (which is about to get used).
4EA6
SBC HL,DE ED 52
Subtract with Carry DE from HL to see if the date flag is valid.
4EA8
POP HL E1
Restore Register HL (the date flag) from the top of the STACK.
4EA9
If the result of the SBC is zero, then the date flag is valid, so skip to 4F2EH
4EAC
LD (42B5H),DE ED 53 B5 42
If we are here, then the date flag wasn't valid, so store the value held in Register DE (the valid date flag) into the memory location 42B5H.
4EB0
JUMP to 4EB8H to get the DATE and TIME from the user.
4EB2H - Get Current Date from System User
4EB2S8ERR
LD HL,512DH 21 2D 51
LET Register Pair HL = 512DH to point to the message storage area of TRY AGAIN.
4EB5
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
4EB8GETDAT
LD HL,513BH 21 3B 51
LET Register Pair HL = 513BH to point to the message storage area of the DATE PROMPT.
4EBB
GOSUB to 4F84H to display the DATE PROMPT and get the date from the user. On exit, Register A holds the number of characters entered, and HL points to the buffer location where those characters are stored.
4EBE
CP 08H FE 08
Compare the value held in Register A against 08H (meaning, 8 characters were returned from the user). Results: If Register A equals 08H, the Z FLAG is set; otherwise the NZ FLAG is set.
4EC0
If the NZ FLAG (Not Zero) is set then we didn't get 8 characters so JUMP BACK to 4EB2H to display the TRY AGAIN message and try to get a valid date from the user.
4EC2
LD C,2FH 0E 2F
LET Register C = 2FH (ASCII: / so we can further try to validate the 8 characters we got into a valid date.
4EC4
GOSUB to 4FA6H to decode the date from the input and check the delimiter in Register C. Return NZ FLAG for an error.
4EC7
If the NZ FLAG (Not Zero) is set then the prior subroutine exited with an error, so JUMP BACK to 4EB2H to display the TRY AGAIN message and try to get a valid date from the user.
4EC9
LD HL,4F81H 21 81 4F
LET Register Pair HL = 4F81H (the TRSDOS v1.3 memory storage location for the decoded SECONDS or YEAR).
4ECC
LD DE,42B7H 11 B7 42
LET Register Pair DE = 42B7H (DTSAVE), the date save area.
4ECF
LD BC,0003H 01 03 00
LET Register Pair BC = 0003H to signify a move of 3 bytes.
4ED2
LDIR ED B0
Copy the three date bytes (year, day, month) from 4F81H-4F83H to 42B7H-42B9H (DTSAVE).
4ED4
LD A,(4F81H) 3A 81 4F
Fetch the value stored at memory location 4F81H (the TRSDOS v1.3 memory storage location for the decoded SECONDS or YEAR) and put it into Register A.
4ED7
CP 64H FE 64
Compare the value held in Register A against 64H (Decimal: 100). Results:
- If Register A equals 64H, the Z FLAG is set.
- If A < 64H, the CARRY FLAG will be set.
- if A >= 64H, the NO CARRY FLAG will be set.
4ED9
If the NC FLAG (Carry) is set, then the YEAR is 100 or higher, which is too much, so so JUMP BACK to 4EB2H to display the TRY AGAIN message and try to get a valid date from the user.
4EDB
LD B,A 47
If we're here the YEAR is GOOD, so LET Register B = Register A (the year).
4EDC
LD A,(4F83H) 3A 83 4F
Fetch the value stored at memory location 4F83H (the TRSDOS v1.3 memory storage location for the decoded HOURS or MONTH) and put it into Register A.
4EDF
CP 0DH FE 0D
Compare the value held in Register A against 0DH (Decimal: 13). Results:
- If Register A equals 0DH, the Z FLAG is set.
- If A < 0DH, the CARRY FLAG will be set.
- if A >= 0DH, the NO CARRY FLAG will be set.
4EE1
If the NC FLAG (Carry) is set, then the MONTH is 13 or higher, which is too much, so so JUMP BACK to 4EB2H to display the TRY AGAIN message and try to get a valid date from the user.
4EE3
OR A B7
Set FLAGS based on the contents of Register A to set up for a test against MONTH of ZERO.
4EE4
If the Z FLAG (Zero) is set, then the MONTH is 0, which is too low, so so JUMP BACK to 4EB2H to display the TRY AGAIN message and try to get a valid date from the user.
4EE6
ADD A,B 80
If we're here then we have a valid YEAR and a valid MONTH, so to prepare to test the DAY we must first ADD the value held in Register B (YEAR) to Register A (MONTH).
4EE7
LD B,A 47
Save that MONTH + YEAR (held in Register A) into Register B.
4EE8
LD A,(4F82H) 3A 82 4F
Fetch the value stored at memory location 4F82H (the TRSDOS v1.3 memory storage location for the decoded MINUTES or DAY) and put it into Register A.
4EEB
CP 20H FE 20
Compare the value held in Register A against 20H (Decimal: 32). Results:
- If Register A equals 20H, the Z FLAG is set.
- If A < 20H, the CARRY FLAG will be set.
- if A >= 20H, the NO CARRY FLAG will be set.
4EED
If the NC FLAG (Carry) is set, then the DAY is 32 or higher, which is too much, so so JUMP BACK to 4EB2H to display the TRY AGAIN message and try to get a valid date from the user.
4EEF
OR A B7
Set FLAGS based on the contents of Register A to set up for a test against DAY of ZERO.
4EF0
If the Z FLAG (Zero) is set, then the DAY is 0, which is too low, so so JUMP BACK to 4EB2H to display the TRY AGAIN message and try to get a valid date from the user.
4EF2
ADD A,B 80
ADD the value held in Register B (the MONTH + YEAR) to Register A (the DAY). Results held in Register A.
4EF3
OR A B7
Set FLAGS based on the contents of Register A.
4EF4
If the Z FLAG (Zero) is set, then something is WAY off, so so JUMP BACK to 4EB2H to display the TRY AGAIN message and try to get a valid date from the user.
4EF6
JUMP to 4EFEH (GETTIM) to get the time.
4EF8H - Get Current TIME from System User
4EF8S8ERR1
LD HL,512DH 21 2D 51
LET Register Pair HL = 512DH to point to the message storage area of TRY AGAIN.
4EFB
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
4EFEH - Continue Time/Date Processing
4EFEGETTIM
LD HL,5154H 21 54 51
LET Register Pair HL = 5154H to point to the message storage area of the TIME PROMPT.
4F01
GOSUB to 4F84H to display the TIME PROMPT and get the time from the user. On exit, Register A holds the number of characters entered, and HL points to the buffer location where those characters are stored.
4F04
OR A B7
Set FLAGS based on the contents of Register A.
4F05
If the Z FLAG (Zero) is set then we got a null response so JUMP to 4F2EH to continue.
4F07
LD C,3AH 0E 3A
LET Register C = 3AH (ASCII: :).
4F09
GOSUB to 4FA6H (CONV1) to convert the time typed into binary at 4F81H-4F83H, checking for the delimiter in Register C. It returns NZ for an error.
4F0C
If the NZ FLAG (Not Zero) is set then the prior subroutine exited with an error, so JUMP BACK to 4EF8H to display the TRY AGAIN message and try to get a valid time from the user.
4F0E
LD A,(4F81H) 3A 81 4F
Fetch the value stored at memory location 4F81H the TRSDOS v1.3 memory storage location for the decoded SECONDS or YEAR) and put it into Register A.
4F11
CP 3DH FE 3D
Compare the value held in Register A against 3DH (Decimal: 61). Results:
- If Register A equals 3DH, the Z FLAG is set.
- If A < 3DH, the CARRY FLAG will be set.
- if A >= 3DH, the NO CARRY FLAG will be set.
4F13
If the NC FLAG (Carry) is set, then the SECONDS are 61 or higher, which is too much, so so JUMP BACK to 4EF8H to display the TRY AGAIN message and try to get a valid time from the user.
4F15
LD A,(4F82H) 3A 82 4F
Fetch the value stored at memory location 4F82H (the TRSDOS v1.3 memory storage location for the decoded MINUTES or DAY) and put it into Register A.
4F18
CP 3DH FE 3D
Compare the value held in Register A against 3DH (Decimal: 61). Results:
- If Register A equals 3DH, the Z FLAG is set.
- If A < 3DH, the CARRY FLAG will be set.
- if A >= 3DH, the NO CARRY FLAG will be set.
4F1A
If the NC FLAG (Carry) is set, then the MINUTES are 61 or higher, which is too much, so so JUMP BACK to 4EF8H to display the TRY AGAIN message and try to get a valid time from the user.
4F1C
LD A,(4F83H) 3A 83 4F
Fetch the value stored at memory location 4F83H (the TRSDOS v1.3 memory storage location for the decoded HOURS or MONTH) and put it into Register A.
4F1F
CP 18H FE 18
Compare the value held in Register A against 18H (Decimal: 24). Results:
- If Register A equals 18H, the Z FLAG is set.
- If A < 18H, the CARRY FLAG will be set.
- if A >= 18H, the NO CARRY FLAG will be set.
4F21
If the NC FLAG (Carry) is set, then the HOUR is 24 or higher, which is too much, so so JUMP BACK to 4EF8H to display the TRY AGAIN message and try to get a valid time from the user.
4F23
LD HL,4F81H 21 81 4F
LET Register Pair HL = 4F81H (the TRSDOS v1.3 memory storage location for the decoded SECONDS or YEAR).
4F26
LD DE,4217H 11 17 42
LET Register Pair DE = 4217H (SECOND), the start of the clock's seconds, minutes and hours bytes.
4F29
LD BC,0003H 01 03 00
LET Register Pair BC = 0003H (i.e., the number of bytes to move).
4F2C
LDIR ED B0
Move the user entered time into the system time storage area.
4F2ESTART2
LD HL,42B7H 21 B7 42
START2: LET Register Pair HL = 42B7H (DTSAVE), the saved date.
4F31
LD DE,421AH 11 1A 42
LET Register Pair DE = 421AH (YEAR), the clock's year, day and month bytes.
4F34
LD BC,0003H 01 03 00
LET Register Pair BC = 0003H (i.e., the number of bytes to move).
4F37
LDIR ED B0
Copy the saved date into 421AH-421CH.
4F39
LD A,00H 3E 00
KEYFLG: LET Register A = the keyboard byte stored into the operand at 4F3AH by 4E8EH (00H in the file).
4F3B
OR A B7
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
4F3C
If the NZ FLAG (Not Zero) is set then a key was pressed so JUMP to 4296H.
NOTE: 4296H is the DOS READY jump routine.
4F3F
LD C,00H 0E 00
LET Register C = 00H to signify DRIVE 0.
4F41
GOSUB to 4A93H to read the GAT into Buffer # 2.
4F44
If the NZ FLAG (Not Zero) is set then the prior subroutine exited with an error, so JUMP to 4409H.
4F47
LD A,(4DE0H) 3A E0 4D
Fetch 4DE0H, offset E0H of the GAT sector (the source's DAUTO, 224), the first byte of the AUTO command, into Register A.
4F4A
CP 0DH FE 0D
Compare the value held in Register A against 0DH. Results: If Register A equals 0DH, the Z FLAG is set; otherwise the NZ FLAG is set.
4F4C
If the Z FLAG (Zero) is set then there was no AUTO command so JUMP to 4296H.
NOTE: 4296H is the DOS READY jump routine.
4F4F
LD A,C9H 3E C9
LET Register A = C9H, the opcode of RET.
4F51
LD (42AEH),A 32 AE 42
Store C9H into 42AEH, the BREAK vector, so it becomes a RET.
4F54
LD HL,4DE0H 21 E0 4D
LET Register Pair HL = 4DE0H, which is a pointer to the AUTO command.
4F57
LD DE,4225H 11 25 42
LET Register Pair DE = 4225H, which is the start of the DOS command buffer.
4F5A
LD BC,0020H 01 20 00
LET Register Pair BC = 0020H (Decimal: 32) for the number of bytes to move.
4F5D
LDIR ED B0
Move the 32 potential bytes for an AUTO command into the DOS command buffer, so it is as if that command was just typed in.
4F5F
LD HL,4F6BH 21 6B 4F
LET Register Pair HL = 4F6BH, the AUTO Function Engaged message.
4F62
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
4F65
LD HL,4225H 21 25 42
LET Register Pair HL = 4225H, which is the start of the DOS command buffer.
4F68
JUMP to 4299H to execute the command in the DOS command buffer and exit.
4F6BH - Message Storage Area
4F6B-4F7F
DEFM "AUTO Function Engaged" 41 55 54 4F 20 46 75 6E 63 74 69 6F 6E 20 45 6E 67 61 67 65 64
The message 4F5FH displays before it runs the AUTO command.
4F80
DEFB 0DH 0D
0DH, which ends the AUTO message for 021BH.
4F81BIN
DEFB 00H 00
BIN: the first of the three bytes CONV1 fills: the year for a date, the seconds for a time.
4F82
DEFB 00H 00
BIN+1: the day for a date, the minutes for a time.
4F83
DEFB 00H 00
BIN+2: the month for a date, the hours for a time.
4F84H - Subroutine to display the DATE (or TIME) PROMPT and get the date (or time) from the user. On exit, Register A holds the number of characters entered, and HL points to the buffer location where those characters are stored.
4F84GETAN
GOSUB to 021BH.
NOTE: 021BH will display the character at (HL) until a 03H is found.
4F87
LD B,08H 06 08
LET Register B = 08H to get up to 8 characters from a ROM call to 0040H.
4F89
LD HL,4225H 21 25 42
LET Register Pair HL = 4225H (the keyboard buffer). HL must be set for a ROM call to 0040H.
4F8C
GOSUB to 0040H in the ROM.
NOTE: This routine gets a full line from the keyboard. The line is terminated by a carriage return or BREAK. Characters typed are echoed to the display. On entry, B must be the maximum length of line to be accepted and (HL) must be the storage buffer which should be set to B+1. On Exit, CARRY will be set if the BREAK key was hit, Register B will contain the number of characters entered, and (HL) will contain the line from the keyboard followed by the terminating character. Register paid DE is altered in this routine.
4F8F
LD A,B 78
Copy the number of characters received (which the ROM call of 0040H puts into Register B) into Register A.
4F90
CP 05H FE 05
Compare the value held in Register A against 05H. Results: If Register A equals 05H, the Z FLAG is set; otherwise the NZ FLAG is set.
4F92
RET NZ C0
If the NZ FLAG (Not Zero) is set, then we did not get exactly 5 characters, so RETurn to the caller.
This doesn't make entire sense to me because this routine is shared by DATA and TIME, and the next instructions appear to say "Well, if we got 5 characters, then let's just set the rest to :00"
4F93
PUSH HL E5
PUSH Register HL (the buffer location) to the top of the STACK.
4F94
LD HL,422BH 21 2B 42
LET Register Pair HL = 422BH (the ":nn" [seconds] in the keyboard buffer collecting this information).
4F97
LD (HL),3AH 36 3A
Store a : into the memory location pointed to by Register Pair HL.
4F99
INC HL 23
Bump Register Pair HL by 1.
4F9A
LD (HL),30H 36 30
Store a 0 into the memory location pointed to by Register Pair HL.
4F9C
INC HL 23
Bump Register Pair HL by 1.
4F9D
LD (HL),30H 36 30
Store a 0 into the memory location pointed to by Register Pair HL.
4F9F
INC HL 23
Bump Register Pair HL by 1.
4FA0
LD (HL),0DH 36 0D
Store an ENTER into the memory location pointed to by Register Pair HL.
4FA2
POP HL E1
Restore the buffer location from the top of the STACK into Register Pair HL.
4FA3
LD A,08H 3E 08
LET Register A = 08H to denote that now we have 8 characters (the original 5, plus ":00").
4FA5
RET C9
RETurn to the caller.
4FA6H - Subroutine to read the value of HOURS/MONTHS, MINUTES/DAY, or SECONDS/YEARS from their memory location and convert that value from text.
4FA6CONV1
LD DE,4F83H 11 83 4F
LET Register Pair DE = 4F83H (the TRSDOS v1.3 memory storage location for the decoded HOURS or MONTH).
4FA9
LD B,03H 06 03
LET Register B = 03H to set a loop for 3 numbers (i.e., memory storage locations 4F83 [HOURS/MONTH], 4F82 [MINUTES/DAY], and 4F81 [SECONDS/YEAR]).
4FABLOOP1
PUSH DE D5
Save the current pointer to the TIME or DATE storage area.
4FAC
GOSUB to 4FBBH to decode the number from text.
4FAF
POP DE D1
Restore the current pointer to the TIME or DATE storage agrea from the top of the STACK into Register Pair DE.
4FB0
RET NZ C0
If the NZ FLAG (Not Zero) is set then there was a conversion error reported by the routine at 4FBBH, so RETurn to the caller.
4FB1
LD (DE),A 12
Store the decoded number (Register A) into the memory location pointed to by Register Pair DE.
4FB2
DEC DE 1B
DECrement Register Pair DE by 1 (so 4F83H [H/M] changes to 4F82 [M/D] and again to 4F81 [S/Y]).
4FB3
DEC B 05
DECrement Register B by 1 to count down from 3 to 1.
4FB4
RET Z C8
If the Z FLAG (Zero) is set, meaning that we have processed all 3 memory locations, then RETurn to the caller.
4FB5
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL and put it into Register A. This should be the applicable delimeter of either / if this routine involves processing the date, or : if this routine involves processing the time.
4FB6
INC HL 23
Bump Register Pair HL by 1 since we just filled the memory location pointed to by HL with a delimeter.
4FB7
CP C B9
Compare the value held in Register A (the delimeter in memory) against the value held in Register C (the appropriate delimeter fof the routine), to make sure they match. Results: If Register A equals C, the Z FLAG is set; otherwise the NZ FLAG is set.
4FB8
If the Z FLAG (Zero) is set then the appropriate delimiter was used, so continue on with the 3 numbers via a JUMP to 4FABH.
4FBA
RET C9
If we are here, NZ FLAG is set because the delimiter was not appropriate, so RETurn to the caller in an error state.
4FBBH - DECBIN: Convert two ASCII digits into a binary number
4FBBDECBIN
DECBIN: GOSUB to 4FD2H (DECCHK) to turn the ASCII digit at (HL) into its value. It returns the C FLAG set when the character is a digit 0-9.
4FBE
If the NC FLAG (Carry) is set then the digit provided was invalid, so JUMP to 4FD0H to set the error flag (via an OR A) and RETurn.
4FC0
LD E,A 5F
LET Register E = Register A (the digit being processed).
4FC1
RLCA 07
Rotate the bits in A left, which is the same as A = A * 2.
4FC2
RLCA 07
Rotate the bits in A left, which is the same as A = A * 2 (so now the original A = A * 4).
4FC3
ADD A,E 83
ADD the value held in Register E to Register A (Results held in Register A, so now the original A = A * 5).
4FC4
RLCA 07
Rotate the bits in A left, which is the same as A = A * 2 (so now the original A = A * 10).
4FC5
LD E,A 5F
LET Register E = Register A (which is the first digit * 10, forming the "tens place" number).
4FC6
GOSUB to 4FD2H (DECCHK) for the second digit. It returns the C FLAG set when the character is a digit 0-9.
4FC9
If the NC FLAG (Carry) is set then the digit provided was invalid, so JUMP to 4FD0H to set the error flag (via an OR A) and RETurn.
4FCB
ADD A,E 83
ADD the value held in Register E (the "tens place") to Register A (Results held in Register A).
4FCC
LD E,A 5F
LET Register E = Register A (which is the completed number).
4FCD
XOR A AF
Set Register A to ZERO and clear all Flags.
4FCE
LD A,E 7B
LET Register A = Register E.
4FCF
RET C9
RETurn to the caller.
4FD0H - Routine JUMPed to from the prior decoding routine if there was an error. This will set the NZ FLAG to indicate an error and RETurn.
4FD0RET1
OR A B7
Set FLAGS based on the contents of Register A, which will trigger a NZ FLAG set - meaning an error condition.
4FD1
RET C9
RETurn to the caller.
4FD2H - DECCHK: Convert an ASCII digit to its value. The C FLAG is set for a digit 0-9.
4FD2DECCHK
LD A,(HL) 7E
Fetch the value stored at memory location pointed to by Register Pair HL and put it into Register A.
4FD3
INC HL 23
Bump Register Pair HL by 1 to point to the next memory location.
4FD4
SUB 30H D6 30
SUBtract the value 30H from Register A which adjusts the number to BINARY.
4FD6
RET C D8
If the C FLAG (Carry) is set, the character was below 30H (the source calls it punctuation): RETurn with the C FLAG set. DECBIN only rejects a character when the C FLAG is clear, so a character below 30H is not rejected here.
4FD7
CP 0AH FE 0A
Compare the value held in Register A against 0AH to see if the value was too high to be a number. Results:
- If Register A equals 0AH, the Z FLAG is set.
- If A < 0AH, the CARRY FLAG will be set.
- if A >= 0AH, the NO CARRY FLAG will be set.
4FD9
RET C9
RETurn with the C FLAG set for a digit 0-9 and clear for a value of 0AH or more.
4FDAH - CKHDRV: Subroutine called from 4E69H to test whether the disk drive in Register C is present on the system.
4FDACKHDRV
CKHDRV: GOSUB to 4566H (TERM) to send the Force Interrupt command to the FDC.
4FDD
GOSUB to 4404H.
NOTE: 4404H is the routine which has a slight delay.
4FE0
LD A,0CH 3E 0C
LET Register A = 0CH (0000 1100).
When this bit pattern in sent to Port F0H (the Floppy Disk Control Port) and bits 7-4 are 0000, this is a RESTORE command and is a Type I command. Bits 0-1 are the stepping rate (00=6ms, 01=12ms, 10=20ms, 11=30ms), Bit 2 is the Track Number Verify Flag (0=No Verify), and Bit 3 is the Head Load Flag (1=Load Head).
When activated, the Track Register is checked, and if its 0 (meaning at Track 0) an interrupt is generated. If it is not 0, stepping pulses are issued until the TR00 goes to 0, and then an interrupt is generated.
4FE2
OUTput the value held in Register A to port F0H.
NOTE: Port F0H is the Floppy Disk Command/Status Register.
4FE4
LD BC,6000H 01 00 60
LET Register Pair BC = 6000H as a delay.
4FE7
GOSUB to 0060H to delay for BC iterations.
4FEA
LD BC,0000H 01 00 00
LET Register Pair BC = 0000H, so the loop below runs up to 65,536 times.
Start of a loop of 65,535 tries.
4FEDS8DLY
DEC BC 0B
DECrement Register Pair BC by 1.
4FEE
LD A,B 78
LET Register A = Register B and OR it with Register C: the Z FLAG is set only when Register Pair BC is 0000H.
4FEF
OR C B1
OR Register C into Register A: the Z FLAG is set only when Register Pair BC is 0000H.
4FF0
RET Z C8
If the Z FLAG (Zero) is set, then BC=0 and we have run out of retries so RETurn to the caller.
4FF1
INput a byte from Port F0H and put it into Register A.
NOTE: Port F0H is the FDC Status port on input. Input Results:
- Bit 0: Busy
- Bit 1: Index/DRQ
- Bit 2: Track 0/Data Lost
- Bit 3: CRC error
- Bit 4: Seek error/Record not found
- Bit 5: If Reading, Record Type, if Writing, Write Fault/Head loaded
- Bit 6: Write Protect
- Bit 7: Not ready
4FF3
BIT 2,A CB 57
Test Bit 2 of Register A (=Track 0).
4FF5
RET NZ C0
If the NZ FLAG (Not Zero) is set then we have hit TRACK 0 and there is definitely a drive there, so RETurn to the caller.
End of a loop of 65,535 tries.
4FF8H - Subroutine to convert a two-digit binary-coded-decimal number into ASCII text.
4FF8MOVDIG
RLD ED 6F
MOVDIG: RLD: the high nibble of (HL) goes into the low nibble of Register A, the low nibble of (HL) moves to its high nibble, and the old low nibble of A goes into the low nibble of (HL). Register A now holds the first digit.
4FFA
GOSUB to 4FFFH to convert that RLD'd number to ASCII.
4FFD
RLD ED 6F
RLD again: Register A now holds the second digit. After two RLDs the byte at (HL) has its two nibbles swapped. Execution falls into PRTDIG.
4FFFPRTDIG
AND 0FH E6 0F
PRTDIG: MASK Register A with 0FH to keep the digit.
5001
If the NZ FLAG (Not Zero) is set, meaning that we have a non-zero leading digit, skip the next 2 instructions and JUMP to 5006H.
5003
BIT 0,D CB 42
Test Bit 0 of Register D to see if we still have leading zeroes.
5005
RET Z C8
If the Z FLAG (Zero) is set then we still have a leading zero, so RETurn to the caller.
5006PNTDG1
SET 0,D CB C2
PNTDG1: SET bit 0 of Register D to show a non zero digit has been stored, so later zeros are kept.
5008
OR 30H F6 30
OR Register A against 30H to turn the nybble into ASCII (since 30H is "0", 39H is "9").
500A
LD (IX+00H),A DD 77 00
Store the value held in Register A (which is now ASCII text) into the memory location IX+00H.
500D
INC IX DD 23
Bump Register Pair IX by 1 to point to the next text location.
500F
RET C9
RETurn to the caller.
End of a loop of 65,535 tries.
5010H - RAM size text Storage Area.
5010-5011M64
DEFM "48" 34 38
M64: the text 48 for a 48K system. 4E46H points Register Pair HL here and 4E59H copies the two characters into the sign on message at 504CH.
5012-5013M32
DEFM "32" 33 32
M32: the text 32 for a 32K system, used by 4E4FH.
5014-5015M16
DEFM "16" 31 36
M16: the text 16 for a 16K system, used by 4E56H.
5016H - Message Storage Area
5016-504ATITLE
DEFM "TRS-80 Model III TRSDOS version 1.3 Wed Jul 1, 1981" 54 52 53 2D 38 30 20 4D 6F 64 65 6C 20 49 49 49 20 54 52 53 44 4F 53 20 76 65 72 73 69 6F 6E 20 31 2E 33 20 57 65 64 20 20 4A 75 6C 20 20 31 2C 20 31 39 38 31
TITLE: the first line of the sign on message, printed by 4E91H-4E94H. The source builds the date at the end (from 503AH) with its DATE macro.
504B
DEFB 0AH 0A
0AH, the line feed that ends the first line of the sign on message.
504C-506AMEM
DEFM "00K System, Number of Drives = " 30 30 4B 20 53 79 73 74 65 6D 2C 20 4E 75 6D 62 65 72 20 6F 66 20 44 72 69 76 65 73 20 3D 20
MEM: the memory size line. 4E59H-4E5FH copies 48, 32 or 16 over the first two characters.
506BNUMDRV
DEFM "0" 30
NUMDRV: the number of drives. 4E7AH stores the ASCII digit here.
506C-5078
DEFM " Serial #: " 20 20 20 53 65 72 69 61 6C 20 23 3A 20
The text in front of the serial number.
5079-5089SERMSG
DEFM " " 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
SERMSG (17 bytes): the boot code at 4E11H-4E25H writes the serial number here as ASCII digits, dropping leading zeros, and ends it with 0DH.
508A-50BDPART2
DEFM "(c)(p) 1980 TANDY CORPORATION. All rights reserved." 28 63 29 28 70 29 20 31 39 38 30 20 54 41 4E 44 59 20 43 4F 52 50 4F 52 41 54 49 4F 4E 2E 20 20 41 6C 6C 20 72 69 67 68 74 73 20 72 65 73 65 72 76 65 64 2E
PART2: the copyright notice, printed by 4E97H-4E9AH.
50BE
DEFB 0AH 0A
0AH, the line feed that ends the line.
50BF-50F6
DEFM "Unauthorized reproduction of this software is prohibited" 55 6E 61 75 74 68 6F 72 69 7A 65 64 20 72 65 70 72 6F 64 75 63 74 69 6F 6E 20 6F 66 20 74 68 69 73 20 73 6F 66 74 77 61 72 65 20 69 73 20 70 72 6F 68 69 62 69 74 65 64
The second line of the copyright notice.
50F7
DEFB 0AH 0A
0AH, the line feed that ends the line.
50F8-512B
DEFM "and is in violation of United States copyright laws." 61 6E 64 20 69 73 20 69 6E 20 76 69 6F 6C 61 74 69 6F 6E 20 6F 66 20 55 6E 69 74 65 64 20 53 74 61 74 65 73 20 63 6F 70 79 72 69 67 68 74 20 6C 61 77 73 2E
The third line of the copyright notice.
512C
DEFB 0DH 0D
0DH, which ends the copyright notice for 021BH.
512D-5139TRYAGN
DEFM "Try Again " 54 72 79 20 41 67 61 69 6E 20 20 20 20
TRYAGN: printed by 4EB2H and 4EF8H when a date or time is not valid.
513A
DEFB 03H 03
03H, which ends the text for 021BH without a new line.
513B-5151DATMSG
DEFM "Enter Date (MM/DD/YY)? " 45 6E 74 65 72 20 44 61 74 65 20 28 4D 4D 2F 44 44 2F 59 59 29 3F 20
DATMSG: the date prompt, printed by GETAN (4F84H) for 4EB8H.
5152-5153
DEFB 0EH,03H 0E 03
0EH (turn the cursor on) and 03H, which ends the prompt without a new line. The source writes the two bytes as DEFW 030EH.
5154-516ATIMMSG
DEFM "Enter Time (HH:MM:SS)? " 45 6E 74 65 72 20 54 69 6D 65 20 28 48 48 3A 4D 4D 3A 53 53 29 3F 20
TIMMSG: the time prompt, printed by GETAN (4F84H) for 4EFEH.
516B
DEFB 03H 03
03H, which ends the prompt without a new line.
516C-518BMSG1
DEFB 0D0H,0BFH,9FH,87H,83H x 24,8BH,0AFH,0BFH,0AH D0 BF 9F 87 83 x 24 8B AF BF 0A
MSG1: the Model III picture printed by 4E85H-4E88H, nine lines of space compression codes (C0H-FFH, a code of C0H plus n stands for n spaces) and graphics characters (80H-BFH). Line 1: 16 spaces (D0H), BFH, 9FH, 87H, 24 x 83H, 8BH, AFH, BFH and the 0AH that ends the line.
518C-5190LINE2
DEFB 0D0H,0BFH,0DCH,0BFH,0AH D0 BF DC BF 0A
Line 2: 16 spaces, BFH, 28 spaces (DCH), BFH, 0AH.
5191-519CLINE3
DEFB 0D0H,0BFH,0C9H / DEFM "TRSDOS" / DEFB 0CDH,0BFH,0AH D0 BF C9 54 52 53 44 4F 53 CD BF 0A
Line 3: 16 spaces, BFH, 9 spaces (C9H), the text TRSDOS, 13 spaces (CDH), BFH, 0AH.
519D-51ABLINE4
DEFB 0D0H,0BFH,0C8H / DEFM "MODEL III" / DEFB 0CBH,0BFH,0AH D0 BF C8 4D 4F 44 45 4C 20 49 49 49 CB BF 0A
Line 4: 16 spaces, BFH, 8 spaces (C8H), the text MODEL III, 11 spaces (CBH), BFH, 0AH.
51AC-51B0LINE5
DEFB 0D0H,0BFH,0DCH,0BFH,0AH D0 BF DC BF 0A
Line 5: 16 spaces, BFH, 28 spaces, BFH, 0AH.
51B1-51D0LINE6
DEFB 0D0H,0BFH,0BDH,0B4H,0B0H x 24,0B8H,0BEH,0BFH,0AH D0 BF BD B4 B0 x 24 B8 BE BF 0A
Line 6: 16 spaces, BFH, BDH, B4H, 24 x B0H, B8H, BEH, BFH, 0AH.
51D1-51F2LINE7
DEFB 0CFH,0BEH,0BDH,9CH x 28,0BEH,0BDH,0AH CF BE BD 9C x 28 BE BD 0A
Line 7: 15 spaces (CFH), BEH, BDH, 28 x 9CH, BEH, BDH, 0AH.
51F3-5214LINE8
DEFB 0CFH,0BFH,0B6H x 30,0BFH,0AH CF BF B6 x 30 BF 0A
Line 8: 15 spaces, BFH, 30 x B6H, BFH, 0AH.
5215-5219LINE9
DEFB 0D0H,83H,0DCH,83H,0DH D0 83 DC 83 0D
Line 9: 16 spaces, 83H, 28 spaces, 83H and the 0DH that ends the picture.