DOSPLUS 3.5 for the Model III - TRAP/CMD Disassembled

Page Customization

Introduction/Summary

DOSPLUS 3.5 TRAP/CMD Disassembly - The Disk Error Trap (Model III)

TRAP/CMD puts a trap for disk errors into high memory: once it is in place, a read, write, verify or format that fails shows the message of the error and the prompt Abort,Cont,Retry,Ignore ?. Its heading reads TRAP - DOSPLUS Disk error trapper - 3.50. It is a load module of 2 blocks, 332 bytes, at 5200H-534BH with the transfer address 5200H, after the two comment records (the name TRAP and the copyright notice). TRAP/CMD is on the Model III master only.

The Parts of TRAP/CMD

AddressContents
5200H-524FHThe installation: HMEM$, the two address operands, the hook of DISKIO%, the copy and the message (5200H).
5250H-5270HA word shown in hexadecimal (5250H).
5271H-52DFHThe heading and the text Driver installed at (5271H).
52E0H-534DHThe resident part, copied above the new HMEM$: the trap and its prompt (52E0H).

How TRAP Works

TRAP lowers HMEM$ (4411H) by 110 bytes, the length of the resident part 52E0H-534DH, and copies the part to the first byte above the new HMEM$ (523CH). DISKIO% (4488H) is a JP in SYS0/SYS; TRAP keeps its operand, the disk routine it went to (46A4H, or a trap installed before), as the operand of the resident part's CALL, and puts the address of the resident part in its place (522CH). Running TRAP twice puts a second trap in front of the first. The address of the part is shown after Driver installed at (5244H).

The resident part (52E0H) does the function through the old routine. An error code of a function 03H-09H (DREAD, DVERF, DWRITE, SREAD, SWRITE, DWRITA and DFORMT) is trapped, except the code 06H, a sector read with the data address mark of the directory, which the system takes as a result and not an error; errors of DCHECK, DHOME and DSEEK (functions 00H-02H) go back to the caller as they are (52EBH). A trapped error is shown by ERROR@ with bits 7 and 6 set (return, and no frame of asterisks), then the prompt, and a reply of one character is taken by the ROM's line input 0040H (5313H). A (or BREAK) goes to ABORT@, C returns the error to the caller, I returns 00H with the Z FLAG as if the function had worked, and any other reply, R or not, does the function again with the caller's registers (5321H).

A Slip in the Installation

The resident part holds two addresses of its own, the prompt (the operand at 5309H) and the buffer for the reply (530FH), which TRAP must move by the distance from 52E0H to the new place. The prompt is moved right (521CH). For the buffer TRAP adds the distance to the old operand and then stores the distance itself, LD (530FH),BC where LD (530FH),HL was meant (5227H). The moved part therefore takes the reply into the two bytes at the address the distance gives, the new place less 52E0H: with the resident part at FF92H, for one, at ACB2H-ACB3H, inside the memory of the program that called DISKIO%. The prompt still works, since the reply is read back from where it was written, but each reply writes the character and its 0DH over those two bytes of that program.

Differences from the Manual

The manual (Utilities, TRAP) describes the prompt as Abort, Continue, Retry, Ignore?; the file shows Abort,Cont,Retry,Ignore ?. The manual does not say which errors are trapped (only those of the reads, writes, verify and format, and not the code 06H), that BREAK aborts as A does, or that any reply other than A, C and I retries. It says the trap stays until a reset or until a configuration file without TRAP is loaded; TRAP itself has no way to remove the trap.

Variables

TRAP/CMD Variables

Address
Size
Contents
52E2H-52E3H
2 bytes
Old disk routine
The operand of the resident part's CALL: the old target of DISKIO% (522FH).
5309H-530AH
2 bytes
Prompt address
The operand of LD HL at 5308H, moved at 5220H (521CH).
530FH-5310H
2 bytes
Buffer address
The operand of LD HL at 530EH, set to the distance at 5227H (5223H).
534CH-534DH
2 bytes
Reply buffer
The character and its 0DH, as loaded (530EH).

Memory Outside TRAP/CMD

Address
Size
Contents
4411H-4412H
2 bytes
HMEM$
Lowered by 110 bytes (5206H).
4489H-448AH
2 bytes
DISKIO% operand
The operand of the JP at 4488H, set to the resident part (5232H).

Outside Routines

AddressContents
4467HSYS0/SYS: DSPLY@ (5203H, 5241H, 530BH).
4409HSYS0/SYS: ERROR@ (5305H).
4030HSYS0/SYS: ABORT@ (5317H, 531EH).
4488HSYS0/SYS: DISKIO%, hooked (522CH).
0033HROM: display a character (524CH, 5258H, 52FFH).
0040HROM: line input (5313H).

Disassembly

5200H - TRAP

TRAP/CMD's transfer address, entered from the DOS command level (TRAP has no parameters). TRAP shows its heading, takes 6EH bytes below HMEM$ for its resident part (52E0H-534DH), sets that part's two address operands for the new place, hooks DISKIO% (4488H) through the operand of its JP at 4489H-448AH, copies the part up and shows Driver installed at with the address in hexadecimal. It returns to the DOS by RET.

5200
LD HL,5271H 21 71 52
Point Register Pair HL to 5271H, TRAP's heading (TRAP - DOSPLUS Disk error trapper - 3.50) and the copyright line.
5203
GOSUB to 4467H, DSPLY@, to display the text at Register Pair HL up to and with the 0DH after the copyright line.
5206
LD HL,(4411H) 2A 11 44
Load Register Pair HL with HMEM$ from 4411H-4412H, the highest address free for programs.
5209
LD BC,006EH 01 6E 00
Load Register Pair BC with 006EH, the length of the resident part 52E0H-534DH: 110 bytes.
520C
OR A B7
OR Register A against itself, to clear the C FLAG for the SBC below.
520D
SBC HL,BC ED 42
SUBtract Register Pair BC (006EH) from Register Pair HL (HMEM$) with the C FLAG: the new HMEM$, below the resident part.
520F
LD (4411H),HL 22 11 44
Store Register Pair HL, the new HMEM$, into 4411H-4412H, so that no later program or driver takes the memory of the resident part.
5212
INC HL 23
INCrement Register Pair HL by 1: the first byte above the new HMEM$, where the resident part goes.
5213
PUSH HL E5
Save Register Pair HL, the address of the resident part, to the top of the stack for the hook below.
5214
LD BC,52E0H 01 E0 52
Load Register Pair BC with 52E0H, the address of the resident part in TRAP/CMD as loaded.
5217
OR A B7
OR Register A against itself, to clear the C FLAG for the SBC below.
5218
SBC HL,BC ED 42
SUBtract Register Pair BC (52E0H) from Register Pair HL with the C FLAG: the distance from 52E0H to the new place.
521A
LD C,L 4D
Load Register C with Register L, the low byte of the distance the resident part moves.
521B
LD B,H 44
Load Register B with Register H, the high byte: Register Pair BC = the distance the resident part moves.
521C
LD HL,(5309H) 2A 09 53
Load Register Pair HL with 5331H from 5309H-530AH, the operand of LD HL at 5308H, the address of the prompt.
521F
ADD HL,BC 09
ADD Register Pair BC (the distance) to Register Pair HL: the address of the prompt in the moved part.
5220
LD (5309H),HL 22 09 53
Store Register Pair HL, the moved address of the prompt, into 5309H-530AH, the operand of LD HL at 5308H.
5223
LD HL,(530FH) 2A 0F 53
Load Register Pair HL with 534CH from 530FH-5310H, the operand of LD HL at 530EH, the address of the buffer for the reply.
5226
ADD HL,BC 09
ADD Register Pair BC (the distance) to Register Pair HL: the address of the buffer in the moved part, which is never stored.
5227
LD (530FH),BC ED 43 0F 53
Store Register Pair BC, the distance itself, into 530FH-5310H: a slip for Register Pair HL, so the moved part keeps its reply at the address the distance gives.
522B
POP DE D1
Restore Register Pair DE, the address of the resident part, from the top of the stack.
522C
LD HL,(4489H) 2A 89 44
Load Register Pair HL with the operand of DISKIO%'s JP from 4489H-448AH: the disk routine DISKIO% goes to now (46A4H, or an earlier hook).
522F
LD (52E2H),HL 22 E2 52
Store Register Pair HL into 52E2H-52E3H, the operand of the CALL at 52E1H, so that the resident part calls the old disk routine.
5232
LD (4489H),DE ED 53 89 44
Store Register Pair DE, the address of the resident part, into 4489H-448AH: from now on DISKIO% jumps to TRAP.
5236
LD HL,52E0H 21 E0 52
Point Register Pair HL to 52E0H, the start of the resident part as loaded, the source of the copy.
5239
LD BC,006EH 01 6E 00
Load Register Pair BC with 006EH, the 110 bytes of the resident part, the count of the copy.
523C
LDIR ED B0
Copy the resident part: Register Pair BC bytes from Register Pair HL to Register Pair DE, the place above the new HMEM$ (LDIR).
523E
LD HL,52CBH 21 CB 52
Point Register Pair HL to 52CBH, the text Driver installed at, shown before the address of the resident part.
5241
GOSUB to 4467H, DSPLY@, to display the text at Register Pair HL up to its 03H.
5244
LD HL,(4489H) 2A 89 44
Load Register Pair HL with the address of the resident part from 4489H-448AH, the operand of DISKIO%'s JP.
5247
GOSUB to 5250H to display Register Pair HL as four hexadecimal digits and the letter H.
524A
LD A,0DH 3E 0D
Load Register A with 0DH, a carriage return, to end the line after the address.
524C
GOSUB to 0033H, the ROM's display of the character in Register A, the carriage return.
524F
RET C9
RETurn to the DOS, which called TRAP from the command level, with the trap of disk errors in place.

5250H - Show a Word in Hexadecimal

Displays Register Pair HL as four hexadecimal digits followed by H, through the ROM's 0033H.

5250
LD A,H 7C
Load Register A with Register H, the high byte of the word in Register Pair HL.
5251
GOSUB to 525DH to display Register A as two hexadecimal digits, the high byte of the word.
5254
LD A,L 7D
Load Register A with Register L, the low byte of the word in Register Pair HL.
5255
GOSUB to 525DH to display Register A as two hexadecimal digits, the low byte of the word.
5258
LD A,48H 3E 48
Load Register A with 48H, the letter H, which follows the four digits.
525A
JUMP to 0033H, the ROM's display of the character in Register A, which returns to the caller.
525D
PUSH AF F5
Save Register Pair AF, the byte in Register A, to the top of the stack for its low digit.
525E
RRA 1F
Rotate Register A right through the C FLAG (RRA), the first of four moves of the high digit to bits 0-3.
525F
RRA 1F
Rotate Register A right through the C FLAG (RRA), the second of four moves of the high digit.
5260
RRA 1F
Rotate Register A right through the C FLAG (RRA), the third of four moves of the high digit.
5261
RRA 1F
Rotate Register A right through the C FLAG (RRA): the high digit is in bits 0-3, the rest is masked at 5266H.
5262
GOSUB to 5266H to display the digit in bits 0-3 of Register A, the high digit.
5265
POP AF F1
Restore Register Pair AF, the byte in Register A, from the top of the stack, and fall into 5266H for the low digit.
5266
AND 0FH E6 0F
AND Register A with 0FH to keep bits 0-3, one hexadecimal digit.
5268
ADD A,90H C6 90
ADD 90H to Register A: 90H-99H for the digits 0-9, 9AH-9FH for A-F, the first step to an ASCII character.
526A
DAA 27
Decimal Adjust Register A (DAA): 90H-99H stay with the C FLAG clear, 9AH-9FH become 00H-05H with the C FLAG set.
526B
ADC A,40H CE 40
ADD 40H and the C FLAG to Register A (ADC): D0H-D9H for the digits 0-9, 41H-46H for A-F.
526D
DAA 27
Decimal Adjust Register A (DAA): D0H-D9H become 30H-39H, the characters 0-9, while 41H-46H, the letters A-F, stay.
526E
JUMP to 0033H, the ROM's display of the character in Register A, which returns to the caller.
5271-52CA
DEFM "TRAP - DOSPLUS Disk error trapper - 3.50" / DEFB 0AH / DEFM "(c) Copyright 1983, Micro-Systems Software Inc." / DEFB 0AH,0DH 54 52 41 50 20 2D 20 44 4F 53 50 4C 55 53 20 44 69 73 6B 20 65 72 72 6F 72 20 74 72 61 70 70 65 72 20 2D 20 33 2E 35 30 0A 28 63 29 20 43 6F 70 79 72 69 67 68 74 20 31 39 38 33 2C 20 4D 69 63 72 6F 2D 53 79 73 74 65 6D 73 20 53 6F 66 74 77 61 72 65 20 49 6E 63 2E 0A 0D
The heading (5200H): TRAP - DOSPLUS Disk error trapper - 3.50, a line feed, the copyright line, a line feed and the 0DH at which DSPLY@ stops.
52CB-52DF
DEFM "Driver installed at " / DEFB 03H 44 72 69 76 65 72 20 69 6E 73 74 61 6C 6C 65 64 20 61 74 20 03
The text shown after the copy (523EH), followed by the address of the resident part in hexadecimal (5247H).

52E0H - The Resident Part: DISKIO%

110 bytes (52E0H-534DH) copied above the new HMEM$ at 523CH; DISKIO% (4488H) jumps here with Register A the function, Register C the drive, Register D the cylinder, Register E the sector and Register Pair HL the buffer. The old disk routine does the function. An error of a function 03H-09H, other than the code 06H, shows the message of the error and the prompt Abort,Cont,Retry,Ignore ?: A or BREAK ends through ABORT@, C returns the error, I returns 00H with the Z FLAG as if the function had worked, and any other reply does the function again. The addresses on this page are those of TRAP/CMD as loaded.

52E0
PUSH AF F5
Save Register Pair AF, the function in Register A, to the top of the stack for a retry or the prompt.
52E1
GOSUB to the old disk routine, the operand 52E2H-52E3H set at 522FH (0000H as loaded), to do the function in Register A on drive Register C.
52E4
If the NZ FLAG is set (the old routine returned an error code in Register A), JUMP to 52E9H.
52E6
INC SP 33
INCrement the Stack Pointer by 1, the first of two, to drop the function saved at 52E0H.
52E7
INC SP 33
INCrement the Stack Pointer by 1 again: the Register Pair AF saved at 52E0H is dropped.
52E8
RET C9
RETurn to the caller of DISKIO% with Register A = 00H and the Z FLAG: the function was done.
52E9
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: Register H = the function saved at 52E0H, and the caller's Register Pair HL goes to the stack.
52EA
PUSH AF F5
Save Register Pair AF, the error code in Register A with the NZ FLAG, to the top of the stack.
52EB
CP 06H FE 06
Compare Register A against 06H, the code of a sector read with the data address mark of the directory: not an error to trap.
52ED
If the Z FLAG is set (code 06H), JUMP to 52F4H to return the code to the caller as it is.
52EF
LD A,H 7C
Load Register A with Register H, the function of the call that failed.
52F0
CP 03H FE 03
Compare Register A against 03H: the NC FLAG for the functions 03H-09H, the reads, writes, verify and format of sectors and tracks.
52F2
If the NC FLAG is set (DREAD, DVERF, DWRITE, SREAD, SWRITE, DWRITA or DFORMT), JUMP to 52F7H to trap the error.
52F4
POP AF F1
Restore Register Pair AF, the error code in Register A with the NZ FLAG, from the top of the stack.
52F5
POP HL E1
Restore Register Pair HL, the caller's, from the top of the stack, as it was before DISKIO%.
52F6
RET C9
RETurn to the caller of DISKIO% with the error code in Register A and the NZ FLAG, as the old routine gave it.
52F7
POP AF F1
Restore Register Pair AF, the error code in Register A, from the top of the stack.
52F8
PUSH AF F5
Save Register Pair AF, the error code, to the top of the stack again, for the return of a Continue.
52F9
PUSH BC C5
Save Register Pair BC, the caller's drive in Register C, to the top of the stack.
52FA
PUSH DE D5
Save Register Pair DE, the caller's cylinder and sector, to the top of the stack.
52FB
PUSH HL E5
Save Register Pair HL, the function in Register H, to the top of the stack for a retry.
52FC
PUSH AF F5
Save Register Pair AF, the error code in Register A, to the top of the stack for ERROR@ below.
52FD
LD A,0DH 3E 0D
Load Register A with 0DH, a carriage return, to start the message on a new line.
52FF
GOSUB to 0033H, the ROM's display of the character in Register A, the carriage return.
5302
POP AF F1
Restore Register Pair AF, the error code in Register A, from the top of the stack.
5303
OR C0H F6 C0
OR Register A with C0H: bit 7 makes ERROR@ return, and bit 6 shows the message without the frame of asterisks.
5305
GOSUB to 4409H, ERROR@, to display the message of the error code in Register A and return.
5308
LD HL,5331H 21 31 53
Point Register Pair HL to 5331H, the prompt Abort,Cont,Retry,Ignore ? (the operand that 5220H sets for the moved part).
530B
GOSUB to 4467H, DSPLY@, to display the prompt at Register Pair HL up to its 03H.
530E
LD HL,534CH 21 4C 53
Point Register Pair HL to 534CH, the buffer for the reply; in the moved part the operand is the distance that 5227H stores.
5311
LD B,01H 06 01
Load Register B with 01H, the most characters the reply may have.
5313
GOSUB to 0040H, the ROM's line input of up to Register B characters into the buffer at Register Pair HL; the C FLAG for BREAK.
5316
LD A,(HL) 7E
Load Register A with the first character of the reply at Register Pair HL; the load leaves the C FLAG of 0040H as it was.
5317
If the C FLAG is set (BREAK), JUMP to 4030H, ABORT@, which ends the program that called DISKIO%.
531A
RES 5,A CB AF
Reset bit 5 of Register A, which makes a lower case letter upper case.
531C
CP 41H FE 41
Compare Register A against 41H, the letter A, the reply Abort.
531E
If the Z FLAG is set (A), JUMP to 4030H, ABORT@, which ends the program and goes back to the DOS.
5321
POP HL E1
Restore Register Pair HL, the function in Register H, from the top of the stack.
5322
POP DE D1
Restore Register Pair DE, the caller's cylinder and sector, from the top of the stack.
5323
POP BC C1
Restore Register Pair BC, the caller's drive in Register C, from the top of the stack.
5324
CP 43H FE 43
Compare Register A against 43H, the letter C, the reply Continue.
5326
If the Z FLAG is set (C), JUMP to 52F4H to return the error code to the caller of DISKIO%.
5328
CP 49H FE 49
Compare Register A against 49H, the letter I, the reply Ignore.
532A
LD A,H 7C
Load Register A with Register H, the function, for a retry; the load leaves the flags of the compare as they were.
532B
POP HL E1
Restore Register Pair HL from the top of the stack: the error code saved at 52F8H, which is dropped.
532C
POP HL E1
Restore Register Pair HL, the caller's, from the top of the stack, as it was before DISKIO%.
532D
If the NZ FLAG is set (not I: R or any other reply), JUMP to 52E0H to do the function in Register A again.
532F
XOR A AF
Set Register A to 00H by XORing it with itself, with the Z FLAG: the error is ignored.
5330
RET C9
RETurn to the caller of DISKIO% with Register A = 00H and the Z FLAG, as if the function had worked.
5331-534B
DEFM "Abort,Cont,Retry,Ignore ? " / DEFB 03H 41 62 6F 72 74 2C 43 6F 6E 74 2C 52 65 74 72 79 2C 49 67 6E 6F 72 65 20 3F 20 03
The prompt after the message of a disk error (5308H), ended by the 03H at which DSPLY@ stops.
534C-534D
DEFS 2
The buffer for the reply (530EH): the character and its 0DH. Copied with the resident part though not loaded; the moved part does not use it (5227H).