LDOS 5.3.1 for the Model III - HITAPE/CMD Disassembled

Page Customization

Introduction/Summary

LDOS 5.3.1 HITAPE/CMD Disassembly - The 1500 Baud Cassette Interrupts (Model III)

HITAPE/CMD gives the 1500 baud cassette back to the ROM under LDOS. The ROM of the Model III reads a 1500 baud tape with the cassette's edge interrupts (bits 0 and 1 of the interrupt latch, port E0H), whose service routines are in the ROM (3365H and 3369H); LDOS 5.3.1 takes the RST 38H vector at 4012H for its own interrupt service (44A5H), which has no place for them. The manual (M-40-060) says so: the 1500 baud cassette loading was left out of the resident system for space, and HITAPE adds a routine to the DOS so that BASIC and CMDFILE can use 1500 baud tapes; without it a 1500 baud load does not load. The command is HITAPE; the parameter table also knows HITAPE (OFF), which the manual does not name.

The file is a load module of 456 bytes: a record of type 1FH with the text Copyright 1991 MISOSYS, Inc., All rights reserved, two load blocks for 5200H-5388H (393 bytes) and the transfer address record for 5200H. HITAPE copies a module of 28 bytes (536DH-5388H) to the top of the free memory, lowers HIGH$ below it, and points the RST 38H vector at it. The module sends the two cassette interrupts to the ROM and every other interrupt on to SYS0/SYS's service, entering it after its first three instructions with the stack as they would have left it. The manual adds that a SYSTEM (SYSGEN) done while HITAPE is in saves it with the configuration; the list of SYSGEN in SYS7/SYS holds both HIGH$ (4411H) and the vector at 4013H.

What HITAPE Does

StepWhat Happens
The banner and the parameterThe Stack Pointer is kept for the end, the banner is displayed and @PARAM reads OFF (5200H); a bad parameter gives error 2CH.
HITAPEThe module $HT is looked for above HIGH$ through SYS10/SYS (request BCH, 5296H). Found: the vector is pointed at it again. Not found: at LDOS command level only (@EXIT not taken over, the command not from a program; else Can't -- Valid only at LDOS Command level!), the module gets the HIGH$ and the vector of the moment and is copied below HIGH$, HIGH$ goes down by 28, and 4013H points at it (523CH).
HITAPE (OFF)The module is looked for (Module is not resident! when it is not in memory); when it is the newest, HIGH$ goes back to its link word. The vector is then stored from the wrong word (5215H).
The endRegister Pair HL = 0000H after success, FFFFH after an error; an error during a JCL job ends at @ABORT (527BH).

About This Page

The Model I diskette of LDOS 5.3.1 has no HITAPE/CMD (the Model I has no 1500 baud cassette), so this page is written from the bytes of the Model III file alone. Every byte of the file is shown at its address; the module is shown where it is in the file, 536DH-5388H, and runs at HIGH$ + 1 after the copy. Found in the code: HITAPE (OFF) computes the address of the saved vector from Register Pair HL after the SBC at 522AH has turned it into the module less HIGH$ less 1, so it reads 0008H-0009H of the ROM for the newest module and stores 00C3H as the RST 38H vector (5232H-5239H, 5278H); running HITAPE a second time points the vector at the module again (5242H), past any interrupt routine installed after it.

Memory Map

Load Blocks in File Order

The two load blocks of the file, after the copyright record: 393 bytes, 5200H-5388H. The transfer address is 5200H.

AddressContents
5200H-52FFH256 bytes
5300H-5388H137 bytes

Sections of the Disassembly

AddressContents
5200HEntry: the Banner and the Parameter
5215HHITAPE (OFF): Take the Module Out
523CHInstall the Module
527BHThe End
528DHThe Error Exits and the Module Search
52B6HThe Texts and the Parameter Table
536DHThe Module: the Cassette Interrupts First (Copied below HIGH$)

Memory HITAPE/CMD Uses

AddressContents
3365H, 3369HROM: the routines of the cassette's rising and falling edge interrupts of the 1500 baud read (537BH, 537FH).
402DH, 4065HThe first byte of @EXIT, and during a JCL job the copy of it that SYS11/SYS keeps: C3H when a program has taken @EXIT over (5249H, 524EH).
4012H-4014HThe RST 38H vector, JP 44A5H: 4013H-4014H is read (5265H) and pointed at the module (5278H).
4030H, 4409H, 428AH, 4454H, 4467H@ABORT, @ERROR, @LOGOT, @PARAM and @DSPLY.
4411H-4412HHIGH$: lowered by 28 for the module (5274H), given back by HITAPE (OFF) (522EH).
442BHSFLAG$: bit 5 a JCL job runs (5244H, 5284H).
44A9HSYS0/SYS's interrupt service after its PUSH HL, PUSH AF and IN A,(E0H): the module goes on there (5386H).
4758HThe command interpreter's status byte: bit 1, the command came from a program (5256H).
RST 28H, BCHSYS10/SYS: look for a module above HIGH$ by name (52A3H).

Variables

The entry points of HITAPE/CMD, then the data of the file, the operands it changes, and the cells outside the file that it uses, by address.

Entry Points

AddressContents
5200HThe start of HITAPE/CMD, the transfer address of the file.
5296HLook for the module $HT: the Z FLAG, Register Pair HL = the module, Register Pair DE = its link word.
5377HThe code of the module (its +0AH), entered through the RST 38H vector after the copy.

Data in the File

Address
Size
Contents
52B6H
1 byte
DEFB 0AH
52B6H: 0AH, a new line: the start of the banner displayed by 5208H.
52B7H-52E8H
50 bytes
DEFM "HITAPE - 1500 baud cassette driver - Version 5.3.1"
52B7H-52E8H: the name of the program, what it is and its version.
52E9H
1 byte
DEFB 0AH
52E9H: 0AH, a new line: the copyright goes on the next line.
52EAH-531AH
49 bytes
DEFM "Copyright 1991 MISOSYS, Inc., All rights reserved"
52EAH-531AH: the copyright line, the same text as the copyright record of the file.
531BH-531CH
2 bytes
DEFB 0AH, 0DH
531BH-531CH: 0AH, a new line, and 0DH, the end of the banner.
531DH-5346H
42 bytes
DEFM "Can't -- Valid only at LDOS Command level!"
531DH-5346H: the text of 52AAH, displayed by @LOGOT when HITAPE is run from a program or while @EXIT is taken over.
5347H
1 byte
DEFB 0DH
5347H: 0DH, the end of the line and of the text.
5348H-535EH
23 bytes
DEFM "Module is not resident!"
5348H-535EH: the text of 52A6H, for HITAPE (OFF) when no module $HT is in memory.
535FH
1 byte
DEFB 0DH
535FH: 0DH, the end of the line and of the text.
5360H-5362H
3 bytes
DEFM "$HT"
5360H-5362H: $HT, the name of the module that 521CH and 523CH give to the search; the same as in the module's header (5372H).
5363H
1 byte
DEFB 00H
5363H: 00H, a character below 21H: the end of the name for SYS10/SYS's search.
5364H-536BH
8 bytes
DEFM "OFF " / DEFW 5216H
5364H-536BH: OFF, padded with spaces to 6 characters, and 5216H, the operand of LD HL,0000H at 5215H, where @PARAM stores its value.
536CH
1 byte
DEFB 00H
536CH: 00H, the end of the table: @PARAM stops here.
536FH-5370H
2 bytes
DEFW 0000H
536FH-5370H, the module +02H-+03H: the link word, 0000H in the file; 5261H stores HIGH$ before the copy: SYS10/SYS's search goes on from it, and HITAPE (OFF) gives it back to HIGH$.
5371H
1 byte
DEFB 03H
5371H, the module +04H: 03H, the length of the name in bits 3-0.
5372H-5374H
3 bytes
DEFM "$HT"
5372H-5374H, the module +05H-+07H: the name of the module, $HT, which 5360H looks for.
5375H-5376H
2 bytes
DEFW 0000H
5375H-5376H, the module +08H-+09H: the vector found at 4013H-4014H, 0000H in the file; 5268H stores it before the copy. The code jumps to 44A9H itself and does not use it.

Operands Changed While It Runs

Address
Size
Contents
5216H-5217H
2 bytes
The operand of LD HL,0000H at 5215H: OFF, FFFFH when @PARAM found it.
527FH-5280H
2 bytes
The operand of LD SP,0000H at 527EH: the Stack Pointer as LDOS left it (5200H).
536FH-5370H, 5375H-5376H
2 bytes each
The module's link word (5261H) and saved vector (5268H), stored before the copy.

Cells Outside the File That HITAPE/CMD Uses

Address
Size
Contents
HIGH$ - 27 to HIGH$
28 bytes
The copy of the module at the top of the free memory, HIGH$ as it was before HITAPE; HIGH$ is then 28 lower.

Disassembly

5200H - Entry: the Banner and the Parameter

LDOS Ready loads HITAPE/CMD at 5200H-5388H and jumps to 5200H, the transfer address, with Register Pair HL at the rest of the command line after the word HITAPE. The command is HITAPE, or HITAPE (OFF) to take the module out again (the parameter table at 5364H; the manual, M-40-060, names only HITAPE). The Stack Pointer is kept in the operand of LD SP at 527EH, so every exit can leave from a clean stack; the banner is displayed and @PARAM reads the parameter.

5200
LD (527FH),SP ED 73 7F 52
Store the Stack Pointer at 527FH-5280H, the operand of LD SP,0000H at 527EH: every exit of the program goes through 527EH with the stack as LDOS left it.
5204
PUSH HL E5
Save Register Pair HL (the pointer to the command line after HITAPE) to the stack across the display of the banner.
5205
LD HL,52B6H 21 B6 52
Point Register Pair HL to 52B6H, the banner: a new line, HITAPE - 1500 baud cassette driver - Version 5.3.1, the copyright line and 0DH.
5208
GOSUB to 4467H, @DSPLY, to display the text at Register Pair HL (52B6H) up to its 0DH.
520B
POP HL E1
Restore Register Pair HL from the stack: the pointer to the command line, for @PARAM.
520C
LD DE,5364H 11 64 53
Point Register Pair DE to 5364H, the table of the parameters: OFF and the address of its operand, 5216H.
520F
GOSUB to 4454H, @PARAM, to read the parameters at Register Pair HL against the table at Register Pair DE (5364H): OFF given stores FFFFH at 5216H. The Z FLAG on success.
5212
If the NZ FLAG is set (an unknown parameter or a bad value), JUMP to 528DH to give error 2CH, Parameter error.

5215H - HITAPE (OFF): Take the Module Out

With OFF the module $HT is looked for above HIGH$ (5296H). Not found: Module is not resident!. Found: when it is the newest module (it starts at HIGH$ + 1), HIGH$ goes back to the link word of its header, the HIGH$ before it was installed. Then the RST 38H vector at 4013H should get back the address the module saved at its +08H-+09H; but the code reads that word from Register Pair HL + 8 after the SBC at 522AH has changed Register Pair HL to the module less HIGH$ less 1: for the newest module from 0008H-0009H in the ROM (C3H 00H), so the vector becomes JP 00C3H and the next interrupt does not reach SYS0/SYS's service routine.

5215
LD HL,0000H 21 00 00
Load Register Pair HL with the OFF parameter: the operand 5216H-5217H, 0000H in the file, FFFFH when @PARAM found OFF.
5218
LD A,H 7C
Copy Register H (the high byte of the OFF parameter) into Register A.
5219
OR L B5
OR Register L (the low byte) into Register A: the Z FLAG is set when OFF was not given.
521A
If the Z FLAG is set (no OFF), JUMP to 523CH to install the module.
521C
LD DE,5360H 11 60 53
Point Register Pair DE to 5360H, the name $HT ended by 00H, the name of the module in its header (5372H).
521F
GOSUB to 5296H to look for the module named at Register Pair DE (5360H) above HIGH$: the Z FLAG and Register Pair HL = the module when it is found, Register Pair DE = its link word.
5222
If the NZ FLAG is set (the module is not in memory), JUMP to 52A6H to display Module is not resident! and end with an error.
5225
LD BC,(4411H) ED 4B 11 44
Fetch HIGH$ from 4411H-4412H into Register Pair BC.
5229
INC BC 03
INCrement Register Pair BC: HIGH$ + 1, where the newest module starts.
522A
SBC HL,BC ED 42
SUBtract Register Pair BC (HIGH$ + 1) and the CARRY FLAG (clear: the search ends with XOR A) from Register Pair HL (the module): the Z FLAG when the module is the newest. Register Pair HL keeps the difference, 0000H in that case.
522C
If the NZ FLAG is set (another module was put below it later), JUMP to 5232H: HIGH$ stays, the memory of the module cannot be given back.
522E
LD (4411H),DE ED 53 11 44
Store Register Pair DE (the link word of the module, the HIGH$ before it was installed) at 4411H-4412H, HIGH$: the memory of the module is free again.
5232
LD DE,0008H 11 08 00
Load Register Pair DE with 0008H, the offset of the saved vector in the module's header (5375H in the file).
5235
ADD HL,DE 19
ADD Register Pair DE (8) to Register Pair HL. Register Pair HL holds the difference left by the SBC at 522AH, not the module, so it becomes 0008H for the newest module: the word read below is the ROM's 0008H-0009H.
5236
LD A,(HL) 7E
Fetch the byte at Register Pair HL into Register A: meant as the low byte of the saved vector (C3H when Register Pair HL is 0008H).
5237
INC HL 23
INCrement Register Pair HL to the next byte, meant as the high byte of the saved vector.
5238
LD H,(HL) 66
Fetch the byte at Register Pair HL into Register H (00H at 0009H).
5239
LD L,A 6F
Copy Register A (the low byte) into Register L: Register Pair HL = the word read, 00C3H for the newest module.
523A
JUMP to 5278H to store Register Pair HL at 4013H, the address of the RST 38H vector, and end.

523CH - Install the Module

The module is looked for first: when $HT is already in memory, the RST 38H vector is simply pointed at it again. Else HITAPE must run at LDOS command level: @EXIT (402DH, or during a JCL job the copy SYS11/SYS keeps at 4065H) must not be taken over by a running program (a JP, C3H, there), and the command must not come from a program (bit 1 of 4758H); otherwise Can't -- Valid only at LDOS Command level!. Then the 28 byte module 536DH-5388H gets the HIGH$ (its link word) and the RST 38H vector (its +08H-+09H) of the moment and is copied to the top of the free memory, just below the old HIGH$; HIGH$ goes down by 28 and the vector at 4013H points at the module.

523C
LD DE,5360H 11 60 53
Point Register Pair DE to 5360H, the name $HT ended by 00H.
523F
GOSUB to 5296H to look for the module named at Register Pair DE (5360H) above HIGH$: the Z FLAG and Register Pair HL = the module when it is found.
5242
If the Z FLAG is set (HITAPE was installed before), JUMP to 5278H to store the module's address in Register Pair HL at 4013H: the vector points at it again.
5244
LD A,(442BH) 3A 2B 44
Fetch SFLAG$ from 442BH into Register A: bit 5 is set while a JCL job runs.
5247
BIT 5,A CB 6F
Test bit 5 of Register A (SFLAG$): the NZ FLAG during a JCL job. The LD A below does not change the flags.
5249
LD A,(402DH) 3A 2D 40
Fetch the first byte of @EXIT from 402DH into Register A: 3EH, the LD A of LDOS, or C3H when a running program has put a JP there.
524C
If the Z FLAG is set (no JCL job), JUMP to 5251H with the byte of 402DH.
524E
LD A,(4065H) 3A 65 40
A JCL job runs: fetch the first byte of @EXIT as it was before the job from 4065H, where SYS11/SYS saved 402DH-4032H, into Register A.
5251
CP C3H FE C3
Compare Register A (the first byte of @EXIT) against C3H, the opcode of JP.
5253
If the Z FLAG is set (a program has taken over @EXIT), JUMP to 52AAH, inside the LD IX at 52A9H, to display Can't -- Valid only at LDOS Command level!.
5256
LD A,(4758H) 3A 58 47
Fetch the command interpreter's status byte from 4758H into Register A.
5259
BIT 1,A CB 4F
Test bit 1 of Register A: set when the command line came from a program (SYS1/SYS's function 20H).
525B
If the NZ FLAG is set (the command came from a program), JUMP to 52AAH to display Can't -- Valid only at LDOS Command level!.
525D
LD DE,(4411H) ED 5B 11 44
Fetch HIGH$ from 4411H-4412H into Register Pair DE: the last byte of the free memory, where the copy of the module will end.
5261
LD (536FH),DE ED 53 6F 53
Store Register Pair DE (HIGH$) at 536FH-5370H, the link word of the module's header: SYS10/SYS's search goes on from it, and HITAPE (OFF) puts it back into HIGH$.
5265
LD HL,(4013H) 2A 13 40
Fetch the address of the RST 38H vector from 4013H-4014H into Register Pair HL (the operand of the JP at 4012H: 44A5H, the interrupt service of SYS0/SYS, or a module installed before).
5268
LD (5375H),HL 22 75 53
Store Register Pair HL (the vector) at 5375H-5376H, +08H-+09H of the module's header: the module chains to the service at 44A9H, and the word is kept for HITAPE (OFF).
526B
LD HL,5388H 21 88 53
Point Register Pair HL to 5388H, the last byte of the module, the source of the copy below.
526E
LD BC,001CH 01 1C 00
Load Register Pair BC with 001CH, the 28 bytes of the module 536DH-5388H.
5271
LDDR ED B8
Copy the module from Register Pair HL (5388H down) to Register Pair DE (HIGH$ down), Register Pair BC the count (LDDR): it ends at HIGH$ and starts 27 bytes below. Register Pair DE comes out one below its first byte.
5273
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the byte below the copy, the new HIGH$.
5274
LD (4411H),HL 22 11 44
Store Register Pair HL (the new HIGH$, 28 below the old one) at 4411H-4412H, HIGH$: the module is above it, out of the way of programs.
5277
INC HL 23
INCrement Register Pair HL to the first byte of the copy: the module's start, HIGH$ + 1.
5278
LD (4013H),HL 22 13 40
Store Register Pair HL at 4013H-4014H, the operand of the JP at 4012H that ROM 0038H jumps to: every maskable interrupt now enters the module (or, from 523AH, the word read for HITAPE (OFF)).

527BH - The End

Every exit comes through 527EH with Register Pair HL as the return code: 0000H for success, FFFFH after an error. The Stack Pointer is put back as LDOS left it (5200H); then success returns to LDOS, and an error does too unless a JCL job runs, which is ended at @ABORT.

527B
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, the return code of a program that ended without an error.
527E
LD SP,0000H 31 00 00
Load the Stack Pointer with the value saved at 5200H: the operand 527FH-5280H, 0000H in the file. 52B3H comes here with Register Pair HL = FFFFH.
5281
LD A,H 7C
Copy Register H (the high byte of the return code) into Register A.
5282
OR L B5
OR Register L (the low byte) into Register A: the Z FLAG for the return code 0000H.
5283
RET Z C8
If the Z FLAG is set (no error), RETurn to LDOS with Register Pair HL = 0000H.
5284
LD A,(442BH) 3A 2B 44
Fetch SFLAG$ from 442BH into Register A: bit 5 is set while a JCL job runs.
5287
BIT 5,A CB 6F
Test bit 5 of Register A (SFLAG$): the Z FLAG when no JCL job runs.
5289
RET Z C8
If the Z FLAG is set (no JCL job), RETurn to LDOS with Register Pair HL = FFFFH, the return code of an error.
528A
JUMP to 4030H, @ABORT: the JCL job is ended after the error.

528DH - The Error Exits and the Module Search

528DH gives error 2CH through @ERROR, which returns (bit 7 set); 52A6H displays Module is not resident! and 52AAH (inside the LD IX at 52A9H) Can't -- Valid only at LDOS Command level!, both through @LOGOT; all three end at 527EH with Register Pair HL = FFFFH. 5296H looks for the module through SYS10/SYS (request BCH) and returns its link word in Register Pair DE.

528D
LD A,2CH 3E 2C
Load Register A with 2CH, error 2CH, Parameter error.
528F
OR C0H F6 C0
OR C0H into Register A (ECH): bit 7, @ERROR returns to the caller, and bit 6, the short message.
5291
GOSUB to 4409H, @ERROR, to display the short message of error 2CH; with bit 7 set it returns here.
5294
JUMP to 52B0H to end with Register Pair HL = FFFFH.
5296
GOSUB to 52A3H, the request BCH: SYS10/SYS looks for the module named at Register Pair DE above HIGH$ and returns to 5299H with the Z FLAG and Register Pair HL = the module when it is found.
5299
PUSH HL E5
Save Register Pair HL (the module, when found) to the stack, to move it into Index Register IX.
529A
POP IX DD E1
Restore it into Index Register IX: Index Register IX = the module's header.
529C
LD E,(IX+02H) DD 5E 02
Fetch +02H of the module's header at Index Register IX into Register E: the low byte of its link word.
529F
LD D,(IX+03H) DD 56 03
Fetch +03H of the module's header at Index Register IX into Register D: Register Pair DE = the link word, the HIGH$ before the module was installed.
52A2
RET C9
RETurn to the caller with the flags of the search: the Z FLAG when the module was found (the LD and POP above leave the flags alone).
52A3
LD A,BCH 3E BC
Load Register A with BCH, the request for SYS10/SYS function 30H: look for a module above HIGH$ by the name at Register Pair DE.
52A5
RST 28H EF
RST 28H with Register A = BCH: the supervisor's dispatcher drops the return address the RST pushed, so SYS10/SYS returns to the caller of 52A3H (5299H).
52A6
LD HL,5348H 21 48 53
Point Register Pair HL to 5348H, the text Module is not resident! ended by 0DH.
52A9
LD IX,531DH DD 21 1D 53
Load Index Register IX with 531DH. Nothing uses Index Register IX here: the DD byte only lets 52A6H pass over 21H 1DH 53H at 52AAH-52ACH, which the jumps from 5253H and 525BH take as LD HL,531DH, the text Can't -- Valid only at LDOS Command level!.
52AD
GOSUB to 428AH, @LOGOT, to display the text at Register Pair HL (5348H or 531DH) and write it to the job log.
52B0
LD HL,FFFFH 21 FF FF
Load Register Pair HL with FFFFH, the return code of an error. 5294H comes here after @ERROR.
52B3
JUMP to 527EH to put back the Stack Pointer and end with the return code FFFFH.

52B6H - The Texts and the Parameter Table

The banner, the two messages, the name of the module for the search, and the table @PARAM reads.

52B6
DEFB 0AH 0A
52B6H: 0AH, a new line: the start of the banner displayed by 5208H.
52B7-52E8
DEFM "HITAPE - 1500 baud cassette driver - Version 5.3.1" 48 49 54 41 50 45 20 2D 20 31 35 30 30 20 62 61 75 64 20 63 61 73 73 65 74 74 65 20 64 72 69 76 65 72 20 2D 20 56 65 72 73 69 6F 6E 20 35 2E 33 2E 31
52B7H-52E8H: the name of the program, what it is and its version.
52E9
DEFB 0AH 0A
52E9H: 0AH, a new line: the copyright goes on the next line.
52EA-531A
DEFM "Copyright 1991 MISOSYS, Inc., All rights reserved" 43 6F 70 79 72 69 67 68 74 20 31 39 39 31 20 4D 49 53 4F 53 59 53 2C 20 49 6E 63 2E 2C 20 41 6C 6C 20 72 69 67 68 74 73 20 72 65 73 65 72 76 65 64
52EAH-531AH: the copyright line, the same text as the copyright record of the file.
531B-531C
DEFB 0AH, 0DH 0A 0D
531BH-531CH: 0AH, a new line, and 0DH, the end of the banner.
531D-5346
DEFM "Can't -- Valid only at LDOS Command level!" 43 61 6E 27 74 20 2D 2D 20 56 61 6C 69 64 20 6F 6E 6C 79 20 61 74 20 4C 44 4F 53 20 43 6F 6D 6D 61 6E 64 20 6C 65 76 65 6C 21
531DH-5346H: the text of 52AAH, displayed by @LOGOT when HITAPE is run from a program or while @EXIT is taken over.
5347
DEFB 0DH 0D
5347H: 0DH, the end of the line and of the text.
5348-535E
DEFM "Module is not resident!" 4D 6F 64 75 6C 65 20 69 73 20 6E 6F 74 20 72 65 73 69 64 65 6E 74 21
5348H-535EH: the text of 52A6H, for HITAPE (OFF) when no module $HT is in memory.
535F
DEFB 0DH 0D
535FH: 0DH, the end of the line and of the text.
5360-5362
DEFM "$HT" 24 48 54
5360H-5362H: $HT, the name of the module that 521CH and 523CH give to the search; the same as in the module's header (5372H).
5363
DEFB 00H 00
5363H: 00H, a character below 21H: the end of the name for SYS10/SYS's search.
5364-536B
DEFM "OFF " / DEFW 5216H 4F 46 46 20 20 20 16 52
5364H-536BH: OFF, padded with spaces to 6 characters, and 5216H, the operand of LD HL,0000H at 5215H, where @PARAM stores its value.
536C
DEFB 00H 00
536CH: 00H, the end of the table: @PARAM stops here.

536DH - The Module: the Cassette Interrupts First (Copied below HIGH$)

536DH-5388H are 28 bytes copied to the top of the free memory (5271H) and entered from there through the RST 38H vector at 4012H for every maskable interrupt. The header: a JR over it, the link word (the HIGH$ before the module), 03H the length of the name, the name $HT, and the vector the module found at 4013H. The code reads the interrupt latch, port E0H (a bit is 0 while its interrupt is pending): bit 0, the cassette's rising edge, goes to the ROM's routine at 3365H and bit 1, the falling edge, to 3369H, the routines of the ROM's 1500 baud cassette read; any other interrupt goes on into SYS0/SYS's interrupt service at 44A9H with the stack as its own start (44A5H-44A8H) would have left it. The rows show the module at its address in the file; the JR and the jumps out of it work at any address.

536D
JUMP over the header to 5377H (the JR is relative: in the copy, to the module's +0AH). SYS10/SYS's search takes the 18H of this JR as the mark of a module.
536F-5370
DEFW 0000H 00 00
536FH-5370H, the module +02H-+03H: the link word, 0000H in the file; 5261H stores HIGH$ before the copy: SYS10/SYS's search goes on from it, and HITAPE (OFF) gives it back to HIGH$.
5371
DEFB 03H 03
5371H, the module +04H: 03H, the length of the name in bits 3-0.
5372-5374
DEFM "$HT" 24 48 54
5372H-5374H, the module +05H-+07H: the name of the module, $HT, which 5360H looks for.
5375-5376
DEFW 0000H 00 00
5375H-5376H, the module +08H-+09H: the vector found at 4013H-4014H, 0000H in the file; 5268H stores it before the copy. The code jumps to 44A9H itself and does not use it.
5377
PUSH AF F5
Save Register Pair AF to the stack: the interrupted program's Register A and flags.
5378
IN A,(E0H) DB E0
Read the interrupt latch from port E0H into Register A: a bit is 0 while its interrupt is pending.
537A
RRA 1F
Rotate Register A right through the CARRY FLAG (RRA): bit 0, the cassette's rising edge interrupt, goes into the CARRY FLAG.
537B
If the NO CARRY FLAG is set (bit 0 was 0: a rising edge of the cassette signal), JUMP to 3365H, the ROM's routine for it (Register E = 01H), with Register Pair AF on the stack.
537E
RRA 1F
Rotate Register A right through the CARRY FLAG (RRA): bit 1, the cassette's falling edge interrupt, goes into the CARRY FLAG.
537F
If the NO CARRY FLAG is set (bit 1 was 0: a falling edge), JUMP to 3369H, the ROM's routine for it (Register E = 00H), with Register Pair AF on the stack.
5382
RLA 17
Rotate Register A left through the CARRY FLAG (RLA): bit 1 goes back from the CARRY FLAG.
5383
RLA 17
Rotate Register A left through the CARRY FLAG (RLA) again: Register A holds the latch as it was read from port E0H.
5384
EX (SP),HL E3
Exchange Register Pair HL with the word at the Stack Pointer, the top of the stack: the interrupted program's Register Pair HL goes onto the stack and Register Pair HL takes the saved Register Pair AF.
5385
PUSH HL E5
Save Register Pair HL (the interrupted Register Pair AF) to the stack: the stack now holds Register Pair HL and Register Pair AF, as 44A5H-44A6H push them.
5386
JUMP to 44A9H, the interrupt service of SYS0/SYS after its PUSH HL, PUSH AF and IN A,(E0H): it goes on with the latch in Register A.