; Disassembly of the file "C:\lab\if1-2.rom"
;
; CPU Type: Z80
;
; Created with dZ80 1.50
;
; on Sunday, 28 of April 2002 at 12:35 PM
;

; ------------------------
; last updated 14-JAN-2004
; ------------------------

#define DEFB .BYTE
#define DEFW .WORD
#define DEFM .TEXT
#define EQU  .EQU
#define ORG  .ORG

        ORG     $0000

; ---------------------------------------
; FLAGS3 System Variable - IY+$7C ($5CB6)
; ---------------------------------------
; Bit 0 - set when executing an extended command.
; Bit 1 - set during CRT-VARS and CLEAR #, CLOSE etc.
; Bit 2 - settable by User to force the ERR_SP routine to handle errors.
; Bit 3 - set when networking.
; Bit 4 - set during LOAD and MOVE
; Bit 5 - set during SAVE
; Bit 6 - set during MERGE
; Bit 7 - set during VERIFY
;
; Note. before initialization of FLAGS_3, this is considered to be the first
; byte of channels and so PEEK 23734 gives 244 decimal (%11110100) the high
; order byte of the Main ROM address PRINT-OUT - $09F4.
;
; -------------------------------------------

; --------------------------------
; THE 'RETURN TO MAIN ROM' ROUTINE
; --------------------------------
;   The system is initialized by the Main ROM so this address is accessed 
;   solely by a RST 00H instruction.  It is used from five locations to return 
;   to the Main ROM.

;; MAIN-ROM
L0000:  POP     HL              ; discard the return address in this ROM.
        LD      (IY+$7C),$00    ; reset all the bits of FLAGS_3.
        JP      L0700           ; jump forward to UNPAGE address.

; -------------------
; THE 'START' ROUTINE
; -------------------
;   An instruction fetch on address $0008 pages in this ROM.
;   The three-byte instruction at this location must exist on both sides of
;   the looking-glass.  The value fetched is immediately discarded.
;   It follows that this restart should never be invoked from this ROM.

;; ST-SHADOW
L0008:  LD      HL,($5C5D)      ; fetch character address from CH_ADD.
        POP     HL              ; pop return address to HL register.
        PUSH    HL              ; and save again on machine stack.

        JP      L009A           ; jump forward to continue at START-2.

; -----------------------------
; THE 'CALL A MAIN ROM' ROUTINE
; -----------------------------
;   Call an address in the main ROM. The address follows the restart so this
;   is as convenient and as brief as a CALL instruction.
;   The SBRT routine within the system variables area reads
;
;   L5CB9         LD      HL,value
;   L5C5C         CALL    addr
;   L5C5F         LD      (L5CB9+1),HL
;   L5CC2         RET
;
;   By immediately placing the current value of HL in the subroutine, then
;   all registers before the call are as they were before the RST
;   instruction.  The value of HL after the call is stored immediately in
;   this now redundant location so that, after this ROM is paged back in,
;   the registers, after the RST instruction has executed, are as they were
;   immediately after the CALL.
;   see START-2.

;; CALBAS
L0010:  LD      ($5CBA),HL      ; insert the current value of HL in the
                                ; Z80 code to be picked up later.

        POP     HL              ; drop the return address - the location
                                ; of address to be called.
        PUSH    DE              ; preserve the DE register contents.

        JR      L0081           ; forward to continue at CALBAS-2.

        DEFB    $FF             ; unused.

; ---------------------------------------------
; THE 'TEST IF SYNTAX IS BEING CHECKED' ROUTINE
; ---------------------------------------------
;   On the ZX80, testing the syntax flag was done with the 4-byte
;   instruction that tests the System Variable FLAGS.  On the ZX81 and
;   ZX Spectrum, a call to SYNTAX-Z reduced the invocation to a three-byte
;   CALL.   Here it is reduced to a one-byte restart.

;; CHKSYNTAX
L0018:  BIT     7,(IY+$01)      ; test most significant bit of FLAGS
        RET                     ; return the result.
                                ; (Z = Syntax, NZ = Run-time)

        DEFB    $FF             ; unused.
        DEFB    $FF             ; unused.
        DEFB    $FF             ; unused.

; --------------------------
; THE 'SHADOW-ERROR' ROUTINE
; --------------------------
;   This is similar to the Main ROM error handler and the following byte 
;   indicates the type of error and in runtime the message that should be
;   printed.  If checking syntax then the error pointer is set before a
;   return is made to the Main ROM.

;; SH-ERR
L0020:  RST     18H             ; checking syntax ?
        JR      Z,L0068         ; forward, if so, to ST-ERROR

        JR      L003A           ; forward, in run-time, to TEST-SP,
                                ; and then REP-MSG

        DEFB    $FF             ; unused.
        DEFB    $FF             ; unused.
        DEFB    $FF             ; unused.

; ------------------------------------
; THE 'MAIN ROM ERROR RESTART' ROUTINE
; ------------------------------------
;   This restart invokes the error handler of the Main 16K ROM.  The required 
;   error number is usually first placed in the System Variable ERR_NR.  In 
;   some cases the error code is already present and this restart is used when 
;   the error situations handled by this ROM have been eliminated.
;   Since the exit from this point is by manipulating the stack, the return 
;   address is of no importance as that route is never taken.  There are also
;   three conditional jumps back to this point.

;; ROMERR
L0028:  RES     3,(IY+$02)      ; update TV_FLAG - signal no change in mode.
        JR      L0040           ; forward to RMERR-2.

        DEFB    $FF             ; unused.
        DEFB    $FF             ; unused.

; -------------------------------------------------
; THE 'CREATE NEW SYSTEM VARIABLES RESTART' ROUTINE
; -------------------------------------------------
;    This restart is used the first time that that the ROM is paged in to
;    create the System Variables.  This will be either by an instruction
;    fetch on $0008 or $1708.

;; NEWVARS
L0030:  JP      L01F7           ; jump to CRT-VARS

        DEFB    $FF             ; unused.
        DEFB    $FF             ; unused.
        DEFB    $FF             ; unused.
        DEFB    $FF             ; unused.
        DEFB    $FF             ; unused.

; --------------------------------
; THE 'MASKABLE INTERRUPT' ROUTINE
; --------------------------------
;   There is no service routine but should the routine be called either
;   directly or by straying into a RST $38 instruction, then interrupts are
;   enabled.

;; INT-SERV
L0038:  EI                      ; Enable Interrupts
        RET                     ; return.


; ------------------------
; THE 'TEST SYSTEM' BRANCH
; ------------------------
;   This branch allows the user to trap errors before this ROM is used to print
;   the error report. 

;; TEST-SP
L003A:  CALL    L0077           ; routine CHECK-SP
                                ; usually returns.
        JP      L0260           ; jump to REP-MSG

; ----------------------------
; THE 'MAIN ROM ERROR' ROUTINE
; ----------------------------
;   a continuation of RST 28H.
;   This ROM has inserted a Main ROM error code into ERR_NR and the routine in 
;   the Main ROM is now invoked.
;   First a check is made to see if the user wishes to trap errors using a 
;   custom routine in ERR_SP.  This will be used in the syntax path anyway.
; 

;; RMERR-2
L0040:  RST     18H             ; checking syntax ?
        JR      Z,L0068         ; forward, if so, to ST-ERROR.

        CALL    L0077           ; routine CHECK-SP allows the user to trap 
                                ; run-time errors at this point but normally 
                                ; returns here.

        CALL    L17B7           ; routine RCL-T-CH reclaims any temporary
                                ; channels and stops all microdrive motors.

        BIT     1,(IY+$7C)      ; test FLAGS_3.
        JR      Z,L0068         ; forward, if executing CLOSE, to ST-ERROR.

        BIT     4,(IY+$7C)      ; test FLAGS_3 - loading filename 'run' ?
        JR      Z,L0068         ; forward, if not, to ST-ERROR.

;   As a security measure, the file 'run' can not be hacked.

        LD      A,(IY+$00)      ; fetch error number from the System Variable
                                ; ERR_NR.
        CP      $14             ; is it "CODE error" ?
        JR      NZ,L0068        ; forward, if not, to ST-ERROR.

;   The user has pressed BREAK while trying to load the program 'run'.

        LD      HL,$0000        ; cause a system reset.
        PUSH    HL              ; place address zero on machine stack.
        RST     00H             ; switch to MAIN-ROM.

;

        DEFB    $FF             ; unused
        DEFB    $FF             ; unused
        DEFB    $FF             ; unused
        DEFB    $FF             ; unused
        DEFB    $FF             ; unused

; ------------------------------------
; THE 'NON-MASKABLE INTERRUPT' ROUTINE
; ------------------------------------
;   There is no NMI functionality.

;; NMINT-SRV
L0066:  RETN                    ; return to previous interrupt state.


; --------------------------
; THE 'SYNTAX ERROR' ROUTINE
; --------------------------
;   An error has occurred during syntax checking so the position must be 
;   highlighted when a return is made to the Editor in the Main ROM.

;; ST-ERROR
L0068:  LD      HL,($5C5D)      ; fetch character address from CH_ADD.
        LD      ($5C5F),HL      ; set X_PTR to same to position error cursor.

        LD      SP,($5C3D)      ; set the Stack Pointer from ERR_SP.

        LD      HL,$16C5        ; prepare address of main SET-STK.
        PUSH    HL              ; push on the machine stack.

        RST     00H             ; switch to MAIN-ROM where SET-STK will clean up 
                                ; the work areas before returning to the Error 
                                ; Routine obtained from ERR_SP.

; ---------------------------------------
; THE 'CHECK ERROR STACK POINTER' ROUTINE
; ---------------------------------------
;   This allows the user's software to trap any errors at this point by setting 
;   the otherwise unused bit 2 of FLAGS_3 after inserting a custom error 
;   handler in the System Variable ERR_SP.
;   Both Shadow ROM situations and Main ROM situations can be trapped and the 
;   routine is called from BOTH RST 20H and RST 28H.

;; CHECK-SP
L0077:  BIT     2,(IY+$7C)      ; test FLAGS_3 has the user set up a custom
                                ; error handler in Main RAM ?
        RET     Z               ; return if not.

;   Otherwise the user, or the third party software, has set up a custom routine
;   in the system variable ERR_SP and set bit 2 of FLAGS_3 so that it is invoked
;   at this point.

        LD      SP,($5C3D)      ; set stack pointer from ERR_SP.
        RST     00H             ; switch to MAIN-ROM.

; ----------------------
; THE 'CALBAS-2' ROUTINE
; ----------------------
;   A continuation of the code at $0010.
;   Continue by picking up the address to be called, located after the RST
;   instruction and placing after the CALL instruction in the SBRT sequence.

;; CALBAS-2
L0081:  LD      E,(HL)          ; fetch low byte of called address
        INC     HL              ; advance pointer.
        LD      D,(HL)          ; fetch high byte.

        LD      ($5CBD),DE      ; place in the Z80 code SBRT
        INC     HL              ; increment pointer.

        EX      (SP),HL         ; transfer continuation address to machine
                                ; stack - and the stack value (was DE) to HL.

        EX      DE,HL           ; original DE value now restored.

        LD      HL,$0000        ; signal CALBAS routine in use.
        PUSH    HL              ; place on stack.

        LD      HL,$0008        ; address of main ERROR restart
        PUSH    HL              ; place on stack

        LD      HL,$5CB9        ; address of calling SBRT subroutine.
        PUSH    HL              ; place on stack.

        JP      L0700           ; jump to UNPAGE

; ---------------------
; THE 'CONTROL' ROUTINE
; ---------------------
;   A continuation of code at L0008. The return address has been dropped off
;   the machine stack into HL.
;
;   First see if this ROM was paged in as a result of the $0008 address
;   stacked during the CALBAS routine. (see above)

;; START-2
L009A:  PUSH    AF              ; preserve accumulator and status flags.

        LD      A,H             ; test HL for zero - the CALBAS
        OR      L               ; indicator value.
        JR      NZ,L00A5        ; forward, if not, to START-3.

        POP     AF              ; restore accumulator and flags.

        POP     HL              ; discard address stacked by RST 08.
        LD      HL,($5CBA)      ; pick up post-CALL HL value from SBRT.
        RET                     ; return.

;------------------------------------------------------------------------------
;   Now consider that the address $0008 may have been an input or output
;   routine that precedes the letter of one of the new channels.  These
;   paging addresses ensure that this ROM is paged in so that the real
;   input/output addresses can be read from the locations after the
;   channel's letter. In this case, the return address is towards the end
;   of the CALL-SUB routine in the Main ROM, i.e.
;   L15FB         CALL    $162C   ; routine CALL-JUMP (a JP (HL) instr.)
;   L15FE         POP     HL      ; return address
;------------------------------------------------------------------------------

;; START-3
L00A5:  PUSH    DE              ; preserve DE.
        LD      DE,$15FE        ; test against possible return address 0x15FE
        SBC     HL,DE           ; subtract (carry is clear)
        POP     DE              ; restore DE.
        JR      NZ,L00BC        ; forward with no match to START-4.

;   This ROM has been paged by an attempt to use a stream.

        POP     AF              ; restore accumulator.

        LD      HL,L0700        ; stack the address UNPAGE to switch to 
        PUSH    HL              ; the Main ROM afterwards.

        LD      HL,$0004        ; the shadow routine is 4 bytes forward
        ADD     HL,DE           ; adjust input/output address pointer.
        LD      E,(HL)          ; pick up low-order byte of I/O routine.
        INC     HL              ; bump pointer.
        LD      D,(HL)          ; pick up high-order byte of routine.
        EX      DE,HL           ; transfer I/O address to HL.

        JP      (HL)            ; jump to routine and then to UNPAGE

; ---

;   By elimination, the address $0008 has been reached as a result of a
;   RST 08 instruction in the Main ROM.  This may be the very first time
;   that this ROM has been paged in after startup or NEW.

;; START-4
L00BC:  RST     30H             ; create new system variables if first time.

        LD      A,$01           ; %00000001
        OUT     ($F7),A         ;

        LD      A,$EE           ; %11101110
        OUT     ($EF),A         ;

        POP     AF              ; temporarily drop the accumulator.
        POP     HL              ; fetch address of error code/hook code to HL.
        PUSH    AF              ; save accumulator again.

;   Note. the address of the code could be anywhere in the 64K address space
;   but it is not in this ROM.  Luckily in the Main ROM at $007B is the
;   sequence ld a,(hl) ; ret which will fetch the unknown error code from
;   the known address.

        RST     10H             ; CALBAS
        DEFW    $007B           ; main TEMP-PTR3

        LD      ($5C3A),A       ; place the error code in sysvar ERR_NR

;   The error code at this stage is one less than actual code.

        CP      $FF             ; is it 'OK'
        JR      NZ,L00E9        ; forward, if not, to TEST-CODE

        BIT     1,(IY+$7C)      ; test FLAGS_3  - first time ?
        JR      Z,L00E7         ; forward, if not, to NREPORT-2
                                ; 'Program finished'

        BIT     7,(IY+$0C)      ; test PPC_hi - a direct command ?
        JR      Z,L00E7         ; forward, if not, to NREPORT-2

        LD      HL,($5C59)      ; use E_LINE to address the first character of 
                                ; the edit buffer.
        LD      A,(HL)          ; searching for RUN without whitespace.

        CP      $F7             ; is character the token 'RUN' ?
        JP      Z,L0A99         ; jump forward, if so, to LOAD-RUN

;; NREPORT-2
L00E7:  RST     20H             ; Shadow Error Restart
        DEFB    $FF             ; 'Program finished'

; ---

;   Continue to consider the error code.  This may have occurred after the
;   Error RESTART in the Main ROM - range $00 (NEXT without FOR) to
;   $1A (Tape Loading Error) or a RESTART in RAM which could also include
;   the Hook Codes.

;; TEST-CODE
L00E9:  SUB     $1B             ; subtract lowest Hook Code (PAUSE)
        JP      NC,L1E71        ; jump, if same or higher, to HOOK-CODE

        CP      $F0             ; was it $0B 'Nonsense in basic'
        JR      Z,L00FB         ; forward to COPYCHADD

        CP      $F3             ; was it $0D 'Invalid file name'
        JR      Z,L00FB         ; forward to COPYCHADD

        CP      $FC             ; was it $17 'Invalid stream'
        JP      NZ,L0028        ; jump, if not, to ROMERR

;   If one of the above three reports, then this is possibly an extended
;   command and further investigation is required. A number of situations
;   may apply. The error could have occurred -
;
;   1) In INPUT - just pass control back to Main ROM. This is just a normal
;      Nonsense in BASIC and will not be due to anything new.
;   2) While already investigating an error. Too much - just use Main ROM.
;   3) While entering a new or modified line and syntax failed.
;   4) While running the program and an error was encountered.
;
;   The character address CH_ADD is not much use as that is the place
;   after the command where the standard ROM encountered an error.
;   It will be required by the Main ROM if control is passed back so, in
;   order that the Main ROM parsing routines can be used, make a copy of the
;   error character position. We will have to work forward from the
;   beginning of the line if checking syntax or from the start of the
;   program in run-time so that the errant command can be found. It may also
;   be necessary to remove hidden characters from the BASIC line.

;; COPYCHADD
L00FB:  LD      HL,($5C5D)      ; fetch character address from CH_ADD and
        LD      ($5CCB),HL      ; store in shadow system variable CHADD_

        POP     AF              ; restore accumulator.

        BIT     5,(IY+$37)      ; test FLAGX - in INPUT mode ?

        JP      NZ,L0028        ; jump back, if so, to ROMERR

;   Continue if in Editing or Run-time Mode.

        BIT     0,(IY+$7C)      ; test FLAGS_3 - already extended command ?
        JP      NZ,L0028        ; jump, if so, to ROMERR

;   else signal - handling an extended command - so that such a double error
;   can be trapped.

        SET     0,(IY+$7C)      ; update FLAGS_3 - signal executing an
                                ; extended command.

        RST     18H             ; checking syntax ?

        JR      NZ,L011B        ; skip forward, if not, to RUNTIME

        LD      (IY+$0C),$FF    ; set bit 7 of PPC_hi to indicate a line
                                ; entry situation.

;    In both cases, load B with the statement number where the error was
;    encountered.  Previous validated statements are not to be disturbed.

;; RUNTIME
L011B:  LD      B,(IY+$0D)      ; load B with statement number from SUBPPC
        LD      C,$00           ; and set C to zero for a quotes flag.

        BIT     7,(IY+$0C)      ; test PPC_hi - line entry ?
        JR      Z,L0130         ; forward, if not, to PROG-LINE

;   An edit line may have a line number at start and whitespace. We need to
;   set CH_ADD at the first command.

        PUSH    BC              ; save BC

        RST     10H             ; CALBAS
        DEFW    $19FB           ; main E-LINE-NO fetches any line number to
                                ; BC, setting CH_ADD at the command token.

        POP     BC              ; restore BC - discarding line number.

        RST     10H             ; CALBAS
        DEFW    $0018           ; main GET-CHAR gets first command of the
                                ; first statement of the errant line.

        JR      L016F           ; forward to statement loop - S-STAT to find
                                ; the errant statement.

; ---

;; PROG-LINE
L0130:  LD      HL,($5C53)      ; set pointer to start of program from PROG.

;; SC-L-LOOP
L0133:  LD      A,($5C46)       ; fetch high byte of errant line from PPC_hi
        CP      (HL)            ; compare with tested high byte.
        JR      NC,L013B        ; forward, if errant line higher or same,
                                ; to TEST-LOW

; else, unusually, the current line is not there so let Main ROM handle.

;; NREPORT-1
L0139:  RST     20H             ; Shadow Error Restart
        DEFB    $00             ; Nonsense in BASIC

; ---

;; TEST-LOW
L013B:  INC     HL              ; increment program pointer to address low byte.
        JR      NZ,L0144        ; forward, if high bytes not same, to LINE-LEN

        LD      A,($5C45)       ; fetch low byte of current line from PPC_lo
        CP      (HL)            ; compare to addressed byte.
        JR      C,L0139         ; back, if not in program area, to NREPORT-1


;; LINE-LEN
L0144:  INC     HL              ; increment program
        LD      E,(HL)          ; pointer and
        INC     HL              ; pick up the
        LD      D,(HL)          ; length of the BASIC line
        INC     HL              ; resting at the first character.

        JR      Z,L016F         ; forward, if line numbers matched, to S-STAT
                                ; the mid-entry point of the statement loop.

        ADD     HL,DE           ; else add length to current address.
        JR      L0133           ; loop back to SC-L-LOOP

; --------------------
; THE 'STATEMENT LOOP'
; --------------------
;    Entered at mid-point S-STAT with statement counter in B and a quotes
;    counter, C, set at an even zero.

;; SKIP-NUM
L014E:  LD      DE,$0006        ; a hidden floating point number has six bytes.
        ADD     HL,DE           ; add to skip to next character.

; -> The Looping Point.

;; EACH-ST
L0152:  LD      A,(HL)          ; fetch addressed BASIC character.
        CP      $0E             ; is it the hidden number indicator ?
        JR      Z,L014E         ; back to SKIP-NUM to ignore.

        INC     HL              ; else increase pointer.

        CP      $22             ; is it quotes character '"' ?
        JR      NZ,L015D        ; skip forward, if not, to CHKEND

        DEC     C               ; decrement quotes counter.

;; CHKEND
L015D:  CP      $3A             ; is character ':' ?
        JR      Z,L0165         ; skip forward to CHKEVEN

        CP      $CB             ; is character 'THEN' ?
        JR      NZ,L0169        ; skip forward to CHKEND-L


;; CHKEVEN
L0165:  BIT     0,C             ; are quotes balanced ?
        JR      Z,L016F         ; forward, if so, to S-STAT
                                ; for next statement.

;   A carriage return must not appear within quotes.

;; CHKEND-L
L0169:  CP      $0D             ; carriage return ?
        JR      NZ,L0152        ; back, if not, to EACH-ST

        JR      L0139           ; back to NREPORT-1
                                ; 'Nonsense in BASIC'


;    The Statement Loop Entry Point -->

;; S-STAT
L016F:  DJNZ    L0152           ; decrement statement counter and loop back
                                ; to EACH-ST.

;    The errant statement has been located and CH_ADD is set to start.

        DEC     HL              ; point to start or ':'

        LD      ($5C5D),HL      ; set the Main ROM system variable CH_ADD

        RST     18H             ; checking syntax ?

        JR      NZ,L01AA        ; forward, if not, to CL-WORK

        BIT     7,(IY+$0C)      ; test PPC_hi - is it an Edit Line ?
        JP      Z,L01F0         ; jump forward, if not, to ERR-6.

        DEC     HL              ; prepare to enter loop below.

        LD      C,$00           ; ??

;   It is well to reflect on what has been achieved up to this point.  At
;   each statement, the first attempt at validation is made by the Main ROM.
;   Then if that should encounter something not to its liking, this ROM has
;   a bash.  There could be ten or more statements before this one and each
;   will have been validated by the Main ROM or by this routine.  As part of
;   that validation process, when a number is parsed, then the integer or
;   floating point form of the number is inserted after the digits, rendered
;   invisible by a CHR$(14).
;
;   Once a statement has passed validation by either ROM, then it is not
;   undone.  If, say, the Main ROM has failed on the third statement of
;
;   10 PRINT "Hi :" : LET vat = 15 : OPEN# 7, "T" : LET tax = cost * (vat/100)
;
;   then it will have already inserted six bytes after the '7' before raising
;   the error 'Invalid stream'.  This ROM has located the separator before
;   the command but needs to remove the hidden numbers before parsing the
;   statement as the latter process will put them back in and we can't
;   double up.  The easiest way to do this is to search for hidden numbers
;   right to the end of the line.  There won't be any after this statement
;   but stopping at a CHR$(13) is easier than considering end of statement
;   markers in quotes.  It seems that this neat solution was not arrived at
;   immediately and the instruction, above, sets C to the quotes flag again
;   and it is needlessly preserved on the stack.
;
;   The end-user is oblivious to this elegant toing and froing between ROMS
;   and the unseen error code generation and cancellation. All that is
;   apparent is that when the RETURN key is pressed, the line simply enters
;   the program.

;; RCLM-NUM
L0182:  INC     HL              ; increment character pointer
        LD      A,(HL)          ; fetch the character.

        CP      $0E             ; is it the number marker ?
        JR      NZ,L01A5        ; forward, if not, to NEXTNUM

        PUSH    BC              ; preserve BC (zero)

        LD      BC,$0006        ; six bytes to reclaim.

        RST     10H             ; CALBAS
        DEFW    $19E8           ; main RECLAIM-2

        PUSH    HL              ; preserve character pointer.

        LD      DE,($5CCB)      ; fetch error pointer from CHADD_
        AND     A               ; prepare for true subtraction.
        SBC     HL,DE           ; test if character position less than error.
        JR      NC,L01A3        ; forward, if not, to NXT-1

        EX      DE,HL           ; transfer CHADD_ value to HL.
        LD      BC,$0006        ; 
        AND     A               ;
        SBC     HL,BC           ; reduce by six.
        LD      ($5CCB),HL      ; store back in system variable CHADD_

;; NXT-1
L01A3:  POP     HL              ; restore character pointer.
        POP     BC              ; and restore BC (zero)

;; NEXTNUM
L01A5:  LD      A,(HL)          ; fetch character.
        CP      $0D             ; carriage return ?
        JR      NZ,L0182        ; loop back, if not, to RCLM-NUM

;  The run-time path rejoins here

;; CL-WORK
L01AA:  RST     10H             ; CALBAS
        DEFW    $16BF           ; main SET-WORK

        CALL    L0255           ; routine RES-VARS sets new system variables
                                ; from that following CHADD_ to that preceding
                                ; COPIES to the value $FF.

        RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR advances CH_ADD and fetches
                                ; the command character.

        SUB     $CE             ; reduce tokens - why?

        CP      $01             ; 'CAT' ?
        JP      Z,L0486         ; jump to CAT-SYN

        CP      $02             ; 'FORMAT' ?
        JP      Z,L04B4         ; jump to FRMT-SYN

        CP      $03             ; 'MOVE' ?
        JP      Z,L053D         ; jump to MOVE-SYN

        CP      $04             ; 'ERASE' ?
        JP      Z,L0531         ; jump to ERASE-SYN

        CP      $05             ; 'OPEN #' ?
        JP      Z,L04ED         ; jump to OPEN-SYN

        CP      $2A             ; 'SAVE' ?
        JP      Z,L082F         ; jump to SAVE-SYN

        CP      $21             ; 'LOAD' ?
        JP      Z,L0898         ; jump to LOAD-SYN

        CP      $08             ; 'VERIFY' ?
        JP      Z,L08A2         ; jump to VERIF-SYN

        CP      $07             ; 'MERGE' ?
        JP      Z,L08AC         ; jump to MRG-SYN

        CP      $2D             ; 'CLS' ?
        JP      Z,L0559         ; jump to CLS#-SYN

        CP      $2F             ; 'CLEAR' ?
        JP      Z,L057F         ; jump to CLR#-SYN

;   If none of the new extended commands then load HL from the VECTOR
;   system variable which normally points to the error routine below.
;   However the user, or a third party software publisher, may have
;   altered the vector to point to their own extended BASIC routines.

;; ERR-V
L01EC:  LD      HL,($5CB7)      ; fetch address from system variable VECTOR
        JP      (HL)            ; jump to address.

; ---

;; ERR-6
L01F0:  LD      HL,($5CCB)      ; fetch original character address from
                                ; CHADD_
        LD      ($5C5D),HL      ; and place in standard CH_ADD
        RST     28H             ; Error Main ROM.

; -----------------------------------------
; THE 'CREATE NEW SYSTEM VARIABLES' ROUTINE
; -----------------------------------------
;   A continuation of the restart code at $0030. A check is made to see if
;   the 58 variables already exist and the stack is set up to create the
;   room using the main ROM routine. If there isn't 58 free bytes available
;   then an 'Out of memory' report is generated by the Main ROM.

;; CRT-VARS
L01F7:  LD      HL,($5C4F)      ; system variable CHANS normally   $5CB6.
        LD      DE,$A349        ; add test value                   $A349.
                                ;                                   ----
        ADD     HL,DE           ; add - if uninitialized will give $FFFF.
        JR      C,L023D         ; forward, if higher, to VAR-EXIST

        LD      HL,L0224        ; prepare address of DEFAULT routine
        PUSH    HL              ; push on machine stack

        LD      HL,($5C63)      ; use system variable STKBOT
        LD      ($5C65),HL      ; to set system variable STKEND

        LD      HL,$5C92        ; use system variable MEMBOT
        LD      ($5C68),HL      ; to set system variable MEM

        LD      HL,$5CB5        ; the last standard system variable.
                                ; P-RAMT_hi - the location before new area.
        LD      BC,L003A        ; 58 bytes to allocate.

;   Now call MAKE-ROOM in the Main ROM by placing a sequence of addresses
;   on the machine stack as it is not possible to use the CALBAS routine yet.

        LD      DE,$0000        ; indicator - signals Main ROM has been used.
        PUSH    DE              ; stack word.

        LD      E,$08           ; form address $0008 in Main ROM.
        PUSH    DE              ; stack word.

        LD      DE,$1655        ; the Main ROM address MAKE-ROOM.
        PUSH    DE              ; stack word.

;   The machine stack now has the hierarchy DEFAULT; $0000; ERROR-1;
;   MAKE-ROOM which will be handled in reverse order.

        JP      L0700           ; jump to UNPAGE.

;   After creating room and paging this ROM back in, 'return' to the next
;   address which was the first in the sequence pushed on machine stack
;   earlier.

;; DEFAULT
L0224:  LD      HL,L0242        ; default system variable values.
        LD      BC,$0013        ; nineteen bytes to move.
        LD      DE,$5CB6        ; old CHANS area, new sysvar FLAGS_3.
        LDIR                    ; copy the bytes.

;   Note. So far the value in the accumulator, which may be the number of a
;   stream to close, has not been altered.  This next instruction is worded 
;   wrongly and 
;
;   OPEN #7,"s" : CLOSE #7 
;
;   may not work.
;   The fix would be to use 'ld hl $5cef ; ld (hl), $01' (5 bytes)
;   or even 'dec h ; ld ($5cee),hl' (4 bytes)
;   The next pair of instructions would have been better if executed using
;   the HL register pair also.

        LD      A,$01           ; set accumulator to 1.
        LD      ($5CEF),A       ; set system variable COPIES.

        LD      (IY+$77),$50    ; set NMI_ADD_hi to eighty.
        LD      (IY+$76),$00    ; set NMI_ADD_lo to zero.

        RET                     ; return.

; ---

;   The extended System Variables already exist.

;; VAR-EXIST
L023D:  RES     1,(IY+$7C)      ; reset indicator in FLAGS_3.
        RET                     ; return.


; -------------------------------------------
; THE 'SYSTEM VARIABLES DEFAULT VALUES' TABLE
; -------------------------------------------
;   These are the initial values of the first section of the extended System
;   Variables that are copied, once only, to a newly opened area following
;   the standard 48K Spectrum System Variables.  The memory area that was at
;   this location (CHANS) is moved upwards to make room.
;   The first new location (which was the first byte of CHANS) is now
;   FLAGS_3, accessible by the IY register, and normally zero when the Main
;   ROM becomes active again.  Bit 1 is set when a CLEAR# is active and also
;   by the copy itself.

;; SV-DEFS
L0242:  DEFB    $02             ; FLAGS3 (with bit 1 already set).
        DEFW    $01F0           ; VECTOR

        LD      HL,$0000        ; SBRT located at $5CB9
        CALL    $0000           ;
        LD      ($5CBA),HL      ;
        RET                     ;

        DEFW    $000C           ; BAUD
        DEFB    $01             ; NTSTAT
        DEFB    $00             ; IOBORD - black.
        DEFW    $0000           ; SER_FL


; ----------------------------------------
; THE 'RESET NEW SYSTEM VARIABLES' ROUTINE
; ----------------------------------------
;   The central area is filled with $FF bytes.
;   This occurs whenever a new extended command is invoked.

;; RES-VARS
L0255:  LD      HL,$5CCD        ; set pointer to NTRESP - start of area.
        LD      B,$22           ; thirty four bytes to fill.

;; EACH-VAR
L025A:  LD      (HL),$FF        ; insert a default $FF value.
        INC     HL              ; bump the pointer.
        DJNZ    L025A           ; loop back to EACH-VAR.

        RET                     ; return.

; ------------------------------------
; THE 'SHADOW REPORT PRINTING' ROUTINE
; ------------------------------------
;   This routine prints the error reports of the Shadow ROM.
;   These relate to the code that follows a RST 20H restart.  The error code
;   is not printed as it would conflict with Main ROM reports.  The text of
;   the message is printed and then the Main ROM routine is used to print a
;   comma and then the line number and statement.  For example,
;   Program finished, 0:1
;   The code is similar to that at MAIN-4 in the Main ROM.  Some improvements
;   have been made but at least one slight error has been replicated.

;; REP-MSG
L0260:  LD      (IY+$7C),$00    ; clear FLAGS_3 in preparation for leaving 
                                ; this ROM.

        EI                      ; Enable Interrupts.

        HALT                    ; wait for the first interrupt.

        CALL    L17B7           ; routine RCL-T-CH reclaims any temporary
                                ; channels and stops any running drive motor.

        RES     5,(IY+$01)      ; update FLAGS - 'Ready for new key'.
        BIT     1,(IY+$30)      ; test FLAGS2 - is printer buffer empty ?
        JR      Z,L0276         ; forward, if so, to FETCH-ERR

        RST     10H             ; CALBAS - call a Base ROM routine.
        DEFW    $0ECD           ; main routine - COPY-BUFF
                                ; Note. the programmer has neglected to
                                ; set bit 1 of FLAGS first.

;; FETCH-ERR
L0276:  POP     HL              ; drop the return address - after RST.
        LD      A,(HL)          ; fetch the error code.
        LD      (IY+$00),A      ; place in system variable ERR_NR.
        INC     A               ; increment setting zero if was $FF.
        PUSH    AF              ; save actual code and status flags.

        LD      HL,$0000        ; prepare to blank some system variables.
        LD      (IY+$37),H      ; clear all the bits of FLAGX.
        LD      (IY+$26),H      ; blank X_PTR_hi to suppress error marker.
        LD      ($5C0B),HL      ; blank DEFADD to signal that no defined
                                ; function is being evaluated.

        INC     L               ; select offset of 1 (explicit in main ROM ).
        LD      ($5C16),HL      ; update STRMS_00 - inputs from keyboard.

        RST     10H             ; CALBAS
        DEFW    $16B0           ; main SET-MIN clears workspace etc.

        RES     5,(IY+$37)      ; update FLAGX - signal in EDIT mode
                                ; not INPUT mode.
                                ; Note. all the bits were reset earlier.

        RST     10H             ; CALBAS
        DEFW    $0D6E           ; main CLS-LOWER

        SET     5,(IY+$02)      ; update TV_FLAG - signal lower screen
                                ; requires clearing.
        RES     3,(IY+$02)      ; update TV_FLAG - no change in mode.

        POP     AF              ; restore the incremented error code.
        LD      HL,L02BF        ; start search at REP-MSGS table below.
        LD      B,$04           ; roughly ensure that BC does not limit
                                ; search area as code must be found.
        CPIR                    ; search for code $00 - $17 skipping
                                ; all ASCII text.

;   At this point HL addresses first character of message.

;; PR-REP-LP
L02A7:  LD      A,(HL)          ; fetch each character in turn.
        CP      $20             ; compare to space.
        JR      C,L02B4         ; forward if less to END-PR-MS

        PUSH    HL              ; save the character pointer
        RST     10H             ; CALBAS
        DEFW    $0010           ; main PRINT-A

        POP     HL              ; restore pointer
        INC     HL              ; and increment.
        JR      L02A7           ; loop back to PR-REP-LP

; ---

;; END-PR-MS
L02B4:  LD      SP,($5C3D)      ; set machine stack pointer from ERR_SP
        INC     SP              ; prepare to overwrite the MAIN-4
        INC     SP              ; address $1303.
        LD      HL,$1349        ; substitute with the part that prints
                                ; the comma and line statement.
        PUSH    HL              ; push address to base of stack.
        RST     00H             ; return to MAIN-ROM.

;   Note. at this stage we have, say, "Program finished" on the screen and
;   the Main ROM routine at $1349 will complete the ", 0:1" part looping
;   back to MAIN-2 to put $1303 on the stack again.

; ------------------------------------
; THE 'SHADOW REPORT MESSAGES' ROUTINE
; ------------------------------------
;   These are the Shadow Error Reports.  Note. that the never used
;   "Header mismatch error" has been largely reclaimed.  Each error code,
;   which must be less than a space, serves to delimit the preceding text.
;   The final delimiter might just as well be $18.

;; REP-MSGS
L02BF   DEFB    $00
        DEFM    "Program finished"
        DEFB    $01
        DEFM    "Nonsense in BASIC"     ; Duplicate of a Main ROM error
        DEFB    $02
        DEFM    "Invalid stream number"
        DEFB    $03
        DEFM    "Invalid device expression"
        DEFB    $04
        DEFM    "Invalid name"
        DEFB    $05
        DEFM    "Invalid drive number"
        DEFB    $06
        DEFM    "Invalid station number"
        DEFB    $07
        DEFM    "Missing name"
        DEFB    $08
        DEFM    "Missing station number"
        DEFB    $09
        DEFM    "Missing drive number"
        DEFB    $0A
        DEFM    "Missing baud rate"
        DEFB    $0B
        DEFM    "er mismatch e"         ; Note. remnants of unused text.
        DEFB    $0C
        DEFM    "Stream already open"
        DEFB    $0D
        DEFM    "Writing to a 'read' file"
        DEFB    $0E
        DEFM    "Reading a 'write' file"
        DEFB    $0F
        DEFM    "Drive 'write' protected"
        DEFB    $10
        DEFM    "Microdrive full"
        DEFB    $11
        DEFM    "Microdrive not present"
        DEFB    $12
        DEFM    "File not found"
        DEFB    $13
        DEFM    "Hook code error"       ; not listed in manual.
        DEFB    $14
        DEFM    "CODE error"
        DEFB    $15
        DEFM    "MERGE error"
        DEFB    $16
        DEFM    "Verification has failed"
        DEFB    $17
        DEFM    "Wrong file type"
        DEFB    $18                     ; end-marker

; *********************************************
; **  T H E   S Y N T A X   R O U T I N E S  **
; *********************************************

; --------------------------------
; THE 'CAT COMMAND SYNTAX' ROUTINE
; --------------------------------
;   e.g. CAT 3
;   Without the syntax tables of the Main ROM, checking syntax is quite
;   laborious.  Although the Main ROM allowed CAT without a parameter, a
;   single expression in the range 1 - 8 is now required.  By default, CAT
;   outputs to the upper screen but output may be directed to any stream in
;   the range 0 to 15 decimal.  The subroutines used to evaluate the numeric
;   expressions use the SCANNING routine, in Main ROM, which inserts the
;   hidden five-byte numbers after any numeric arguments.

;; CAT-SYN
L0486:  LD      HL,$5CD8        ; address system variable S_STR1.
        LD      (HL),$02        ; default to stream 2 the screen.

        RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR

        CP      $0D             ; carriage return ?
        JR      Z,L0494         ; forward, if so, to MISSING-D

        CP      $3A             ; is character ':' ?

;; MISSING-D
L0494:  JP      Z,L0683         ; jump if no parameter to NREPORT-9

        CP      $23             ; is character '#' ?
        JR      NZ,L04A6        ; forward to CAT-SCRN

;   Output is directed at a specific stream.

        CALL    L064E           ; routine EXPT-STRM checks for number in range.
        CALL    L05B1           ; routine SEPARATOR checks for ',' or ';'.
        JR      NZ,L04B2        ; forward, if not present, to OREPORT-1
                                ; 'Nonsense in BASIC'

        RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR

;; CAT-SCRN
L04A6:  CALL    L061E           ; routine EXPT-NUM
        CALL    L05B7           ; routine ST-END
        CALL    L066D           ; routine CHECK-M-2 checks that drive is in 
                                ; range 1 - 8.

        JP      L1AB5           ; jump forward to CAT-RUN

; ---

;; OREPORT-1
L04B2:  RST     20H             ; Shadow Error Restart
        DEFB    $00             ; Nonsense in BASIC

; -----------------------------------
; THE 'FORMAT COMMAND SYNTAX' ROUTINE
; -----------------------------------
;   e.g.

;; FRMT-SYN
L04B4:  CALL    L05F2           ; routine EXPT-SPEC
        CALL    L05B1           ; routine SEPARATOR
        JR      NZ,L04BF        ; forward to NO-FOR-M

        CALL    L062F           ; routine EXPT-NAME

;; NO-FOR-M
L04BF:  CALL    L05B7           ; routine ST-END
        LD      A,($5CD9)       ; sv L_STR1 device letter.
        CP      $54             ; is character  "T" ?
        JR      Z,L04CD         ; forward to FOR-B-T

        CP      $42             ; is character  "B" ?
        JR      NZ,L04D3        ; forward to NOT-FOR-B


;; FOR-B-T
L04CD:  CALL    L06B0           ; routine TEST-BAUD
        JP      L0ACD           ; jump to SET-BAUD

;; NOT-FOR-B
L04D3:  CP      $4E             ; is character "N" ?
        JR      NZ,L04E7        ; forward to FOR-M

        CALL    L068F           ; routine TEST-STAT
        LD      A,($5CD6)       ; sv D_STR1 drive number
        AND     A
        JP      Z,L069F         ; jump to NREPORT-6
        LD      ($5CC5),A       ; sv NTSTAT
        JP      L05C1           ; jump to END1

;; FOR-M
L04E7:  CALL    L0685           ; routine TEST-MNAM
        JP      L1ABA           ; jump to FOR-RUN

; ---------------------------------
; THE 'OPEN COMMAND SYNTAX' ROUTINE
; ---------------------------------
;

;; OPEN-SYN
L04ED:  CALL    L064E           ; routine EXPT-STRM
        CALL    L05B1           ; routine SEPARATOR
        JR      NZ,L04B2        ; back to OREPORT-1
                                ; 'Nonsense in BASIC'

        CALL    L05F2           ; routine EXPT-SPEC
        CALL    L05B1           ; routine SEPARATOR
        JR      NZ,L0500        ; forward to NOT-OP-M

        CALL    L062F           ; routine EXPT-NAME

;; NOT-OP-M
L0500:  CALL    L05B7           ; routine ST-END
        LD      A,($5CD8)       ; sv D_STR1

        RST     10H             ; CALBAS
        DEFW    $1727           ; main STR-DATA1

        LD      HL,$0011        ;
        AND     A               ;
        SBC     HL,BC           ;
        JR      C,L052F         ; forward to NREPORT-C

        LD      A,($5CD9)       ; sv L_STR1 device letter.
        CP      $54             ; "T" ?
        JR      Z,L051C         ; forward to OPEN-RS

        CP      $42             ; "B" ?
        JR      NZ,L051F        ; forward to NOT-OP-B


;; OPEN-RS
L051C:  JP      L0B4E           ; jump to OP-RSCHAN

; ---

;; NOT-OP-B
L051F:  CP      $4E             ; is character "N" ?
        JR      NZ,L0529        ; forward to OP-M-C

        CALL    L068F           ; routine TEST-STAT
        JP      L0F40           ; jump to OPEN-N-ST

; ---

;; OP-M-C
L0529:  CALL    L0685           ; routine TEST-MNAM
        JP      L1ABF           ; jump to OP-RUN

; ---

;; NREPORT-C
L052F:  RST     20H             ; Shadow Error Restart
        DEFB    $0B             ; Stream already open

; ----------------------------------
; THE 'ERASE COMMAND SYNTAX' ROUTINE
; ----------------------------------
;

;; ERASE-SYN
L0531:  CALL    L06A3           ; routine EXPT-EXPR
        CALL    L05B7           ; routine ST-END
        CALL    L0685           ; routine TEST-MNAM
        JP      L1AAB           ; jump to ERASE-RUN

; ---------------------------------
; THE 'MOVE COMMAND SYNTAX' ROUTINE
; ---------------------------------
;

;; MOVE-SYN
L053D:  CALL    L06B9           ; routine EXPT-EXP1
        CALL    L059F           ; routine EX-D-STR
        RST     10H             ; CALBAS
        DEFW    $0018           ; main GET-CHAR

        CP      $CC             ; 'TO' ?
        JR      NZ,L0584        ; forward to NONSENSE

        CALL    L06B9           ; routine EXPT-EXP1
        CALL    L059F           ; routine EX-D-STR
        RST     10H             ; CALBAS
        DEFW    $0018           ; main GET-CHAR

        CALL    L05B7           ; routine ST-END
        JP      L1AB0           ; jump to MOVE-RUN

; --------------------------
; THE 'CLS# COMMAND' ROUTINE
; --------------------------
;

;; CLS#-SYN
L0559:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR

        CP      $23             ; is the character '#' ?
        JR      NZ,L0584        ; forward, if not, to NONSENSE

        RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR

        CALL    L05B7           ; routine ST-END

        LD      HL,L0038        ; prepare a zero and black ink on white paper.
        LD      ($5C8D),HL      ; set system variables ATTR_P and MASK_P.
        LD      ($5C8F),HL      ; set system variables ATTR_T and MASK_T.
                                ; Note. not really necessary as done by CLS.
        LD      (IY+$0E),L      ; set system variable BORDCR to colour scheme.
        LD      (IY+$57),H      ; set system variable P_FLAG to zero.

        LD      A,$07           ; load A with white.
        OUT     ($FE),A         ; directly change border colour.

        RST     10H             ; CALBAS
        DEFW    $0D6B           ; main CLS clears screen and sets colours.

        JP      L05C1           ; jump forward to END1.

; ----------------------------
; THE 'CLEAR# COMMAND' ROUTINE
; ----------------------------
;

;; CLR#-SYN
L057F:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        CP      $23             ; '#' ?

;; NONSENSE
L0584:  JP      NZ,L04B2        ; jump to OREPORT-1
                                ; 'Nonsense in BASIC'

        RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        CALL    L05B7           ; routine ST-END


        XOR     A               ;

;; ALL-STRMS
L058E:  PUSH    AF              ;
        SET     1,(IY+$7C)      ; sv FLAGS_3
        CALL    L1718           ; routine CLOSE
        POP     AF              ;
        INC     A               ;
        CP      $10             ;
        JR      C,L058E         ; back to ALL-STRMS

        JP      L05C1           ; jump to END1


; -----------------------------------------------------
; THE 'EXCHANGE FILE SPECIFIERS DSTRI AND STR2' ROUTINE
; -----------------------------------------------------
;   This routine is used by the MOVE routines to bring one of the two 8-byte
;   file specifiers into context.  There were two similar routines in the
;   first Interface 1 ROM and this, the most efficient, has survived.

;; EX-D-STR
L059F:  LD      HL,$5CD6        ; sv D_STR1. drive number
        LD      DE,$5CDE        ; sv D_STR2.
        LD      B,$08           ; eight bytes to swap.

;; ALL-BYTES
L05A7:  LD      A,(DE)          ; fetch byte 1.
        LD      C,(HL)          ; fetch byte 2.
        LD      (HL),A          ; place byte 1.
        LD      A,C             ; byte 2 to accumulator.
        LD      (DE),A          ; place byte 2.

        INC     HL              ; increment the
        INC     DE              ; two pointers.
        DJNZ    L05A7           ; loop back, for all eight, to ALL-BYTES.

        RET                     ; return.


; -----------------------
; THE 'SEPARATOR' ROUTINE
; -----------------------
;   This routine returns with zero flag set if the current character is
;   either a comma or semi-colon.

;; SEPARATOR
L05B1:  CP      $2C             ; is character ',' ?
        RET     Z               ; return with zero set if so.

        CP      $3B             ; is character ';' ?
        RET                     ; return.

; ------------------------------
; THE 'END OF STATEMENT' ROUTINE
; ------------------------------
;

;; ST-END
L05B7:  CP      $0D             ; is character carriage return ?
        JR      Z,L05BF         ; forward, if so, to TEST-RET

        CP      $3A             ; is character a ':' ?
        JR      NZ,L0584        ; back, if not, to NONSENSE


;; TEST-RET
L05BF:  RST     18H             ; checking syntax ?
        RET     NZ              ; return if not.


; --------------------------------------------
; THE 'RETURN TO THE MAIN INTERPRETER' ROUTINE
; --------------------------------------------
;

;; END1
L05C1:  LD      SP,($5C3D)      ; sv ERR_SP
        LD      (IY+$00),$FF    ; sv ERR_NR

        LD      HL,$1BF4        ; Main ROM address STMT-NEXT

        RST     18H             ; checking syntax ?
        JR      Z,L05E0         ; forward, if so, to RETAD-SYN

        LD      A,$7F           ;
        IN      A,($FE)         ;
        RRA                     ;
        JR      C,L05DD         ; forward to RETAD-RUN

        LD      A,$FE           ;
        IN      A,($FE)         ;
        RRA                     ;
        JR      NC,L05E2        ; forward to BREAK-PGM


;; RETAD-RUN
L05DD:  LD      HL,$1B7D        ; Main ROM address STMT-R-1

;; RETAD-SYN
L05E0:  PUSH    HL              ;
        RST     00H             ; to MAIN-ROM

; ---

;; BREAK-PGM
L05E2:  LD      (IY+$00),$14    ; insert error code in system variable ERR_NR.
        RST     28H             ; Error Main ROM 
                                ; 'BREAK into program'

; ----------------------------------------
; THE 'EVALUATE STRING EXPRESSION' ROUTINE
; ----------------------------------------
;

;; EXPT-STR
L05E7:  RST     10H             ; CALBAS
        DEFW    $1C8C           ; main EXPT-EXP
        RST     18H             ; checking syntax ?
        RET     Z

        PUSH    AF
        RST     10H             ; CALBAS
        DEFW    $2BF1           ; main STK-FETCH
        POP     AF
        RET


; -----------------------------------------
; THE 'EVALUATE CHANNEL EXPRESSION' ROUTINE
; -----------------------------------------
;

;; EXPT-SPEC
L05F2:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


;; EXP-SPEC2
L05F5   CALL    L05E7           ; routine EXPT-STR evaluates a string e.g. "m"
                                ; start in DE, length in BC.

; one of the main tenets of Sinclair BASIC is that a value can be replaced 
; by an expression of the same type at any time, so this routine must allow
; something like "tomato"(3) as well as the more conventional "m" specifier.
; Only in runtime when the expression is evaluated can a single character be
; insisted upon.

        JR      Z,L060C         ; forward, if checking syntax, to TEST-NEXT.

        PUSH    AF              ; save following character.

        LD      A,C             ; in runtime check 
        DEC     A               ; immediately for 
        OR      B               ; a single character.

        JR      NZ,L062D        ; forward, if not, to NREPORT-3
                                ; 'Invalid device expression'

        LD      A,(DE)          ; fetch the addressed character.

        RST     10H             ; CALBAS
        DEFW    $2C8D           ; main ALPHA

        JR      NC,L062D        ; forward, if not alphabetic, to NREPORT-3

        AND     $DF             ; convert to uppercase with 'AND %11011111'

        LD      ($5CD9),A       ; place in system variable L_STR1 device letter.

        POP     AF              ; restore the following character.

;; TEST-NEXT
L060C:  CP      $0D             ; test for carriage return.
        RET     Z               ; return if so.

        CP      $3A             ; is character ':' ?
        RET     Z               ; return if so.

        CP      $A5             ; RND
        RET     NC              ; return with a token??

        CALL    L05B1           ; routine SEPARATOR tests for both ';' and ','.

        JP      NZ,L04B2        ; jump back, if not, to OREPORT-1
                                ; 'Nonsense in BASIC'

        RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR

; -----------------------------------------------
; THE 'EVALUATE NUMERIC DRIVE EXPRESSION' ROUTINE
; -----------------------------------------------
;   This routine is called once only to evaluate the numeric expression
;   following a 'CAT' command token or is used from above to check a numeric 
;   expression following for example "M"; .

;; EXPT-NUM
L061E:  RST     10H             ; CALBAS
        DEFW    $1C82           ; main EXPT-1NUM
        RST     18H             ; checking syntax ?
        RET     Z               ; return if checking syntax.

        PUSH    AF              ; save NZ not syntax flag

        RST     10H             ; CALBAS
        DEFW    $1E99           ; main FIND-INT2

        LD      ($5CD6),BC      ; set system variable D_STR1 drive number

        POP     AF              ; restore NZ not syntax flag

        RET                     ; return.

; ---

;; NREPORT-3
L062D:  RST     20H             ; Shadow Error Restart
        DEFB    $02             ; 'Invalid device expression'

; -------------------------------
; THE 'EVALUATE FILENAME' ROUTINE
; -------------------------------
;

;; EXPT-NAME
L062F:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        CALL    L05E7           ; routine EXPT-STR
        RET     Z

        PUSH    AF
        LD      A,C
        OR      B
        JR      Z,L064C         ; forward to NREPORT-4

        LD      HL,$000A
        SBC     HL,BC
        JR      C,L064C         ; forward to NREPORT-4

        LD      ($5CDA),BC      ; sv N_STR1
        LD      ($5CDC),DE      ; sv D_STR1
        POP     AF
        RET

; ---

;; NREPORT-4
L064C:  RST     20H             ; Shadow Error Restart
        DEFB    $03             ; Invalid name

; ------------------------------------
; THE 'EVALUATE STREAM NUMBER' ROUTINE
; ------------------------------------
;

;; EXPT-STRM
L064E:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        RST     10H             ; CALBAS
        DEFW    $1C82           ; main EXPT-1NUM
        RST     18H             ; checking syntax ?
        RET     Z               ;

        PUSH    AF              ;
        RST     10H             ; CALBAS
        DEFW    $1E94           ; main FIND-INT1
        CP      $10             ;
        JR      NC,L0663        ; forward to NREPORT-2

        LD      ($5CD8),A       ; sv D_STR1
        POP     AF              ;
        RET                     ;

; ---

;; NREPORT-2
L0663:  RST     20H             ; Shadow Error Restart
        DEFB    $01             ; Invalid stream number


; ----------------------------------
; THE 'CHECK "M" PARAMETERS' ROUTINE
; ----------------------------------
; called once from TEST-MNAM

;; CHECK-M
L0665:  LD      A,($5CD9)       ; fetch system variable L_STR1 device letter.
        CP      $4D             ; is character "M" ?
        JP      NZ,L062D        ; jump back, if not, to NREPORT-3
                                ; Error: 'Invalid device expression'.

;; CHECK-M-2
L066D:  LD      DE,($5CD6)      ; fetch system variable D_STR1 drive number.
        LD      A,E             ; test for
        OR      D               ; zero.
        JR      Z,L0681         ; forward, if so, to NREPORT-5
                                ; 'Invalid drive number'

        INC     DE              ; also test that
        LD      A,E             ; location does not hold
        OR      D               ; the default $FFFF value.
        JR      Z,L0683         ; forward, if so, to NREPORT-9
                                ; 'Missing drive number'.

        DEC     DE              ; restore to initial value.
        LD      HL,L0008        ; and test that
        SBC     HL,DE           ; drive is in range 1 - 8.
        RET     NC              ; return if so.


;; NREPORT-5
L0681:  RST     20H             ; Shadow Error Restart
        DEFB    $04             ; Invalid drive number
; ---

;; NREPORT-9
L0683:  RST     20H             ; Shadow Error Restart
        DEFB    $08             ; Missing drive number

; -----------------------------------------------
; THE 'CHECK "M" PARAMETERS AND FILENAME' ROUTINE
; -----------------------------------------------
; This routine checks that the device expression is "M", that the drive is in
; the range 1 - 8 and that the filename is not null.

;; TEST-MNAM
L0685:  CALL    L0665           ; routine CHECK-M checks for "M" and valid 
                                ; drive number.

        LD      A,($5CDB)       ; load A with D_STR1 the high byte of length
                                ; of filename.
        AND     A               ; test for zero.
        RET     Z               ; return if so.

; else system default $FF.

        RST     20H             ; Shadow Error Restart
        DEFB    $06             ; Missing name


; ----------------------------------
; THE 'CHECK STATION NUMBER' ROUTINE
; ----------------------------------
;

;; TEST-STAT
L068F:  LD      DE,($5CD6)      ; sv D_STR1 drive number
        INC     DE
        LD      A,E
        OR      D
        JR      Z,L06A1         ; forward to NREPORT-8

        DEC     DE
        LD      HL,L0040
        SBC     HL,DE
        RET     NC


;; NREPORT-6
L069F:  RST     20H             ; Shadow Error Restart
        DEFB    $05             ; Invalid station number

;; NREPORT-8
L06A1:  RST     20H             ; Shadow Error Restart
        DEFB    $07             ; Missing station number

; -----------------------------------
; THE 'EVALUATE "X";N;"NAME"' ROUTINE
; -----------------------------------
;

;; EXPT-EXPR
L06A3:  CALL    L05F2           ; routine EXPT-SPEC
        CALL    L05B1           ; routine SEPARATOR
        JP      NZ,L04B2        ; jump to OREPORT-1
                                ; 'Nonsense in BASIC'

        CALL    L062F           ; routine EXPT-NAME
        RET                     ; return...


; -----------------------------
; THE 'CHECK BAUD RATE' ROUTINE
; -----------------------------
;

;; TEST-BAUD
L06B0:  LD      HL,($5CD6)      ; sv D_STR1 drive number
        INC     HL
        LD      A,L
        OR      H
        RET     NZ

        RST     20H             ; Shadow Error Restart
        DEFB    $09             ; Missing baud rate

; -------------------------------------------
; THE 'EVALUATE STREAM OR EXPRESSION' ROUTINE
; -------------------------------------------
;

;; EXPT-EXP1
L06B9:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        CP      $23             ; is character '#' ?
        JP      Z,L064E         ; jump to EXPT-STRM

        CALL    L05F5           ; routine EXP-SPEC2
        CALL    L05B1           ; routine SEPARATOR
        JR      NZ,L06CC        ; forward to ENDHERE

        CALL    L062F           ; routine EXPT-NAME

;; ENDHERE
L06CC:  RST     18H             ; checking syntax ?
        RET     Z

        LD      A,($5CD9)       ; sv L_STR1 device letter.
        CP      $54             ; is character "T" ?
        RET     Z               ;

        CP      $42             ; is character "B" ?
        RET     Z               ;

        CP      $4E             ; is character "N" ?
        JP      Z,L068F         ; jump, if so, to TEST-STAT

        JP      L0685           ; jump to TEST-MNAM

; ---

        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF

; --------------------
; THE 'UNPAGE' ROUTINE
; --------------------
;

;; UNPAGE
L0700:  RET


; ---------------------------------
; THE 'EVALUATE PARAMETERS' ROUTINE
; ---------------------------------
;

;; EXPT-PRMS
L0701:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        CP      $2A             ; is character '*'
        JR      NZ,L073C        ; forward, if not, to OREP-1-2

        RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        CALL    L05F5           ; routine EXP-SPEC2
        CALL    L05B1           ; routine SEPARATOR
        JR      NZ,L0716        ; forward to NO-NAME

        CALL    L062F           ; routine EXPT-NAME

;; NO-NAME
L0716:  PUSH    AF
        LD      A,($5CD9)       ; sv L_STR1 device letter.

        CP      $4E             ; is character "N" ?
        JR      NZ,L0722        ; forward, if not, to NOT-NET

        SET     3,(IY+$7C)      ; update FLAGS_3 signal networking.

;; NOT-NET
L0722:  POP     AF
        CP      $0D             ; is character carriage return ?
        JR      Z,L0750         ; forward to END-EXPT

        CP      $3A             ; is character ':' ?
        JR      Z,L0750         ; forward to END-EXPT

        CP      $AA             ; is character the token 'SCREEN$' ?
        JR      Z,L0771         ; forward to SCREEN$

        CP      $AF             ; is character the token 'CODE' ?
        JR      Z,L0789         ; forward to CODE

        CP      $CA             ; is character the token 'LINE' ?
        JR      Z,L073E         ; forward to LINE

        CP      $E4             ; is character the token 'DATA' ?
        JP      Z,L07D2         ; jump to DATA

;; OREP-1-2
L073C:  RST     20H             ; Shadow Error Restart
        DEFB    $00             ; Nonsense in BASIC

; ---

;; LINE
L073E:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR

        RST     10H             ; CALBAS
        DEFW    $1C82           ; main EXPT-1NUM

        CALL    L05B7           ; routine ST-END

        RST     10H             ; CALBAS
        DEFW    $1E99           ; main FIND-INT2

        LD      ($5CED),BC      ; sv HD_11
        JR      L0753           ; forward to PROG

; ---

;; END-EXPT
L0750:  CALL    L05B7           ; routine ST-END

; the 'PROGRAM' SUBROUTINE is used when loading 'run'.

;; PROG
L0753:  XOR     A               ;
        LD      ($5CE6),A       ; sv HD_00
        LD      HL,($5C59)      ; sv E_LINE
        LD      DE,($5C53)      ; sv PROG
        LD      ($5CE9),DE      ; sv HD_0D
        SCF                     ;
        SBC     HL,DE           ;
        LD      ($5CE7),HL      ; sv HD_0B
        LD      HL,($5C4B)      ; sv VARS
        SBC     HL,DE           ;
        LD      ($5CEB),HL      ; sv HD_0F
        RET

; ---

;; SCREEN$
L0771:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR

        CALL    L05B7           ; routine ST-END
        LD      HL,$1B00
        LD      ($5CE7),HL      ; sv HD_0B
        LD      HL,$4000
        LD      ($5CE9),HL      ; sv HD_0D
        LD      A,$03
        LD      ($5CE6),A       ; sv HD_00
        RET

; ---

;; CODE
L0789:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR

        CP      $0D             ; is character a carriage return ?
        JR      Z,L079A         ; forward to DEFLT-0

        CP      $3A             ; is character a ':' ?
        JR      NZ,L079F        ; forward to PAR-1

        BIT     5,(IY+$7C)      ; sv FLAGS_3
        JR      NZ,L073C        ; back to OREP-1-2


;; DEFLT-0
L079A:  RST     10H             ; CALBAS
        DEFW    $1CE6           ; main USE-ZERO
        JR      L07A7           ; forward to TEST-SAVE

; ---

;; PAR-1
L079F:  RST     10H             ; CALBAS
        DEFW    $1C82           ; main EXPT-1NUM
        CALL    L05B1           ; routine SEPARATOR
        JR      Z,L07B2         ; forward to PAR-2


;; TEST-SAVE
L07A7:  BIT     5,(IY+$7C)      ; sv FLAGS_3
        JR      NZ,L073C        ; back to OREP-1-2

        RST     10H             ; CALBAS
        DEFW    $1CE6           ; main USE-ZERO
        JR      L07B8           ; forward to END-CODE

; ---

;; PAR-2
L07B2:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        RST     10H             ; CALBAS
        DEFW    $1C82           ; main EXPT-1NUM

;; END-CODE
L07B8:  RST     10H             ; CALBAS
        DEFW    $0018           ; main GET-CHAR

        CALL    L05B7           ; routine ST-END

        RST     10H             ; CALBAS
        DEFW    $1E99           ; main FIND-INT2
        LD      ($5CE7),BC      ; sv HD_0B

        RST     10H             ; CALBAS
        DEFW    $1E99           ; main FIND-INT2
        LD      ($5CE9),BC      ; sv HD_0D

        LD      A,$03
        LD      ($5CE6),A       ; sv HD_00
        RET                     ; return.

; ---
;
; ---


;; DATA
L07D2:  BIT     6,(IY+$7C)      ; sv FLAGS_3
        JR      Z,L07DA         ; forward to NO-M-ARR

        RST     20H             ; Shadow Error Restart
        DEFB    $14             ; MERGE error

;; NO-M-ARR
L07DA:  RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        RST     10H             ; CALBAS
        DEFW    $28B2           ; main LOOK-VARS

        SET     7,C
        JR      NC,L07F2        ; forward to EXISTING

        LD      HL,$0000
        BIT     4,(IY+$7C)      ; sv FLAGS_3
        JR      NZ,L080E        ; forward to LD-DATA

        LD      (IY+$00),$01    ; sv ERR_NR to '2 Variable not found'
        RST     28H             ; Error Main ROM

; ---

;; EXISTING
L07F2:  JR      Z,L07F6         ; forward to G-TYPE


;; NONS-BSC
L07F4:  RST     20H             ; Shadow Error Restart
        DEFB    $00             ; Nonsense in BASIC

; ---

;; G-TYPE
L07F6:  RST     18H             ; checking syntax ?
        JR      Z,L081C         ; forward to END-DATA

        BIT     5,(IY+$7C)      ; sv FLAGS_3
        JR      Z,L0803         ; forward to VR-DATA

        BIT     7,(HL)
        JR      Z,L07F4         ; back to NONS-BSC


;; VR-DATA
L0803:  INC     HL
        LD      A,(HL)
        LD      ($5CE7),A       ; sv HD_0B
        INC     HL
        LD      A,(HL)
        LD      ($5CE8),A       ; sv HD_0B_hi
        INC     HL

;; LD-DATA
L080E:  LD      A,C
        LD      ($5CEB),A       ; sv HD_0F
        LD      A,$01
        BIT     6,C
        JR      Z,L0819         ; forward to NUM-ARR

        INC     A

;; NUM-ARR
L0819:  LD      ($5CE6),A       ; sv HD_00

;; END-DATA
L081C:  EX      DE,HL
        RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        CP      $29             ; is character ')' ?
        JR      NZ,L07F4        ; back to NONS-BSC

        RST     10H             ; CALBAS
        DEFW    $0020           ; main NEXT-CHAR


        CALL    L05B7           ; routine ST-END
        LD      ($5CE9),DE      ; sv HD_0D
        RET                     ; return.


; ---------------------------------
; THE 'SAVE COMMAND SYNTAX' ROUTINE
; ---------------------------------
;

;; SAVE-SYN
L082F:  SET     5,(IY+$7C)      ; sv FLAGS_3
        CALL    L0701           ; routine EXPT-PRMS

        LD      A,($5CD9)       ; sv L_STR1 device letter.

        CP      $42             ; is character 'B' ?
        JR      Z,L084F         ; forward to SA-HEADER

        CP      $4E             ; is character 'N' ?
        JR      NZ,L0849        ; forward to SAVE-M

        CALL    L068F           ; routine TEST-STAT
        CALL    L0F46           ; routine OP-TEMP-N
        JR      L084F           ; forward to SA-HEADER

; ---

;; SAVE-M
L0849:  CALL    L0685           ; routine TEST-MNAM
        JP      L1AC4           ; jump to SAVE-RUN

; ---

;; SA-HEADER
L084F:  LD      B,$09
        LD      HL,$5CE6        ; sv HD_00

;; HD-LOOP
L0854:  CALL    L0884           ; routine SA-BYTE
        INC     HL
        DJNZ    L0854           ; back to HD-LOOP

        LD      HL,($5CE9)      ; sv HD_0D
        BIT     3,(IY+$7C)      ; sv FLAGS_3
        JR      Z,L086E         ; forward to SA-BLOCK

        LD      A,($5CE6)       ; sv HD_00
        CP      $03             ; compare with three - type CODE
        JR      NC,L086E        ; forward to SA-BLOCK

        LD      DE,$0114        ;
        ADD     HL,DE           ;

;; SA-BLOCK
L086E:  LD      BC,($5CE7)      ; sv HD_0B

;; SA-BLK-LP
L0872:  LD      A,C             ;
        OR      B               ;
        JR      Z,L0881         ; forward to S-BLK-END

        PUSH    IX              ;;;

        CALL    L0884           ; routine SA-BYTE

        POP     IX              ;;;

        DEC     BC              ;
        INC     HL              ;
        JR      L0872           ; back to SA-BLK-LP

; ---

;; S-BLK-END
L0881:  JP      L098C           ; jump to TST-MR-M

; --------------------------------------------------
; THE 'SAVE A BYTE TO NETWORK OR RS232 LINK' ROUTINE
; --------------------------------------------------
;

;; SA-BYTE
L0884:  PUSH    HL              ;
        PUSH    BC              ;
        BIT     3,(IY+$7C)      ; sv FLAGS_3
        LD      A,(HL)          ;
        JR      NZ,L0892        ; forward to SA-NET

        CALL    L0D07           ; routine BCHAN-OUT
        JR      L0895           ; forward to SA-B-END

; ---

;; SA-NET
L0892:  CALL    L0E09           ; routine NCHAN-OUT

;; SA-B-END
L0895:  POP     BC              ;
        POP     HL              ;
        RET                     ;


; ---------------------------------
; THE 'LOAD COMMAND SYNTAX' ROUTINE
; ---------------------------------
;

;; LOAD-SYN
L0898:  SET     4,(IY+$7C)      ; sv FLAGS_3
        CALL    L0701           ; routine EXPT-PRMS
        JP      L08B3           ; jump to LD-VF-MR

; -----------------------------------
; THE 'VERIFY COMMAND SYNTAX' ROUTINE
; -----------------------------------
;

;; VERIF-SYN
L08A2:  SET     7,(IY+$7C)      ; sv FLAGS_3
        CALL    L0701           ; routine EXPT-PRMS
        JP      L08B3           ; jump to LD-VF-MR

; ----------------------------------
; THE 'MERGE COMMAND SYNTAX' ROUTINE
; ----------------------------------
;

;; MRG-SYN
L08AC:  SET     6,(IY+$7C)      ; sv FLAGS_3
        CALL    L0701           ; routine EXPT-PRMS

; ----------------------------------------
; THE 'LOAD-VERIFY-MERGE COMMANDS' ROUTINE
; ----------------------------------------
;

;; LD-VF-MR
L08B3:  LD      HL,$5CE6        ; set source to HD_00
        LD      DE,$5CDE        ; set destination to D_STR2
        LD      BC,$0007        ; seven bytes to copy.
        LDIR                    ; copy type, start, length, length of program.

        LD      A,($5CD9)       ; sv L_STR1 device letter.

        CP      $4E             ; "N" ?

        JR      Z,L08D1         ; forward to TS-L-NET

        CP      $42             ; "B" ?

        JR      Z,L08D7         ; forward to TS-L-RS

; proceed with Microdrive device.

        CALL    L0685           ; routine TEST-MNAM return without error if
                                ; device is "M" and drive and filename are OK.

        CALL    L1971           ; routine F-M-HEAD loads the header type
                                ; record for the above filename and populates
                                ; the locations HD_00 to HD_11.

        JR      L08F6           ; forward to TEST-TYPE which tests that file
                                ; types agree and then loads rest of records.

; ---

;; TS-L-NET
L08D1:  CALL    L068F           ; routine TEST-STAT
        CALL    L0F46           ; routine OP-TEMP-N

;; TS-L-RS
L08D7:  LD      HL,$5CE6        ; sv HD_00
        LD      B,$09           ;

;; LD-HEADER
L08DC:  PUSH    HL
        PUSH    BC
        BIT     3,(IY+$7C)      ; sv FLAGS_3
        JR      Z,L08EB         ; forward to LD-HD-RS


;; LD-HD-NET
L08E4:  CALL    L0DAF           ; routine NCHAN-IN
        JR      NC,L08E4        ; back to LD-HD-NET

        JR      L08F0           ; forward to LD-HDR-2

; ---

;; LD-HD-RS
L08EB:  CALL    L0B88           ; routine BCHAN-IN
        JR      NC,L08EB        ; back to LD-HD-RS


;; LD-HDR-2
L08F0:  POP     BC
        POP     HL
        LD      (HL),A
        INC     HL
        DJNZ    L08DC           ; back to LD-HEADER

; -->

;; TEST-TYPE
L08F6:  LD      A,($5CDE)       ; sv D_STR2
        LD      B,A
        LD      A,($5CE6)       ; sv HD_00
        CP      B
        JR      NZ,L0906        ; forward to NREPORT-N

        CP      $03             ; compare with three - type CODE
        JR      Z,L0915         ; forward to T-M-CODE

        JR      C,L0908         ; forward to TST-MERGE

;; NREPORT-N
L0906:  RST     20H             ; Shadow Error Restart
        DEFB    $16             ; Wrong file type

; ---

;; TST-MERGE
L0908:  BIT     6,(IY+$7C)      ; sv FLAGS_3
        JR      NZ,L096B        ; forward to MERGE-BLK

        BIT     7,(IY+$7C)      ; sv FLAGS_3
        JP      Z,L09A7         ; jump to LD-PR-AR

;; T-M-CODE
L0915:  BIT     6,(IY+$7C)      ; sv FLAGS_3
        JR      Z,L091D         ; forward to LD-BLOCK

        RST     20H             ; Shadow Error Restart
        DEFB    $14             ; MERGE error

; ---

;; LD-BLOCK
L091D:  LD      HL,($5CDF)      ; sv D_STR2 (+1) length of data
        LD      DE,($5CE7)      ; sv HD_0B
        LD      A,H             ;
        OR      L               ;
        JR      Z,L0936         ; forward to LD-BLK-2

        SBC     HL,DE           ;
        JR      NC,L0936        ; forward to LD-BLK-2

        BIT     4,(IY+$7C)      ; sv FLAGS_3
        JR      Z,L0934         ; forward to NREPORT-L

        RST     20H             ; Shadow Error Restart
        DEFB    $13             ; Code Error

; ---

;; NREPORT-L
L0934:  RST     20H             ; Shadow Error Restart
        DEFB    $15             ; Verification has failed

; ---

;; LD-BLK-2
L0936:  LD      HL,($5CE1)      ; sv L_STR2
        LD      A,(IX+$04)      ; channel letter
        CP      $CD             ; 'M' +$80 ?
        JR      NZ,L0945        ; forward to LD-BLK-3

        LD      HL,($5CE4)      ; sv D_STR2             ********
        JR      L0956           ; forward to LD-BLK-4

; ---

;; LD-BLK-3
L0945:  BIT     3,(IY+$7C)      ; sv FLAGS_3
        JR      Z,L0956         ; forward to LD-BLK-4

        LD      A,($5CE6)       ; sv HD_00
        CP      $03             ; compare with three - type CODE
        JR      Z,L0956         ; forward to LD-BLK-4

        LD      BC,$0114        ;
        ADD     HL,BC           ;

;; LD-BLK-4
L0956:  LD      A,H             ;
        OR      L               ;
        JR      NZ,L095D        ; forward to LD-BLK-5

        LD      HL,($5CE9)      ; sv HD_0D

;; LD-BLK-5
L095D:  LD      A,($5CE6)       ; sv HD_00
        AND     A               ;
        JR      NZ,L0966        ; forward to LD-NO-PGM

        LD      HL,($5C53)      ; sv PROG

;; LD-NO-PGM
L0966:  CALL    L0A60           ; routine LV-ANY
        JR      L098C           ; forward to TST-MR-M

; ---


;; MERGE-BLK
L096B:  LD      A,($5CEE)       ; sv HD_11_hi
        AND     $C0             ;
        JR      NZ,L0977        ; forward to NO-AUTOST

        CALL    L17B7           ; routine RCL-T-CH


        RST     20H             ; Shadow Error Restart
        DEFB    $14             ; MERGE error

; ---

;; NO-AUTOST
L0977:  LD      BC,($5CE7)      ; sv HD_0B
        PUSH    BC              ;
        INC     BC              ;

        RST     10H             ; CALBAS
        DEFW    $0030           ; main BC-SPACES

        LD      (HL),$80        ;
        EX      DE,HL           ;
        POP     DE              ;
        PUSH    HL              ;
        CALL    L0A60           ; routine LV-ANY
        POP     HL              ;

        RST     10H             ; CALBAS
        DEFW    $08CE           ; main ME-CTRLX

; ---

;; TST-MR-M
L098C:  LD      A,(IX+$04)      ; channel letter
        CP      $CD             ; 'M' + $80 ?
        JR      NZ,L0998        ; forward to TST-MR-N

        CALL    L138E           ; routine CLOSE-M2
        JR      L09A4           ; forward to MERGE-END

; ---

;; TST-MR-N
L0998:  BIT     3,(IY+$7C)      ; sv FLAGS_3
        JR      Z,L09A4         ; forward to MERGE-END

        CALL    L0FAE           ; routine SEND-NEOF
        CALL    L17B7           ; routine RCL-T-CH

;; MERGE-END
L09A4:  JP      L05C1           ; jump to END1

; ---

;; LD-PR-AR
L09A7:  LD      DE,($5CE7)      ; sv HD_0B
        LD      HL,($5CE1)      ; sv L_STR2
        PUSH    HL              ;
        LD      A,H             ;
        OR      L               ;
        JR      NZ,L09B9        ; forward to LD-PROG

        INC     DE              ;
        INC     DE              ;
        INC     DE              ;
        EX      DE,HL           ;
        JR      L09C2           ; forward to TST-SPACE

; ---


;; LD-PROG
L09B9:  LD      HL,($5CDF)      ; sv D_STR2 (+1) length of data
        EX      DE,HL           ;
        SCF                     ;
        SBC     HL,DE           ;
        JR      C,L09CB         ; forward to TST-TYPE


;; TST-SPACE
L09C2:  LD      DE,$0005        ;
        ADD     HL,DE           ;
        LD      B,H             ;
        LD      C,L             ;

        RST     10H             ; CALBAS
        DEFW    $1F05           ; main TEST-ROOM

;   Note. that before the above call, interrupts are disabled and the motor
;   of the microdrive is running.  If there should be insufficient room,
;   then the processor stops at the HALT instruction at address $1303
;   (MAIN-4), in the main ROM, while trying to output the "Out of Memory"
;   report.  This could be corrected by replacing the above 3 bytes to a
;   call to a 6-byte subroutine which carries out the same instructions
;   between an EI/DI pair.  In the production of the "Out of Memory" report
;   this ROM will be paged again by the instruction fetch at 0008. The
;   motors are stopped at START-4 and then Control will then pass to the
;   other ROM to execute the "LD A,(HL)", then back to this ROM to eliminate
;   the "OK" message before a final switch to the Main ROM for the actual
;   message text.

;; TST-TYPE
L09CB:  POP     HL
        LD      A,($5CE6)       ; sv HD_00
        AND     A
        JR      Z,L0A19         ; forward to SET-PROG

        LD      A,H
        OR      L
        JR      Z,L09F7         ; forward to CRT-NEW

        LD      A,(IX+$04)      ; channel letter
        CP      $CD             ; is character an inverted "M" ?
        JR      NZ,L09E2        ; forward to T-LD-NET

        LD      HL,($5CE4)      ; sv D_STR2
        JR      L09EC           ; forward to RCLM-OLD

; ---

;; T-LD-NET
L09E2:  BIT     3,(IY+$7C)      ; sv FLAGS_3
        JR      Z,L09EC         ; forward to RCLM-OLD

        LD      DE,$0114
        ADD     HL,DE

;; RCLM-OLD
L09EC:  DEC     HL
        LD      B,(HL)
        DEC     HL
        LD      C,(HL)
        DEC     HL
        INC     BC
        INC     BC
        INC     BC
        RST     10H             ; CALBAS
        DEFW    $19E8           ; main RECLAIM-2

;; CRT-NEW
L09F7:  LD      HL,($5C59)      ; sv E_LINE
        DEC     HL
        LD      BC,($5CE7)      ; sv HD_0B
        PUSH    BC
        INC     BC
        INC     BC
        INC     BC
        LD      A,($5CE3)       ; sv D_STR2
        PUSH    AF
        RST     10H             ; CALBAS
        DEFW    $1655           ; main MAKE-ROOM
        INC     HL
        POP     AF
        LD      (HL),A
        POP     DE
        INC     HL
        LD      (HL),E
        INC     HL
        LD      (HL),D
        INC     HL

;; END-LD-PR
L0A13:  CALL    L0A60           ; routine LV-ANY

        JP      L098C           ; jump to TST-MR-M

; ---

;; SET-PROG
L0A19:  RES     1,(IY+$7C)      ; sv FLAGS_3
        LD      DE,($5C53)      ; sv PROG
        LD      HL,($5C59)      ; sv E_LINE
        DEC     HL
        RST     10H             ; CALBAS
        DEFW    $19E5           ; main RECLAIM-1
        LD      BC,($5CE7)      ; sv HD_0B
        LD      HL,($5C53)      ; sv PROG
        RST     10H             ; CALBAS
        DEFW    $1655           ; main MAKE-ROOM
        INC     HL
        LD      BC,($5CEB)      ; sv HD_0F
        ADD     HL,BC
        LD      ($5C4B),HL      ; sv VARS
        LD      A,($5CEE)       ; sv HD_11_hi
        LD      H,A
        AND     $C0
        JR      NZ,L0A52        ; forward to NO-AUTO

        SET     1,(IY+$7C)      ; sv FLAGS_3
        LD      A,($5CED)       ; sv HD_11
        LD      L,A
        LD      ($5C42),HL      ; sv NEWPPC
        LD      (IY+$0A),$00    ; sv NSPPC

;; NO-AUTO
L0A52:  LD      HL,($5C53)      ; sv PROG
        LD      DE,($5CE7)      ; sv HD_0B
        DEC     HL
        LD      ($5C57),HL      ; sv DATADD
        INC     HL
        JR      L0A13           ; back to END-LD-PR


; ----------------------------
; THE 'LOAD OR VERIFY' ROUTINE
; ----------------------------
;   This routine is able to either LOAD or VERIFY a block of bytes, from any 
;   of the three possible binary sources, A Microdrive cartridge, the Binary
;   "B" RS232 channel or the Network "N" channel.
;   The block could be a program, code bytes or an array and the first 
;   receiving location is in HL and the length in DE.

;; LV-ANY
L0A60:  LD      A,D             ; test the length
        OR      E               ; for zero.
        RET     Z               ; return if so.

        LD      A,(IX+$04)      ; fetch channel letter
        CP      $CD             ; is letter "M" + $80 ?

        JR      NZ,L0A6E        ; forward, if not, to LV-BN to load from 
                                ; the B channel or network.

; else is a temporary "M" channel so load or verify and then return.

        CALL    L199A           ; routine LV-MCH loads or verifies a block
                                ; of code from microdrive.

        RET                     ; return after called routine.

; ---

; Load or Verify from B channel or Network.

;; LV-BN
L0A6E:  PUSH    HL              ; save address.
        PUSH    DE              ; save byte count.
        BIT     3,(IY+$7C)      ; test FLAGS_3 - using network ?
        JR      Z,L0A7D         ; forward, if not, to LV-B

; Load or Verify from "N" channel.

;; LV-N
L0A76:  CALL    L0DAF           ; routine NCHAN-IN
        JR      NC,L0A76        ; back to LV-N

        JR      L0A82           ; forward to LV-BN-E

; ---

; Load or Verify from "B" channel.

;; LV-B
L0A7D:  CALL    L0B88           ; routine BCHAN-IN
        JR      NC,L0A7D        ; back to LV-B

; Load or Verify "B","N" end test.

;; LV-BN-E
L0A82:  POP     DE              ; restore code length.
        DEC     DE              ; and decrement.
        POP     HL              ; restore load address.

        BIT     7,(IY+$7C)      ; test FLAGS_3 - verify operation.
        JR      NZ,L0A8E        ; forward, if so missing load, to VR-BN

        LD      (HL),A          ; load the byte into memory.
        JR      L0A93           ; forward to LVBN-END

; ---

; Verify "B" or "N" bytes.

;; VR-BN
L0A8E:  CP      (HL)            ; compare the received byte with the byte in
                                ; memory.
        JR      Z,L0A93         ; forward, with match, to LVBN-END.

        RST     20H             ; Shadow Error Restart
        DEFB    $15             ; 'Verification has failed'

; ---

; Load or Verify "B","N" end.

;; LVBN-END
L0A93:  INC     HL              ; increment the address.
        LD      A,E             ; test the byte 
        OR      D               ; counter for zero.
        JR      NZ,L0A6E        ; back, if not, to LV-BN

        RET                     ; return.


; --------------------------------
; THE 'LOAD "RUN" PROGRAM' ROUTINE
; --------------------------------
;

;; LOAD-RUN
L0A99:  LD      BC,$0001        ; set drive to one.
        LD      ($5CD6),BC      ; update D_STR1 drive number.

        LD      BC,$0003        ; length of "run" is three.
        LD      ($5CDA),BC      ; update N_STR1 length of filename.

        LD      BC,L0ACA        ; addr: NAME-RUN (below)
        LD      ($5CDC),BC      ; update A_STR1 - address of filename.

        SET     4,(IY+$7C)      ; update FLAGS_3 signal a LOAD operation.

        CALL    L0753           ; routine PROG sets up the first seven header 
                                ; bytes for a program.

        LD      HL,$5CE6        ; set start to HD_00
        LD      DE,$5CDE        ; set destination to D_STR2
        LD      BC,$0009        ; nine bytes are copied.
                                ; Note. should be seven but is mostly harmless.

        LDIR                    ; block copy.

        SET     7,(IY+$0A)      ; update Main NSPPC - signal no jump to be made.

        CALL    L1971           ; routine F-M-HEAD loads the header type 
                                ; record for the 'run' file and populates
                                ; the nine locations HD_00 to HD_11.

        JP      L08F6           ; jump back to TEST-TYPE to test that type is
                                ; 'program' and load the rest.

; ---

;; NAME-RUN
L0ACA:  DEFM    "run"           ; the filename "run"

; *******************************************
; **  T H E   R S 2 3 2   R O U T I N E S  **
; *******************************************

; ----------------------------------------
; THE 'SET "BAUD" SYSTEM VARIABLE' ROUTINE
; ----------------------------------------
;

;; SET-BAUD
L0ACD:  LD      BC,($5CD6)      ; sv D_STR1 drive number
        LD      HL,L0AF3        ; RS-CONSTS

;; NXT-ENTRY
L0AD4:  LD      E,(HL)
        INC     HL
        LD      D,(HL)
        INC     HL
        EX      DE,HL
        LD      A,H
        CP      $4B             ;
        JR      NC,L0AE8        ; forward to END-SET

        AND     A
        SBC     HL,BC
        JR      NC,L0AE8        ; forward to END-SET

        EX      DE,HL
        INC     HL
        INC     HL
        JR      L0AD4           ; loop back to NXT-ENTRY

; ---

;; END-SET
L0AE8:  EX      DE,HL
        LD      E,(HL)
        INC     HL
        LD      D,(HL)
        LD      ($5CC3),DE      ; sv BAUD
        JP      L05C1           ; jump to END1

; ------------------------------------
; THE 'RS232 TIMING CONSTANTS' ROUTINE
; ------------------------------------
;

;; RS-CONSTS
L0AF3:  DEFW    $0032           ;
        DEFW    $0A82           ;
        DEFW    $006E           ;
        DEFW    $04C5           ;
        DEFW    $012C           ;
        DEFW    $01BE           ;
        DEFW    $0258           ;
        DEFW    $00DE           ;
        DEFW    $04B0           ;
        DEFW    $006E           ;
        DEFW    $0960           ;
        DEFW    $0036           ;
        DEFW    $12C0           ;
        DEFW    $001A           ;
        DEFW    $2580           ;
        DEFW    $000C           ;
        DEFW    $4B00           ;
        DEFW    $0005           ;


; ----------------------------------------------
; THE 'OPEN RS232 CHANNEL IN CHANS AREA' ROUTINE
; ----------------------------------------------
;

;; OP-RS-CH
L0B17:  LD      HL,($5C53)      ; use system variable PROG to address the
                                ; location following the Channels area.
        DEC     HL              ; step back to the end-marker.
        LD      BC,$000B        ; eleven bytes of room required.
        PUSH    BC              ; save bytes

        RST     10H             ; CALBAS
        DEFW    $1655           ; main routine MAKE-ROOM opens up the space.
                                ; register HL points to location before room.

        POP     BC              ; bring back the eleven bytes.

        PUSH    DE              ; save DE briefly
        CALL    L1A82           ; routine REST-N-AD adjusts the dynamic memory
                                ; pointers to filenames in D_STR1 and D_STR2.
        POP     DE              ; restore DE.

        LD      HL,L0B76 - 1    ; last byte of T-Channel info.
        LD      BC,$000B        ; eleven bytes to copy.
        LDDR                    ; block copy downwards.

        INC     DE              ;
        LD      A,($5CD9)       ; sv L_STR1 device letter.
        CP      $42             ; is it "B" ?
        RET     NZ              ; return as must be "T".

; but if this is to be a binary channel then overwrite the letter and the output
; and input routines.

        PUSH    DE              ;

        LD      HL,$0004        ;
        ADD     HL,DE           ;

        LD      (HL),$42        ; 'B'
        INC     HL              ;

        LD      DE,L0D07        ; address B-CHAN-OUT
        LD      (HL),E          ;
        INC     HL              ;
        LD      (HL),D          ;
        INC     HL              ;

        LD      DE,L0B7C        ; address B-INPUT
        LD      (HL),E          ;
        INC     HL              ;
        LD      (HL),D          ;

        POP     DE              ;
        RET                     ; return.


; ----------------------------------------
; THE 'ATTACH CHANNEL TO A STREAM' ROUTINE
; ----------------------------------------
;

;; OP-RSCHAN
L0B4E:  CALL    L0B17           ; routine OP-RS-CH

;; OP-STREAM
L0B51:  LD      HL,($5C4F)      ; sv CHANS
        DEC     HL
        EX      DE,HL
        AND     A
        SBC     HL,DE
        EX      DE,HL
        LD      HL,$5C16        ; sv STRMS_00
        LD      A,($5CD8)       ; sv D_STR1
        RLCA
        LD      C,A
        LD      B,$00
        ADD     HL,BC
        LD      (HL),E
        INC     HL
        LD      (HL),D
        JP      L05C1           ; jump to END1

; ----------------------
; THE '"T" CHANNEL DATA'
; ----------------------
; the eleven-byte "T" CHANNEL descriptor.

;; TCHAN-DAT
L0B6B:  DEFW    $0008           ; main ERROR-1
        DEFW    $0008           ; main ERROR-1
        DEFB    $54             ; character "T"
        DEFW    L0C3A           ; TCHAN-OUT
        DEFW    L0B76           ; T-INPUT
        DEFW    $000B           ; channel length - 11 bytes.

; -------------------------------
; THE '"T" CHANNEL INPUT' ROUTINE
; -------------------------------
;

;; T-INPUT
L0B76:  LD      HL,L0B82        ; address of routine TCHAN-IN
        JP      L0D5A           ; jump to CALL-INP

; -------------------------------
; THE '"B" CHANNEL INPUT' ROUTINE
; -------------------------------
;

;; B-INPUT
L0B7C:  LD      HL,L0B88        ; address of routine BCHAN-IN
        JP      L0D5A           ; jump to CALL-INP

; ---------------------------------------
; THE '"T" CHANNEL INPUT SERVICE' ROUTINE
; ---------------------------------------
;

;; TCHAN-IN
L0B82:  CALL    L0B88           ; routine BCHAN-IN
        RES     7,A
        RET


; ---------------------------------------
; THE '"B" CHANNEL INPUT SERVICE' ROUTINE
; ---------------------------------------
; (Hook Code: $1D)

;; BCHAN-IN
L0B88:  LD      HL,$5CC7        ; sv SER_FL
        LD      A,(HL)          ;
        AND     A               ;
        JR      Z,L0B95         ; forward to REC-BYTE

        LD      (HL),$00        ;
        INC     HL              ;
        LD      A,(HL)          ;
        SCF                     ;

        RET                     ; Return.

; ---

;; REC-BYTE
L0B95:  CALL    L163E           ; routine TEST-BRK

        DI                      ; Disable Interrupts

        LD      A,($5CC6)       ; sv IOBORD
        OUT     ($FE),A

        LD      DE,($5CC3)      ; sv BAUD
        LD      HL,$0320        ; 800d.
        LD      B,D             ;
        LD      C,E             ;
        SRL     B               ;
        RR      C               ;
        LD      A,$FE           ;
        OUT     ($EF),A         ;

;; READ-RS
L0BAF:  IN      A,($F7)         ; bit 7 is input serial data (txdata)
        RLCA                    ;
        JR      NC,L0BC3        ; forward to TST-AGAIN

        IN      A,($F7)         ;
        RLCA                    ;
        JR      NC,L0BC3        ; forward to TST-AGAIN

        IN      A,($F7)         ;
        RLCA                    ;
        JR      NC,L0BC3        ; forward to TST-AGAIN

        IN      A,($F7)         ;
        RLCA                    ;
        JR      C,L0BCF         ; forward to START-BIT


;; TST-AGAIN
L0BC3:  DEC     HL              ;
        LD      A,H             ;
        OR      L               ;
        JR      NZ,L0BAF        ; back to READ-RS

        PUSH    AF              ;
        LD      A,$EE           ;
        OUT     ($EF),A         ;
        JR      L0BEE           ; forward to WAIT-1

; ---

;; START-BIT
L0BCF:  LD      H,B             ; Load HL with halved BAUD value.
        LD      L,C             ;

        LD      B,$80           ; Load B with the start bit.

        DEC     HL              ; Reduce the counter by the time for the four
        DEC     HL              ; tests.
        DEC     HL              ;

;; SERIAL-IN
L0BD6:  ADD     HL,DE           ; Add the BAUD value.
        NOP                     ; (4) a timing value.

;; BD-DELAY
L0BD8:  DEC     HL              ; (6) Delay for 26 * BAUD
        LD      A,H             ; (4)
        OR      L               ; (4)
        JR      NZ,L0BD8        ; (12) back to BD-DELAY

        ADD     A,$00           ; (7) wait
        IN      A,($F7)         ; Read a bit.
        RLCA                    ; Rotate bit 7 to carry.
        RR      B               ; pick up carry in B
        JR      NC,L0BD6        ; back , if no start bit, to SERIAL-IN

        LD      A,$EE           ; Send CTS line low  (comms data 0 also)
        OUT     ($EF),A         ; send to serial port

        LD      A,B             ; Transfer the received byte to A.
        CPL                     ; Complement.
        SCF                     ; Set Carry to signal success.
        PUSH    AF              ; (*) push the success flag.

;   The success and failure (time out) paths converge here with the HL register
;   holding zero.

;; WAIT-1
L0BEE:  ADD     HL,DE           ; (11) transfer DE (BAUD) to HL.

;; WAIT-2
L0BEF:  DEC     HL              ; ( 6) delay for stop bit.
        LD      A,L             ; ( 4)
        OR      H               ; ( 4)
        JR      NZ,L0BEF        ; (12/7) back to WAIT-2

;   Register HL is now zero again.

        ADD     HL,DE           ; HL = 0 + BAUD
        ADD     HL,DE           ; HL = 2 * BAUD
        ADD     HL,DE           ; HL = 3 * BAUD

;   The device at the other end of the cable (not a Spectrum) may send a 
;   second byte even though CTS (Clear To Send) is low.

;; T-FURTHER
L0BF7:  DEC     HL              ; Decrement counter.
        LD      A,L             ; Test for
        OR      H               ; zero.
        JR      Z,L0C34         ; forward, if no second byte, to END-RS-IN

        IN      A,($F7)         ; Read TXdata.
        RLCA                    ; test the bit read.
        JR      NC,L0BF7        ; back, if none,  to T-FURTHER

;   As with first byte, TXdata must be high four four tests.

        IN      A,($F7)         ;
        RLCA                    ;
        JR      NC,L0BF7        ; back to T-FURTHER

        IN      A,($F7)         ;
        RLCA                    ;
        JR      NC,L0BF7        ; back to T-FURTHER

        IN      A,($F7)         ;
        RLCA                    ;
        JR      NC,L0BF7        ; back to T-FURTHER


;   A second byte is on its way and is received exactly as before.

        LD      H,D             ;
        LD      L,E             ;
        SRL     H               ;
        RR      L               ;
        LD      B,$80           ;
        DEC     HL              ;
        DEC     HL              ;
        DEC     HL              ;

;; SER-IN-2
L0C1B:  ADD     HL,DE           ;
        NOP                     ; timing.

;; BD-DELAY2
L0C1D:  DEC     HL              ;
        LD      A,H             ;
        OR      L               ;
        JR      NZ,L0C1D        ; back to BD-DELAY2

        ADD     A,$00           ;
        IN      A,($F7)         ;
        RLCA                    ;
        RR      B               ;
        JR      NC,L0C1B        ; back to SER-IN-2

;  The start bit has been pushed out and B contains the second received byte.

        LD      HL,$5CC7        ; Address the SER_FL System Variable.

        LD      (HL),$01        ; Signal there is a byte in the next location.
        INC     HL              ; Address that location.
        LD      A,B             ; Transfer the byte to A.
        CPL                     ; Complement
        LD      (HL),A          ; and insert in the second byte of serial flag.

;; END-RS-IN
L0C34:  CALL    L0D4D           ; routine BORD-REST

        POP     AF              ; ( either 0 and NC or the first received byte
                                ;   and the carry flag set ) 

        EI                      ; Enable Interrupts

        RET                     ; Return.

; --------------------------------
; THE '"T" CHANNEL OUTPUT' ROUTINE
; --------------------------------
;   The text channel output routine is able to list programs and, when 
;   printing, takes correct action with TAB values etc.

;; TCHAN-OUT
L0C3A:  CP      $A5             ; 'RND' - first token
        JR      C,L0C44         ; forward, if less, to NOT-TOKEN

        SUB     $A5             ; reduce to range $00-5A
        RST     10H             ; CALBAS
        DEFW    $0C10           ; main PO-TOKENS
        RET                     ; return.

; ---

;; NOT-TOKEN
L0C44:  LD      HL,$5C3B        ; Address the FLAGS System Variable.
        RES     0,(HL)          ; update FLAGS - allow for leading space.
        CP      $20             ; compare to space
        JR      NZ,L0C4F        ; forward, if not, to NOT-LEAD

        SET     0,(HL)          ; update FLAGS - signal suppress leading space.

;; NOT-LEAD
L0C4F:  CP      $7F             ; compare to copyright symbol. (DEL in ASCII)
        JR      C,L0C55         ; forward, if less, to NOT-GRAPH

        LD      A,$3F           ; output CHR$(127) and graphics as '?'

;; NOT-GRAPH
L0C55:  CP      $20             ; compare against space.
        JR      C,L0C70         ; forward to CTRL-CD

        PUSH    AF              ; Preserve character.

        INC     (IY+$76)        ; Increment width         NMI_ADD_lo
        LD      A,($5CB1)       ; Load A with limit from  NMI_ADD_hi
        CP      (IY+$76)        ; Compare to width        NMI_ADD_lo

        JR      NC,L0C6C        ; forward, if less or equal, to EMIT-CH

        CALL    L0C74           ; routine TAB-SETZ emits CR/LF.

        LD      (IY+$76),$01    ; Set width to one        NMI_ADD_lo

;; EMIT-CH
L0C6C:  POP     AF              ; Restore the unprinted character.

        JP      L0D07           ; jump to BCHAN-OUT

; ---

;; CTRL-CD
L0C70:  CP      $0D             ; carriage return ?
        JR      NZ,L0C82        ; forward to NOT-CR


;; TAB-SETZ
L0C74:  LD      (IY+$76),$00    ; sv NMI_ADD_lo
        LD      A,$0D           ; output a CR carriage return.
        CALL    L0D07           ; routine BCHAN-OUT
        LD      A,$0A           ; output a LF line feed.
        JP      L0D07           ; jump to BCHAN-OUT

; ---

;; NOT-CR
L0C82:  CP      $06             ;
        JR      NZ,L0CA5        ; forward to NOT-CMM

        LD      BC,($5CB0)      ; sv NMI_ADD
        LD      E,$00           ;

;; SPC-COUNT
L0C8C:  INC     E
        INC     C
        LD      A,C
        CP      B
        JR      Z,L0C9A         ; forward to CMM-LP2


;; CMM-LOOP
L0C92:  SUB     $08
        JR      Z,L0C9A         ; forward to CMM-LP2

        JR      NC,L0C92        ; back to CMM-LOOP

        JR      L0C8C           ; back to SPC-COUNT


;; CMM-LP2
L0C9A:  PUSH    DE
        LD      A,$20
        CALL    L0C3A           ; routine TCHAN-OUT
        POP     DE
        DEC     E
        RET     Z

        JR      L0C9A           ; back to CMM-LP2

; ---

;; NOT-CMM
L0CA5:  CP      $16
        JR      Z,L0CB5         ; forward to TAB-PROC

        CP      $17
        JR      Z,L0CB5         ; forward to TAB-PROC

        CP      $10
        RET     C

        LD      DE,$0CD0
        JR      L0CB8           ; forward to STORE-COD

; ---

;; TAB-PROC
L0CB5:  LD      DE,L0CC8        ; addr: TAB-SERV

;; STORE-COD
L0CB8:  LD      ($5C0E),A       ; sv TVDATA

;; ALTER-OUT
L0CBB:  LD      HL,($5C51)      ; sv CURCHL
        PUSH    DE
        LD      DE,$0005
        ADD     HL,DE
        POP     DE
        LD      (HL),E
        INC     HL
        LD      (HL),D
        RET

; ---

;; TAB-SERV
L0CC8:  LD      DE,L0CD0        ; addr: TAB-SERV2
        LD      ($5C0F),A       ; sv TVDATA
        JR      L0CBB           ; back to ALTER-OUT

; ---

;; TAB-SERV2
L0CD0:  LD      DE,L0C3A        ; addr: TCHAN-OUT
        CALL    L0CBB           ; routine ALTER-OUT
        LD      D,A
        LD      A,($5C0E)       ; sv TVDATA
        CP      $16             ; AT control code ?
        JR      Z,L0CE6         ; forward to TST-WIDTH

        CP      $17             ; TAB control code ?
        CCF
        RET     NZ

        LD      A,($5C0F)       ; sv TVDATA
        LD      D,A

;; TST-WIDTH
L0CE6:  LD      A,($5CB1)       ; sv NMI_ADD
        CP      D
        JR      Z,L0CEE         ; forward to TAB-MOD

        JR      NC,L0CF4        ; forward to TABZERO


;; TAB-MOD
L0CEE:  LD      B,A
        LD      A,D
        SUB     B
        LD      D,A
        JR      L0CE6           ; back to TST-WIDTH

; ---

;; TABZERO
L0CF4:  LD      A,D
        OR      A
        JP      Z,L0C74         ; jump to TAB-SETZ

;; TABLOOP
L0CF9:  LD      A,($5CB0)       ; sv NMI_ADD_lo
        CP      D               ;
        RET     Z               ;

        PUSH    DE              ;
        LD      A,$20           ;
        CALL    L0C3A           ; routine TCHAN-OUT
        POP     DE              ;
        JR      L0CF9           ; back to TABLOOP


; --------------------------------
; THE '"B" CHANNEL OUTPUT' ROUTINE
; --------------------------------
; (Hook Code: $1E)
;   The bits of a byte are sent inverted. They are fixed in length and heralded
;   by a start bit and followed by two stop bits.

;; BCHAN-OUT
L0D07:  LD      B,$0B           ; Set bit count to eleven - 1 + 8 + 2.

        CPL                     ; Invert the bits of the character.
        LD      C,A             ; Copy the character to C.

        LD      A,($5CC6)       ; Load A from System Variable IOBORD
        OUT     ($FE),A         ; Change the border colour.

        LD      A,$EF           ; Set to %11101111
        OUT     ($EF),A         ; Make CTS (Clear to Send) low.

        CPL                     ; reset bit 0 (other bits of no importance)
        OUT     ($F7),A         ; Make RXdata low. %00010000

        LD      HL,($5CC3)      ; Fetch value from BAUD System Variable.
        LD      D,H             ; Copy BAUD value to DE for count.
        LD      E,L             ;

;; BD-DEL-1
L0D1C:  DEC     DE              ; ( 6) Wait 26 * BAUD cycles
        LD      A,D             ; ( 4) 
        OR      E               ; ( 4)
        JR      NZ,L0D1C        ; (12) back to BD-DEL-1

;; TEST-DTR
L0D21:  CALL    L163E           ; routine TEST-BRK allows user to stop.
        IN      A,($EF)         ; Read the communication port.
        AND     $08             ; isolate DTR (Data Terminal Ready) bit.
        JR      Z,L0D21         ; back, until DTR found high, to TEST-DTR

        SCF                     ; Set carry flag as the start bit.
        DI                      ; Disable Interrupts.

;; SER-OUT-L
L0D2C:  ADC     A,$00           ; Set bit 0            76543210 <- C  
        OUT     ($F7),A         ; Send RXdata the start bit.

        LD      D,H             ; Transfer the BAUD value to DE for count.
        LD      E,L             ;

;; BD-DEL-2
L0D32:  DEC     DE              ; ( 6) Wait for 26 * BAUD
        LD      A,D             ; ( 4)
        OR      E               ; ( 4)
        JR      NZ,L0D32        ; (12) back to BD-DEL-2

        DEC     DE              ; ( 6) 
        XOR     A               ; ( 4) clear rxdata bit
        SRL     C               ;      shift a bit of output byte to carry.
        DJNZ    L0D2C           ; back for 11 bits to SER-OUT-L

;   Note the last two bits will have been sent reset as C is exhausted.

        EI                      ; Enable Interrupts.

        LD      A,$01           ; Set RXdata

        LD      C,$EF           ; prepare port address.
        LD      B,$EE           ; prepare value %11101110
        OUT     ($F7),A         ; Send RXdata high.
        OUT     (C),B           ; Send CTS and comms data low - switch off RS232

;; BD-DEL-3
L0D48:  DEC     HL              ; ( 6) The final 26 * BAUD delay
        LD      A,L             ; ( 4) 
        OR      H               ; ( 4) 
        JR      NZ,L0D48        ; (12) back to BD-DEL-3


; -----------------------------------
; THE 'BORDER COLOUR RESTORE' ROUTINE
; -----------------------------------
;

;; BORD-REST
L0D4D:  PUSH    AF              ; Preserve the accumulator value throughout.

        LD      A,($5C48)       ; Fetch System Variable BORDCR
        AND     $38             ; Mask off the paper bits.
        RRCA                    ; Rotate to the range 0 - 7
        RRCA                    ;
        RRCA                    ;
        OUT     ($FE),A         ; Change the border colour.

        POP     AF              ; Restore accumulator and flags.

        RET                     ; Return.


; ----------------------
; THE 'CALL-INP' ROUTINE
; ----------------------
;   If the extended streams e.g. #7 are being used for input then this ROM
;   will be paged in as a result of the $0008 address in the normal INPUT
;   channel position. Since 'INPUT #7' or 'INKEYS #7' could have been used 
;   it is the purpose of this routine to determine which has been used.
;   Note also that 'MOVE #7 TO #2' could also invoke this routine and that MOVE
;   operations are further differentiated in the INKEY$ branch.

;; CALL-INP
L0D5A:  RES     3,(IY+$02)      ; update TV_FLAG - The mode is to be considered 
                                ; unchanged.
                                ; Note. this should have been done by the Main
                                ; ROM before entering the EDITOR.

        PUSH    HL              ; (*) Preserve HL the address of the actual 
                                ; service routine - either NCHAN_IN, MCHAN_IN,
                                ; BCHAN_IN ot T_CHAN_IN.

        LD      HL,($5C3D)      ; Fetch address of Error Stack Pointer ERR_SP

        LD      E,(HL)          ; Extract the address of the error handler
        INC     HL              ; If INPUT is being used this will be
        LD      D,(HL)          ; address $107F in the Main ROM.

        AND     A               ; Prepare to subtract.

        LD      HL,$107F        ; address of ED-ERROR in the Main ROM

        SBC     HL,DE           ; subtract from test value.

        JR      NZ,L0D98        ; forward if not in EDITOR to INKEY$

;   continue to handle INPUT from a stream.

        POP     HL              ; (*) POP service routine to HL e.g. NCHAN_IN

        LD      SP,($5C3D)      ; set Stack Pointer from System Variable ERR_SP
        POP     DE              ; discard the known ED-ERROR address $107F.
        POP     DE              ; POP the next value in hierarchy - MAIN-4
                                ; (usually).
        LD      ($5C3D),DE      ; and set the system variable ERR_SP

;; IN-AGAIN.
L0D78:  PUSH    HL              ; Push the address of the service routine
                                ; e.g. NCHAN_IN on the machine stack.

        LD      DE,L0D7E        ; addr: IN-AG-RET (below)
        PUSH    DE              ; push this address 

        JP      (HL)            ; jump to the service routine either MCHAN_IN,
                                ; NCHAN_IN, BCHAN_IN or TCHAN_IN and then return
                                ; to the next address IN-AG-RET.

; ---

;; IN-AG-RET
L0D7E   JR      C,L0D8A         ; forward with acceptable codes to ACC-CODE

        JR      Z,L0D87         ; forward with time-out to NO-READ

;   Otherwise Iris has closed her channel or the microdrive file was exhausted.

;; OREPORT-8
L0D82:  LD      (IY+$00),$07    ; set ERR_NR to  '8 End of file'
        RST     28H             ; Error Main ROM.

; ---

;; NO-READ
L0D87:  POP     HL              ; Retrieve the address of teh service routine
                                ; and try again as always for INPUT.
        JR      L0D78           ; back to IN-AGAIN.

; ---

;; ACC-CODE
L0D8A:  CP      $0D             ; Is the acceptable code ENTER?
        JR      Z,L0D94         ; forward, if so, to END-INPUT

        RST     10H             ; CALBAS - Call the Base ROM.
        DEFW    $0F85           ; main ADD-CHRX 
                                ; A special entry point within ADD-CHAR to add
                                ; the character to WORKSPACE.

        POP     HL              ; Retrieve the address of the saved service 
                                ; routine.
        JR      L0D78           ; back for another character to IN-AGAIN.

; ---

;; END-INPUT
L0D94:  POP     HL              ; Discard the service routine.
        JP      L0700           ; jump to UNPAGE

; -------------------
; THE 'INKEY$' BRANCH
; -------------------

;; INKEY$
L0D98:  POP     HL              ; (*) POP service routine to HL e.g. NCHAN_IN
        LD      DE,L0D9E        ; ret addr. INK-RET (below)
        PUSH    DE              ; push this address for the return address.

        JP      (HL)            ; jump to the service routine either MCHAN_IN,
                                ; NCHAN_IN, BCHAN_IN or TCHAN_IN and then return
                                ; to the next address IN-AG-RET.

; ---

;; INK-RET
L0D9E   RET     C               ; Return with acceptable character.

        RET     Z               ; Return with no character.

        BIT     4,(IY+$7C)      ; sv FLAGS_3               MOVE?
        JR      Z,L0D82         ; back to OREPORT-8

        OR      $01             ;
        RET                     ; return with zero and carry reset.


; ***********************************************
; **  T H E   N E T W O R K   R O U T I N E S  **
; ***********************************************

; -------------------------------
; THE '"N" CHANNEL INPUT' ROUTINE
; -------------------------------
;

;; N-INPUT
L0DA9:  LD      HL,L0DAF        ; Address: NCHAN-IN
        JP      L0D5A           ; jump to CALL-INP

; ---------------------------------------
; THE '"N" CHANNEL INPUT SERVICE' ROUTINE
; ---------------------------------------
;

;; NCHAN-IN
L0DAF:  LD      IX,($5C51)      ; sv CURCHL
        LD      A,(IX+$10)      ; NCOBL
        AND     A
        JR      Z,L0DBB         ; forward to TEST-BUFF

        RST     20H             ; Shadow Error Restart
        DEFB    $0D             ; Reading a 'write' file

; ---

;; TEST-BUFF
L0DBB:  LD      A,(IX+$14)      ; NCIBL
        AND     A
        JR      Z,L0DD5         ; forward to TST-N-EOF

        LD      E,(IX+$13)      ; NCCUR
        DEC     A
        SUB     E
        JR      C,L0DD5         ; forward to TST-N-EOF

        LD      D,$00
        INC     E
        LD      (IX+$13),E      ; NCCUR
        ADD     IX,DE
        LD      A,(IX+$14)      ;
        SCF
        RET

; ---

;; TST-N-EOF
L0DD5:  LD      A,(IX+$0F)      ; NCTYPE
        AND     A
        JR      Z,L0DDC         ; forward to GET-N-BUF

        RET

; ---

;; GET-N-BUF
L0DDC:  LD      A,($5CC6)       ; sv IOBORD
        OUT     ($FE),A
        DI

;; TRY-AGAIN
L0DE2:  CALL    L0FD3           ; routine WT-SC-E
        JR      NC,L0DFC        ; forward to TIME-OUT

        CALL    L0EB5           ; routine GET-NBLK
        JR      NZ,L0DFC        ; forward to TIME-OUT

        EI

        CALL    L0D4D           ; routine BORD-REST

        LD      (IX+$13),$00    ; NCCUR
        LD      A,($5CD2)       ; sv NTTYPE
        LD      (IX+$0F),A      ; NCTYPE
        JR      L0DBB           ; back to TEST-BUFF

; ---

;; TIME-OUT
L0DFC:  LD      A,(IX+$0B)      ; NCIRIS
        AND     A               ;
        JR      Z,L0DE2         ; back to TRY-AGAIN

        EI                      ;
        CALL    L0D4D           ; routine BORD-REST
        AND     $00             ;
        RET                     ;


; --------------------------------
; THE '"N" CHANNEL OUTPUT' ROUTINE
; --------------------------------
;

;; NCHAN-OUT
L0E09:  LD      IX,($5C51)      ; sv CURCHL
        LD      B,A
        LD      A,(IX+$14)      ; NCIBL
        AND     A
        LD      A,B
        JR      Z,L0E17         ; forward to TEST-OUT

        RST     20H             ; Shadow Error Restart
        DEFB    $0C             ; Writing to a 'read' file

;; TEST-OUT
L0E17:  LD      E,(IX+$10)      ; NCOBL
        INC     E               ;
        JR      NZ,L0E25        ; forward to ST-BF-LEN

        PUSH    AF              ;
        XOR     A               ;
        CALL    L0E48           ; routine S-PACK-1
        POP     AF              ;
        LD      E,$01           ;

;; ST-BF-LEN
L0E25:  LD      (IX+$10),E      ; NCOBL
        LD      D,$00           ;
        ADD     IX,DE           ;
        LD      (IX+$14),A      ; NCIBL
        RET                     ;


; -----------------------
; THE 'OUT-BLK-N' ROUTINE
; -----------------------
;

;; OUT-BLK-N
L0E30:  CALL    L1082           ; routine OUTPAK
        LD      A,(IX+$0B)      ; NCIRIS
        AND     A               ;
        RET     Z               ;

        LD      HL,$5CCD        ; sv NTRESP
        LD      (HL),$00        ;
        LD      E,$01           ;
        CALL    L104F           ; routine INPAK
        RET     NZ              ;

        LD      A,($5CCD)       ; sv NTRESP
        DEC     A               ;
        RET                     ;


; ----------------------
; THE 'S-PACK-1' ROUTINE
; ----------------------
;

;; S-PACK-1
L0E48:  CALL    L0E4F           ; routine SEND-PACK
        RET     NZ              ;

        JP      L0EAC           ; jump to BR-DELAY

; -----------------------
; THE 'SEND-PACK' ROUTINE
; -----------------------
; (Hook Code: $30)

;; SEND-PACK
L0E4F:  LD      (IX+$0F),A      ; NCTYPE
        LD      B,(IX+$10)      ; NCOBL
        LD      A,($5CC6)       ; sv IOBORD
        OUT     ($FE),A         ;

        PUSH    IX              ;
        POP     DE              ;

        LD      HL,$0015        ;
        ADD     HL,DE           ;
        XOR     A               ;

;; CHKS1
L0E62:  ADD     A,(HL)          ;
        INC     HL              ;
        DJNZ    L0E62           ; back to CHKS1

        LD      (IX+$11),A      ; NCDCS
        LD      HL,$000B        ;
        ADD     HL,DE           ;
        PUSH    HL              ;
        LD      B,$07           ;
        XOR     A               ;

;; CHKS2
L0E71:  ADD     A,(HL)          ;
        INC     HL              ;
        DJNZ    L0E71           ; back to CHKS2

        LD      (HL),A          ;
        DI                      ;

;; SENDSCOUT
L0E77:  CALL    L101E           ; routine SEND-SC
        POP     HL              ;
        PUSH    HL              ;
        LD      E,$08           ;
        CALL    L0E30           ; routine OUT-BLK-N
        JR      NZ,L0E77        ; back to SENDSCOUT

        PUSH    IX              ;
        POP     HL              ;

        LD      DE,$0015        ;
        ADD     HL,DE           ;
        LD      E,(IX+$10)      ; NCOBL
        LD      A,E             ;
        AND     A               ;
        JR      Z,L0E9A         ; forward to INC-BLKN

        LD      B,$20           ;

;; SP-DL-1
L0E93:  DJNZ    L0E93           ; back to SP-DL-1

        CALL    L0E30           ; routine OUT-BLK-N
        JR      NZ,L0E77        ; back to SENDSCOUT


;; INC-BLKN
L0E9A:  INC     (IX+$0D)        ; NCNUMB
        JR      NZ,L0EA2        ; forward to SP-N-END

        INC     (IX+$0E)        ; NCNUMB_hi

;; SP-N-END
L0EA2:  POP     HL              ;
        CALL    L0D4D           ; routine BORD-REST
        EI                      ;
        LD      A,(IX+$0B)      ; NCIRIS
        AND     A               ;
        RET                     ;


; ----------------------
; THE 'BR-DELAY' ROUTINE
; ----------------------
;

;; BR-DELAY
L0EAC:  LD      DE,$1500        ;

;; DL-LOOP
L0EAF:  DEC     DE              ;
        LD      A,E             ;
        OR      D               ;
        JR      NZ,L0EAF        ; back to DL-LOOP

        RET                     ;


; ---------------------------------------------
; THE 'HEADER AND DATA BLOCK RECEIVING' ROUTINE
; ---------------------------------------------
;

;; GET-NBLK
L0EB5:  LD      HL,$5CCE        ; sv NTDEST
        LD      E,$08
        CALL    L104F           ; routine INPAK
        RET     NZ

        LD      HL,$5CCE        ; sv NTDEST
        XOR     A
        LD      B,$07

;; CHKS3
L0EC4:  ADD     A,(HL)
        INC     HL
        DJNZ    L0EC4           ; back to CHKS3

        CP      (HL)
        RET     NZ

        LD      A,($5CCE)       ; sv NTDEST
        AND     A
        JR      Z,L0EDD         ; forward to BRCAST

        CP      (IX+$0C)        ; NCSELF
        RET     NZ

        LD      A,($5CCF)       ; sv NTSRCE
        CP      (IX+$0B)        ; NCIRIS
        RET     NZ

        JR      L0EE2           ; forward to TEST-BLKN

; ---

;; BRCAST
L0EDD:  LD      A,(IX+$0B)      ; NCIRIS
        OR      A
        RET     NZ


;; TEST-BLKN
L0EE2:  LD      HL,($5CD0)      ; sv NTNUMB
        LD      E,(IX+$0D)      ; NCNUMB_lo
        LD      D,(IX+$0E)      ; NCNUMB_hi
        AND     A
        SBC     HL,DE
        JR      Z,L0F02         ; forward to GET-NBUFF

        DEC     HL
        LD      A,H
        OR      L
        RET     NZ

;   Note. The return status of the next routine should really be checked.

        CALL    L0F02           ; routine GET-NBUFF

;   Note. The DEC instruction does not affect the carry flag.

        DEC     (IX+$0D)        ; NCNUMB_lo
        JR      NC,L0EFF        ; forward, with no carry, to GETNB-END !!

        DEC     (IX+$0E)        ; NCNUMB_hi

;; GETNB-END
L0EFF:  OR      $01
        RET


;; GET-NBUFF
L0F02:  LD      A,($5CCE)       ; sv NTDEST
        OR      A
        CALL    NZ,L107B        ; routine SEND-RESP
        LD      A,($5CD3)       ; sv NTLEN
        AND     A
        JR      Z,L0F30         ; forward to STORE-LEN

        PUSH    IX
        POP     HL

        LD      DE,$0015
        ADD     HL,DE
        PUSH    HL
        LD      E,A
        CALL    L104F           ; routine INPAK
        POP     HL
        RET     NZ

        LD      A,($5CD3)       ; sv NTLEN
        LD      B,A
        LD      A,($5CD4)       ; sv NTDCS

;; CHKS4
L0F24:  SUB     (HL)
        INC     HL
        DJNZ    L0F24           ; back to CHKS4

        RET     NZ

        LD      A,($5CCE)       ; sv NTDEST
        AND     A
        CALL    NZ,L107B        ; routine SEND-RESP

;; STORE-LEN
L0F30:  LD      A,($5CD3)       ; sv NTLEN
        LD      (IX+$14),A      ; NCIBL
        INC     (IX+$0D)        ; NCNUMB_lo
        JR      NZ,L0F3E        ; forward to GETBF-END

        INC     (IX+$0E)        ; NCNUMB_hi

;; GETBF-END
L0F3E:  CP      A
        RET


; --------------------------------------
; THE 'OPEN "N" CHANNEL COMMAND' ROUTINE
; --------------------------------------
;

;; OPEN-N-ST
L0F40:  CALL    L0F52           ; routine OP-PERM-N
        JP      L0B51           ; jump to OP-STREAM

; ----------------------------------------
; THE 'OPEN TEMPORARY "N" CHANNEL' ROUTINE
; ----------------------------------------
; (Hook Code: $2D)
;

;; OP-TEMP-N
L0F46:  CALL    L0F52           ; routine OP-PERM-N
        LD      IX,($5C51)      ; sv CURCHL
        SET     7,(IX+$04)      ; channel letter
        RET


; ----------------------------------------
; THE 'OPEN PERMANENT "N" CHANNEL' ROUTINE
; ----------------------------------------
;

;; OP-PERM-N
L0F52:  LD      HL,($5C53)      ; sv PROG
        DEC     HL

        LD      BC,$0114
        PUSH    BC
        PUSH    HL
        PUSH    BC
        LD      HL,($5C65)      ; sv STKEND
        ADD     HL,BC
        JP      C,L0F9E         ; jump to OUTMEM

        LD      BC,$0050
        ADD     HL,BC
        JP      C,L0F9E         ; jump to OUTMEM

        SBC     HL,SP
        JP      NC,L0F9E        ; jump to OUTMEM

        POP     BC
        POP     HL

        RST     10H             ; CALBAS
        DEFW    $1655           ; main MAKE-ROOM

        INC     HL
        POP     BC
        CALL    L1A82           ; routine REST-N-AD
        LD      ($5C51),HL      ; sv CURCHL

        EX      DE,HL           ;
        LD      HL,L0FA3        ; NCHAN-DAT
        LD      BC,$000B        ; eleven bytes.
        LDIR                    ;

        LD      A,($5CD6)       ; sv D_STR1 drive number
        LD      (DE),A
        INC     DE
        LD      A,($5CC5)       ; sv NTSTAT
        LD      (DE),A
        INC     DE
        XOR     A
        LD      (DE),A
        LD      H,D
        LD      L,E
        INC     DE
        LD      BC,$0106
        LDIR
        LD      DE,($5C51)      ; sv CURCHL
        RET

; ---


;; OUTMEM
L0F9E:  LD      (IY+$00),$03    ; sv ERR_NR
        RST     28H             ; Error Main ROM


; ------------------------------
; THE '"N" CHANNEL DATA' ROUTINE
; ------------------------------
;

;; NCHAN_DAT
L0FA3:  DEFW    $0008           ; main ERROR-1
        DEFW    $0008           ; main ERROR-1
        DEFB    $4E             ; character "N"
        DEFW    L0E09           ; NCHAN-OUT
        DEFW    L0DA9           ; N-INPUT
        DEFW    $0114           ; length


; ---------------------------------------
; THE 'SEND EOF BLOCK TO NETWORK' ROUTINE
; ---------------------------------------
;

;; SEND-NEOF
L0FAE:  LD      IX,($5C51)      ; sv CURCHL
        LD      A,(IX+$10)      ; NCOBL
        AND     A               ;
        RET     Z               ;

        LD      A,$01           ;
        JP      L0E48           ; jump to S-PACK-1

; ---------------------------
; THE 'NETWORK STATE' ROUTINE
; ---------------------------
;

;; NET-STATE
L0FBC:  LD      A,R             ;
        OR      $C0             ;
        LD      B,A             ;
        CALL    L0FC7           ; routine CHK-REST
        JR      C,L0FBC         ; back to NET-STATE

        RET                     ;


; ---------------------------
; THE 'CHECK-RESTING' ROUTINE
; ---------------------------
;

;; CHK-REST
L0FC7:  CALL    L163E           ; routine TEST-BRK

;; MAKESURE
L0FCA:  PUSH    BC              ;
        POP     BC              ;
        IN      A,($F7)         ;
        RRCA                    ;
        RET     C               ;

        DJNZ    L0FCA           ; back to MAKESURE

        RET                     ;


; ------------------------
; THE 'WAIT-SCOUT' ROUTINE
; ------------------------
;

;; WT-SC-E
L0FD3:  CALL    L163E           ; routine TEST-BRK
        LD      HL,$01C2        ;

;; CLAIMED
L0FD9:  LD      B,$80           ;
        CALL    L0FC7           ; routine CHK-REST
        JR      NC,L0FED        ; forward to WT-SYNC

        DEC     HL              ;
        DEC     HL              ;
        LD      A,H             ;
        OR      L               ;
        JR      NZ,L0FD9        ; back to CLAIMED

        LD      A,(IX+$0B)      ; NCIRIS
        AND     A               ;
        JR      Z,L0FD9         ; back to CLAIMED

        RET                     ;


;; WT-SYNC
L0FED:  IN      A,($F7)         ;
        RRCA                    ;
        JR      C,L1013         ; forward to SCOUT-END

        LD      A,$7F           ;
        IN      A,($FE)         ;
        OR      $FE             ;
        IN      A,($FE)         ;
        RRA                     ;
        CALL    NC,L163E        ; routine TEST-BRK
        DEC     HL              ;
        LD      A,H             ;
        OR      L               ;
        JR      NZ,L0FED        ; back to WT-SYNC

        LD      A,(IX+$0B)      ; NCIRIS
        AND     A               ;
        JR      Z,L0FED         ; back to WT-SYNC

        RET                     ;


; --------------------------------------
; THE 'BREAK INTO I/O OPERATION' ROUTINE
; --------------------------------------
; Note. an obsolete duplicate.

;; E-READ-N
L100A:  EI                      ;
        CALL    L0D4D           ; routine BORD-REST
        LD      (IY+$00),$14    ; sv ERR_NR
        RST     28H             ; Error Main ROM

; ----------------------
; THE 'SCOUT END' BRANCH
; ----------------------
;

;; SCOUT-END
L1013:  LD      L,$09

;; LP-SCOUT
L1015:  DEC     L
        SCF
        RET     Z

        LD      B,$0E

;; DELAY-SC
L101A:  DJNZ    L101A           ; back to DELAY-SC

        JR      L1015           ; back to LP-SCOUT


; ------------------------
; THE 'SEND-SCOUT' ROUTINE
; ------------------------
;

;; SEND-SC
L101E:  CALL    L0FBC           ; routine NET-STATE
        LD      C,$F7
        LD      HL,$0009
        LD      A,($5CC5)       ; sv NTSTAT
        LD      E,A
        IN      A,($F7)
        RRCA
        JR      C,L101E         ; back to SEND-SC


;; ALL-BITS
L102F:  OUT     (C),H
        LD      D,H
        LD      H,$00
        RLC     E
        RL      H


        LD      B,$08

;; S-SC-DEL
L103A:  DJNZ    L103A           ; back to S-SC-DEL

        IN      A,($F7)
        AND     $01
        CP      D
        JR      Z,L101E         ; back to SEND-SC

        DEC     L
        JR      NZ,L102F        ; back to ALL-BITS

        LD      A,$01
        OUT     ($F7),A
        LD      B,$0E

;; END-S-DEL
L104C:  DJNZ    L104C           ; back to END-S-DEL

        RET


; -------------------
; THE 'INPAK' ROUTINE
; -------------------
;

;; INPAK
L104F:  LD      B,$FF

;; N-ACTIVE
L1051:  IN      A,($F7)
        RRA
        JR      C,L105A         ; forward to INPAK-2

        DJNZ    L1051           ; back to N-ACTIVE

        INC     B
        RET

; ---

;; INPAK-2
L105A:  LD      B,E

;; INPAK-L
L105B:  LD      E,$80
        LD      A,$CE
        OUT     ($EF),A
        NOP
        NOP
        INC     IX
        DEC     IX
        INC     IX
        DEC     IX

;; UNTIL-MK
L106B:  LD      A,$00
        IN      A,($F7)
        RRA
        RR      E
        JP      NC,L106B        ; jump to UNTIL-MK
        LD      (HL),E
        INC     HL
        DJNZ    L105B           ; back to INPAK-L

        CP      A
        RET


; --------------------------------
; THE 'SEND RESPONSE BYTE' ROUTINE
; --------------------------------
;

;; SEND-RESP
L107B:  LD      A,$01
        LD      HL,$5CCD        ; sv NTRESP
        LD      (HL),A
        LD      E,A

; --------------------
; THE 'OUTPAK' ROUTINE
; --------------------
;

;; OUTPAK
L1082:  XOR     A
        OUT     ($F7),A
        LD      B,$04

;; DEL-0-1
L1087:  DJNZ    L1087           ; back to DEL-0-1


;; OUTPAK-L
L1089:  LD      A,(HL)
        CPL
        SCF
        RLA
        LD      B,$0A

;; UNT-MARK
L108F:  OUT     ($F7),A
        RRA
        AND     A
        DEC     B
        LD      D,$00
        JP      NZ,L108F        ; jump to UNT-MARK
        INC     HL
        DEC     E
        PUSH    HL
        POP     HL
        JP      NZ,L1089        ; jump to OUTPAK-L
        LD      A,$01
        OUT     ($F7),A
        RET

; *****************************************************
; **  T H E   M I C R O D R I V E   R O U T I N E S  **
; *****************************************************
; The shadow ROM uses the alternate HL register solely in connection with the
; microdrive maps. This does not conflict with the Main ROM use in the
; calculator.  When used as a Hook Codes, then the calculator is implicitly in
; use by the user and so HL' should be preserved throughout.

; -----------------------------------------
; THE 'SET A TEMPORARY "M" CHANNEL' ROUTINE
; -----------------------------------------
; (Hook Code: $2B)
; This routine is used to create all microdrive channels. The routine that 
; creates a permanent channel (as used by a print file) uses this routine and
; then converts the temporary channel to a permanent one.
; Temporary channels are created by LOAD, SAVE, CAT etc. and last just as long
; as required. They are deleted before returning to the Main ROM by the next 
; routine DEL-M-BUF.

;; SET-T-MCH
L10A5:  EXX                     ; exx
        LD      HL,$0000        ; set HL' to zero as the default no-map-exists
                                ; condition.
        EXX                     ; exx

        LD      IX,($5C4F)      ; set IX from system variable CHANS.
        LD      DE,$0014        ; skip over the twenty bytes of the standard
        ADD     IX,DE           ; channels to point to the next or end-marker.

; now enter a search of existing "M" channels to see if any use the same drive.

;; CHK-LOOP
L10B3:  LD      A,(IX+$00)      ; fetch the next byte.
        CP      $80             ; compare to end-marker.
        JR      Z,L10F1         ; forward, if so, to CHAN-SPC.

        LD      A,(IX+$04)      ; fetch the letter of the extended channel.
        AND     $7F             ; reset bit 7.
        CP      $4D             ; is it character 'M' ?
        JR      NZ,L10E7        ; forward, if not, to NEXT-CHAN.

; an existing Microdrive Channel has been found.

        LD      A,($5CD6)       ; fetch drive number from system variable D_STR1
        CP      (IX+$19)        ; compare to CHDRIV the drive associated with
                                ; this channel.
        JR      NZ,L10E7        ; forward, if not the same, to NEXT-CHAN.

; a Microdrive Channel has been found that matches the current drive.
; It will not be necessary to create a new map for the temporary channel.

        EXX                     ; -
        LD      L,(IX+$1A)      ; load address of the associated microdrive.
        LD      H,(IX+$1B)      ; map into the HL' register.
        EXX                     ; -

        LD      BC,($5CDA)      ; load BC with length of filename from N_STR1.
        LD      HL,($5CDC)      ; load HL with address of filename.

        CALL    L1403           ; routine CHK-NAME checks name in channel
                                ; against name addressed by HL.

        JR      NZ,L10E7        ; forward, with name mismatch, to NEXT-CHAN.

        BIT     0,(IX+$18)      ; test CHFLAG.
        JR      Z,L10E7         ; forward to NEXT-CHAN.

        RST     20H             ; Shadow Error Restart.
        DEFB    $0D             ; Reading a 'write' file.

;; NEXT-CHAN
L10E7:  LD      E,(IX+$09)      ; fetch length of channel.
        LD      D,(IX+$0A)      ; to the DE register pair.
        ADD     IX,DE           ; add to point to the following location.
        JR      L10B3           ; loop back to CHK-LOOP until end-marker found.

; ---

; Now create the space for the channel.

;; CHAN-SPC
L10F1:  LD      HL,($5C53)      ; set pointer from system variable PROG.
        DEC     HL              ; now points to channels end-marker (as does IX)

        PUSH    HL              ; * save a copy of new location.
        LD      BC,$0253        ; set amount of bytes required.

;   Note. interrupts are disabled so on the original shadow ROM, which launched 
;   straight into the MAKE-ROOM routine, the system hung if there was 
;   insufficient free memory, at the HALT instruction in the Main error report.
;   The solution here is to perform the same checks that will be performed by 
;   the Main MAKE-ROOM routine.

        PUSH    HL              ; save first location
        PUSH    BC              ; and amount while free memory is checked.

        LD      HL,($5C65)      ; fetch start of free memory from STKEND
        ADD     HL,BC           ; add bytes required producing carry if
                                ; result is higher than 65535
        JP      C,L119A         ; jump, if so, to OUTMEM2

        LD      BC,$0050        ; now allow for overhead of eighty bytes.
        ADD     HL,BC           ; and perform same test.
        JP      C,L119A         ; jump, if too high, to OUTMEM2

        SBC     HL,SP           ; finally test that result is less than the
                                ; stack pointer at the other side of free memory.
        JP      NC,L119A        ; jump, if higher, to OUTMEM2.

        POP     BC              ; restore the new room
        POP     HL              ; parameters.

; now call the MAKE-ROOM routine in the certain knowledge that nothing can
; go wrong.

        RST     10H             ; CALBAS
        DEFW    $1655           ; main MAKE-ROOM

        POP     DE              ; * restore pointer to first new location.
        PUSH    DE              ; * and save on machine stack again.

        LD      HL,L14B1        ; the default "M" CHANNEL DATA.
        LD      BC,$0019        ; twenty five bytes to copy including blank
        LDIR                    ; filename to start of new channel.

        LD      A,($5CD6)       ; fetch drive number from D_STR1.
        LD      (IX+$19),A      ; insert at CHDRIV.

        LD      BC,$0253        ; set BC to amount of room that was created.

        PUSH    IX              ; move start of channel
        POP     HL              ; to HL register.

        CALL    L1A82           ; routine REST-N-AD corrects filename pointers
                                ; leaving DE at first filename D_STR1.

        EX      DE,HL           ; transfer filename pointer to HL.

        LD      BC,($5CDA)      ; set BC to length of filename from N_STR1.

        BIT     7,B             ; test for the default $FF bytes.
        JR      NZ,L1143        ; forward, with no name, to TEST-MAP

; now enter a loop to transfer the filename to CHNAME, counting BC down to zero.
; The filename could be in ROM with 'run' or more usually in string workspace
; with its parameters on the calculator stack as with 
; LOAD * "m";1;"crapgame"
; SAVE * "M";7; CHR$0 + "secret".


;; T-CH-NAME
L1135:  LD      A,B             ; check length
        OR      C               ; for zero.
        JR      Z,L1143         ; forward, if so, to TEST-MAP.

        LD      A,(HL)          ; fetch character of filename.
        LD      (IX+$0E),A      ; transfer to same position in CHNAME.

        INC     HL              ; increment
        INC     IX              ; both pointers.
        DEC     BC              ; decrement length.
        JR      L1135           ; loop back to T-CH-NAME.

; ---

;; TEST-MAP
L1143:  POP     IX              ; * restore pointer to first location of channel.

        EXX                     ; exchange set - no need now to keep balanced.
        LD      A,H             ; test map address for zero .
        OR      L               ; indicating that this drive has no map.
        JR      NZ,L1168        ; forward, if map exists, to ST-MAP-AD.

; a microdrive map is now created for this drive.

        LD      HL,($5C4F)      ; set pointer from system variable CHANS.
        PUSH    HL              ; save this pointer to the new area.
        DEC     HL              ; set HL to location before new room.
        LD      BC,$0020        ; thirty two bytes are required.

        RST     10H             ; CALBAS
        DEFW    $1655           ; main MAKE-ROOM.

; now handle dynamic pointers outside the control of the Main ROM

        POP     HL              ; restore pointer to first location.
        LD      BC,$0020        ; thirty two bytes were created.
        ADD     IX,BC           ; channel was moved up so adjust that pointer.

        CALL    L1A82           ; routine REST-N-AD corrects filename pointers.

; fill map with $FF bytes

        LD      A,$FF           ; the fill byte.
        LD      B,$20           ; thirty two locations.
        PUSH    HL              ; save map address pointer.

;; FILL-MAP
L1163:  LD      (HL),A          ; insert the byte
        INC     HL              ; next location.
        DJNZ    L1163           ; loop back to FILL-MAP

        POP     HL              ; restore address.

;; ST-MAP-AD
L1168:  LD      (IX+$1A),L      ; place map address in
        LD      (IX+$1B),H      ; channel at CHMAP.

; now make DE point to IX+$19 the header preamble and copy ROM preamble bytes.

        PUSH    IX              ; push start of channel
        POP     HL              ; pop to HL

        LD      DE,$001C        ; the offset is $1C
        ADD     HL,DE           ; add to point to start of header preamble.
        EX      DE,HL           ; transfer this destination to DE.

        LD      HL,L14CA        ; point HL to PREAMBLE data in this ROM.
        LD      BC,$000C        ; twelve bytes to copy to channel.
        LDIR                    ; in they go.

; now use the same technique to copy the same 12 bytes of ROM preamble
; to IX+$37, the data block preamble in the channel.
; A little long-winded as the destination only requires adjustment.

        PUSH    IX              ;
        POP     HL              ;
        LD      DE,$0037        ;
        LD      BC,$000C        ;

        ADD     HL,DE           ;
        EX      DE,HL           ;
        LD      HL,L14CA        ; the PREAMBLE data.
        LDIR                    ;

; now form the offset from CHANS to this channel for a return value to be
; inserted in the STRMS area.

        PUSH    IX              ; transfer
        POP     HL              ; pointer.

        LD      DE,($5C4F)      ; fetch start of CHANS area from CHANS
        OR      A               ; clear carry for subtraction.
        SBC     HL,DE           ; the true offset.

        INC     HL              ; add one as the offset is to second location.

        RET                     ; return.               >>>

; ---

;; OUTMEM2
L119A:  LD      (IY+$00),$03    ; set ERR_NR for '4 Out of memory'
        RST     28H             ; Error Main ROM

; ---------------------------------
; THE 'RECLAIM "M" CHANNEL' ROUTINE
; ---------------------------------
; (Hook Code: $2C)
; This routine is used to reclaim a temporary "M" channel such as that created 
; by the routine above and to reclaim a permanent "M" channel by the CLOSE
; command routines.

;; DEL-M-BUF
L119F:  LD      L,(IX+$1A)      ; fetch map address.
        LD      H,(IX+$1B)      ; from CHMAP.
        PUSH    HL              ; and save.
        LD      A,(IX+$19)      ; fetch drive number from CHDRIV.
        PUSH    AF              ; and save also.

        PUSH    IX              ; transfer channel base address
        POP     HL              ; to the HL register pair.

        LD      BC,$0253        ; set BC to bytes to reclaim.

        RST     10H             ; CALBAS
        DEFW    $19E8           ; main RECLAIM-2 reclaims the channel.

        PUSH    IX              ; transfer channel
        POP     HL              ; base address again.

        LD      DE,($5C4F)      ; set DE to start of channels from CHANS
        OR      A               ; clear carry.
        SBC     HL,DE           ; subtract to form the offset.
        INC     HL              ; add 1 as points to second byte.

        LD      BC,$0253        ; set the number of bytes reclaimed.

        CALL    L1444           ; routine REST-STRM corrects all stream offsets
                                ; in the standard systems variables area
                                ; reducing them if they followed the deleted
                                ; channel.

        POP     AF              ; restore drive number
        POP     HL              ; and old map address.

; now consider deleting the map if it was used only by the reclaimed channel.

        LD      B,A             ; transfer drive to B
        LD      IX,($5C4F)      ; set IX from CHANS
        LD      DE,$0014        ; prepare to step over the twenty standard bytes
        ADD     IX,DE           ; to address next channel or end-marker.

;; TEST-MCHL
L11D0:  LD      A,(IX+$00)      ; fetch current byte.
        CP      $80             ; compare to end-marker.
        JR      Z,L11EF         ; forward, with match, to RCLM-MAP

        LD      A,(IX+$04)      ; fetch the channel letter.
        AND     $7F             ; cancel any inverted bit.
        CP      $4D             ; is character "M" ?
        JR      NZ,L11E5        ; forward, if not, to NXTCHAN

        LD      A,(IX+$19)      ; fetch this channel drive number.
        CP      B               ; compare to that of deleted channel.
        RET     Z               ; return with match - the microdrive map is
                                ; still in use.                              >>

; else continue search.

;; NXTCHAN
L11E5:  LD      E,(IX+$09)      ; fetch length of channel
        LD      D,(IX+$0A)      ; to DE register.
        ADD     IX,DE           ; add to address next channel.
        JR      L11D0           ; loop back to TEST-MCHL

; ---

; the branch was here when the end-marker was encountered without finding a
; channel that uses the map.

;; RCLM-MAP
L11EF:  LD      BC,$0020        ; thirty two bytes to reclaim.
        PUSH    HL              ; save pointer to start.
        PUSH    BC              ; save the 32 bytes.

        RST     10H             ; CALBAS
        DEFW    $19E8           ; main RECLAIM-2 reclaims the microdrive map.

        POP     BC              ; restore 32 counter.
        POP     HL              ; restore map address.

        CALL    L1476           ; routine REST-MAP adjusts all channel map
                                ; addresses.

        RET                     ; return.

; -------------------------------
; THE '"M" CHANNEL INPUT' ROUTINE
; -------------------------------
;

;; M-INPUT
L11FD:  LD      IX,($5C51)      ; sv CURCHL
        LD      HL,L1207        ; addr: MCHAN-IN
        JP      L0D5A           ; jump to CALL-INP

; ---------------------------------------
; THE '"M" CHANNEL INPUT SERVICE' ROUTINE
; ---------------------------------------
;

;; MCHAN-IN
L1207:  BIT     0,(IX+$18)      ; test CHFLAG
        JR      Z,L120F         ; forward, if reset, to TEST-M-BF

;; rwf-err
L120D:  RST     20H             ; Shadow Error Restart
        DEFB    $0D             ; Reading a 'write' file

; ---

;; TEST-M-BF
L120F:  LD      E,(IX+$0B)      ; load DE with the offset from CHDATA of the
        LD      D,(IX+$0C)      ; next byte to be received from CHBYTE.

        LD      L,(IX+$45)      ; load HL with the number of data bytes
        LD      H,(IX+$46)      ; in CHDATA from RECLEN.

        SCF                     ; set carry to include
        SBC     HL,DE           ; subtract the two relative positions.
        JR      C,L1233         ; forward to CHK-M-EOF

        INC     DE              ; else increment pointer.
        LD      (IX+$0B),E      ; store back
        LD      (IX+$0C),D      ; in CHBYTE.
        DEC     DE              ; decrement pointer.

        PUSH    IX              ; save start of channel.
        ADD     IX,DE           ; add the offset within CHDATA first.
        LD      A,(IX+$52)      ; now apply offset of CHDATA from start of
                                ; channel to character.
        POP     IX              ; restore channel start.
        SCF                     ; set carry flag.
        RET                     ; return.

; ---

;; CHK-M-EOF
L1233:  BIT     1,(IX+$43)      ; bit 1 of RECFLG is set if this is the last
                                ; record in this file.
        JR      Z,L123D         ; forward, if not EOF, to NEW-BUFF.

        XOR     A               ; set accumulator to zero.
        ADD     A,$0D           ; add to carriage return clearing the
                                ; carry flag and resetting the zero flag.
        RET                     ; return.

; ---

;; NEW-BUFF
L123D:  LD      DE,$0000        ; set next byte offset to zero.
        LD      (IX+$0B),E      ; and update the
        LD      (IX+$0C),D      ; pointer CHBYTE.

        INC     (IX+$0D)        ; increment record number CHREC.
        CALL    L1252           ; routine GET-RECD gets the record specified
                                ; by CHREQ matching filename CHNAME from the 
                                ; cartridge in the drive CHDRIV which is 
                                ; started.

        XOR     A               ; signal stop all motors.
        CALL    L1532           ; routine SEL-DRIVE.

        JR      L120F           ; back to TEST-M-BF.

; --------------------------
; THE 'GET A RECORD' ROUTINE
; --------------------------
;   This routine is used to read a specific record from a PRINT type file.
;   It is called twice -
;   1) From the "M" input routine when the current record is exhausted and the 
;      next record is to be read in.
;   2) From Hook Code $27 READ-RANDOM.

;; GET-RECD
L1252:  LD      A,(IX+$19)      ; get drive number from CHDRIV.
        CALL    L1532           ; routine SEL-DRIVE starts the motor.

; ->

;; GET-R-2
L1258:  LD      BC,$04FB        ; set sector counter to 1275 = 255*5
        LD      ($5CC9),BC      ; update system variable SECTOR

;; GET-R-LP
L125F:  CALL    L1280           ; routine G-HD-RC reads in the next header and
                                ; matching record to pass the tape head.

        JR      C,L1279         ; forward, with name mismatch, to NXT-SCT

        JR      Z,L1279         ; forward, if not in use, to NXT-SCT

        LD      A,(IX+$44)      ; fetch the record number 0-n from RECNUM
        CP      (IX+$0D)        ; compare with that required in CHREC
        JR      NZ,L1279        ; forward, if no number match, to NXT-SCT

        PUSH    IX              ; transfer address of Microdrive channel
        POP     HL              ; from the IX to HL registers.

        LD      DE,$0052        ; offset to CHDATA
        ADD     HL,DE           ; add to form address of start of 512 byte data
        CALL    L142B           ; routine CHKS-BUFF
        RET     Z               ; return if checksums match.


;; NXT-SCT
L1279:  CALL    L13F7           ; routine DEC-SECT
        JR      NZ,L125F        ; loop back, if not zero, to GET-R-LP

; else produce the Error Report.

        RST     20H             ; Shadow Error Restart
        DEFB    $11             ; File not found


; ---------------------------------------
; THE 'GET HEADER AND DATA BLOCK' ROUTINE
; ---------------------------------------
; This routine fetches at random a header and matching record and sets the
; flags to indicate three possible outcomes.
; 
; Zero flag set - record is not in use.
; Carry flag set - name does not match required
; Both flags reset - the name matches required.

;; G-HD-RC
L1280:  CALL    L13A9           ; routine GET-M-HD2 reads in and checksums
                                ; the next 14 byte header to pass tape heads.

        LD      DE,$001B        ; prepare the offset from header to RECFLG and
        ADD     HL,DE           ; add to address the start of 528 byte RECORD

        CALL    L15EB           ; routine GET-M-BUF reads in the record 
                                ; descriptor and data.
                                ; register HL addresses RECFLG

        CALL    L1426           ; routine CHKS-HD-R checksums the 14 bytes
                                ; of the record descriptor.

        JR      NZ,L12B1        ; forward, with error, to G-REC-ERR

        BIT     0,(IX+$43)      ; check RECFLG - should be reset.
        JR      NZ,L12B1        ; forward, if not, to G-REC-ERR

; now test descriptor for an unused record.

        LD      A,(IX+$43)      ; load A with RECFLG - bit 1 indicates EOF
        OR      (IX+$46)        ; combine with RECLEN_hi bit 1 set if full.
        AND     $02             ; test for either full record or EOF.
        RET     Z               ; return if not with zero set and carry reset
                                ; signaling that record is unused.

; the record is a contender for a header record.

        PUSH    IX              ; transfer start of channel
        POP     HL              ; to the HL register pair.

        LD      DE,$0047        ; offset to 10 characters of filename.
        ADD     HL,DE           ; add so HL addresses the start of RECNAM.
        LD      BC,$000A        ; ten bytes to compare against required CHNAME.

        CALL    L1403           ; routine CHK-NAME

        JR      NZ,L12B1        ; forward, with name mismatch, to G-REC-ERR

; else set flags to signal success before returning.

        LD      A,$FF           ; prepare to reset zero flag
        OR      A               ; also reset carry
        RET                     ; return with zero reset and carry reset.

; ---

; else set carry to signal names do not match.

;; G-REC-ERR
L12B1:  SCF                     ; set carry flag to signal failure and 
                                ; instigate another search.
        RET                     ; return with zero reset and carry set.


; --------------------------------
; THE '"M" CHANNEL OUTPUT' ROUTINE
; --------------------------------
; labeled MWRCH in source code.

;; MCHAN-OUT
L12B3:  LD      IX,$FFFA
        ADD     IX,DE
        BIT     0,(IX+$18)      ; ???? CHFLAG
        JR      NZ,L12C1        ; forward to NOREAD

        RST     20H             ; Shadow Error Restart
        DEFB    $0C             ; Writing to a 'read' file

;; NOREAD
L12C1:  LD      E,(IX+$0B)      ; CHBYTE


        LD      D,(IX+$0C)      ; CHBYTE_hi
        PUSH    IX
        ADD     IX,DE
        LD      (IX+$52),A      ; indexed
        POP     IX
        INC     DE
        LD      (IX+$0B),E      ; CHBYTE
        LD      (IX+$0C),D      ; CHBYTE_hi
        BIT     1,D             ; is CHBYTE the maximum $0200 ?
        RET     Z               ; return if not.


; ------------------------------------------
; THE 'WRITE RECORD ONTO MICRODRIVE' ROUTINE
; ------------------------------------------
; (Hook Code: $26)
;

;; WR-RECD
L12DA:  LD      A,(IX+$19)      ; fetch drive number.
        CALL    L1532           ; routine SEL-DRIVE

        LD      BC,$32C8        ; set BC to 13000 decimal
        CALL    L1652           ; routine DELAY-BC

        CALL    L12EE           ; routine WRITE-PRC

        XOR     A               ; signal stop motor
        CALL    L1532           ; routine SEL-DRIVE

        RET                     ; return.

; -----------------------------
; THE 'WRITE RECORD' SUBROUTINE
; -----------------------------
;
;

;; WRITE-PRC
L12EE:  CALL    L1349           ; routine CHK-FULL.

        JR      NZ,L12FC        ; forward, if not, to NOFULL.

        CALL    L119F           ; routine DEL-M-BUF reclaims the buffer.

        XOR     A               ; set accumulator to zero.
        CALL    L1532           ; routine SEL-DRIVE stops the motor.

        RST     20H             ; Shadow Error Restart.
        DEFB    $0F             ; 'Microdrive full'

; ---

;; NOFULL
L12FC:  PUSH    IX              ; save the pointer to channel base.
        LD      B,$0A           ; count ten characters.

;; CP-NAME
L1300:  LD      A,(IX+$0E)      ; copy a character of CHNAME
        LD      (IX+$47),A      ; to RECNAM
        INC     IX              ; increment the index pointer.
        DJNZ    L1300           ; loop back for all ten characters to CP-NAME

        POP     IX              ; restore base of "M" channel.

        LD      C,(IX+$0B)      ; fetch  CHBYTE_lo
        LD      (IX+$45),C      ; update RECLEN_lo

        LD      A,(IX+$0C)      ; fetch  CHBYTE_hi
        LD      (IX+$46),A      ; update RECLEN_hi

        LD      A,(IX+$0D)      ; fetch  CHREC
        LD      (IX+$44),A      ; update RECNUM

        RES     0,(IX+$43)      ; reset RECFLG indicating a record.

        PUSH    IX              ; transfer channel base address 
        POP     HL              ; to the HL register.

        LD      DE,$0043        ; prepare offset to point to RECFLG
        ADD     HL,DE           ; and add to address the record descriptor.

        CALL    L1426           ; routine CHKS-HD-R checksums the 14 bytes.

        LD      DE,$000F        ; add extra offset to CHDATA
        ADD     HL,DE           ; the 512 bytes of data.

        CALL    L142B           ; routine CHKS-BUFF checksums the buffer.

        PUSH    IX              ; Note. this code is redundant and erroneous.
        POP     HL              ; the three registers are set up properly
        LD      DE,$0047        ; in the next routine.

        CALL    L135A           ; routine SEND-BLK writes block to microdrive
                                ; cartridge as indicated my microdrive map 
                                ; which is updated.

; now prepare channel for next record. accumulator could be used to set CHBYTE.

        LD      DE,$0000        ; set DE to zero.
        LD      (IX+$0B),E      ; set CHBYTE_lo to zero
        LD      (IX+$0C),D      ; set CHBYTE_hi to zero
        INC     (IX+$0D)        ; increment the record counter CHREC

        RET                     ; return.


; ----------------------
; THE 'CHK-FULL' ROUTINE
; ----------------------
; Check the thirty two bytes of a microdrive map for a reset bit.

;; CHK-FULL
L1349:  LD      L,(IX+$1A)      ; load the address of the microdrive map
        LD      H,(IX+$1B)      ; from CHMAP to HL.
        LD      B,$20           ; set counter to thirty two.

;; NXT-B-MAP
L1351:  LD      A,(HL)          ; fetch each byte in turn.
        CP      $FF             ; compare to the all-full indicator.
        RET     NZ              ; return if there is a spare sector       >>

        INC     HL              ; next address.
        DJNZ    L1351           ; loop back to NXT-B-MAP

        XOR     A               ; set the zero flag for failure.
        RET                     ; return.


; ----------------------
; THE 'SEND-BLK' ROUTINE
; ----------------------
;   This important routine is called from the FORMAT routine and the WRITE-PRC
;   routine to write the record to the cartridge at the next available free
;   sector as indicated by the microdrive map. 

;; SEND-BLK
L135A:  PUSH    IX              ; transfer the channel
        POP     HL              ; address to HL.

        LD      DE,$0037        ; offset to data preamble.
        ADD     HL,DE           ; add to address using HL
        PUSH    HL              ; save pointer to data block

; now enter a loop to find the header of an available record on microdrive.
; This SEND-BLK routine is only called when there is known to be a record
; available on the tape.

;; FAILED
L1362:  CALL    L13A9           ; routine GET-M-HD2 gets any old header.
        CALL    L13C4           ; routine CHECK-MAP checks if sector is free 
                                ; on the microdrive map.
        JR      NZ,L1362        ; back, if not, to FAILED.

; A usable sector has been found on the drive. HL addresses byte within map.

        EX      (SP),HL         ; map address to stack, bring back data pointer.
        PUSH    BC              ; preserve B the map byte mask.

        IN      A,($EF)         ; test the drive.
        AND     $01             ; examine 'write protect' bit.
        JR      NZ,L1374        ; forward, if not protected, to NO-PRT.

        RST     20H             ; Shadow Error Restart.
        DEFB    $0E             ; Drive 'write' protected

;; NO-PRT
L1374:  LD      A,$E6           ;      xx100110
        OUT     ($EF),A         ; enable writing.

        LD      BC,$0168        ; a delay value of 360 decimal.
        CALL    L1652           ; routine DELAY-BC pauses briefly as the 
                                ; record now approaches the tape heads.

        CALL    L15B3           ; routine OUT-M-BUF writes descriptor and
                                ; data buffer.

        LD      A,$EE           ;       xx101110
        OUT     ($EF),A         ; disable writing.

        POP     BC              ; restore the map bit.
        POP     HL              ; and the address of the byte within microdrive
                                ; map.
        LD      A,B             ; transfer masked bit to A.
        OR      (HL)            ; combine with status of other 7 sectors.
        LD      (HL),A          ; update the map to show this sector is now 
                                ; used.

        RET                     ; return.


; ------------------------
; THE 'CLOSE FILE' ROUTINE
; ------------------------
; Note. The first entry point is not used.

;; close-m
L138B:  PUSH    HL              ;
        POP     IX              ;

; (Hook Code: $23)

;; CLOSE-M2
L138E:  BIT     0,(IX+$18)      ; CHFLAG
        JR      Z,L139B         ; forward to NOEMP

        SET     1,(IX+$43)      ; RECFLG
        CALL    L12DA           ; routine WR-RECD

;; NOEMP
L139B:  XOR     A               ;
        CALL    L1532           ; routine SEL-DRIVE
        CALL    L119F           ; routine DEL-M-BUF
        RET                     ; return after subroutine.

; ------------------------------------------
; THE 'MAIN ERROR RESTART EMULATION' ROUTINE
; ------------------------------------------

;; ERR-RS
L13A3:  POP     HL              ;
        LD      A,(HL)          ;
        LD      ($5C3A),A       ; sv ERR_NR
        RST     28H             ; Error Main ROM

; ------------------------------------------
; THE 'FETCH HEADER FROM MICRODRIVE' ROUTINE
; ------------------------------------------
;   This routine fetches the next valid 14-byte header to pass the tape heads 
;   ensuring that it is a header as opposed to a record descriptor.

;; GET-M-HD2
L13A9:  PUSH    IX              ; transfer start of channel
        POP     HL              ; to the HL register pair.

        LD      DE,$0028        ; offset to HDFLAG
        ADD     HL,DE           ; add to form first receiving location.

        CALL    L15E2           ; routine GET-M-HD reads 15 bytes from
                                ; microdrive - last is a checksum byte.

        CALL    L1426           ; routine CHKS-HD-R checksums the bytes.

        JR      NZ,L13A9        ; back, with error, to GET-M-HD2

        BIT     0,(IX+$28)      ; test HDFLAG should be set.
        JR      Z,L13A9         ; back, if not a header, to GET-M-HD2

        RET                     ; return - with HL addressing start of header.


; ---------------------------------
; THE 'CHECK MAP BIT STATE' ROUTINE
; ---------------------------------
;

;; CHK-MAP-2
L13BF:  LD      E,(IX+$44)      ; pick up record from RECNUM
        JR      L13C7           ; forward to ENTRY

; ---

;; CHECK-MAP
L13C4:  LD      E,(IX+$29)      ; pick up sector from HDNUMB

; ->

;; ENTRY
L13C7:  LD      L,(IX+$1A)      ; fetch address of associated
        LD      H,(IX+$1B)      ; microdrive map from CHMAP

; the pseudo-map routine enters here with a temporary map address.

;; ENTRY-2
L13CD:  XOR     A               ; clear accumulator is one way to
        LD      D,A             ; clear D in preparation for addition.
        LD      A,E             ; transfer sector to A.
        AND     $07             ; and mask off lower 8 bits for later

        SRL     E               ; returning to E,
        SRL     E               ; divide the
        SRL     E               ; sector or record by eight.
        ADD     HL,DE           ; add to map base to give address of map bit.
        LD      B,A             ; now load sector mod 8 to B and
        INC     B               ; increment to form counter 1 - 8.

        XOR     A               ; clear A
        SCF                     ; and set carry bit ready to rotate in.

;; ROTATE
L13DD:  RLA                     ; rotate left A
        DJNZ    L13DD           ; back, while counter not zero, to ROTATE

        LD      B,A             ; return sector bit in B.
        AND     (HL)            ; AND accumulator with map sector byte.
        RET                     ; return - Z = free, NZ = occupied.


; -----------------------------------
; THE 'RESET BIT IN MAP AREA' ROUTINE
; -----------------------------------
;   This routine is called when opening a channel and by FORMAT, CAT and ERASE
;   to mark a map bit representing a sector as available.

;; RES-B-MAP
L13E3:  CALL    L13C4           ; routine CHECK-MAP fetches bit mask for map
                                ; location addressed by HL into B register.

        LD      A,B             ; fetch sector mask with one bit set.
        CPL                     ; complement - seven bits set and one bit reset.
        AND     (HL)            ; combine with other sector bits.
        LD      (HL),A          ; and update map byte resetting the bit.
        RET                     ; return.


; ------------------------------------------
; THE 'CHECK 'PSEUDO-MAP' BIT STATE' ROUTINE
; ------------------------------------------
;

;; TEST-PMAP
L13EB:  PUSH    IX              ;
        POP     HL              ;

        LD      DE,$0052        ;
        ADD     HL,DE           ;
        LD      E,(IX+$29)      ; HDNUMB
        JR      L13CD           ; back to ENTRY-2


; -------------------------------------
; THE 'DECREASE SECTOR COUNTER' ROUTINE
; -------------------------------------
;

;; DEC-SECT
L13F7:  LD      BC,($5CC9)      ; sv SECTOR
        DEC     BC              ;
        LD      ($5CC9),BC      ; sv SECTOR
        LD      A,B             ;
        OR      C               ;
        RET                     ;


; ------------------------
; THE 'CHECK-NAME' ROUTINE
; ------------------------
;

;; CHK-NAME
L1403:  PUSH    IX              ; preserve original channel base address.

        LD      B,$0A           ;

;; ALL-CHARS
L1407:  LD      A,(HL)          ;
        CP      (IX+$0E)        ; CHNAME
        JR      NZ,L1423        ; forward to CKNAM-END

        INC     HL              ;
        INC     IX              ;
        DEC     B               ;
        DEC     C               ;
        JR      NZ,L1407        ; back to ALL-CHARS

        LD      A,B             ;
        OR      A               ;
        JR      Z,L1423         ; forward to CKNAM-END


;; ALLCHR-2
L1418:  LD      A,(IX+$0E)      ; CHNAME
        CP      $20             ;
        JR      NZ,L1423        ; forward to CKNAM-END

        INC     IX              ;
        DJNZ    L1418           ; back to ALLCHR-2


;; CKNAM-END
L1423:  POP     IX              ;
        RET                     ;


; -----------------------------------------
; THE 'CALCULATE/COMPARE CHECKSUMS' ROUTINE
; -----------------------------------------
; Used for microdrive channels only.
; While the two checksums within a Network buffer are simple 8-bit sums of
; the data, the algorithm used for the microdrive channels is a little more
; sophisticated as it avoids the formation of the result $FF. While across the
; network a byte is as good as its neighbour, with microdrives the value $FF
; might arise as a result of a failed read.
; The same routine is used both to prepare the checksum prior to saving and to
; calculate and compare the checksum after reading.
; The first entry point is used for the 14 bytes of HDCHK and DESCHK
; and the second entry point is used for the 512 bytes of DCHK.

;; CHKS-HD-R
L1426:  LD      BC,$000E        ; fourteen bytes
        JR      L142E           ; forward to CHKS-ALL

; ---
; ->

;; CHKS-BUFF
L142B:  LD      BC,$0200        ; 512 bytes.

; common code.

;; CHKS-ALL
L142E:  PUSH    HL              ; save pointer to first address.
        LD      E,$00           ; initialize checksum to zero

;; NXT-BYTE
L1431:  LD      A,E             ; fetch running sum
        ADD     A,(HL)          ; add to current location.
        INC     HL              ; point to next location.


        ADC     A,$01           ; avoid the value $FF.
        JR      Z,L1439         ; forward to STCHK

        DEC     A               ; decrement.

;; STCHK
L1439:  LD      E,A             ; update the 8-bit sum.

        DEC     BC              ; reduce counter
        LD      A,B             ; and check
        OR      C               ; for zero.
        JR      NZ,L1431        ; back, if not, to NXT-BYTE

        LD      A,E             ; fetch running sum
        CP      (HL)            ; compare to checksum contents
        LD      (HL),A          ; before inserting the byte.

        POP     HL              ; restore pointer to first address.
        RET                     ; return - with zero flag set if sums agree.


; ---------------------------------
; THE 'RESTORE STREAM DATA' ROUTINE
; ---------------------------------
; When a channel is deleted, then the streams that point to channels beyond
; that one have to have their offsets reduced by the deleted amount.
; Also a stream that exactly matches the offset to the deleted channel, and
; there could be several, will have its entry set to zero.
; On entry, HL = offset, BC = $0253

;; REST-STRM
L1444:  PUSH    HL              ; save the offset
        LD      A,$10           ; maximum streams + 1
        LD      HL,$5C16        ; the start of the user streams area STRMS_00

;; NXT-STRM
L144A:  LD      ($5C5F),HL      ; save stream pointer temporarily in X_PTR

        LD      E,(HL)          ; fetch low byte of offset.
        INC     HL              ; bump address.
        LD      D,(HL)          ; fetch high byte of streams offset.

        POP     HL              ; retrieve the
        PUSH    HL              ; supplied offset.

        OR      A               ; clear carry.
        SBC     HL,DE           ; subtract looking for an exact match
        JR      NZ,L145C        ; forward, if not, to NOTRIGHT

        LD      DE,$0000        ; else set displacement to zero.
        JR      L1463           ; forward to STO-DISP to close the stream.

; ---

;; NOTRIGHT
L145C:  JR      NC,L1469        ; forward, if entry lower, to UPD-POINT ->

; else this stream entry is to be reduced by $0253 bytes.

        EX      DE,HL           ; streams offset to HL
        OR      A               ; clear carry
        SBC     HL,BC           ; reduce by 595 decimal bytes
        EX      DE,HL           ; transfer reduced entry to DE.

;; STO-DISP
L1463:  LD      HL,($5C5F)      ; fetch stream address from X_PTR
        LD      (HL),E          ; and insert
        INC     HL              ; the updated
        LD      (HL),D          ; offset.

; ->

;; UPD-POINT
L1469:  LD      HL,($5C5F)      ; fetch stream address from X_PTR.
        INC     HL              ; bump - each stream entry
        INC     HL              ; is two bytes.
        DEC     A               ; decrement the loop counter.
        JR      NZ,L144A        ; back, if not zero, to NXT-STRM

; else clean up and return.

        LD      ($5C5F),A       ; set X_PTR_hi to zero resting value.
        POP     HL              ; balance stack.
        RET                     ; return.


; -----------------------------------
; THE 'RESTORE MAP ADDRESSES' ROUTINE
; -----------------------------------
; When a microdrive map is reclaimed, then all the addresses of the microdrive
; maps in the "M" channels are examined and if higher than the deleted map, the
; address is reduced by thirty two bytes.
; On entry, HL = map address, BC = $0020.

;; REST-MAP
L1476:  LD      BC,$0020        ; set BC to thirty two. Already done.
        LD      IX,($5C4F)      ; load IX from system variable CHANS.
        LD      DE,$0014        ; there are 20 bytes of the standard 4 channels
        ADD     IX,DE           ; add to skip these.

; now enter a loop.

;; LCHAN
L1482:  LD      A,(IX+$00)      ; fetch first byte.
        CP      $80             ; is it the channels area end-marker ?
        RET     Z               ; return if so - all maps adjusted.       >>

        PUSH    HL              ; save map address.
        LD      A,(IX+$04)      ; fetch channel letter.
        AND     $7F             ; reset bit 7.
        CP      $4D             ; compare to "M"
        JR      NZ,L14A6        ; forward, if not, to LPEND

; a microdrive channel has been found so compare the address of the map.

        LD      E,(IX+$1A)      ; fetch address of the microdrive
        LD      D,(IX+$1B)      ; map for this channel from CHMAP.
        SBC     HL,DE           ; subtract from that of deleted map.
        JR      NC,L14A6        ; forward, if is lower, to LPEND

; address of this microdrive map is higher than the one deleted.

        EX      DE,HL           ; transfer address to HL.
        OR      A               ; clear carry.
        SBC     HL,BC           ; subtract thirty two.
        LD      (IX+$1A),L      ; and place back
        LD      (IX+$1B),H      ; in CHMAP.

;; LPEND
L14A6:  POP     HL              ; restore address of deleted map.
        LD      E,(IX+$09)      ; fetch length of channel
        LD      D,(IX+$0A)      ; to DE.
        ADD     IX,DE           ; add to address next channel.
        JR      L1482           ; loop back to LCHAN.

; ------------------------------
; THE '"M" CHANNEL DEFAULT' DATA
; ------------------------------
;

;; MCH-DAT
L14B1:  DEFW    $0008           ; main ERROR-1
        DEFW    $0008           ; main ERROR-1
        DEFB    $CD             ; inverted "M" character
        DEFW    L12B3           ; MCHAN-OUT
        DEFW    L11FD           ; M-INPUT
        DEFW    $0253           ; length
        DEFW    $0000           ;
        DEFB    $00             ;
        DEFM    "          "    ; 10 spaces
        DEFB    $FF             ; CHFLAG

; -------------------
; THE 'PREAMBLE DATA'
; -------------------
;   The PREAMBLE consists of twelve distinctive bytes that are saved to a
;   microdrive cartridge before the data.  They are not read back but allow 
;   the ULA of the microdrive to recognize the start of a saved data block.

;; PREAMBLE
L14CA:  DEFB    $00, $00, $00
        DEFB    $00, $00, $00
        DEFB    $00, $00, $00
        DEFB    $00, $FF, $FF

; -------------------------------
; THE 'NOT-USED TOOLKIT' ROUTINES
; -------------------------------
; The following four routines are for debugging
; purposes during development.

; ----------------------
; THE 'DISP-HEX' ROUTINE
; ----------------------
;   display a byte as two hex characters.

;; DISP-HEX
L14D6:  PUSH    AF              ;
        RRA                     ;
        RRA                     ;
        RRA                     ;
        RRA                     ;
        CALL    L14DF           ; routine DISP-NIB
        POP     AF              ;

;; DISP-NIB
L14DF:  AND     $0F             ;

        CP      $0A             ;

        JR      C,L14E7         ; forward to CONV-1

        ADD     A,$07           ;

;; CONV-1
L14E7:  ADD     A,$30           ;

        CALL    L14F8           ; routine DISP-CH
        RET                     ;


; -----------------------
; THE 'DISP-HEX2' ROUTINE
; -----------------------
;   display a byte in hexadecimal followed by a space

;; DISP-HEX2
L14ED:  PUSH    AF              ;
        CALL    L14D6           ; routine DISP-HEX
        LD      A,$20           ;
        CALL    L14F8           ; routine DISP-CH
        POP     AF              ;
        RET                     ;


; ---------------------
; THE 'DISP-CH' ROUTINE
; ---------------------
;

;; DISP-CH
L14F8:  PUSH    HL              ;
        PUSH    DE              ;
        PUSH    BC              ;
        PUSH    AF              ;
        EXX                     ;
        PUSH    HL              ;
        PUSH    DE              ;
        PUSH    BC              ;
        PUSH    AF              ;
        LD      HL,($5C51)      ; sv CURCHL
        PUSH    HL              ;
        PUSH    AF              ;
        LD      A,$02           ;
        RST     10H             ; CALBAS
        DEFW    $1601           ; main CHAN-OPEN
        POP     AF              ;
        RST     10H             ; CALBAS
        DEFW    $0010           ; main PRINT-A


        POP     HL              ;
        LD      ($5C51),HL      ; sv CURCHL
        POP     AF              ;
        POP     BC              ;
        POP     DE              ;
        POP     HL              ;
        EXX                     ;
        POP     AF              ;
        POP     BC              ;
        POP     DE              ;
        POP     HL              ;
        RET                     ;


; ----------------------
; THE 'HEX-LINE' ROUTINE
; ----------------------
;   The Master routine which displays ten bytes of memory, addressed by HL, 
;   in Hexadecimal followed by a CR.  The thirty output characters sit 
;   comfortably within the 32 character display of the Spectrum.

;; HEX-LINE
L151D:  PUSH    HL              ;
        PUSH    BC              ;
        PUSH    AF              ;
        LD      B,$0A           ;

;; HEX-LINE2
L1522:  LD      A,(HL)          ;
        CALL    L14ED           ; routine DISP-HEX2
        INC     HL              ;
        DJNZ    L1522           ; back to HEX-LINE2

        LD      A,$0D           ;
        CALL    L14F8           ; routine DISP-CH
        POP     AF              ;
        POP     BC              ;
        POP     HL              ;
        RET                     ; return.


; --------------------------------
; THE 'SELECT DRIVE MOTOR' ROUTINE
; --------------------------------
; (Hook Code: $21)
;   This important routine is called on over twenty occasions to activate a
;   microdrive whose number is in the accumulator, or with a parameter of
;   zero, to stop all motors.  It is the sole means of controlling the real
;   or virtual bank of eight microdrives.
;   It is called with interrupts disabled and this condition should be in
;   force when the Hook Code is used.

;; SEL-DRIVE
L1532:  PUSH    HL              ; preserve the original HL value throughout.

        CP      $00             ; is the parameter zero ?
        JR      NZ,L153D        ; forward, if not, to TURN-ON.

;   The requirement is to ensure that all eight drives are switched off.

        CALL    L1565           ; routine SW-MOTOR with A holding zero.

        EI                      ; Enable Interrupts.

        POP     HL              ; restore original HL value.
        RET                     ; return.                               >>


; --------------------
; THE 'TURN ON' BRANCH
; --------------------
;   This route turns on a drive in the range 1 - 8.  If the Hook Code has
;   been erroneously invoked with a higher value, then this will be treated
;   in much the same way as with zero.  See later.

;; TURN-ON
L153D:  DI                      ; Disable Interrupts.

        CALL    L1565           ; routine SW-MOTOR

        LD      HL,$1388        ; prepare decimal 5,000 delay value.

;; TON-DELAY
L1544:  DEC     HL              ; a simple
        LD      A,H             ; delay loop to
        OR      L               ; let things settle down.
        JR      NZ,L1544        ; back, if not zero, to TON-DELAY

        LD      HL,$1388        ; load with five thousand again.

; Now enter another 5000 loop testing for break and searching for a GAP on
; the tape at each iteration.

;; REPTEST
L154C:  LD      B,$06           ; six consecutive reads required to register
                                ; as a gap.

;; CHK-PRES
L154E:  CALL    L163E           ; routine TEST-BRK allows the user to stop.

        IN      A,($EF)         ; read the microdrive port.
        AND     $04             ; test for the gap bit
        JR      NZ,L155B        ; forward, if not, to NOPRES

        DJNZ    L154E           ; loop back six times to CHK-PRES

; A gap has been found - a formatted cartridge is in the drive.

        POP     HL              ; restore original HL value.
        RET                     ; return with motor running, interrupts
                                ; disabled.                               >>

; -------------------
; THE 'NO GAP' BRANCH
; -------------------
;   If no gap signal found on drive so far then continue counting down from
;   5000 and looping back to test for six gaps.

;; NOPRES
L155B:  DEC     HL              ; decrement the counter
        LD      A,H             ; test for
        OR      L               ; zero.
        JR      NZ,L154C        ; back, if not, to REPTEST

        CALL    L1532           ; routine SEL-DRIVE with accumulator zero
                                ; stops the drive motor.

        RST     20H             ; Shadow Error Restart
        DEFB    $10             ; 'Microdrive not present'

; -----------------------------
; THE 'SWITCH MOTOR' SUBROUTINE
; -----------------------------
;   The main developer of the microdrives and acknowledged co-inventor was
;   the late Ben Cheese, 14-Jul-1954 - 15-Jan-2001.
;
;   This ROM software always handles the switching of microdrives as if
;   there were eight drives connected.  There is no short cut to directly
;   switch on a drive and they must be handled as an array of eight devices.
;   Each microdrive includes a D-flip flop, capable of holding logic state
;   one or zero.  When the flip-flop is set at logic one then the
;   recording/playback device is switched on.
;
;   The first microdrive has the D-input terminal of the flip-flop connected
;   to the comms data line of the Interface 1 and the clock-input terminal
;   connected to the clock-output terminal of Interface 1.  Subsequent
;   microdrives have the D-input terminal connected to the Q-output terminal
;   of the next innermost drive/flip-flop and the CLOCK-input terminal
;   connected to the CLOCK-input terminal of the same adjacent
;   drive/flip-flop.
;
;   The eight microdrives thus behave as a shift register allowing a logic 1
;   condition, originating at the Interface 1 control device, to be loaded
;   into the first flip-flop by a single clock pulse and to be shifted out
;   to the appropriate flip-flop by a series of further clock pulses.
;
;   As eight pulses will be required, then the logic state of drive eight is
;   considered first and drive one is the last to be considered.
;
;   By negating the drive number and adding nine, the routine below begins
;   by effecting this reversal and, by converting zero to nine, it ensures
;   that eight logic zeros are shifted out for this case and for the case
;   of any out-of-range parameter, which can arise in the case of a User
;   experimenting with Hook Codes.
;   The limit of eight microdrives is set in the routine below and not in
;   hardware.
;
;   As Ben pointed out on his patent from which some of these details are
;   taken, "it will be appreciated that the control device may be used to
;   select associated devices other than recording/playback devices and that
;   any number of associated devices may be accommodated by use of the
;   technique described."

;; SW-MOTOR
L1565:  PUSH    DE              ; preserve the original DE value throughout.

        LD      DE,$0100        ; load DE with the constants logic one and
                                ; logic zero.

        NEG                     ; negate the supplied drive number 0 - n
        ADD     A,$09           ; add 9 so that 0 = 9, -1 = 8, -8 = 1, -10 = -1
        LD      C,A             ; place the reversed parameter in C.
        LD      B,$08           ; set clock shift counter to eight.

;; ALL-MOTRS
L1570:  DEC     C               ; decrement the drive selector.
        JR      NZ,L1586        ; forward, if not in position, to OFF-MOTOR.

; The time has come to send out a signal to start this drive.

        LD      A,D             ; select logic one.
        OUT     ($F7),A         ; output to data port.

        LD      A,$EE           ; select comms clock 1, comms data 0
        OUT     ($EF),A         ; output to D-flip flop.

        CALL    L15A2           ; routine DEL-S-1 holds for a millisecond.

        LD      A,$EC           ; select comms clock 0, comms data 0
        OUT     ($EF),A         ; output to D-flip flops.

        CALL    L15A2           ; routine DEL-S-1 holds for a millisecond.

        JR      L1597           ; forward to NXT-MOTOR

; ---

;; OFF-MOTOR
L1586:  LD      A,$EF           ; select comms clock 1, comms data 1
        OUT     ($EF),A         ; output to D-flip flop.

        LD      A,E             ; select logic 0.
        OUT     ($F7),A         ; output to data port.

        CALL    L15A2           ; routine DEL-S-1 holds for a millisecond.

        LD      A,$ED           ; select comms clock 0, comms data 1
        OUT     ($EF),A         ; output to microdrive port.

        CALL    L15A2           ; routine DEL-S-1 holds for a millisecond.

;; NXT-MOTOR
L1597:  DJNZ    L1570           ; back, for all eight drives, to ALL-MOTRS.

        LD      A,D             ; select logic one.
        OUT     ($F7),A         ; output to data port.
        LD      A,$EE           ; select comms clock 1, comms data 0.
        OUT     ($EF),A         ; output to microdrive port.

        POP     DE              ; restore original DE value.
        RET                     ; return.


; ---------------------------------
; THE '1 MILLISECOND DELAY' ROUTINE
; ---------------------------------
;   This subroutine is used to time the transitions of the Delay-flip-flops
;   used, above, to control the array of microdrives attached to Interface 1.
;   Delay flip flops become unstable if transitions are too close together
;   and this routine provides a 1 millisecond delay between clock pulses.

;; DEL-S-1
L15A2:  PUSH    BC              ; preserve counters.
        PUSH    AF              ;

        LD      BC,$0087        ; 135 decimal.
        CALL    L1652           ; routine DELAY-BC

        POP     AF              ;
        POP     BC              ; restore counters

        RET                     ; return.


; ---------------------------------------------
; THE 'SEND HEADER BLOCK TO MICRODRIVE' ROUTINE
; ---------------------------------------------
;   Routine is called once from the FORMAT routine.

;; OUT-M-HD
L15AD:  PUSH    HL              ;
        LD      DE,$001E        ; 30 bytes.
        JR      L15B7           ; forward to OUT-M-BLK ->

; -------------------------------------------
; THE 'SEND DATA BLOCK TO MICRODRIVE' ROUTINE
; -------------------------------------------
;

;; OUT-M-BUF
L15B3:  PUSH    HL              ;
        LD      DE,$021F        ; 543 bytes.

; -> Common code.

;; OUT-M-BLK
L15B7:  IN      A,($EF)         ;
        AND     $01             ; isolate write prot. bit.
        JR      NZ,L15BF        ; forward to NOT-PROT

        RST     20H             ; Shadow Error Restart
        DEFB    $0E             ; Drive 'write' protected

; ---

;; NOT-PROT
L15BF:  LD      A,($5CC6)       ; sv IOBORD
        OUT     ($FE),A         ;
        LD      A,$E2           ;
        OUT     ($EF),A         ;
        INC     D               ;
        LD      A,D             ;
        LD      B,E             ;
        LD      C,$E7           ;

        NOP                     ;
        NOP                     ;
        NOP                     ;

;; OUT-M-BYT
L15D0:  OTIR                    ;
        DEC     A               ;
        JR      NZ,L15D0        ; back to OUT-M-BYT

        LD      A,$E6           ;
        OUT     ($EF),A         ;
        CALL    L0D4D           ; routine BORD-REST
        POP     HL              ;
        RET                     ; return.

; -----------------------------
; THE 'SIGNAL ERROR' EXIT POINT
; -----------------------------
;   This exit point is used  twice from the next routines when the required
;   header or record block is not found within the requisite time.

;; SIGN-ERR
L15DE:  POP     BC              ; balance the stack.
        POP     HL              ; first byte of destination.
        INC     (HL)            ; increment RECFLG or HDFLAG.
        RET                     ; return.


; --------------------------------------------------
; THE 'RECEIVE BLOCK FROM MICRODRIVE HEADER' ROUTINE
; --------------------------------------------------
;

;; GET-M-HD
L15E2:  PUSH    HL              ; save destination
        LD      DE,$000F        ; set fifteen bytes to load.
        LD      HL,$0000        ; set large delay when waiting for a header.
        JR      L15F2           ; forward to GET-M-BLK

; --------------------------------------------------
; THE 'RECEIVE BLOCK FROM MICRODRIVE RECORD' ROUTINE
; --------------------------------------------------
;

;; GET-M-BUF
L15EB:  PUSH    HL              ; save destination.
        LD      DE,$0210        ; set 528d bytes to load.
        LD      HL,$01F4        ; set delay counter to 500d.

; -->

;; GET-M-BLK
L15F2:  LD      B,E             ; load B register for first INIR load.
        LD      C,D             ; load C register with count of further loads.
        INC     C               ; adjust to count down to zero.
        PUSH    BC              ; save the INIR counters.

;

;; CHK-AGAIN
L15F6:  LD      B,$08           ; set gap counter to eight.

        DEC     HL              ;
        LD      A,H             ;
        OR      L               ;

        JR      Z,L15DE         ; back to SIGN-ERR

;; CHKLOOP
L15FD:  CALL    L163E           ; routine TEST-BRK

        IN      A,($EF)         ;
        AND     $04             ; isolate gap bit.
        JR      Z,L15F6         ; back to CHK-AGAIN

        DJNZ    L15FD           ; back to CHKLOOP

;; CHK-AG-2
L1608:  LD      B,$06           ;
        DEC     HL              ;
        LD      A,H             ;
        OR      L               ;
        JR      Z,L15DE         ; back to SIGN-ERR


;; CHK-LP-2
L160F:  CALL    L163E           ; routine TEST-BRK
        IN      A,($EF)         ;
        AND     $04             ; isolate gap bit.
        JR      NZ,L1608        ; back to CHK-AG-2

        DJNZ    L160F           ; back to CHK-LP-2

        LD      A,$EE           ;
        OUT     ($EF),A         ;

        LD      B,$3C           ; set count 60 decimal.

;; DR-READY
L1620:  IN      A,($EF)         ;
        AND     $02             ; isolate sync bit.
        JR      Z,L162A         ; forward to READY-RE

        DJNZ    L1620           ; back to DR-READY

        JR      L15F6           ; back to CHK-AGAIN

; ---

;; READY-RE
L162A:  POP     BC              ; retrieve counters from the stack.
        POP     HL              ; retrieve the destination
        PUSH    HL              ; and stack again.
        CALL    L163E           ; routine TEST-BRK.
        LD      A,C             ; transfer repeat counter to A.
        LD      C,$E7           ; set port to $E7.

;   Now the INIR (INput to memory Increment and Repeat) instruction is used.

;; IN-M-BLK
L1633:  INIR                    ; read B bytes from port C to destination HL.

;   B (zero) will now count 256 bytes if first block was not the total.

        DEC     A               ; decrement repeat counter.
        JR      NZ,L1633        ; back, if not zero, to IN-M-BLK

;   All bytes, 15 or 528 have now been read.

        LD      A,$EE           ;
        OUT     ($EF),A         ;

        POP     HL              ; restore pointer to first byte.
        RET                     ; return.

; ----------------------
; THE 'TEST-BRK' ROUTINE
; ----------------------
;   Note. used more consistently in this ROM.

;; TEST-BRK
L163E:  LD      A,$7F           ; read port $7FFE - keys B, N, M, SYM, SPACE.
        IN      A,($FE)         ;
        RRA                     ; test for SPACE key.
        RET     C               ; return if not pressed.

        LD      A,$FE           ; read port $FEFE - keys SHIFT, Z, X, C, V.
        IN      A,($FE)         ;
        RRA                     ; test for SHIFT key.
        RET     C               ; return if not pressed.

        CALL    L0D4D           ; routine BORD-REST.

        LD      (IY+$00),$14    ; set ERR_NR to main 'L BREAK into program'
        RST     28H             ; invoke the Main ROM error routine.

; ----------------------
; THE 'DELAY-BC' ROUTINE
; ----------------------
;

;; DELAY-BC
L1652:  PUSH    AF              ;

;; DELAY-BC1
L1653:  DEC     BC              ;
        LD      A,B             ;
        OR      C               ;
        JR      NZ,L1653        ; back to DELAY-BC1

        POP     AF              ;
        RET                     ;

; ------------------------
; THE 'READ BLOCK' ROUTINE
; ------------------------
;   Note. new in this ROM.
;   Used by format routine.

;; READ-BLK
L165A:  PUSH    HL
        PUSH    BC

;; RDLOOP1
L165C:  LD      B,$08

;; RDLOOP2
L165E:  CALL    L163E           ; routine TEST-BRK

        IN      A,($EF)
        AND     $04             ; isolate gap bit.

        JR      Z,L165C         ; back to RDLOOP1

        DJNZ    L165E           ; back to RDLOOP2


;; RDLOOP3
L1669:  LD      B,$06

;; RDLOOP4
L166B:  CALL    L163E           ; routine TEST-BRK

        IN      A,($EF)
        AND     $04             ; isolate gap bit.

        JR      NZ,L1669        ; back to RDLOOP3

        DJNZ    L166B           ; back to RDLOOP4

        LD      A,$EE
        OUT     ($EF),A

        LD      B,$3C           ; set counter to 60d.

;; SYNC-RD
L167C:  IN      A,($EF)
        AND     $02             ; isolate sync bit.
        JR      Z,L1686         ; forward to READY-R2

        DJNZ    L167C           ; back to SYNC-RD

        JR      L165C           ; back to RDLOOP1

; ---


;; READY-R2
L1686:  POP     BC
        POP     HL
        PUSH    HL
        CALL    L163E           ; routine TEST-BRK

        LD      C,$E7           ; port
        LD      E,$FC           ; required test byte
        LD      B,$0F           ; initial counter.
        LD      D,$64           ; final counter.
        INIR

;; RD-BYT-1
L1696:  IN      A,(C)
        CP      E
        JR      NZ,L16AD        ; forward to ENDRD

        DJNZ    L1696           ; back to RD-BYT-1


;; RD-BYT-2
L169D:  IN      A,(C)
        CP      E
        JR      NZ,L16AD        ; forward to ENDRD

        DJNZ    L169D           ; back to RD-BYT-2

        LD      B,D             ; final counter is $64

;; RD-BYT-3
L16A5:  IN      A,(C)
        CP      E
        JR      NZ,L16AD        ; forward to ENDRD

        DJNZ    L16A5           ; back to RD-BYT-3

        XOR     A               ; set zero flag to signal successful read

;; ENDRD
L16AD:  POP     HL
        RET                     ; return.

; -------------------------
; THE 'WRITE BLOCK' ROUTINE
; -------------------------
;   Note. new in this ROM.
;   Called once from the FORMAT routine.

;; WR-BLK
L16AF:  PUSH    HL              ; preserve HL throughout.

        LD      A,($5CC6)       ; fetch the value of IOBORD
        OUT     ($FE),A         ; and change the border colour.

        LD      A,$E2
        OUT     ($EF),A         ; enable writing

        LD      E,$66
        LD      C,$E7
        LD      B,$1B
        LD      A,$FC           ; test byte written
        NOP                     ;
        OTIR                    ;

;; WR-BYT-1
L16C4:  OUT     (C),A
        DJNZ    L16C4           ; back to WR-BYT-1


;; WR-BYT-2
L16C8:  OUT     (C),A
        DJNZ    L16C8           ; back to WR-BYT-2

        LD      B,E             ; load counter with $66

;; WR-BYT-3
L16CD:  OUT     (C),A
        DJNZ    L16CD           ; back to WR-BYT-3

        LD      A,$E6
        OUT     ($EF),A

        CALL    L0D4D           ; routine BORD-REST

        POP     HL              ; restore initial HL value.

        RET                     ; return.

; --------------------
; THE 'UNUSED' SECTION
; --------------------
;   Contains copyright holder and initials of the main programmer.  The rest
;   is set to $FF.  This section is situated before the fixed-position CLOSE
;   rectification routine.

        DEFB    $7F             ; copyright  © 
        DEFM    " 1983 Sinclair"
        DEFM    " Research Ltd"
        DEFM    " MJB "         ; Martin Brennan

        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF
        DEFB    $FF

; --------------------------
; THE 'CLOSE STREAM' ROUTINE
; --------------------------
;   Note. An instruction fetch on main address L1708 pages in this ROM.

;; CLOSE-CH
L1708:  INC     HL              ; Same instruction as in Main ROM

        RST     30H             ; Create the new system variables

;   Note. If extra System Variables were created then the accumulator will 
;   now hold the value 1 from the setting of COPIES.
;   A command like       OPEN #7,"s" : CLOSE #7      will not work.
;   If the system variables were already created then it is possible to 
;   derive the stream from the accumulator by reversing the operations 
;   that were performed on the value in the main ROM.


        SRL     A               ; Shift Right Logical halves the value
        SUB     $03             ; Subtraction produced the original stream.

        RES     1,(IY+$7C)      ; set FLAGS_3 to indicate a CLOSE operation.

        CALL    L1718           ; routine CLOSE (below)

        JP      L05C1           ; jump back to normal command exit at END1

; ---------------------------
; THE 'CLOSE COMMAND' ROUTINE
; ---------------------------
;   This command is called from above and also from ALL-STRMS as part of the
;   CLEAR # command execution.

;; CLOSE
L1718:  RST     10H             ; CALBAS
        DEFW    $1727           ; main STR-DATA1

;   Now perform the check that should have taken place in the original ROM.

        LD      A,C             ; Test offset for zero.
        OR      B               ;
        RET     Z               ; Return if the stream is already closed.

        PUSH    BC              ;
        PUSH    HL              ;

        LD      HL,($5C4F)      ; sv CHANS
        DEC     HL              ;
        ADD     HL,BC           ;
        EX      (SP),HL         ;
        RST     10H             ; CALBAS
        DEFW    $16EB           ; main CLOSEX
        LD      HL,($5C4F)      ; sv CHANS
        LD      DE,$0014        ;
        ADD     HL,DE           ;

        POP     DE              ;
        SCF                     ;
        SBC     HL,DE           ;
        POP     BC              ;


        RET     NC              ;

        PUSH    BC              ;
        PUSH    DE              ;
        EX      DE,HL           ;
        LD      ($5C51),HL      ; sv CURCHL
        INC     HL              ;


        INC     HL              ;
        INC     HL              ;
        INC     HL              ;

        LD      A,(HL)          ; fetch the letter.

;   Now mark the channel as temporary so that if anything goes wrong, such
;   as the user pressing BREAK, then the channel can be reclaimed by CLEAR #.

L1741:  SET     7,(HL)          ; As suggested by Andrew Pennell 1983.

        LD      DE,$0005        ;
        ADD     HL,DE           ;
        LD      E,(HL)          ;
        INC     HL              ;
        LD      D,(HL)          ;
        PUSH    DE              ;
        CP      $54             ; compare to "T"
        JR      NZ,L175C        ; forward to CL-N-CH

        BIT     1,(IY+$7C)      ; sv FLAGS_3
        JR      NZ,L177D        ; forward to RCLM-CH

        LD      A,$0D
        CALL    L0D07           ; routine BCHAN-OUT
        JR      L177D           ; forward to RCLM-CH

; ---

;; CL-N-CH
L175C:  CP      $4E             ; character "N" ?
        JR      NZ,L176B        ; forward to CL-M-CH

        BIT     1,(IY+$7C)      ; sv FLAGS_3
        JR      NZ,L177D        ; forward to RCLM-CH

        CALL    L0FAE           ; routine SEND-NEOF
        JR      L177D           ; forward to RCLM-CH

; ---


;; CL-M-CH
L176B:  CP      $4D             ; character "M"
        JR      NZ,L177D        ; forward to RCLM-CH

        POP     DE              ;
        POP     IX              ;
        POP     DE              ;
        BIT     1,(IY+$7C)      ; sv FLAGS_3
        JP      Z,L138E         ; jump to CLOSE-M2

        JP      L119F           ; jump to DEL-M-BUF

; ---

;; RCLM-CH
L177D:  POP     BC              ;
        POP     HL              ;
        PUSH    BC              ;
        RST     10H             ; CALBAS
        DEFW    $19E8           ; main RECLAIM-2
        XOR     A               ;
        LD      HL,$5C16        ; sv STRMS_00

;; UPD-STRM
L1787:  LD      E,(HL)          ;
        INC     HL              ;
        LD      D,(HL)          ;
        DEC     HL              ;
        LD      ($5C5F),HL      ; sv X_PTR
        POP     BC              ;
        POP     HL              ;
        PUSH    HL              ;
        PUSH    BC              ;
        AND     A               ;
        SBC     HL,DE           ;
        JR      NC,L17A2        ; forward to UPD-NXT-S

        EX      DE,HL           ;
        AND     A               ;
        SBC     HL,BC           ;
        EX      DE,HL           ;
        LD      HL,($5C5F)      ; sv X_PTR
        LD      (HL),E          ;
        INC     HL              ;
        LD      (HL),D          ;

;; UPD-NXT-S
L17A2:  LD      HL,($5C5F)      ; sv X_PTR
        INC     HL              ;
        INC     HL              ;
        INC     A               ;
        CP      $10             ;
        JR      C,L1787         ; back to UPD-STRM

        LD      (IY+$26),$00    ; sv X_PTR_hi
        POP     HL              ;
        POP     HL              ;
        RES     1,(IY+$7C)      ; sv FLAGS_3
        RET                     ; return.

; ----------------------------------------
; THE 'RECLAIM TEMPORARY CHANNELS' ROUTINE
; ----------------------------------------
;

;; RCL-T-CH
L17B7:  LD      IX,($5C4F)      ; sv CHANS
        LD      DE,$0014
        ADD     IX,DE

;; EX-CHANS
L17C0:  LD      A,(IX+$00)      ; first character of channel
        CP      $80             ; is it the end-marker ?
        JR      NZ,L17D0        ; forward to CHK-TEMPM

        LD      A,$EE
        OUT     ($EF),A

        XOR     A
        JP      L1532           ; jump to SEL-DRIVE

; ---

        RET                     ; unused - the above JP was probably once a CALL.

; ---

;; CHK-TEMPM
L17D0:  LD      A,(IX+$04)      ; channel letter
        CP      $CD             ; is it an inverted "M" ?
        JR      NZ,L17DC        ; forward to CHK-TEMPN

        CALL    L119F           ; routine DEL-M-BUF
        JR      L17B7           ; back to RCL-T-CH


;; CHK-TEMPN
L17DC:  CP      $CE             ; is channel letter an inverted "N" ?
        JR      NZ,L17EB        ; forward to PT-N-CHAN

        LD      BC,$0114
        PUSH    IX
        POP     HL
        RST     10H             ; CALBAS
        DEFW    $19E8           ; main RECLAIM-2
        JR      L17B7           ; back to RCL-T-CH


;; PT-N-CHAN
L17EB:  LD      E,(IX+$09)      ; length of
        LD      D,(IX+$0A)      ; channel
        ADD     IX,DE
        JR      L17C0           ; back to EX-CHANS


; --------------------------
; THE 'MOVE COMMAND' ROUTINE
; --------------------------
;

;; MOVE
L17F5:  SET     4,(IY+$7C)      ; update FLAGS_3 to indicate a MOVE is in 
                                ; progress - see INKEY$ 

        CALL    L1859           ; routine OP-STRM
        LD      HL,($5C4F)      ; sv CHANS
        PUSH    HL
        CALL    L059F           ; routine EX-D-STR
        CALL    L1859           ; routine OP-STRM
        CALL    L059F           ; routine EX-D-STR
        POP     DE
        LD      HL,($5C4F)      ; sv CHANS
        OR      A
        SBC     HL,DE
        LD      DE,($5CDA)      ; sv N_STR1
        ADD     HL,DE
        LD      ($5CDA),HL      ; sv N_STR1

;; M-AGAIN
L1818:  LD      HL,($5CDA)      ; sv N_STR1
        LD      ($5C51),HL      ; sv CURCHL

;; I-AGAIN
L181E:  RST     10H             ; CALBAS
        DEFW    $15E6           ; main INPUT-AD
        JR      C,L1827         ; forward to MOVE-OUT

        JR      Z,L181E         ; back to I-AGAIN

        JR      L1832           ; forward to MOVE-EOF


;; MOVE-OUT
L1827:  LD      HL,($5CE2)      ; sv D_STR2
        LD      ($5C51),HL      ; sv CURCHL
        RST     10H             ; CALBAS
        DEFW    $0010           ; main PRINT-A

        JR      L1818           ; back to M-AGAIN

;; MOVE-EOF
L1832:  RES     4,(IY+$7C)      ; sv FLAGS_3
        LD      HL,($5C4F)      ; sv CHANS
        PUSH    HL
        CALL    L059F           ; routine EX-D-STR
        CALL    L18A8           ; routine CL-CHAN
        CALL    L059F           ; routine EX-D-STR
        POP     DE
        LD      HL,($5C4F)      ; sv CHANS
        OR      A
        SBC     HL,DE
        LD      DE,($5CDA)      ; sv N_STR1
        ADD     HL,DE
        LD      ($5CDA),HL      ; sv N_STR1
        CALL    L18A8           ; routine CL-CHAN
        CALL    L17B7           ; routine RCL-T-CH

        RET                     ; RETURN


; ---------------------------------------------
; THE 'USE STREAM OR TEMPORARY CHANNEL' ROUTINE
; ---------------------------------------------
;

;; OP-STRM
L1859:  LD      A,($5CD8)       ; sv D_STR1
        INC     A
        JR      Z,L186A         ; forward to OP-CHAN

        DEC     A
        RST     10H             ; CALBAS
        DEFW    $1601           ; main CHAN-OPEN
        LD      HL,($5C51)      ; sv CURCHL
        LD      ($5CDA),HL      ; sv N_STR1
        RET


;; OP-CHAN
L186A:  LD      A,($5CD9)       ; sv L_STR1 device letter.

        CP      $4D             ; is character "M" ?
        JR      NZ,L1883        ; forward to CHECK-N

        CALL    L1B05           ; routine OP-TEMP-M creates a temporary
                                ; microdrive channel, starts motor, and 
                                ; fetches record zero of named file.
        XOR     A
        CALL    L1532           ; routine SEL-DRIVE
        LD      ($5CDA),IX      ; sv N_STR1
        BIT     2,(IX+$43)      ; RECFLG
        RET     Z

        RST     20H             ; Shadow Error Restart
        DEFB    $16             ; Wrong file type


;; CHECK-N
L1883:  CP      $4E             ; is character "N" ?
        JR      NZ,L188F        ; forward to CHECK-R

        CALL    L0F46           ; routine OP-TEMP-N
        LD      ($5CDA),IX      ; sv N_STR1
        RET

; ---

;   Finally, check for the RS232 channel before producing an error.

;; CHECK-R
L188F:  CP      $54             ; is character "T" ?
        JR      Z,L1899         ; forward to USE-R

        CP      $42             ; is character "B" ?
        JR      Z,L1899         ; forward to USE-R

        RST     20H             ; Shadow Error Restart
        DEFB    $00             ; Nonsense in BASIC

; ---

;; USE-R
L1899:  CALL    L0B17           ; routine OP-RS-CH
        LD      ($5CDA),DE      ; sv N_STR1
        PUSH    DE              ;
        POP     IX              ;
        SET     7,(IX+$04)      ; channel letter
        RET                     ; return.


; ----------------------------------
; THE 'CLOSE 'MOVE' CHANNEL' ROUTINE
; ----------------------------------
;

;; CL-CHAN
L18A8:  LD      A,($5CD8)       ; sv D_STR1
        INC     A
        RET     NZ

        LD      A,($5CD9)       ; sv L_STR1 device letter.
        CP      $4D             ; is character "M" ?
        JR      NZ,L18BC        ; forward to CL-CHK-N

        LD      IX,($5CDA)      ; sv N_STR1
        CALL    L138E           ; routine CLOSE-M2
        RET                     ;


;; CL-CHK-N
L18BC:  CP      $4E             ; is character "N" ?
        RET     NZ              ;

        LD      IX,($5CDA)      ; sv N_STR1
        LD      ($5C51),IX      ; sv CURCHL
        CALL    L0FAE           ; routine SEND-NEOF
        RET


; ---------------------------------------------
; THE 'SAVE DATA BLOCK INTO MICRODRIVE' ROUTINE
; ---------------------------------------------
;

;; SA-DRIVE
L18CB:  LD      A,($5CD6)       ; fetch drive number from D_STR1
        CALL    L1532           ; routine SEL-DRIVE starts motor.

        IN      A,($EF)         ; read microdrive port.
        AND     $01             ; isolate 'write protect' bit.
        JR      NZ,L18D9        ; forward, if not low, to STAR-SA

        RST     20H             ; Shadow Error Restart
        DEFB    $0E             ; 'Drive 'write' protected'

; ---

;; STAR-SA
L18D9:  LD      HL,($5CE9)      ; sv HD_0D
        LD      ($5CE4),HL      ; sv D_STR2

        CALL    L1B05           ; routine OP-TEMP-M creates a temporary
                                ; microdrive channel, starts motor, and 
                                ; attempts to fetch record zero of named file.

        BIT     0,(IX+$18)      ; test CHFLAG
        JR      NZ,L18ED        ; forward, with no existing file, to NEW-NAME

        CALL    L138E           ; routine CLOSE-M2 closes temporary channel
                                ; and stops the motor.

        RST     20H             ; Shadow Error Restart
        DEFB    $0C             ; Writing to a 'read' file

; ---

;; NEW-NAME
L18ED:  SET     2,(IX+$43)      ; update RECFLG signal not a PRINT type file.

;   Note. the microdrive motor has been left running by OP-TEMP-M so the next
;   two lines are not necessary.  Redundant code elsewhere suggests that 
;   OP-TEMP-M once stopped the drive.

        LD      A,(IX+$19)      ; fetch drive from CHDRIV.
        CALL    L1532           ; routine SEL-DRIVE stops and then restarts the 
                                ; motor.

        PUSH    IX              ; transfer the channel base address
        POP     HL              ; to the HL register pair.

        LD      DE,$0052        ; prepare offset to data buffer.
        ADD     HL,DE           ; add to address start of data.
        EX      DE,HL           ; transfer this destination to DE.

        LD      HL,$5CE6        ; set source to the nine byte header at HD_00
        LD      BC,$0009        ; nine bytes to copy.
        LD      (IX+$0B),C      ; update CHBYTE_lo with length saved so far.

        LDIR                    ; block move the header info into the buffer.

        PUSH    DE              ; save destination.

;   Now calculate the number of sectors required using a similar method to
;   the one used for calculating the number of records to load.   
;   Note. there is an error in the calculation as one byte should be subtracted
;   from the total bytes to ensure that there is at least one byte in the EOF
;   record. The next instruction should be to load HL with eight.

L190B:  LD      HL,$0009        ; start with the nine header bytes. ??
        LD      BC,($5CE7)      ; fetch data length from HD_0B.
        ADD     HL,BC           ; add to give total size of block.

        SRL     H               ; halve MSB to convert to 512 byte chunks.
        INC     H               ; increment to include EOF block. Wrong.

;   Note. 
;   511  bytes = 502 bytes + 9 header = $01FF, SRL=$00, INC=$01 sectors OK.
;   512  bytes = 503 bytes + 9 header = $0200, SRL=$01, INC=$02 sectors WRONG!!
;   513  bytes = 504 bytes + 9 header = $0201, SRL=$01, INC=$02 sectors OK.


        PUSH    HL              ; preserve register H the sector counter.

        CALL    L1D43           ; routine FREESECT calculates free sectors on
                                ; cartridge.

        POP     HL              ; bring back the sector estimate in H.
        LD      A,E             ; load accumulator with actual sectors.
        CP      H               ; compare with estimate
        JR      NC,L1921        ; forward, if equal or greater, to SA-DRI-2

        RST     20H             ; Shadow Error Restart
        DEFB    $0F             ; 'Microdrive full'

; ---

;; SA-DRI-2
L1921:  POP     DE              ; bring back destination.
        LD      HL,($5CE4)      ; fetch start from D_STR2
        LD      BC,($5CE7)      ; fetch data length from HD_0B

;; SA-DRI-3
L1929:  LD      A,B             ; test for 
        OR      C               ; zero bytes.
        JR      Z,L194F         ; forward, if all chunks saved, to SA-DRI-4

        LD      A,(IX+$0C)      ; fetch high byte of byte counter from CHBYTE_hi
        CP      $02             ; compare to 2 which would indicate 512 bytes.
        JR      NZ,L1943        ; forward, if less, to SA-DRI-WR

; a sector is written to microdrive.

        PUSH    HL              ; preserve start of data.
        PUSH    BC              ; preserve length.

        CALL    L12EE           ; routine WRITE-PRC.

        POP     BC              ; restore length.

        PUSH    IX              ; transfer the channel base address
        POP     HL              ; to the HL register pair.

        LD      DE,$0052        ; add offset to
        ADD     HL,DE           ; point to data buffer.
        EX      DE,HL           ; transfer this destination to DE.

        POP     HL              ; restore the start of data.

;; SA-DRI-WR
L1943:  LDI                     ; transfer one byte at a time decrementing BC
                                ; the total byte counter.

;   now increment the channel byte counter which started at zero and has a 
;   limit of 512 bytes.

        INC     (IX+$0B)        ; increment CHBYTE_lo
        JR      NZ,L1929        ; back, if not 256, to SA-DRI-3

        INC     (IX+$0C)        ; increment CHBYTE_hi
        JR      L1929           ; back to SA-DRI-3 to check high byte.

; ---

;; SA-DRI-4
L194F:  SET     1,(IX+$43)      ; update RECFLG mark this as EOF record.

        CALL    L12EE           ; routine WRITE-PRC writes last record in set.

        LD      A,($5CEF)       ; fetch user-alterable system variable COPIES
        DEC     A               ; decrement
        JR      Z,L196A         ; forward, if zero, to END-SA-DR

        LD      ($5CEF),A       ; place decremented value back in COPIES

        RES     1,(IX+$43)      ; update RECFLG - signal not the EOF record.
        LD      A,$00           ; prepare to start saving at record zero again.
        LD      (IX+$0D),A      ; update the channel record counter CHREC.

        JR      L18ED           ; back to NEW-NAME

; ---

;; END-SA-DR
L196A:  XOR     A               ; set accumulator to zero.
        CALL    L1532           ; routine SEL-DRIVE stops the motor.

        JP      L119F           ; jump to DEL-M-BUF

; ----------------------------------------------------
; THE 'GET HEADER INFORMATION FROM MICRODRIVE' ROUTINE
; ----------------------------------------------------
; this routine extracts the nine bytes of global header information that
; is prepended to the data saved on microdrive. This relates to the type -
; Basic, Code and length etc. and is the equivalent of a tape header without
; the name which, in contrast, does have to be saved to every record.
; It is obtained therefore from the start of data at record zero.
;
; Note. the destination for this data, (program area or variable location), 
; has already been calculated and since opening a channel will move this
; destination up in memory, the "Start of data" is transferred to the D_STR2
; location, otherwise used for the second filename during moves, so that its
; value is adjusted by REST-N-AD during OP-TEMP-M.

;; F-M-HEAD
L1971:  LD      HL,($5CE1)      ; copy start of data from D_STR2(+3)
        LD      ($5CE4),HL      ; to dynamic location D_STR2(+6)

        CALL    L1B05           ; routine OP-TEMP-M creates a temporary
                                ; microdrive channel, starts motor, and 
                                ; fetches record zero of named file.

        BIT     0,(IX+$18)      ; test CHFLAG for valid first record.
        JR      Z,L1982         ; forward, if OK, to F-HD-2

        RST     20H             ; Shadow Error Restart
        DEFB    $11             ; 'File not found'

; ---

;; F-HD-2
L1982:  BIT     2,(IX+$43)      ; test RECFLG is it a print file
        JR      NZ,L198A        ; forward, if not, to F-HD-3

        RST     20H             ; Shadow Error Restart
        DEFB    $16             ; 'Wrong file type'

; ---

;; F-HD-3
L198A:  PUSH    IX              ; transfer the channel base address
        POP     HL              ; to the HL register pair.

        LD      DE,$0052        ; offset to CHDATA
        ADD     HL,DE           ; add to address start of data.
        LD      DE,$5CE6        ; set destination to nine system variables
                                ; starting at location HD_00.
        LD      BC,$0009        ; nine bytes to copy.

        LDIR                    ; block move to HD_00 - HD_11.

        RET                     ; return.

; --------------------------------------------------
; THE 'LOAD OR VERIFY BLOCK FROM MICRODRIVE' ROUTINE
; --------------------------------------------------
;   This subroutine is called once only from LV-ANY to load a block of code, 
;   previously SAVED to a number of sectors, from microdrive.
;   At this stage a temporary channel has already been created and it holds
;   the first 512 byte record containing at the start the nine header bytes.
;   There will be an accurate microdrive map for the drive which has its    
;   motor running.
;   The block could be a program, code bytes or an array and the first 
;   receiving location is in HL and the length in DE.

;; LV-MCH
L199A:  LD      ($5CE9),HL      ; save start in system variable HD_0D

;   now directly read the header values at the start of the data buffer.

        LD      E,(IX+$53)      ; directly read the saved length 
        LD      D,(IX+$54)      ; from the data buffer into DE.

;   now calculate how many 512 byte microdrive records need to be read in
;   by taking the total minus one to ensure an EOF record.
;   e.g.
;   1023 bytes = 1014 bytes + 9 header - 1 = $03FE, SRL=$01, INC=$02 sectors
;   1024 bytes = 1015 bytes + 9 header - 1 = $03FF, SRL=$01, INC=$02 sectors
;   1025 bytes = 1016 bytes + 9 header - 1 = $0400, SRL=$02, INC=$03 sectors

        LD      HL,$0008        ; add eight in effect +9 for header -1.
        ADD     HL,DE           ; add the program/code length. 

;   the MSB is the number of 256 chunks.

        SRL     H               ; shift right to halve and give 512 byte 
                                ; chunks.
        INC     H               ; increment to include the extra sector.

        LD      A,H             ; use accumulator to store record count
        LD      ($5CE7),A       ; in the temporary system variable HD_0B

;   the microdrive map is now saved on the machine stack, for later recall,
;   and at the same time the current map locations are all set to zero.
;   The new map is to be used for records rather than sectors.

        CALL    L1A04           ; routine SA-MAP saves the thirty two bytes
                                ; of the map on the machine stack safely 
                                ; dipping into the 80 bytes of spare memory.

;   now, since this is record zero, subtract the nine header bytes from the 
;   current record length and put back.

        LD      DE,$0009        ;

        LD      L,(IX+$45)      ; RECLEN_lo
        LD      H,(IX+$46)      ; RECLEN_hi

        OR      A               ; clear carry

        SBC     HL,DE           ;

        LD      (IX+$45),L      ; RECLEN_lo
        LD      (IX+$46),H      ; RECLEN_hi

; 

        PUSH    IX              ; transfer the channel base address
        POP     HL              ; to the HL register pair.

        LD      DE,$005B        ; prepare offset $0052 to data and then an
        ADD     HL,DE           ; extra nine bytes. Add to skip the header.

        LD      DE,($5CE9)      ; set destination from HD_0D

        JR      L19EA           ; forward to LOOK-MAP to enter the record
                                ; loading loop at the mid-point as record
                                ; zero is already in the channel.

; ---

;   The record loading loop loads records in random order.  Consider that 
;   multiple copies of a filename may have been saved so there may be several 
;   sectors with the same record number.

;; USE-REC
L19D0:  CALL    L1A5D           ; routine F-REC2 fetches only a header and
                                ; record that matches the name specified 
                                ; in CHNAME and only if the map bit is reset
                                ; indicating no sector with this record number
                                ; has already been loaded.

        LD      A,(IX+$44)      ; re-fetch record number from RECNUM.

; Note. the next test is a nonsense as a record zero has already been marked 
; so no sector with record zero could be reloaded.

        OR      A               ; test for a record zero.
        JR      Z,L19D0         ; back, if so, to USE-REC.

; now calculate the destination if this 512 byte sector.

        RLA                     ; double recnum to give 512 byte chunks
        DEC     A               ; decrement to adjust for nine bytes of header.
        LD      D,A             ; place in MSB of offset

        LD      E,$F7           ; set LSB of offset to $00 - $09 for header.
        LD      HL,($5CE9)      ; fetch start of data from HD_0D

        ADD     HL,DE           ; add to calculate destination for this sector. 
        EX      DE,HL           ; transfer destination to DE.

        PUSH    IX              ; transfer the channel base address
        POP     HL              ; to the HL register pair.

        LD      BC,$0052        ; prepare offset to start of 512 byte buffer
        ADD     HL,BC           ; add so that HL addresses start of data.

; -> The mid loop entry point.

;; LOOK-MAP
L19EA:  EXX                     ; preserve HL and DE by using alternate 
                                ; registers.

        CALL    L13BF           ; routine CHK-MAP-2 sets HL to the map byte 
                                ; and B to the mask.

; Note. the routine also resets the zero flag if this record has previously
; been loaded but this is not possible.

        JR      NZ,L19D0        ; back, if already loaded, to USE-REC.

;   since this is the first time for this record mark so that not loaded again.

        LD      A,(HL)          ; mark the record bit 
        OR      B               ; by setting it so that it is not 
        LD      (HL),A          ; considered for loading again.

        EXX                     ; restore HL (source) and DE (destination).

        CALL    L1A39           ; routine LD-VE-M loads or verifies a
                                ; data record.

;   now decrement the record count which is beyond reach of IY register.

        LD      A,($5CE7)       ; fetch count of records to be loaded HD_0B
        DEC     A               ; decrement 
        LD      ($5CE7),A       ; and place back in system variable HD_0B

        JR      NZ,L19D0        ; back, if not finished to USE-REC

;   the block is loaded 

        CALL    L1A1E           ; routine RE-MAP restores the true microdrive 
                                ; map from the stack.

        RET                     ; return. 


; ------------------------------------------
; THE 'SAVE MICRODRIVE MAP CONTENTS' ROUTINE
; ------------------------------------------
;   This routine saves the sector-mapped microdrive map on the machine stack
;   at the same time setting each of the 32 vacated locations to zero.

;; SA-MAP
L1A04:  POP     HL              ; drop the return address into HL
        LD      ($5CC9),HL      ; and save in unused system variable SECTOR

        LD      L,(IX+$1A)      ; fetch address of microdrive map from CHMAP
        LD      H,(IX+$1B)      ; fetch address of microdrive map from CHMAP
        LD      BC,$1000        ; set word counter B to sixteen and C to zero.

;   now enter a loop stacking two bytes at a time.

;; SA-MAP-LP
L1A11:  LD      E,(HL)          ; fetch first byte to E. 
        LD      (HL),C          ; set location to zero.
        INC     HL              ; bump address.
        LD      D,(HL)          ; fetch second byte to D.
        LD      (HL),C          ; set location to zero.
        INC     HL              ; bump address.

        PUSH    DE              ; save DE on machine stack.

        DJNZ    L1A11           ; back, for 16 pairs, to SA-MAP-LP

        LD      HL,($5CC9)      ; restore return address from SECTOR
        JP      (HL)            ; and jump to location.

; ---------------------------------------------
; THE 'RESTORE MICRODRIVE MAP CONTENTS' ROUTINE
; ---------------------------------------------
;   This routine is the opposite of the above and restores the sector-mapped
;   microdrive map from the machine stack back to its original location 
;   overwriting the now redundant record-indicating map. 

;; RE-MAP
L1A1E:  POP     HL              ; drop the subroutine return address.
        LD      ($5CC9),HL      ; store in the multi-purpose variable SECTOR.

        LD      L,(IX+$1A)      ; fetch address of microdrive map from CHMAP.
        LD      H,(IX+$1B)      ; fetch address of microdrive map from CHMAP.
        LD      DE,$001F        ; thirty one locations are added.
        ADD     HL,DE           ; to address the last location.
        LD      B,$10           ; set the pop counter to sixteen.

;; RE-MAP-LP
L1A2E:  POP     DE              ; pop two bytes of the map from the stack.

        LD      (HL),D          ; insert a map byte.
        DEC     HL              ; decrement the address.
        LD      (HL),E          ; insert second map byte.
        DEC     HL              ; decrement the address again.

        DJNZ    L1A2E           ; back, sixteen times, to RE-MAP-LP.

        LD      HL,($5CC9)      ; restore the return address from SECTOR.
        JP      (HL)            ; and jump to address.

; ---------------------
; THE 'LD-VE-M' ROUTINE
; ---------------------
;   The Load or Verify from Microdrive routine.
;   This routine loads or verifies up to 512 bytes of data currently in the
;   microdrive channel data buffer.

;; LD-VE-M
L1A39:  LD      C,(IX+$45)      ; RECLEN_lo
        LD      B,(IX+$46)      ; RECLEN_hi

; now test if a VERIFY operation by performing the equivalent of bit 7,(iy+$7c)

        LD      A,($5CB6)       ; load system variable FLAGS_3 to accumulator.
        BIT     7,A             ; test FLAGS_3 value - performing VERIFY ?

        JR      NZ,L1A49        ; forward, if so, to VE-M-E

;   the operation is a LOAD.

        LDIR                    ; block copy the bytes.
        RET                     ; return.

; ---

;   the operation is a VERIFY.

;; VE-M-E
L1A49:  LD      A,(DE)          ; fetch a byte from the destination.
        CP      (HL)            ; compare to that of source
        JR      NZ,L1A55        ; forward, with mismatch, to VE-FAIL

        INC     HL              ; increment source address.
        INC     DE              ; increment destination address.
        DEC     BC              ; decrement byte count.
        LD      A,B             ; test for
        OR      C               ; zero.
        JR      NZ,L1A49        ; back, if not, to VE-M-E

        RET                     ; return.

; ---

;; VE-FAIL
L1A55:  RST     20H             ; Shadow Error Restart
        DEFB    $15             ; 'Verification has failed'

; ------------------------------------------
; THE 'FETCH RECORD FROM MICRODRIVE' ROUTINE
; ------------------------------------------
;   Entered at F-REC2,
;   Note. the first entry point f-rec1 is unused.

;; f-rec1
L1A57:  LD      A,(IX+$19)      ; fetch drive number.
        CALL    L1532           ; routine SEL-DRIVE starts motor.

; -->

;; F-REC2
L1A5D:  LD      BC,$04FB        ; Set sector counter to 5 * 255 = 1275
        LD      ($5CC9),BC      ; Update System Variable SECTOR

;; UNTILFIVE
L1A64:  CALL    L1280           ; routine G-HD-RC fetches the next header and 
                                ; matching record to pass tape head.

        JR      C,L1A7B         ; forward, with name mismatch, to F-ERROR

        JR      Z,L1A7B         ; forward, with unused record, to F-ERROR

        CALL    L13BF           ; routine CHK-MAP-2  checks RECORD.

        JR      NZ,L1A7B        ; forward, if already loaded, to F-ERROR

        PUSH    IX              ; transfer the channel base address
        POP     HL              ; to the HL register pair.

        LD      DE,$0052        ;
        ADD     HL,DE           ;
        CALL    L142B           ; routine CHKS-BUFF
        RET     Z               ;


;; F-ERROR
L1A7B:  CALL    L13F7           ; routine DEC-SECT
        JR      NZ,L1A64        ; back to UNTILFIVE

        RST     20H             ; Shadow Error Restart
        DEFB    $11             ; File not found


; -----------------------------------------
; THE 'RESTORE ADDRESS OF FILENAME' ROUTINE
; -----------------------------------------
;   This subroutine performs a similar function to the Main ROM POINTERS routine
;   by adjusting the extra system variables that point to filenames within
;   the sliding, dynamic areas.
;   On entry HL points to the start of the New Room and BC holds the number of
;   bytes created.

;; REST-N-AD
L1A82:  PUSH    HL              ; Preserve HL throughout.

        PUSH    HL              ; Preserve HL for second call.

        LD      DE,($5CE4)      ; Fetch D_STR2 - start of 2nd filename.
        CALL    L1A9D           ; routine TST-PLACE may adjust fetched value.
        LD      ($5CE4),DE      ; Store in System Variable  D_STR2

        POP     HL              ; Restore HL for second call.

        LD      DE,($5CDC)      ; Fetch D_STR1 - start of 1st filename.
        CALL    L1A9D           ; routine TST-PLACE
        LD      ($5CDC),DE      ; Store in System Variable D_STR1

        POP     HL              ; Restore original HL value.

        RET                     ; return.

; ---------------------------
; THE 'TEST PLACE' SUBROUTINE
; ---------------------------
;   This subroutine is used twice from above to test if the filename address
;   is within the Spectrum's dynamic RAM area.
;   HL = location before new room.
;   DE = address of filename.
;   BC = amount of room just created.

;; TST-PLACE
L1A9D:  SCF                     ; adjust for one before.
        SBC     HL,DE           ; subtract filename address from start of room
        RET     NC              ; and if before new room then return.

        LD      HL,($5C65)      ; fetch STKEND and if the filename is above
        SBC     HL,DE           ; then it is not in dynamic memory.
        RET     C               ;

        EX      DE,HL           ; add the number of bytes created
        ADD     HL,BC           ; to the filename address
        EX      DE,HL           ; to bring it into line.

        RET                     ; return.


; -----------------------------------
; THE 'CALLS TO THE COMMANDS' ROUTINE
; -----------------------------------
;

;; ERASE-RUN
L1AAB:  CALL    L1D79           ; routine ERASE
        JR      L1AC9           ; forward to ENDC

; ---

;; MOVE-RUN
L1AB0:  CALL    L17F5           ; routine MOVE
        JR      L1AC9           ; forward to ENDC

; ---

;; CAT-RUN
L1AB5:  CALL    L1C52           ; routine CAT
        JR      L1AC9           ; forward to ENDC

; ---

;; FOR-RUN
L1ABA:  CALL    L1B5D           ; routine FORMAT
        JR      L1AC9           ; forward to ENDC

; ---

;; OP-RUN
L1ABF:  CALL    L1ACC           ; routine OP-M-STRM
        JR      L1AC9           ; forward to ENDC

; ---

;; SAVE-RUN
L1AC4:  CALL    L18CB           ; routine SA-DRIVE
        JR      L1AC9           ; forward to ENDC

; ---

;; ENDC
L1AC9:  JP      L05C1           ; jump to END1

; ------------------------------------------
; THE 'OPEN A PERMANENT "M" CHANNEL' ROUTINE
; ------------------------------------------
;

;; OP-M-STRM
L1ACC:  LD      A,($5CD8)       ; sv D_STR1
        ADD     A,A             ;
        LD      HL,$5C16        ; sv STRMS_00
        LD      E,A             ;
        LD      D,$00           ;
        ADD     HL,DE           ;
        PUSH    HL              ;
        CALL    L1B05           ; routine OP-TEMP-M creates a temporary
                                ; microdrive channel, starts motor, and 
                                ; fetches record zero of named file.
        BIT     0,(IX+$18)      ; CHFLAG
        JR      Z,L1AE9         ; forward to MAKE-PERM

        IN      A,($EF)         ;
        AND     $01             ; isolate write prot.
        JR      NZ,L1AE9        ; forward to MAKE-PERM

        RST     20H             ; Shadow Error Restart
        DEFB    $0E             ; Drive 'write' protected

; ---

;; MAKE-PERM
L1AE9:  RES     7,(IX+$04)      ; channel letter
        XOR     A               ;
        CALL    L1532           ; routine SEL-DRIVE
        BIT     0,(IX+$18)      ; CHFLAG
        JR      NZ,L1AFF        ; forward to STORE-DSP

        BIT     2,(IX+$43)      ; RECFLG
        JR      Z,L1AFF         ; forward to STORE-DSP

        RST     20H             ; Shadow Error Restart
        DEFB    $16             ; Wrong file type

; ---

;; STORE-DSP
L1AFF:  EX      DE,HL           ;
        POP     HL              ;
        LD      (HL),E          ;
        INC     HL              ;
        LD      (HL),D          ;
        RET                     ;


; ------------------------------------------
; THE 'OPEN A TEMPORARY "M" CHANNEL' ROUTINE
; ------------------------------------------
; (Hook Code: $22)
;

;; OP-TEMP-M
L1B05:  CALL    L10A5           ; routine SET-T-MCH creates a temporary channel
                                ; using either an existing microdrive map from
                                ; a channel also using this drive or allocating
                                ; a new one initialized to $FF bytes.
                                ; fields CHREC etc. are set to zero.

        PUSH    HL              ; preserve the offset to this channel from CHANS

        LD      A,(IX+$19)      ; fetch drive number 1 - 8 from CHDRIV
        CALL    L1532           ; routine SEL-DRIVE starts motor and disables
                                ; interrupts.

        LD      BC,$0032        ; now set temporary unused 
        LD      ($5CC9),BC      ; system variable SECTOR_lo to fifty
                                ; and set SECTOR_hi to zero.

; now enter a loop 

;; OP-F-L
L1B16:  CALL    L1280           ; routine G-HD-RC fetches any header and 
                                ; matching record

        PUSH    AF              ; preserve return status flags.

; maintain the 'maximum sectors to visit' so only one rotation of tape occurs.

        LD      A,(IX+$29)      ; fetch sector from HDNUMB
        ADD     A,$03           ; add 3
        LD      HL,$5CC9        ; address current (max+3) in SECTOR_lo
        CP      (HL)            ; compare
        JR      C,L1B26         ; forward, if less, to OP-F-X

        LD      (HL),A          ; update with new max sectors to visit.

;; OP-F-X
L1B26:  POP     AF              ; restore status flags.

        JR      C,L1B49         ; forward, with no name match, to OP-F-4

        JR      Z,L1B46         ; forward, if unused, to OP-F-3
                                ; to reset map bit.

; the fetched record is one from the file named in CHNAME

        RES     0,(IX+$18)      ; update CHFLAG to indicate success.

        LD      A,(IX+$44)      ; fetch the record number within file RECNUM
        OR      A               ; test for zero - first record.
        JR      NZ,L1B41        ; forward, if not, to OP-F-2

        PUSH    IX              ; transfer the channel base address
        POP     HL              ; to the HL register pair.

        LD      DE,$0052        ; prepare offset to data and
        ADD     HL,DE           ; add to address start of the 512 byte buffer

        CALL    L142B           ; routine CHKS-BUFF checks that checksum agrees.
        JR      Z,L1B5B         ; forward, if OK, to DP-F-5

;; OP-F-2
L1B41:  CALL    L1258           ; routine GET-R-2 repeatedly calls the 
                                ; subroutine G-HD-RC (as at start of loop)
                                ; until the validated record matching CHREC 
                                ; (zero) is loaded.

        JR      L1B5B           ; forward, with success, to DP-F-5.

; ---

;; OP-F-3
L1B46:  CALL    L13E3           ; routine RES-B-MAP resets bit for unused 
                                ; sectors.

; the branch was here 

;; OP-F-4
L1B49:  LD      HL,$5CCA        ; address visited sector count SECTOR_hi

        LD      A,(HL)          ; fetch sector counter.
        INC     A               ; increment
        LD      (HL),A          ; and put back in SECTOR_hi.
        DEC     HL              ; address the max sector value.
        CP      (HL)            ; compare.
        JR      C,L1B16         ; back, if less than one revolution, to OP-F-L

; else a full revolution occurred without finding the record.

        RES     1,(IX+$43)      ; RECFLG
        RES     2,(IX+$43)      ; RECFLG

; the branch was here with record zero of named file.

;; DP-F-5
L1B5B:  POP     HL              ; restore the offset from CHANS.

        RET                     ; return.

; --------------------------------
; THE 'FORMAT "M" COMMAND' ROUTINE
; --------------------------------
; e.g. FORMAT "m";1;"demos"


;; FORMAT
L1B5D:  CALL    L10A5           ; routine SET-T-MCH creates a temporary 
                                ; microdrive channel with name of cartridge.

        LD      A,(IX+$19)      ; fetch drive number from CHDRIV
        CALL    L1565           ; routine SW-MOTOR starts the motor.

        LD      BC,$32C8        ; decimal 1300
        CALL    L1652           ; routine DELAY-BC

        DI                      ; Disable Interrupts.

        IN      A,($EF)         ; read microdrive port.
        AND     $01             ; isolate write prot. bit.
        JR      NZ,L1B75        ; forward, if not low, to FORMAT-1

        RST     20H             ; Shadow Error Restart
        DEFB    $0E             ; Drive 'write' protected

; ---

;; FORMAT-1
L1B75:  LD      A,$E6           ; enable writing.
        OUT     ($EF),A         ; update microdrive port.

        LD      BC,$00FF        ; assume 255 sectors will fit on a tape.
        LD      ($5CC9),BC      ; set system variable SECTOR.

        PUSH    IX              ; transfer the channel base address
        POP     HL              ; to the HL register pair.

        LD      DE,$002C        ; offset to HDNAME
        ADD     HL,DE           ;
        EX      DE,HL           ; make destination HDNAME
        LD      HL,$FFE2        ;
        ADD     HL,DE           ; make source CHNAME

        LD      BC,$000A        ; ten bytes to copy.
        LDIR                    ; copy - C is now zero.

; now prepare an 'unusable' record.

        XOR     A               ; make accumulator zero.

        LD      (IX+$47),A      ; set first character of RECNAM to zero.
        SET     0,(IX+$28)      ; mark HDFLAG indicate a header.
        RES     0,(IX+$43)      ; mark RECFLG indicate a record.
        SET     1,(IX+$43)      ; mark RECFLG indicate an EOF record.

        PUSH    IX              ; transfer the channel base address
        POP     DE              ; to the DE register pair for a change.

        LD      HL,$0043        ; offset to RECFLG - start of record descriptor.
        ADD     HL,DE           ; add offset to start of record descriptor.

        CALL    L1426           ; routine CHKS-HD-R inserts 14 byte checksum.

;   Now enter a loop to write the blocks to the cartridge

;; WR-F-TEST
L1BAB:  CALL    L13F7           ; routine DEC-SECT decrements sector originally
                                ; set to $FF
        JR      Z,L1BDF         ; forward, if BC is zero, to TEST-SCT  ->

        LD      (IX+$29),C      ; insert reduced sector number in HDNUMB

        PUSH    IX              ; transfer the base channel address
        POP     HL              ; to the HL register pair.

        LD      DE,L0028        ; offset to the header
        ADD     HL,DE           ; add to address HDFLAG.

        CALL    L1426           ; routine CHKS-HD-R inserts 14 byte checksum
                                ; preserving the HL value.

        LD      DE,$FFF4        ; subtract twelve 
        ADD     HL,DE           ; to address the header PREAMBLE.

        CALL    L15AD           ; routine OUT-M-HD writes the header to tape.

        LD      BC,$01B2        ; set timer for gap - 434 decimal.
        CALL    L1652           ; routine DELAY-BC

        PUSH    IX              ; transfer start of channel
        POP     HL              ; to HL register pair.

        LD      DE,$0037        ; adjust HL to point to PREAMBLE at
        ADD     HL,DE           ; start of record descriptor.
        CALL    L16AF           ; routine WR-BLK writes record to tape.

        LD      BC,$0100        ; a short delay.
        CALL    L1652           ; routine DELAY-BC

        CALL    L163E           ; routine TEST-BRK

        JR      L1BAB           ; loop back to WR-F-TEST for sectors 254 - 1.

; ---

; -> the branch was to here when all sectors from 254 down to 1 have been 
;    written.

;; TEST-SCT
L1BDF:  LD      BC,$0087        ; use value 35 decimal.
        CALL    L1652           ; routine DELAY-BC

        LD      A,$EE           ; signal disable writing.
        OUT     ($EF),A         ; output to microdrive port.

        LD      A,(IX+$19)      ; select drive number from CHDRIV.
        CALL    L1532           ; routine SEL-DRIVE.

        LD      BC,$0032        ; set max sector to fifty, read sectors to zero.
        LD      ($5CC9),BC      ; insert both values in SECTOR

;; CHK-SCT
L1BF6:  CALL    L13A9           ; routine GET-M-HD2 reads the next valid header
                                ; to pass the tape head.
        LD      A,(IX+$29)      ; fetch the unique sector number from HDNUMB
        ADD     A,$03           ; add three to value.
        LD      HL,$5CC9        ; address system variable SECTOR
        CP      (HL)            ; and compare to total of sectors to visit.
        JR      C,L1C05         ; forward if less to CHK-SCT2

        LD      (HL),A          ; else insert new value for sectors to visit.

;; CHK-SCT2
L1C05:  CALL    L13C4           ; routine CHECK-MAP checks if sector is free 
                                ; on the microdrive map.
        JR      Z,L1C1E         ; forward, if so, to CHK-NSECT

        PUSH    IX              ; transfer channel base address
        POP     HL              ; to the HL register pair.

        LD      DE,$0043        ; offset to the start of record descriptor.
        ADD     HL,DE           ; add to address RECFLG.

        CALL    L165A           ; routine READ-BLK reads in a block.

        JR      NZ,L1C1E        ; forward, with bad read, to CHK-NSECT
                                ; leaving map bit set.

        CALL    L1426           ; routine CHKS-HD-R check the header checksum
        JR      NZ,L1C1E        ; forward, with error, to CHK-NSECT

        CALL    L13E3           ; routine RES-B-MAP resets the map bit marking
                                ; the sector as usable.

;; CHK-NSECT
L1C1E:  LD      HL,$5CCA        ; address SECTOR_hi the visited sector counter.
        LD      A,(HL)          ; fetch the value.
        INC     A               ; increment
        LD      (HL),A          ; and place back.

        DEC     HL              ; decrement to address max sectors to visit.
        CP      (HL)            ; compare counter to limit.
        JR      C,L1BF6         ; back, if counter is less, to CHK-SCT

        LD      L,(IX+$1A)      ; load L from CHMAP_lo
        LD      H,(IX+$1B)      ; load H from CHMAP_hi

;   Register HL now addresses the microdrive maps which at this stage have
;   sectors 0 and 255 marked as unusable. If as is usual, the lower numbered
;   sectors have overwritten the higher numbered sectors then typically 
;   the top seventy sectors, or so, will be marked as unusable though not on an 
;   emulated machine which at this stage will only have 0 and 255 marked 
;   unusable. On a real machine the splice will show up as an unusable sector
;   and there may be some other sectors unusable due to dirt on the recording 
;   film.
;   What happens next is unique to this ROM and is no doubt due to extensive 
;   testing and analysis of the microdrives by Sinclair Research.
;   Microdrive sectors are encountered in descending order, as they are 
;   written, and the following routine marks any sector following a bad sector 
;   as bad also.  One can conclude that Sinclair Research's test programme 
;   revealed that the first sectors to fail were those adjacent to contaminated
;   or damaged sectors.  
;   This perhaps explains why my use of the microdrives with ROM 2 has been 
;   more reliable than early reviews, no doubt with ROM 1, suggested.

        LD      DE,$001F        ; add thirty one to start at the end of the map
        ADD     HL,DE           ; - the byte that refers to sector 255.
        LD      B,$20           ; count the thirty two bytes of a map.

        SCF                     ; set carry flag to ensure that sector 255 
                                ; is unusable - but it is already marked so ??

;; PREP-MARK
L1C35:  LD      A,(HL)          ; fetch a byte representing eight sectors.

        LD      C,A             ; and store it in C - Note. unnecessary.

        RRA                     ; rotate right accumulator  C->76543210->C

        OR      C               ; combine with original value. Why not OR (HL) ?

        LD      (HL),A          ; store the modified byte back in the map.

        DEC     HL              ; point to the next byte for lower-numbered 
                                ; sectors.

L1C3B:  DJNZ    L1C35           ; loop back to PREP-MARK for all 32 map bytes.

;   Note. the above routine is untidy.  There is no need to set the carry flag 
;   and no need to store the original value in C.  While it achieves it's aims,
;   if sector one is bad it has no effect on the next sector to be encountered.
;   That would be hard to implement but the first sector that is marked bad,
;   the highest numbered sector, is marked so solely because it is adjacent to 
;   the overwritten section.

;   Note. from details of addresses Andrew Pennell gave in the magazine "Your 
;   Sinclair" it can be deduced that the unpublished ROM 3 had two extra 
;   instruction bytes at this point and together with a cleanup, this may have 
;   addressed the above issue.

;   Now prepare to overwrite the unusable sectors (which are mapped as usable)
;   with record descriptors which are usable.

        CALL    L1E49           ; routine IN-CHK marks the channel record 
                                ; descriptor fields as usable by blanking
                                ; both RECFLG and RECLEN and then inserting
                                ; the descriptor checksum.

;   A loop is now entered to write usable datablocks to every sector indicated
;   as usable in the microdrive map.

;; MARK-FREE
L1C40:  CALL    L1349           ; routine CHK-FULL checks if there is still a
                                ; usable sector on the cartridge.
        JR      NZ,L1C4D        ; forward, if so, to MK-BLK.

;   The FORMAT operation is now complete.

        XOR     A               ; select no motor
        CALL    L1532           ; routine SEL-DRIVE stops the microdrive motor.

        CALL    L119F           ; routine DEL-M-BUF deletes the microdrive 
                                ; buffer and the microdrive map.

        RET                     ; return.                          >>>>>>>

; ---

;; MK-BLK
L1C4D:  CALL    L135A           ; routine SEND-BLK writes block to microdrive
                                ; cartridge as indicated by the microdrive map 
                                ; which is then updated by the routine.

        JR      L1C40           ; loop back to MARK-FREE


; -------------------------
; THE 'CAT COMMAND' ROUTINE
; -------------------------
;

;; CAT
L1C52:  LD      A,($5CD8)       ; fetch output stream from S_STR1

        RST     10H             ; CALBAS
        DEFW    $1601           ; main CHAN-OPEN

        CALL    L10A5           ; routine SET-T-MCH sets a temporary channel.

        LD      A,(IX+$19)      ; fetch drive number from CHDRIV.
        CALL    L1532           ; routine SEL-DRIVE starts the motor.

        LD      BC,$0032        ; set maximum sector to 50 and initialize
                                ; value of sectors read to zero.
        LD      ($5CC9),BC      ; update system variable SECTOR

;   On the original Interface 1 ROM operations like CAT and ERASE were quite 
;   slow as the routines assumed the theoretical maximum number of sectors was 
;   256.  In reality, the maximum number of sectors on a microdrive is 
;   approximately 180, so the original routines spent the last 3 seconds 
;   reading about 75 sectors for the second time.  The improved algorithm above
;   is to keep a record of the maximum sector + 3 and when the number of 
;   visited sectors is equal to this number then a complete revolution of the 
;   tape has been made and the operation can cease. The overhead of three is 
;   to ensure that bad sectors or the tape splice do not cause the operation to
;   end prematurely.
;   Happily, this algorithm also works with emulators which usually provide the
;   full 256 sectors.

;; CAT-LP
L1C68:  CALL    L13A9           ; routine GET-M-HD2 reads in 14 byte header.

        LD      A,(IX+$29)      ; fetch value of sector from HDNUMB

        ADD     A,$03           ; add 3 to value.

        LD      HL,$5CC9        ; address system variable SECTOR_lo
        CP      (HL)            ; compare to contents
        JR      C,L1C77         ; forward if A is less to CAT-LP-E

        LD      (HL),A          ; else update SECTOR_lo with higher value.

;; CAT-LP-E
L1C77:  CALL    L1E5E           ; routine G-RDES loads only a
                                ; 14 byte record descriptor.
        JR      NZ,L1C68        ; back, with error or mismatch, to CAT-LP

; a record can be considered in use if either the RECLEN is maximum $0200 or
; the RECFLG indicates that it is the seldom full EOF record.

        LD      A,(IX+$43)      ; RECFLG
        OR      (IX+$46)        ; RECLEN_hi
        AND     $02             ;
        JR      NZ,L1C8B        ; forward, if used, to IN-NAME

; else mark sector free in microdrive map and find next sector.

        CALL    L13E3           ; routine RES-B-MAP
        JR      L1CF4           ; forward to F-N-SCT

; a name is to be inserted in the 512 byte data buffer workspace, if it is not
; there already. Secret files are not listed.

;; IN-NAME
L1C8B:  LD      A,(IX+$47)      ; take first character of RECNAM
        OR      A               ; test for zero.
        JR      Z,L1CF4         ; forward, if CHR$ 0, to F-N-SCT

        PUSH    IX              ; transfer base address
        POP     HL              ; to HL register.

        LD      DE,$0052        ; offset to start of data buffer.
        ADD     HL,DE           ; add to address names.
        LD      DE,$000A        ; set DE to ten, the length of a name.
        LD      B,$00           ; set high byte to zero.
        LD      C,(IX+$0D)      ; fetch name total from CHREC initially zero.

;; SE-NAME
L1CA0:  LD      A,C             ; test name count for zero
        OR      A               ;
        JR      Z,L1CDA         ; forward, with first name, to INS-NAME

        PUSH    HL              ; save buffer address.
        PUSH    IX              ; save channel base address.
        PUSH    BC              ; save name total.

        LD      B,$0A           ; set character counter to ten.

;; T-NA-1
L1CAA:  LD      A,(HL)          ; take letter of buffered name.
        CP      (IX+$47)        ; compare to that in RECNAM
        JR      NZ,L1CB5        ; forward, with mismatch, to T-NA-2

        INC     HL              ; increment 
        INC     IX              ; both pointers.
        DJNZ    L1CAA           ; back, for all ten, to T-NA-1


;; T-NA-2
L1CB5:  POP     BC              ; restore
        POP     IX              ; all
        POP     HL              ; pointers.

; if all ten characters match then find next sector.

        JR      Z,L1CF4         ; forward to F-N-SCT

; if buffered name is higher than new name then re-order to create a slot.

        JR      NC,L1CC1        ; forward to ORD-NAM

; else add ten to buffer address and compare with following name performing
; a simple insert if the end of the list is reached.

        ADD     HL,DE           ; add ten to address.
        DEC     C               ; decrement name counter.
        JR      L1CA0           ; back to SE-NAME

; ---


;; ORD-NAM
L1CC1:  PUSH    HL              ; save pointer to start of name slot.
        PUSH    DE              ; save the value ten.
        PUSH    BC              ; save the buffered name counter.

        PUSH    HL              ; save address of name slot again.
        SLA     C               ; double name count.
        LD      H,B             ; set H to zero.
        LD      L,C             ; HL = 2 * count
        ADD     HL,BC           ; HL = 4 * count
        ADD     HL,BC           ; HL = 6 * count        Note. add hl,hl doubles.
        ADD     HL,BC           ; HL = 8 * count        c.f. Main ROM
        ADD     HL,BC           ; HL = 10 * count

        LD      B,H             ; transfer number of bytes
        LD      C,L             ; to be moved to BC register.

        POP     HL              ; restore address of insertion point.
        DEC     HL              ; decrement and then add
        ADD     HL,BC           ; bytes to be moved to point to end of block.

        EX      DE,HL           ; now make DE
        ADD     HL,DE           ; the destination
        EX      DE,HL           ; ten bytes higher.

        LDDR                    ; slide the block of higher names upwards.

        POP     BC              ; restore name count.
        POP     DE              ; restore ten value.
        POP     HL              ; restore insertion point.

;; INS-NAME
L1CDA:  PUSH    IX              ; save channel base address.
        LD      B,$0A           ; set character count to ten.

;; MOVE-NA
L1CDE:  LD      A,(IX+$47)      ; fetch a character from new name at RECNAM
        LD      (HL),A          ; insert into buffer.
        INC     IX              ; increment both
        INC     HL              ; pointers.
        DJNZ    L1CDE           ; loop back to MOVE-NA

        POP     IX              ; restore channel base address.

        LD      A,(IX+$0D)      ; fetch count of names from CHREC
        INC     A               ; increment
        LD      (IX+$0D),A      ; and store back in CHREC

        CP      $32             ; compare to maximum of 50.
        JR      Z,L1CFF         ; forward, if buffer filled, to BF-FILLED


;; F-N-SCT
L1CF4:  LD      HL,$5CCA        ; sv SECTOR_hi
        LD      A,(HL)          ; fetch actual count of used sectors.
        INC     A               ; and increment.
        LD      (HL),A          ; update SECTOR_hi
        DEC     HL              ; address system variable SECTOR_lo
        CP      (HL)            ; compare 
        JP      C,L1C68         ; jump to CAT-LP

;; BF-FILLED
L1CFF:  PUSH    IX              ;

        XOR     A               ; clear accumulator
        CALL    L1532           ; routine SEL-DRIVE stops the motor.

        PUSH    IX              ; transfer the channel base address
        POP     HL              ; to the HL register pair.

        LD      DE,$002C        ; offset to cartridge name HDNAME.
        ADD     HL,DE           ; add the offset to address the name.

        CALL    L1D5B           ; routine PRNAME prints name and a carriage 
                                ; return.

        LD      A,$0D           ; prepare an extra carriage return.
        CALL    L1D71           ; routine PRCHAR outputs it.

        PUSH    IX              ;
        POP     HL              ;

        LD      DE,$0052        ; offset to CHDATA - the 512 byte data buffer.
        ADD     HL,DE           ; add to address list of up to fifty names.

        LD      B,(IX+$0D)      ; load B with count of names from CHREC
        LD      A,B             ; test for
        OR      A               ; zero.
        JR      Z,L1D27         ; forward, if so, to NONAMES


;; OT-NAMS
L1D22:  CALL    L1D5B           ; routine PRNAME
        DJNZ    L1D22           ; loop back to OT-NAMS


;; NONAMES
L1D27:  CALL    L1D43           ; routine FREESECT

        LD      A,E             ;
        SRL     A               ;

        RST     10H             ; CALBAS
        DEFW    $2D28           ; main STACK-A

        LD      A,$0D           ;
        CALL    L1D71           ; routine PRCHAR

        RST     10H             ; CALBAS
        DEFW    $2DE3           ; main PRINT-FP

        LD      A,$0D           ;
        CALL    L1D71           ; routine PRCHAR

        POP     IX              ;

        CALL    L119F           ; routine DEL-M-BUF

        RET                     ; return.


; ----------------------
; THE 'FREESECT' ROUTINE
; ----------------------
;   This routine is called from SAVE and CAT to calculate the number of free 
;   sectors that are present on a microdrive from the map information.
;   The count of free sectors is returned in the E register.

;; FREESECT
L1D43:  LD      L,(IX+$1A)      ; address of microdrive map.
        LD      H,(IX+$1B)      ; for channel transferred to HL.

        LD      E,$00           ; initialize sector count to zero.
        LD      C,$20           ; there are thirty two bytes to examine.

;; FR-SC-LP
L1D4D:  LD      A,(HL)          ; fetch a byte from the map.
        INC     HL              ; address next map location.

        LD      B,$08           ; count eight bits.

;; FR-S-LPB
L1D51:  RRA                     ; rotate right.
        JR      C,L1D55         ; forward, with carry, to FR-S-RES.

        INC     E               ; increment the free sector count.

;; FR-S-RES
L1D55:  DJNZ    L1D51           ; loop back for all eight bits to FR-S-LPB.

        DEC     C               ; decrement byte count.
        JR      NZ,L1D4D        ; loop back for thirty two bytes to FR-SC-LP.

        RET                     ; return.

; --------------------
; THE 'PRNAME' ROUTINE
; --------------------
;   This routine outputs a ten character name, followed by a carriage return,
;   and is used by the CAT command to first print the cartridge name and then 
;   the filenames on the cartridge.  
;   Note. For a routine that can output to any stream, it seems straightforward
;   until one notices the call to TEMPS at the end.  This applies the permanent 
;   colour screen attributes to the temporary set and has been placed within 
;   the routine as a security measure to ensure that if the cartridge name 
;   or filename contains a string of colour control codes that render filenames
;   invisible then their effect does not last beyond the current name.
;
;   On the other hand, colour control codes can be used in the cartridge name
;   without affecting the cartridge contents display.

;; PRNAME
L1D5B:  PUSH    BC              ; preserve name count.

        LD      B,$0A           ; ten characters per name.

;; PRNM-LP
L1D5E:  LD      A,(HL)          ; fetch a character.

        CALL    L1D71           ; routine PRCHAR

        INC     HL              ; point to next character.
        DJNZ    L1D5E           ; loop back for all ten to PRNM-LP

        LD      A,$0D           ; prepare a carriage return.
        CALL    L1D71           ; routine PRCHAR

        PUSH    HL              ; preserve character address.

        RST     10H             ; CALBAS
        DEFW    $0D4D           ; main TEMPS restores temporary colours from
                                ; the permanent colours after each name.

        POP     HL              ; restore character address.
        POP     BC              ; restore name count.

        RET                     ; return.


; --------------------
; THE 'PRCHAR' ROUTINE
; --------------------
;   The PRINT CHARACTER routine utilizes the output restart in the main ROM
;   which outputs to any stream and so a stream such as the "T" channel
;   could be sent output. The IX register has therefore to be preserved.

;; PRCHAR
L1D71:  PUSH    IX              ; preserve this ad hoc channel address.

        RST     10H             ; CALBAS
        DEFW    $0010           ; main PRINT-A

        POP     IX              ; restore this channel address.

        RET                     ; return.


; ---------------------------
; THE 'ERASE COMMAND' ROUTINE
; ---------------------------
; (Hook Code: $24)
;   The ERASE command is in two stages and uses the first 32 bytes of the 
;   otherwise unused data buffer to map out the sectors to be marked clear.
;   The first stage performs this mapping and in one revolution of the tape
;   it should find all sectors that have the specified name.  It should also
;   find the EOF record, which all files have, and which contains in the 
;   RECNUM field the maximum record number. For example with four records the
;   numbers will be 0, 1, 2, 3.                
;   Once the number of marked records equals the max record plus one then the
;   second stage can begin which is to mark free all the records.
;
;   There are two circumstances under which the procedure might not be so 
;   straightforward.
;   The first is if the user has pressed BREAK during a previous ERASE 
;   operation after a few records were marked free.
;   The second is if the file has been saved with the System Variable COPIES
;   holding a value larger than 1. For example with a value of 5, there will
;   be five EOF records and five records with RECNUM equal to zero etc.
; 
;   For the first case the command will make five revolutions of the tape
;   before marking all found sectors free.
;   This may happen in the second case also if more multi records were found
;   before the first EOF record was encountered.
;   It is more likely that the ERASE command will have to be invoked several 
;   times to erase the file.  It is simpler to issue the command within a 
;   loop.  Multiple copy files are usually saved as part of a well-considered
;   scheme and are seldom subsequently erased.

;; ERASE
L1D79:  CALL    L10A5           ; routine SET-T-MCH creates a temporary channel
                                ; using either an existing microdrive map from
                                ; a channel also using this drive or allocating
                                ; a new one initialized to $FF bytes.

        LD      A,(IX+$19)      ; fetch drive number from CHDRIV.
        CALL    L1532           ; routine SEL-DRIVE starts motor.

        IN      A,($EF)         ; read microdrive port.
        AND     $01             ; isolate 'write prot.' bit.
        JR      NZ,L1D8A        ; forward, if not zero, to ERASE-1

        RST     20H             ; Shadow Error Restart
        DEFB    $0E             ; Drive 'write' protected


;; ERASE-1
L1D8A:  PUSH    IX              ; transfer address of start of channel.
        POP     HL              ; to the HL register.

        LD      DE,$0052        ; prepare offset to data buffer.
        ADD     HL,DE           ; add to address start.

;   A pseudo microdrive map will also be created within the buffer conserving 
;   memory.  This is initialized to $00 bytes.

        PUSH    HL              ; transfer buffer address
        POP     DE              ; from HL to DE register
        INC     DE              ; and increment address.

        LD      BC,$001F        ; set counter to 31 and B to zero.
        XOR     A               ; set A to zero.
        LD      (HL),A          ; insert zero in first location.
        LDIR                    ; copy to other 31 addresses

        LD      A,$FF           ; prepare, as a default, to examine every sector.
        LD      (IX+$0D),A      ; update CHREC with max record number.

        LD      BC,$04FB        ; prepare decimal 1275 (5+ revolutions)
        LD      ($5CC9),BC      ; update system variable SECTOR

;   Note. if the EOF record is not found, or if the number of found sectors
;   doesn't equal the maximum record then 5+ revolutions of the tape will
;   occur after which all mapped sectors will be erased. Normally with a 
;   simple file it's all over in less than two revolutions.

;; ERASE-LP
L1DA7:  CALL    L13F7           ; routine DEC-SECT decrements the 1275 counter.
        JR      Z,L1E03         ; forward, if zero, to ERASE-MK

        CALL    L13A9           ; routine GET-M-HD2 reads the next 14-byte 
                                ; header to pass the tape heads.

        CALL    L1E5E           ; routine G-RDES reads the corresponding 
                                ; 14-byte record descriptor for this sector.

        JR      NZ,L1DE5        ; forward, with read error, to TST-NUM

;   now check if sector is in use.  Considered it so if next position is 
;   at $0200 or if it is the EOF record.

        LD      A,(IX+$43)      ; RECFLG
        OR      (IX+$46)        ; RECLEN_hi
        AND     $02
        JR      NZ,L1DC3        ; forward, if in use, to ERASE-2 
                                ; to consider for erasure.

; the sector is not used so reset the REAL microdrive map bit.

        CALL    L13E3           ; routine RES-B-MAP resets sector bit on 
                                ; the REAL microdrive map.

        JR      L1DE5           ; forward to TST-NUM

; ---

;   consider for erasure if filename matches.

;; ERASE-2
L1DC3:  PUSH    IX              ; transfer channel base address
        POP     HL              ; to the HL register.

        LD      DE,$0047        ; offset to 10 characters of filename.
        ADD     HL,DE           ; add so HL addresses the start of RECNAM.
        LD      BC,$000A        ; ten bytes to compare against required CHNAME.

        CALL    L1403           ; routine CHK-NAME

        JR      NZ,L1DE5        ; forward, with no match, to TST-NUM

; the name matches so sector is marked free.

        CALL    L13EB           ; routine TEST-PMAP obtains address of sector 
                                ; bit in HL and bit mask in B.

        LD      A,B             ; transfer mask to B
        OR      (HL)            ; combine with addressed byte
        LD      (HL),A          ; and update setting the sector bit.

        BIT     1,(IX+$43)      ; test RECFLG is this an EOF record.
        JR      Z,L1DE5         ; forward, if not, to TST-NUM

; All files should have an EOF record and, if this is it, then the endpoint 
; can be reduced from $FF to record number plus one as range starts at 1.

        LD      A,(IX+$44)      ; fetch record number from RECNUM
        INC     A               ; increment as CHREC value starts at one not 
                                ; zero.
        LD      (IX+$0D),A      ; update the endpoint CHREC

;; TST-NUM
L1DE5:  PUSH    IX              ; transfer the channel base address
        POP     HL              ; to the HL register.

        LD      DE,$0052        ; add offset to data
        ADD     HL,DE           ; to address the pseudomap.

        LD      E,$00           ; initialize E to zero.
        LD      C,$20           ; and C counter to thirty two.

;; LP-P-MAP
L1DF0:  LD      A,(HL)          ; fetch a byte from pseudomap
        INC     HL              ; and increment the address.

        LD      B,$08           ; set bit counter to eight.

;; LP-B-MAP
L1DF4:  RRA                     ; rotate end bit to carry.
        JR      NC,L1DF8        ; forward, with no carry, to NOINC-C

        INC     E               ; increment recno

;; NOINC-C
L1DF8:  DJNZ    L1DF4           ; back to LP-B-MAP for all eight bits.

        DEC     C               ; decrement byte counter.
        JR      NZ,L1DF0        ; back to LP-P-MAP for all 32 bytes.

; now E holds the number of records marked for erasure in range 1 to NR.

        LD      A,(IX+$0D)      ; fetch records to be erased from CHREC
        CP      E               ; compare to records marked for erasure.
        JR      NZ,L1DA7        ; back, if not exact match, to ERASE-LP

;   Now the second stage begins. Since the pseudomap has a representation of
;   all the records to be erased we can load the headers one by one, and 
;   rewrite the corresponding records with a clear one in the channel.
;   The same record is written after all the appropriate headers. Fields
;   like RECNUM only have relevance when the record is in use.
; 
;   First prepare a clear record descriptor.  The actual data buffer does not 
;   have to be clear and in fact contains the pseudomap. Note also that the
;   checksum for the data need not be calculated but the checksum for the 
;   record descriptor is required to be accurate.

;; ERASE-MK
L1E03:  CALL    L1E49           ; routine IN-CHK marks the channel record 
                                ; descriptor fields as usable by blanking
                                ; both RECFLG and RECLEN and then inserting
                                ; the descriptor checksum.

; now enter a loop for all marked records.

;; ERASE-MK2
L1E06:  CALL    L13A9           ; routine GET-M-HD2 reads the next header 
                                ; to pass the tape heads.
        CALL    L13EB           ; routine TEST-PMAP checks if the sector,
                                ; (in HDNUMB) is marked to be erased in the
                                ; pseudomap.
        JR      Z,L1E31         ; forward, if not, to T-OTHER

; this record is marked for erasure.

        PUSH    HL              ; save pseudomap sector bit address.
        PUSH    BC              ; save pseudomap bit mask which has one set bit.

        LD      A,$E6           ; enable writing.
        OUT     ($EF),A         ; output to microdrive port.

        LD      BC,$0168        ; set counter to 360 decimal.
        CALL    L1652           ; routine DELAY-BC pauses briefly as the 
                                ; record now approaches the tape heads.

        PUSH    IX              ; transfer channel base address
        POP     HL              ; to the HL register pair.

        LD      DE,$0037        ; offset to record PREAMBLE.
        ADD     HL,DE           ; add to form start of save address.

        CALL    L15B3           ; routine OUT-M-BUF rewrites descriptor and
                                ; data buffer. The descriptor is checksummed,
                                ; the data is not.

        LD      A,$EE           ; disable writing
        OUT     ($EF),A         ; output to microdrive port

; now update bit the real microdrive map and the pseudomap.

        CALL    L13E3           ; routine RES-B-MAP resets appropriate bit
                                ; for the now free sector in the REAL 
                                ; microdrive map.

        POP     BC              ; restore the pseudomap bit mask.
        POP     HL              ; restore the pseudomap sector bit address.

        LD      A,B             ; transfer bitmask to B.
        CPL                     ; the set bit is now reset and the other seven 
                                ; bits are set.
        AND     (HL)            ; reset the bit in the pseudomap
        LD      (HL),A          ; and update.

; now check if there are any more sectors to do.

;; T-OTHER
L1E31:  PUSH    IX              ; transfer channel base address 
        POP     HL              ; to the HL register.

        LD      DE,$0052        ; prepare offset to the pseudomap
        ADD     HL,DE           ; and add to address start of map.

        LD      B,$20           ; set byte count to thirty two.

;; CHK-W-MAP
L1E3A:  LD      A,(HL)          ; fetch a byte representing eight sectors.
        OR      A               ; test for zero.
        JR      NZ,L1E06        ; back, if a byte is not zero, to ERASE-MK2

        INC     HL              ; increment the map address
        DJNZ    L1E3A           ; loop back to CHK-W-MAP for all 32 bytes.

; at this point all records have been erased and it only remains to clear up.

        XOR     A               ; select no motor
        CALL    L1532           ; routine SEL-DRIVE stops the motor.

        CALL    L119F           ; routine DEL-M-BUF deletes the adhoc buffer.

        RET                     ; return.


; -----------------------------------
; THE 'PREPARE 'FREE SECTOR'' ROUTINE
; -----------------------------------
;   The two indicators within the current channel are marked clear and the 
;   RECORD DESCRIPTOR is checksumed in preparation for writing to each sector
;   to be marked free.

;; IN-CHK
L1E49:  XOR     A               ; clear accumulator A.
        LD      (IX+$43),A      ; blank RECFLG.
        LD      (IX+$45),A      ; blank RECLEN_lo.
        LD      (IX+$46),A      ; blank RECLEN_hi.

        PUSH    IX              ; transfer the start of channel
        POP     HL              ; to the HL register pair.

        LD      DE,$0043        ; prepare the offset to RECFLG.
        ADD     HL,DE           ; add to form start of record descriptor.

        CALL    L1426           ; routine CHKS-HD-R inserts 14-byte checksum.

        RET                     ; return.

; --------------------------------------
; THE 'OBTAIN RECORD DESCRIPTOR' ROUTINE
; --------------------------------------
; This routine is used by CAT, ERASE and the GET-DESC Hook Code $33.
; It loads and verifies the 14 byte record descriptor from RECFLG to RECNAM.
; This is normally loaded with the following data block
; or with the header block.
; The Zero Flag is set upon successful completion.

;; G-RDES
L1E5E:  PUSH    IX              ; transfer channel address
        POP     HL              ; to HL register.

        LD      DE,$0043        ; offset to RECFLG
        ADD     HL,DE           ; add to form first receiving location.
        CALL    L15E2           ; routine GET-M-HD reads in 15 bytes.
        CALL    L1426           ; routine CHKS-HD-R checksums the first 14 bytes
        RET     NZ              ; return with checksum error.

        BIT     0,(IX+$43)      ; test bit 0 of RECFLAG - should be zero
        RET                     ; return.

; -----------------------
; THE 'HOOK-CODE' ROUTINE
; -----------------------
; This accesses the twenty six hook codes now reduced to the range $00 - $19.

;; HOOK-CODE
L1E71:  CP      $1A             ; compare to upper limit.
        JR      C,L1E77         ; forward, if valid, to CLR-ERR.

        RST     20H             ; Shadow Error Restart.
        DEFB    $12             ; Hook code error.

; ---

;; CLR-ERR
L1E77:  LD      (IY+$00),$FF    ; set ERR_NR to one less than zero - no error.

        SET     2,(IY+$01)      ; update FLAGS signal 'L' mode.

        INC     HL              ; step past the hook code location in RAM.
        EX      (SP),HL         ; make this the return address.
        PUSH    HL              ; push back what was at stack pointer - the
                                ; preserved value of AF on entry.

        ADD     A,A             ; double the code.
        LD      D,$00           ; set D to zero for indexing.
        LD      E,A             ; transfer the code to E.

        LD      HL,L1E99        ; address: HOOK-TAB the base of the Hook Codes.
        ADD     HL,DE           ; index into this table.

        LD      E,(HL)          ; low byte to E.
        INC     HL              ; increment pointer.
        LD      D,(HL)          ; high byte to D.

        POP     AF              ; restore AF from machine stack.

        LD      HL,L0700        ; push the address UNPAGE
        PUSH    HL              ; on the machine stack.

        EX      DE,HL           ; transfer address to HL.
        JP      (HL)            ; jump to Hook Code routine.


; ---------------------------
; THE 'HOOK CODE +32' ROUTINE
; ---------------------------
; (Hook Code: $32)
;   This allows the user to call any address in the shadow ROM.

;; HOOK-32
L1E94:  LD      HL,($5CED)      ; sv HD_11
        JP      (HL)            ; jump to routine.


; ---------------------------
; THE 'HOOK CODE +31' ROUTINE
; ---------------------------
; (Hook Code: $31)
; This Hook Code ensures that the extra System Variables are created. Since
; this has already occurred, as is the case with all Hook Codes, then all that
; remains to do is to return to the address on the stack - the UNPAGE location.

;; HOOK-31
L1E98:  RET                     ; return.


; -------------------------------
; THE 'HOOK CODE ADDRESSES' TABLE
; -------------------------------
;   The addresses of the Hook Codes.  The last two are new to this ROM.

;; HOOK-TAB
L1E99:  DEFW    L1ECD           ; $1B - CONS-IN
        DEFW    L1EE0           ; $1C - CONS-OUT
        DEFW    L0B88           ; $1D - BCHAN-IN
        DEFW    L0D07           ; $1E - BCHAN-OUT
        DEFW    L1EF0           ; $1F - PRT-OUT
        DEFW    L1EF5           ; $20 - KBD-TEST
        DEFW    L1532           ; $21 - SEL-DRIVE
        DEFW    L1B05           ; $22 - OP-TEMP-M
        DEFW    L138E           ; $23 - CLOSE-M2
        DEFW    L1D79           ; $24 - ERASE
        DEFW    L1EFD           ; $25 - READ-SEQ
        DEFW    L12DA           ; $26 - WR-RECD
        DEFW    L1F0B           ; $27 - RD-RANDOM
        DEFW    L1F3F           ; $28 - RD-SECTOR
        DEFW    L1F7A           ; $29 - RD-NEXT
        DEFW    L1F85           ; $2A - WR-SECTOR
        DEFW    L10A5           ; $2B - SET-T-MCH
        DEFW    L119F           ; $2C - DEL-M-BUF
        DEFW    L0F46           ; $2D - OP-TEMP-N
        DEFW    L1F18           ; $2E - CLOSE-NET
        DEFW    L1F25           ; $2F - GET-PACK
        DEFW    L0E4F           ; $30 - SEND-PACK
        DEFW    L1E98           ; $31 - HOOK-31
        DEFW    L1E94           ; $32 - HOOK-32

        DEFW    L1FE4           ; $33 - GET-DESC
        DEFW    L1FF6           ; $34 - OP-B-CHAN


; ---------------------------
; THE 'CONSOLE INPUT' ROUTINE
; ---------------------------
; (Hook Code: $1B)

;; CONS-IN
L1ECD:  EI                      ; enable interrupts.
        RES     5,(IY+$01)      ; update FLAGS signal no new key pressed.

;; WTKEY
L1ED2:  HALT                    ; wait for an interrupt.

        RST     10H             ; CALBAS
        DEFW    $02BF           ; main KEYBOARD

        BIT     5,(IY+$01)      ; test FLAGS - new key ?
        JR      Z,L1ED2         ; loop back, if not, to WTKEY

        LD      A,($5C08)       ; place decoded key in system variable LASTK
        RET                     ; return.


; ----------------------------
; THE 'CONSOLE OUTPUT' ROUTINE
; ----------------------------
; (Hook Code: $1C)
;   outputs a character to the unalterable system stream for the console.

;; CONS-OUT
L1EE0:  PUSH    AF              ; save character to be output.
        LD      A,$FE           ; use system stream $FE - upper screen.

; ->

;; OUT-CODE
L1EE3:  LD      HL,$5C8C        ; address system variable SCR_CT.
        LD      (HL),$FF        ; load with a high number to suppress scroll
                                ; prompt.

        RST     10H             ; CALBAS
        DEFW    $1601           ; main CHAN-OPEN opens selected stream.

        POP     AF              ; fetch the preserved print character.

        RST     10H             ; CALBAS
        DEFW    $0010           ; main PRINT-A prints character in accumulator.


        RET                     ; return.


; ----------------------------
; THE 'PRINTER OUTPUT' ROUTINE
; ----------------------------
; (Hook code: $1D)
;   outputs a character to stream 3.

;; PRT-OUT
L1EF0:  PUSH    AF              ; preserve character to be printed
        LD      A,$03           ; select stream 3
        JR      L1EE3           ; back to OUT-CODE


; ---------------------------
; THE 'KEYBOARD TEST' ROUTINE
; ---------------------------
; ( Hook Code: $20 )
; Normally a single reset bit in A determines which half row is read but by
; resetting all bits the entire keyboard is read.  A pressed key will cause
; a bit to be reset.  Routine returns with zero flag set if no keys pressed,
; NZ otherwise.

;; KBD-TEST
L1EF5:  XOR     A               ; reset all eight high-order bits.
        IN      A,($FE)         ; read the entire keyboard.
        AND     $1F             ; retain any unpressed keys - will be $1F if
                                ; no key.
        SUB     $1F             ; subtract to give zero if no keys.
        RET                     ; return.


; -------------------------------
; THE 'READ SEQUENTIAL' HOOK CODE
; -------------------------------
; (Hook Code: $25)
;

;; READ-SEQ
L1EFD:  BIT     1,(IX+$43)      ; RECFLG
        JR      Z,L1F08         ; forward to INCREC

        LD      (IY+$00),$07    ; set ERR_NR to '8 End of file'
        RST     28H             ; Error Main ROM

; ---

;; INCREC
L1F08:  INC     (IX+$0D)        ; increment the required record in CHREC
                                ; and continue into next routine...

; ---------------------------
; THE 'READ RANDOM' HOOK CODE
; ---------------------------
; (Hook Code: $27)
;   reads a PRINT record randomly.

;; RD-RANDOM
L1F0B:  CALL    L1252           ; routine GET-RECD gets the record specified
                                ; by CHREQ matching filename CHNAME from the 
                                ; cartridge in the drive CHDRIV which is 
                                ; started.

        BIT     2,(IX+$43)      ; test RECFLG - is it a PRINT type file.
        RET     Z               ; return if so.

        CALL    L119F           ; routine DEL-M-BUF reclaims the permanent 
                                ; channel thus losing the buffer contents.

        RST     20H             ; Shadow Error Restart
        DEFB    $16             ; 'Wrong file type'

; -------------------------------------
; THE 'CLOSE NETWORK CHANNEL' HOOK CODE
; -------------------------------------
; (Hook Code: $2E)
; Hook Code Only

;; CLOSE-NET
L1F18:  CALL    L0FAE           ; routine SEND-NEOF

        PUSH    IX              ; pick up start address
        POP     HL              ; of the channel.

        LD      BC,$0114        ; bytes to reclaim.

        RST     10H             ; CALBAS.
        DEFW    $19E8           ; main RECLAIM-2.

        RET                     ; return.


; -------------------------------------
; THE 'GET PACKET FROM NETWORK' ROUTINE
; -------------------------------------
; (Hook Code: $2F)

;; GET-PACK
L1F25:  LD      A,($5CC6)       ; sv IOBORD
        OUT     ($FE),A         ;
        DI
        CALL    L0FD3           ; routine WT-SC-E
        JR      NC,L1F3A        ; forward to GP-ERROR

        CALL    L0EB5           ; routine GET-NBLK
        JR      NZ,L1F3A        ; forward to GP-ERROR

        EI                      ;
        AND     A               ;
        JP      L0D4D           ; jump to BORD-REST

; ---

;; GP-ERROR
L1F3A:  SCF                     ;
        EI                      ;
        JP      L0D4D           ; jump to BORD-REST


; ---------------------------
; THE 'READ SECTOR' HOOK CODE
; ---------------------------
; (Hook Code: $28)
; fetches header from sector specified by CHREC.
; If the sector is from a PRINT type file then it returns with success.
; Otherwise if a program or code file the data area is 'cleared'.

;; RD-SECTOR
L1F3F:  LD      HL,$00FF        ; ensure every sector is tried.
                                ; Note. was $F0 (240) in original ROM which
                                ; would not be compatible with emulators.
        LD      ($5CC9),HL      ; update temporary variable SECTOR

;; NO-GOOD
L1F45:  CALL    L13A9           ; routine GET-M-HD2 reads the next header 
                                ; to pass the tape heads.

        LD      A,(IX+$29)      ; fetch sector number from HDNUMB
        CP      (IX+$0D)        ; compare with required sector in CHREC
        JR      Z,L1F57         ; forward, with match, to USE-C-RC

        CALL    L13F7           ; routine DEC-SECT decrements the counter.
        JR      NZ,L1F45        ; loop back, if not zero, to NO-GOOD

        RST     20H             ; Shadow Error Restart
        DEFB    $11             ; 'File not found'

; ---

;; USE-C-RC
L1F57:  PUSH    IX              ; transfer channel base address
        POP     HL              ; to the HL register.

        LD      DE,$0043        ; offset to RECFLG 
        ADD     HL,DE           ; add to address start of record descriptor.

        CALL    L15EB           ; routine GET-M-BUF reads in the record 
                                ; descriptor and the 512 bytes of data.

        CALL    L1426           ; routine CHKS-HD-R checksums the descriptor.
 
        JR      NZ,L1F75        ; forward, with error, to DEL-B-CT

        LD      DE,$000F        ; additional offset to data.
        ADD     HL,DE           ; add to address data.

        CALL    L142B           ; routine CHKS-BUFF checksums the data buffer.
        JR      NZ,L1F75        ; forward, with error, to DEL-B-CT

        OR      A               ; clear carry
        BIT     2,(IX+$43)      ; test RECFLG - is this a PRINT file ?
        RET     Z               ; return if so.

;; DEL-B-CT
L1F75:  CALL    L1FD4           ; routine CLR-BUFF sets descriptor and data
                                ; contents to same values.
        SCF                     ; signal error.
        RET                     ; return from hook-code.


; --------------------------------
; THE 'READ NEXT SECTOR' HOOK CODE
; --------------------------------
; (Hook Code: $29)
; This hook code just reads the next header to pass the tape head and then,
; without further qualification, reads the corresponding data using the 
; routine above. If not a PRINT file then the data is cleared.
; It needlessly sets up a sector counter in the System Variable SECTOR.

;; RD-NEXT
L1F7A:  LD      HL,$00FF        ; set count to 255. Note. not used.
        LD      ($5CC9),HL      ; insert in system variable SECTOR.

        CALL    L13A9           ; routine GET-M-HD2 reads the next header 
                                ; to pass the tape heads.

        JR      L1F57           ; back to USE-C-RC to read and validate the 
                                ; corresponding descriptor and data.

; ----------------------------
; THE 'WRITE SECTOR' HOOK CODE
; ----------------------------
; (Hook Code: $2A)
; writes to microdrive the sector in CHREC.

;; WR-SECTOR
L1F85:  LD      HL,$00FF        ; set counter to ensure at least one revolution 
        LD      ($5CC9),HL      ; of the tape and update SECTOR

        PUSH    IX              ; transfer base address
        POP     HL              ; of channel to HL.

        LD      DE,$0037        ; offset to header preamble
        ADD     HL,DE           ; add and
        PUSH    HL              ; preserve location on machine stack.

        LD      DE,$000C        ; offset past preamble to  RECFLG
        ADD     HL,DE           ; the start of the record descriptor.

        CALL    L1426           ; routine CHKS-HD-R insert checksum byte.

        LD      DE,$000F        ; 15 byte offset to start  of data.
        ADD     HL,DE           ; add to address first of 512 bytes.
        CALL    L142B           ; routine CHKS-BUFF inserts buffer checksum.

;; WR-S-1
L1FA1:  CALL    L13A9           ; routine GET-M-HD2 reads any header.
        LD      A,(IX+$29)      ; fetch sector from HDNUMB
        CP      (IX+$0D)        ; compare to required sector in CHREC
        JR      Z,L1FB3         ; forward, with match, to WR-S-2

        CALL    L13F7           ; routine DEC-SECT decrements the counter
        JR      NZ,L1FA1        ; back, if not zero, to WR-S-1

; else the header was not found after a complete tape revolution.

        RST     20H             ; Shadow Error Restart
        DEFB    $11             ; File not found

; ---

;; WR-S-2
L1FB3:  IN      A,($EF)         ; read microdrive port.
        AND     $01             ; isolate 'write prot.' bit.
        JR      NZ,L1FBB        ; forward, if not, to WR-S-3

        RST     20H             ; Shadow Error Restart
        DEFB    $0E             ; Drive 'write' protected

; ---

;; WR-S-3
L1FBB:  LD      A,$E6           ; enable writing
        OUT     ($EF),A         ; output to port.

        LD      BC,$0168        ; set delay to 360
        CALL    L1652           ; routine DELAY-BC pauses briefly as the 
                                ; record now approaches the tape heads.

        POP     HL              ; restore pointer to RECFLG
        CALL    L15B3           ; routine OUT-M-BUF writes descriptor and
                                ; data buffer.

        LD      A,$EE           ; disable writing
        OUT     ($EF),A         ; output to port.

        CALL    L13C4           ; routine CHECK-MAP fetches bit mask for map
                                ; location addressed by HL into B register.

        LD      A,B             ; transfer mask to accumulator
        OR      (HL)            ; combine with any set bits already there.
        LD      (HL),A          ; update map marking sector used.

        RET                     ; return.

; -----------------------------------
; THE 'CLEAR BUFFER CONTENTS' ROUTINE
; -----------------------------------
; This routine sets the contents of the 14 byte record descriptor and 
; the 512 byte data buffer to the same value so that they are unreadable.
; This is invoked when the possibility that a secret file, whose name begins
; with CHR$ 0 has been read.

;; CLR-BUFF
L1FD4:  PUSH    IX              ; transfer the channel base
        POP     HL              ; address to HL.

        LD      DE,$0028        ; offset to HDFLAG.
        ADD     HL,DE           ; add to base address.

        LD      D,H             ; transfer same
        LD      E,L             ; address to DE and
        INC     DE              ; make one higher.

        LD      BC,$0229        ; set counter to 553 bytes.
        LDIR                    ; fill with HDFLAG contents.

        RET                     ; return.

; ---------------------------------------
; THE 'FETCH RECORD DESCRIPTOR' HOOK CODE
; ---------------------------------------
; (Hook Code: $33)
; Note. new in this ROM.
; This Hook Code reads the next header and corresponding record descriptor
; returning with carry flag set with header mismatch or if the name starts 
; with CHR$ 0 and should therefore be secret.

;; GET-DESC
L1FE4:  CALL    L13A9           ; routine GET-M-HD2 reads the next 14-byte 
                                ; header to pass the tape heads.
        CALL    L1E5E           ; routine G-RDES reads the corresponding 
                                ; 14-byte record descriptor for this sector.
        JR      NZ,L1FF1        ; forward, with checksum error, to NOT-RECV

; a valid header and matching descriptor has been read. 

        LD      A,(IX+$47)      ; fetch first character of RECNAM.
        OR      A               ; test for CHR$ 0.
        RET     NZ              ; return if not a secret file.

; but if a secret file then ensure that the 14 descriptor bytes (read) and 
; the 512 buffer bytes (not read) are cleared to the same value.

;; NOT-RECV
L1FF1:  CALL    L1FD4           ; routine CLR-BUFF (above).
        SCF                     ; signal error.
        RET                     ; return from hook code.

; --------------------------------
; THE 'OPEN "B" CHANNEL' HOOK CODE
; --------------------------------
; (Hook Code: $34)
; New in this ROM.

;; OP-B-CHAN
L1FF6:  LD      A,$42           ; letter "B"
        LD      ($5CD9),A       ; place in system variable L_STR1
        CALL    L0B17           ; routine OP-RS-CH opens an RS232 channel.
        RET                     ; return.

; ---

        DEFB    $FF             ; spare

; ---

.end

; -----------------------------
; THE 'SHADOW' SYSTEM VARIABLES
; -----------------------------
;
; X1  23734 $5CB6  FLAGS3                 ; IY+$7C - Flags
; X2  23735 $5CB7  VECTOR                 ; Address used to extend BASIC.
; X10 23737 $5CB9  SBRT                   ; 10 bytes of Z80 code to Page ROM.
; 2   23747 $5CC3  BAUD                   ; BAUD=(3500000/(26*baud rate)) -2
; 1   23749 $5CC5  NTSTAT                 ; Own network station number.
; 1   23750 $5CC6  IOBORD                 ; Border colour during I/O
; N2  23751 $5CC7  SER_FL                 ; 2 byte workspace used by RS232
; N2  23753 $5CC9  SECTOR                 ; 2 byte workspace used by Microdrive.
; N2  23755 $5CCB  CHADD_                 ; Temporary store for CH_ADD
; 1   23757 $5CCC  NTRESP                 ; Store for network response code.
; --  ----- -----  ------                 ; ---------------------------------
; 1   23758 $5CCD  NTDEST                 ;  Destination station number 0 - 64.
; 1   23759 $5CCE  NTSRCE                 ;  Source station number.
; X2  23760 $5CD0  NTNUMB                 ;  Network block number 0 - 65535
; N1  23762 $5CD2  NTTYPE                 ;  Header type block.
; X1  23763 $5CD3  NTLEN                  ;  Data block length 0 - 255.
; N1  23764 $5CD4  NTDCS                  ;  Data block checksum.
; N1  23765 $5CD5  NTHDS                  ;  Header block checksum.
; --  ----- -----  ------                 ; ---------------------------------
; N2  23766 $5CD6  D_STR1                 ; 2 byte drive number 1 - 8.
; N1  23768 $5CD8  S_STR1                 ; Stream number 1 - 15. [ also 0 ]
; N1  23769 $5CD9  L_STR1                 ; Device type "M", "N", "T" or "B"
; N2  23770 $5CDA  N-STR1                 ; Length of filename.
; N2  23772 $5CDC             (dynamic)   ; Address of filename.
; --  ----- -----  ------                 ; ---------------------------------
; N1  23774 $5CDE  D_STR2                 ; 2 byte drive   ; File type.
; N1  23775 $5CDF                         ; number.        ; Length of  
; N1  23776 $5CE0  S_STR2                 ; Stream number. ; Data.
; N1  23777 $5CE1  L_STR2                 ; Device type.   ; Start of        
; N1  23778 $5CE2  N-STR2                 ; Length of      ; data.   \
; N1  23779 $5CE3                         ; filename.      ; Program  \ 
; N1  23780 $5CE4             (dynamic)   ; Address of     ; length. ; Start of
; N1  23781 $5CE5             (dynamic)   ; filename       ;         ; data.
; --  ----- -----  ------                 ; ---------------------------------
; N1  23782 $5CE6  HD_00                  ; File type .      _  
; N2  23783 $5CE7  HD_0B                  ; Length of data.   /\
; N2  23785 $5CE9  HD_0D                  ; Start of data.   /
; N2  23787 $5CEB  HD_0F                  ; Program length. /
; N2  23789 $5CED  HD_11                  ; Line number.
; --  ----- -----  ------                 ; ---------------------------------
; 1   23791 $5CEF  COPIES                 ; Number of copies made by SAVE.
; --  ----- -----  ------                 ; ---------------------------------

; Note. the System Variables HD_00 to HD_11 take their names from their
; position in the standard audio tape header. The ten bytes HD_01 to HD_0A
; would be the tape filename and are not held within the above area.
; The area D_STR2 is multipurpose and sometimes the HD_?? variables are       
; copied to this region and sometimes the D_STR1 variables are copied there.

; ----------------------------
; THE 'MICRODRIVE MAPS' FORMAT
; ----------------------------
;
; The creation of the extra system variables moves the start of CHANS up to
; address 23792.  It is at this location that the first of a possible eight
; Microdrive Maps will be created.  Each map is 32 bytes in size containing
; 256 bits for each possible sector and as each map is created, CHANS moves
; up by another 32 bytes.

; 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
; 00000000 00000000 00000000 00000000 00010101 01010100 00000000 00000000
; 00000000 01100000 00000000 00000000 00000000 00000000 00000111 11111111
; 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

; Note. The continuous loop tape is formatted in such a way that sector $FE
; is written first and sector $01 is the last to be written. Sectors $00 and
; $FF are therefore always unavailable.  As there is only room for about 180 
; sectors on a 100 foot long tape, the higher numbered sectors are later 
; overwritten by the lower numbered sectors.
; Where the tape is spliced together one or two bad sectors will appear. 
; When saving bytes there isn't enough time to copy the next 512 bytes from 
; the program/code area to the buffer between sectors so a program or 
; code/data block is written to alternating sectors as with the 3K example
; above.  As the tape cartridge fills up it becomes more difficult to find 
; usable sectors and LOAD/SAVE operations take longer.
; A growing number of Spectrum emulators feature the microdrives and they 
; usually make available all 254 sectors so a typical cartridge will hold 126 
; Kilobytes compared to say 92 K on real hardware.
;
; During a LOAD operation the entire sector map is pushed on the machine stack
; and the microdrive map is used to map loaded records after which the previous
; map is 'popped' of the stack and reverts to mapping sectors again.
;
; ------------------------------
; THE 'STANDARD CHANNELS' FORMAT
; ------------------------------
; The twenty bytes of the standard channels as set up my Main ROM.
;
; CHANS                   $09F4           ; PRINT-OUT
;                         $10A8           ; KEY-INPUT
;                         $4B             ; 'K'
;
;                         $09F4           ; PRINT-OUT
;                         $15C4           ; REPORT-J
;                         $53             ; 'S'
;
;                         $0F81           ; ADD-CHAR
;                         $15C4           ; REPORT-J
;                         $52             ; 'R'
;
;                         $09F4           ; PRINT-OUT
;                         $15C4           ; REPORT-J
;                         $50             ; 'P'
;
;                         $80             ; End Marker

; -------------------------------
; THE 'MICRODRIVE CHANNEL' FORMAT
; -------------------------------
;
;   2 IX+$00              $0008           ; main ERROR-1
;   2 IX+$02              $0008           ; main ERROR-1
;   1 IX+$04              $CD             ; inverted or regular "M" character
;   2 IX+$05              $12B3           ; MCHAN-OUT
;   2 IX+$07              $11FD           ; M-INPUT
;   2 IX+$09              $0253           ; length of channel.
;   2 IX+$0B  CHBYTE      $0000           ; position of next byte rec'd/stored
;   1 IX+$0D  CHREC       $00             ; record number, also temporary sector
;  10 IX+$0E  CHNAME      "          "    ; filename with trailing spaces.
;   1 IX+$18  CHFLAG      %0000000x       ; bit 0 used
;   1 IX+$19  CHDRIV                      ; drive number 0 - 7.
;   2 IX+$1A  CHMAP                       ; address of MAP for this microdrive.
; ------------------------------------------------------------------------------
;  12 IX+$1C                              ; 12 bytes of header preamble
; ------------------------------------------------------------------------------
;   1 IX+$28  HDFLAG                      ; Flag byte.
;                                         ; bit 0 set indicates a header.
;   1 IX+$29  HDNUMB                      ; Sector number. [1-254]
;   2 IX+$2A                              ; Two unused bytes.
;  10 IX+$2C  HDNAME                      ; Cartridge name with trailing spaces.
;   1 IX+$36  HDCHK                       ; Header checksum.
; ------------------------------------------------------------------------------
;  12 IX+$37                              ; 12 bytes of data block preamble.
; ------------------------------------------------------------------------------
;   1 IX+$43  RECFLG                      ; Flag byte. 
;                                         ; bit 0 reset indicates a record.
;                                         ; bit 1 reset no EOF, set EOF
;                                         ; bit 2 reset indicates a PRINT FILE
;   1 IX+$44  RECNUM                      ; Record number in the range 0-255
;   2 IX+$45  RECLEN                      ; Number of databytes in record 0-512.
;  10 IX+$47  RECNAM                      ; Filename with trailing spaces.
;   1 IX+$51  DESCHK                      ; Checksum of the preceding 14 bytes
; ------------------------------------------------------------------------------
; 512 IX+$52  CHDATA                      ; the 512 bytes of data.
;   1 +$0252  DCHK                        ; Checksum of preceding 512 bytes.

; ----------------------------
; THE 'NETWORK CHANNEL' FORMAT
; ----------------------------
;
;   2 IX+$00              $0008           ; main ERROR-1
;   2 IX+$02              $0008           ; main ERROR-1
;   1 IX+$04              $4E             ; "N" character
;   2 IX+$05              $0E09           ; NCHAN-OUT
;   2 IX+$07              $0DA9           ; N-INPUT
;   2 IX+$09              $0114           ; Length of channel 276 bytes.
;   1 IX+$0B NCIRIS                       ; The destination station number.
;   1 IX+$0C NCSELF                       ; This Spectrum's station number.
;   2 IX+$0D NCNUMB                       ; The block number.
;   1 IX+$0F NCTYPE                       ; The packet type code . 0 data, 1 EOF
;   1 IX+$10 NCOBL                        ; Number of bytes in data block.
;   1 IX+$11 NCDCS                        ; The data checksum.
;   1 IX+$12 NCHCS                        ; The header checksum.
;   1 IX+$13 NCCUR                        ; The position of last buffer char taken
;   1 IX+$14 NCIBL                        ; Number of bytes in the input buffer.
;   1 IX+$15 NCB                          ; A 255 byte data buffer.

; ------------------------------
; THE 'RS232 "T" CHANNEL' FORMAT
; ------------------------------
;
;   2 IX+$00              $0008           ; main ERROR-1
;   2 IX+$02              $0008           ; main ERROR-1
;   1 IX+$04              $54             ; "T" character
;   2 IX+$05              $0C3A           ; TCHAN-OUT
;   2 IX+$07              $0B76           ; T-INPUT
;   2 IX+$09              $000B           ; length of channel.

; ------------------------------
; THE 'RS232 "B" CHANNEL' FORMAT
; ------------------------------
; created by overwriting a "T" channel
;
;   2 IX+$00              $0008           ; main ERROR-1
;   2 IX+$02              $0008           ; main ERROR-1
;   1 IX+$04              $42             ; "B" character
;   2 IX+$05              $0D07           ; BCHAN-OUT
;   2 IX+$07              $0B7C           ; B-INPUT
;   2 IX+$09              $000B           ; length of channel.


; Acknowledgements
; ----------------
; Dr Ian Logan          for main ROM labels ( and half on Interface 1)
; Dr Frank O'Hara       for main ROM labels.
; Gianluca Carri        for Interface 1 v1.2 labels

; Credits
; -------
; Jonathan Needle       for requesting said labels on comp.sys.sinclair
;                       thereby kick-starting this project.
;                       Also for the Interface1-aware Spectaculator emulator 
;                       and help with PORTS.
; Paul Dunn             for help with PORTS and the SPIN emulator.
; Chris Born            for documentation.