Spectrum 128 ROM 0 - Incomplete disassembly

; *** SPECTRUM 128 ROM 0 DISASSEMBLY ***

; The Spectrum ROMs are copyright Amstrad, who have kindly given permission \
; to publish ROM disassemblies.

; ** General notes **
;
; (5B66) flags;
; bit 4 for LOAD, bit 5 for SAVE, bit 6 for MERGE, bit 7 for VERIFY
; bit 3 indicates RAMdisk or not
;
; (5b8d-5d91): last value printed by calculator
;
; page 7:
; EC00-02, 03-05 are flags of some sort
; EC06-07 is two-word store
; (EC08;EC09) seems to be the last line number entered
;
; EC0C: current menu index
; 
; EC0D flags:
; bit 0 : ?
;         Forcibly setting it seems to ignore all keys apart from DELETE
;        (which clears it) and ENTER (which doesn't)
; bit 1 : set when a menu is displayed
; bit 2 : ?
; bit 3 : set when the current line has been altered
; bits 4 and 5 set during calculator; bit 4 reset when returning to main menu
; bit 6 : set when editing area is the lower screen
; bit 7 : set during editing (when waiting for editing keypress?)
; 
; EC0E starts at 00, goes to 04 when entering calc mode,
;    goes to FF when aborting Tape Loader,
;    set to 07 in some other Tape Loader scenario
;
; EC13 is the temporary store for P-FLAG
;
; EC15 holds the number of editing lines: 20 for the main screen, 1 for the
;      lower screen.
; EC16... holds the currently editing stuff;
;  32 * chars + 3 * flags
;  characters on the screen but not editable (eg indent chars after line wrap)
;  are zero
;  first flag byte:
;   on first line,       seems to be 09 until full, then goes to 03
;                                    1001                        0011
;   on subsequent lines, seems to be 08 until full, then goes to 02
;                                    1000                        0010
;    bit 0 = first line flag?
; F6EA holds the jump table for the current menu
; F6EC holds the text information for the current menu
; F6EE,F6EF,F6F0 holds the cursor position - row, column, alternate column.
;
; Line being edited has a temporary copy (???) made at f6f8?
; 
; FC9A,B holds the line at the top of the screen, or 0 for the first line
;
; FD81 contains some flag bits used when tokenizing a BASIC line. Bits 0 and 1
; relate to quote marks in the line; bit 2 is used to indicate the presence of
; REM.
;
; FD84 contains more flag bits used when entering a BASIC line. As far as I can see
; bit 0 is set when the last character was a keyword; bit 1 is set when the last
; character was a space.
;
; FD89 holds "<" or ">", if this was the previously examined character
; during tokenization of a BASIC line.
; 
; AY-3-8912 registers
; Register       Function                        Range
; 0              Channel A fine pitch            8-bit (0-255)
; 1              Channel A course pitch          4-bit (0-15)
; 2              Channel B fine pitch            8-bit (0-255)
; 3              Channel B course pitch          4-bit (0-15)
; 4              Channel C fine pitch            8-bit (0-255)
; 5              Channel C course pitch          4-bit (0-15)
; 6              Noise pitch                     5-bit (0-31)
; 7              Mixer                           8-bit
; 8              Channel A volume                4-bit (0-15)
; 9              Channel B volume                4-bit (0-15)
; 10             Channel C volume                4-bit (0-15)
; 11             Envelope fine duration          8-bit (0-255)
; 12             Envelope course duration        8-bit (0-255)
; 13             Envelope shape                  4-bit (0-15)
; 14             I/O port A                      8-bit (0-255)

; RAMdisk format:
;    Files start at 1C000 and build upwards
;    Catalogue entries start at 7EBFF and build downwards
;    Directory stack doesn't go below 7C000
;    Start address at +0A,+0B,+0C
;    Length at +0D,+0E,+0F
;    End addresss at +10,+11,+12

; ROM 1 subroutines
EXPT_EXP    .equ $1c8c
STK_FETCH   .equ $2bf1
CLS         .equ $0d6b 
CLS_LOWER   .equ $0d6e
TEST_SCREEN .equ $3c04

; ** The restart and initialisation routines **
L0000 di                ; Reset the machine.
      ld   bc,$692b     ; 
L0004 dec  bc           ; 
      ld   a,b          ; 
      or   c            ; 
      jr   nz,L0004     ; (There is no RST 8).
      jp   L00c7        ; to the main reset routine
      .byte 00,00,00,00 ; spare bytes

; RST 10,18 and 20 call the equivalent subroutines in ROM 1, via RST 28.

L0010  rst  28h          ; 
L0011  .word $0010       ;
L0013  ret               ;
L0014  .byte 00,00,00,00  ; spare bytes

L0018  rst  28h          ;
       .word $0018       ;
       ret               ;
       .byte 00,00,00,00  ; spare bytes

L0020  rst  28h          ;
L0021  .word $0020       ;
L0023  ret               ;
       .byte 00,00,00,00  ; spare bytes

; RST 28 calls a routine in ROM 1 (or alternatively a routine in RAM while \
; ROM 1 is paged in). Call as follows: RST 28 / .word address
L0028  ex   (sp),hl      ; Get the address after the RST 28 into HL,
                         ; saving HL on the stack.
       push af           ; 
       ld   a,(hl)       ;
L002b  inc  hl           ; Point HL to the byte after
       inc  hl           ; the required address.
       ld   ($5b5a),hl   ; Store this in RETADDR.
L0030  dec  hl           ; 
       ld   h,(hl)       ;
L0032  ld   l,a          ; HL=subroutine to call.
       pop  af           ; Restore AF.
       jp   L005c        ; Jump ahead to continue.
L0037  .byte 0           ; Spare byte.

; Interrupt routine
L0038  push hl           ; e5
       ld   hl,$0048     ; 21 48 00
L003c  push hl           ; e5
       ld   hl,$5b00     ; 21 00 5b
L0040  push hl           ; e5
       ld   hl,$0038     ; 21 38 00
       push hl           ; e5
       jp   $5b00        ; c3 00 5b
L0048  pop  hl           ; e1
       ret               ; c9

L004a  ld   bc,$7ffd     ; 01 fd 7f
       xor  a            ; af
       di                ; f3
       out  (c),a        ; ed 79
       ld   ($5b5c),a    ; 32 5c 5b
       ei                ; fb
       dec  a            ; 3d
       ld   (iy+$00),a   ; fd 77 00
       jp   L0321        ; c3 21 03

L005c  ld   ($5b58),hl   ; 22 58 5b
       ld   hl,$5b14     ; 21 14 5b
       ex   (sp),hl      ; e3
       push hl           ; e5
L0064  ld   hl,($5b58)   ; NB There is no NMI code [AOwen]
       ex   (sp),hl      ; e3
       jp   $5b00        ; c3 00 5b

; The following code will end up at 5b00
L006b  push af           ; (5b00)
       push bc           ; (5b01)
       ld   bc,$7ffd     ; (5b02)
       ld   a,($5b5c)    ; (5b05)
       xor  $10          ; (5b08)
       di                ; (5b0a)
       ld   ($5b5c),a    ; (5b0b)
       out  (c),a        ; (5b0e)
       ei                ; (5b10)
       pop  bc           ;
       pop  af           ;
       ret               ;
       call $5b00        ;
L0082  push hl           ;
       ld   hl,($5b5a)   ;
       ex   (sp),hl      ;
       ret               ;
       di                ;
       ld   a,($5b5c)    ;
       and  $ef          ; (5b21)
       ld   ($5b5c),a    ;
       ld   bc,$7ffd     ;
       out  (c),a        ;
L0096  ei                ;
       jp   L00c3        ;
       ld   hl,$06d8     ; (5b2f)
       jr   L00a2        ;
       ld   hl,$07ca     ;
L00a2  ex   af,af'       ;
       ld   bc,$7ffd     ;
       ld   a,($5b5c)    ;
       push af           ;
       and  $ef          ;
       di                ;
       ld   ($5b5c),a    ;
       out  (c),a        ;
       jp   L05e6        ;
       ex   af,af'       ;
       pop  af           ;
       ld   bc,$7ffd     ;
       di                ;
       ld   ($5b5c),a    ;
       out  (c),a        ;
       ei                ;
       ex   af,af'       ;
       ret               ;

L00c3  ld   hl,($5b8b)   ; 2a 8b 5b
       jp   (hl)         ; e9

; Continuation of the RESET routine
L00c7  ld   b,$08        ; 06 08
L00c9  ld   a,b          ; 78
       exx               ; d9
       dec  a            ; 3d
       ld   bc,$7ffd     ; Switch RAM page
L00cf  out  (c),a        ; 
       ld   hl,$c000     ; 
       ld   de,$c001     ;
       ld   bc,$3fff     ;
       ld   a,$ff        ;
       ld   (hl),a       ; Store FF into RAM
       cp   (hl)         ; Check RAM integrity
       jr   nz,L0131     ; Fatal error
       xor  a            ;
       ld   (hl),a       ;
       cp   (hl)         ;
       jr   nz,L0131     ;
       ldir              ; Clear the whole page
       exx               ;
       djnz L00c9        ; Keep looping through pages
       ld   ($5b88),a    ; 32 88 5b
       ld   c,$fd        ; 0e fd
       ld   d,$ff        ; 16 ff
       ld   e,$bf        ; 1e bf
       ld   b,d          ; 42
       ld   a,$0e        ; 3e 0e
       out  (c),a        ; ed 79
       ld   b,e          ; 43
       ld   a,$ff        ; 3e ff
       out  (c),a        ; ed 79
       jr   L0137        ; 18 38

       .byte $00          ; spare byte

; Jump table. For descriptions of 118..12a, see
; http://groups.google.com/groups?selm=bbbede39.0310140525.5b1e5a78%40posting.google.com
L0100  jp   L17af        ; c3 af 17
L0103  jp   L1838        ; c3 38 18
L0106  jp   L1ecf        ; c3 cf 1e
L0109  jp   L1f04        ; c3 04 1f
L010c  jp   L004a        ; c3 4a 00
L010f  jp   L03a2        ; c3 a2 03
L0112  jp   L182a        ; c3 2a 18
L0115  jp   L18a8        ; c3 a8 18
L0118  jp   L012d        ; Keypad scan
L011b  jp   L0a05        ; Play music strings
L011e  jp   L11a3        ; Send to MIDI
L0121  jp   L06d8        ; RS232 input
L0124  jp   L07ca        ; RS232 output (1)
L0127  jp   L08a3        ; RS232 output (2)
L012a  jp   L08f0        ; COPY (screen dump) routine

L012d  rst  28h          ; Call keypad routine in BASIC ROM.
       .word $3b01       ; BUG: The address should be $3c01. Credit: Paul Farrow.
       ret

; Fatal RAM error
L0131  exx               ;
       ld   a,b          ; Indicate which RAM page failed by
       out  ($fe),a      ; setting the border colour
L0135  jr   L0135        ; Infinite loop

; Next bit by Geoff Wearmouth.

; Reset routine continued
; complete setting up sound chip registers.
L0137  ld   b,d          ; 42
       ld   a,$07        ; 3e 07
       out  (c),a        ; ed 79
       ld   b,e          ; 43
       ld   a,$ff        ; 3e ff
       out  (c),a        ; ed 79

; Now copy the paging mechanism. 

       ld   de,$5b00     ; The destination is the start of the old ZX buffer.
       ld   hl,$006b     ; The source is in this ROM.
       ld   bc,$0058     ; There are eighty eight bytes to copy.
       ldir              ; Copy the block of bytes.

       ld   a,$cf        ; Load A with the code for the Z80 instruction 'RST 08'.
       ld   ($5b5d),a    ; Insert into New System Variable RAMRST.
       ld   sp,$5bff     ; Set the stack pointer to last location of old buffer.

       ld   a,$04        ; page in logical page 4
       call L1c64        ;   (physical page 7)

       ld   ix,$ebec     ; "end of catalogue" marker in RAMdisk
       ld   ($5b83),ix   ; SF_NEXT
       ld   (ix+$0a),$00 ; 
       ld   (ix+$0b),$c0 ;
       ld   (ix+$0c),$00 ;
       ld   hl,$2bec     ;
       ld   a,$01        ; AHL = free space in RAMdisk
       ld   ($5b85),hl   ; 
       ld   ($5b87),a    ;

       ld   a,$05        ; page in logical page 5
       call L1c64        ;  (physical page 0)

       ld   hl,$ffff     ; Load HL with known last working byte - 65535.
       ld   ($5cb4),hl   ; Set P-RAMT standard System Variable.

       ld   de,$3eaf     ; Set DE to address of the last bitmap of 'U' in the
                         ; Main ROM.
       ld   bc,$00a8     ; There are 21 User Defined Graphics to copy.
       ex   de,hl        ; Swap so destination is $FFFF.
       rst  28h          ; 
       .word $1661       ; calling this address (LDDR/RET) in the Main ROM
                         ; cleverly copies the 21 characters to the end of RAM.

       ex   de,hl        ; Transfer DE to HL.
       inc  hl           ; Increment to address first byte of UDG 'A'.
       ld   ($5c7b),hl   ; Update standard System Variable UDG.

       dec  hl           ; decrement HL.
       ld   bc,$0040     ; set values zero and 64.
       ld   ($5c38),bc   ; Update standard System Variables RASP and PIP.
       ld   ($5cb2),hl   ; Update standard System Variable RAMTOP - the last
                         ; byte of the BASIC system area. Any machine code and
                         ; graphics above this address are protected from NEW.

; entry point for NEW with Interrupts disabled and physical page zero occupying
; the upper RAM region $C000 - $FFFF - the normal BASIC memory configuration.

L019d  ld   hl,$3c00     ; Set HL to where, in theory character zero would be.
       ld   ($5c36),hl   ; Update standard System Variable CHARS.

       ld   hl,($5cb2)   ; Load HL with value of System Variable RAMTOP.
       inc  hl           ; Address next location.
       ld   sp,hl        ; Set the Stack Pointer.
       im   1            ; Select Interrupt Mode 1.
       ld   iy,$5c3a     ; Set the IY register to address the Standard System
                         ; Variables and many of the new System Variables and
                         ; even those of Interface 1 in some cases.
       set  4,(iy+$01)   ; Update FLAGS - signal 128K mode
                         ; Note. This bit was unused and therefore never set
                         ; by 48K BASIC.

       ei                ; With a stack and the IY register set, Interrupts can
                         ; be enabled.

       ld   hl,$000b     ; Set HL to eleven.
       ld   ($5b5f),hl   ; Update new System Variable BAUD - the RS232 bit 
                         ; period. A value of eleven is equivalent to 9600 baud.

       xor  a            ; Clear accumulator.
       ld   ($5b61),a    ; Set new System Variable SERFL to zero.
       ld   ($5b63),a    ; Set new System Variable COL to zero.
       ld   ($5b65),a    ; Set new System Variable TVPARS to zero.

       ld   hl,$ec00     ; Should write to  page 7 [AOwen]
       ld   ($ff24),hl   ;

; Note. this is dangerously close to the machine stack. \
; The 1985 Sinclair Research ESPAGNOL source code says that this instruction \
; will write to the [previously cleared] Main BASIC RAM during initialization \
; but that a different page of RAM will be present during NEW. \
; Stuff and Nonsense! Assemblers and other languages will be corrupted by the \
; BASIC NEW command.

       ld   a,$50        ; Set printer width to a default of eighty.
       ld   ($5b64),a    ; Update new System Variable WIDTH for 80 columns.
       ld   hl,$000a     ; set HL to ten.
       ld   ($5b94),hl   ; Store in spare locations between STRIP2 
L01d4  ld   ($5b96),hl   ; and the temporary stack TSTACK.

       ld   hl,$5cb6     ; Load HL with address following System Variables.
       ld   ($5c4f),hl   ; Set standard System Variable CHANS.

       ld   de,$0589     ; Point to Initial Channel Information in this ROM.
                         ; Note. this is similar to that in Main ROM but 
                         ; channel 'P' has input and output addresses in the
                         ; new $5Bxx region.
       ld   bc,$0015     ; There are 21 bytes to copy.
       ex   de,hl        ; Switch pointer so destination is CHANS.
       ldir              ; Copy the block of bytes.

       ex   de,hl        ; Transfer DE to HL.
       dec  hl           ; Decrement to point to $80 end-marker.
       ld   ($5c57),hl   ; Update standard System Variable DATADD to this 
                         ; resting address.
       inc  hl           ; Bump address.
       ld   ($5c53),hl   ; Set standard System Variable PROG.
       ld   ($5c4b),hl   ; Set standard System Variable VARS.
       ld   (hl),$80     ; Insert the Variables end-marker.
       inc  hl           ; Increment the address.
       ld   ($5c59),hl   ; Set standard System Variable ELINE.
       ld   (hl),$0d     ; Insert a carriage return.
       inc  hl           ; Increment address. 
       ld   (hl),$80     ; Insert the $80 end-marker.
       inc  hl           ; increment address.
       ld   ($5c61),hl   ; Set the standard System Variable WORKSP.
       ld   ($5c63),hl   ; Set the standard System Variable STKBOT.
       ld   ($5c65),hl   ; Set the standard System Variable STKEND.

       ld   a,$38        ; Set colour attribute to black ink on white paper.
       ld   ($5c8d),a    ; Set the standard System Variable ATTR_P.
       ld   ($5c8f),a    ; Set the standard System Variable MASK_P.
       ld   ($5c48),a    ; Set the standard System Variable BORDCR.

       xor  a            ; Clear the accumulator.
       ld   ($ec13),a    ; and zero a byte in the upper page of RAM.

; Note $EC13 is the temporary store for P-FLAG in Page 7 of RAM.
; Again Main RAM has been corrupted.

       ld   a,$07        ; Load the accumulator with colour for white.
       out  ($fe),a      ; Output to Port $FE changing border to white.

       ld   hl,$0523     ; The values five and thirty five.
       ld   ($5c09),hl   ; Set the standard System Variables REPDEL and REPPER

       dec  (iy-$3a)     ; Set KSTATE-0 to $FF
       dec  (iy-$36)     ; Set KSTATE-4 to $FF

       ld   hl,$059e     ; Set source to Initial Stream Data in this ROM.
                         ; Note. this is identical to that is Main ROM.
       ld   de,$5c10     ; Set destination to standard System Variable STRMS-FD
       ld   bc,$000e     ; There are fourteen bytes to copy.
       ldir              ; Block copy the bytes.
       res  1,(iy+$01)   ; Update FLAGS - signal printer not is use.
       ld   (iy+$00),$ff ; Set standard System Variable ERR_NR to $FF (OK-1).
       ld   (iy+$31),$02 ; Set standard Sytem Variable DF_SZ to two lines.
       rst  28h
       .word CLS
       rst  28h
       .word TEST_SCREEN
       ld   de,$0561     ; Sinclair copyright message
       call L057d        ; print a message terminated by having bit 7 set.

       ld   (iy+$31),$02 ; Set standard System Variable DF_SZ to two lines.
       set  5,(iy+$02)   ; Update TV-FLAG - signal lower screen will require 
                         ; clearing.
       ld   hl,$5bff     ; Set HL to location of temporary stack
       ld   ($5b81),hl   ; Store in STRIP1.
       call L1f45        ; switch RAM to Page 7
       ld   a,$38        ; set colours to black ink on white paper.
       ld   ($ec11),a    ; 32 11 ec
       ld   ($ec0f),a    ; 32 0f ec

; Note this is where  $EC13 and $FF24 should be set!!!!

       call L2584        ; 
       call L1f20        ; 
       jp   L259f        ;  to menu ........



L026b  ld   hl,$5b66     ; 21 66 5b
       set  0,(hl)       ; cb c6
       ld   (iy+$00),$ff ; '0 OK' status
       ld   (iy+$31),$02 ; fd 36 31 02
       ld   hl,$5b1d     ; 21 1d 5b
       push hl           ; e5
       ld   ($5c3d),sp   ; ed 73 3d 5c
       ld   hl,$02ba     ; 21 ba 02
       ld   ($5b8b),hl   ; 22 8b 5b
       call L228e        ; Point to start of BASIC command
       call L22cb        ; cd cb 22
       jp   z,L21f8      ; ca f8 21
       cp   $28          ; '('
       jp   z,L21f8      ; ca f8 21
       cp   $2d          ; '-'
       jp   z,L21f8      ; ca f8 21
       cp   $2b          ; '+'
       jp   z,L21f8      ; ca f8 21
       call L22e0        ; cd e0 22
       jp   z,L21f8      ; ca f8 21
       call L1f45        ; cd 45 1f
       ld   a,($ec0e)    ; 3a 0e ec
       call L1f20        ; cd 20 1f
       cp   $04          ; Calculator mode?
       jp   nz,L17af     ; c2 af 17
       call L2297        ; cd 97 22
       jp   z,L17af      ; ca af 17
       pop  hl           ; e1
       ret               ; c9

L02ba  bit  7,(iy+$00)   ; fd cb 00 7e
       jr   nz,L02c1     ; 20 01
L02c0  ret               ; c9
L02c1  ld   hl,($5c59)   ; 2a 59 5c
       ld   ($5c5d),hl   ; 22 5d 5c
       rst  28h          ; ef
       .word $19fb ; E-LINE-NO
       ld   a,b          ; 78
       or   c            ; b1
       jp   nz,L03f7     ; c2 f7 03
       rst  18h          ; df
       cp   $0d          ; fe 0d
       ret  z            ; c8
       call L21ef        ; cd ef 21
       bit  6,(iy+$02)   ; fd cb 02 76
       jr   nz,L02df     ; 20 03
       rst  28h          ; ef
       .word CLS_LOWER
L02df  res  6,(iy+$02)   ; fd cb 02 b6
       call L1f45        ; cd 45 1f
       ld   hl,$ec0d     ; 
       bit  6,(hl)       ; Test for editing in lower-screen area
       jr   nz,L02f4     ; 20 07
       inc  hl           ; 23
       ld   a,(hl)       ; 7e
       cp   $00          ; fe 00
       call z,L3881      ; cc 81 38
L02f4  call L1f20        ; cd 20 1f
       ld   hl,$5c3c     ; 21 3c 5c
       res  3,(hl)       ; cb 9e
       ld   a,$19        ; 3e 19
       sub  (iy+$4f)   ; fd 96 4f
       ld   ($5c8c),a    ; 32 8c 5c
       set  7,(iy+$01)   ; fd cb 01 fe
       ld   (iy+$0a),$01 ; fd 36 0a 01
       ld   hl,$3e00     ; 21 00 3e
       push hl           ; e5
       ld   hl,$5b1d     ; 21 1d 5b
       push hl           ; e5
       ld   ($5c3d),sp   ; ed 73 3d 5c
       ld   hl,$0321     ; 21 21 03
       ld   ($5b8b),hl   ; 22 8b 5b
       jp   L1838        ; c3 38 18
L0321  ld   sp,($5cb2)   ; ed 7b b2 5c
       inc  sp           ; 33
       ld   hl,$5bff     ; 21 ff 5b
       ld   ($5b81),hl   ; 22 81 5b
       halt              ; 76
       res  5,(iy+$01)   ; fd cb 01 ae
       ld   hl,$5b66     ; 21 66 5b
       bit  2,(hl)       ; cb 56
       jr   z,L034a      ; 28 12
       call L1f45        ; cd 45 1f
       ld   ix,($5b83)   ; SF_NEXT
       ld   bc,$0014     ; 01 14 00
       add  ix,bc        ; dd 09
       call L1d56        ; cd 56 1d
       call L1f20        ; cd 20 1f
L034a  ld   a,($5c3a)    ; 3a 3a 5c
       inc  a            ; 3c
L034e  push af           ; f5
       ld   hl,$0000     ; 21 00 00
       ld   (iy+$37),h   ; fd 74 37
       ld   (iy+$26),h   ; fd 74 26
       ld   ($5c0b),hl   ; 22 0b 5c
       ld   hl,$0001     ; 21 01 00
       ld   ($5c16),hl   ; 22 16 5c
       rst  28h          ; ef
       .word $16b0 ; SET-MIN  "Clears editing area and areas after it"
       res  5,(iy+$37)
       rst  28h          ; ef
       .word CLS_LOWER
       set  5,(iy+$02)   ; fd cb 02 ee
       pop  af           ; f1
       ld   b,a          ; 47
       cp   $0a          ; Is it a digit?
       jr   c,L037f      ; If so jump ahead to print it
       cp   $1d          ; Is it one of the old errors (A-R)?
       jr   c,L037d      ; If so jump ahead to add 7 and print
       add  a,$14        ; Otherwise add 20
       jr   L037f        ; and jump ahead to print
                         ; [Could have saved two bytes by having add $0c instead
                         ; of these two instructions]
L037d  add  a,$07        ;
L037f  rst  28h          ;
       .word $15ef       ; OUT-CODE
       ld   a,$20        ; Print a space
       rst  10h          ; 
       ld   a,b          ; Restore the error code
       cp   $1d          ; 
       jr   c,L039c      ; Old error message
       sub  $1d          ; 
       ld   b,$00        ;
       ld   c,a          ;
       ld   hl,L046c     ; start of new error messages
       add  hl,bc        ; 
       add  hl,bc        ; 
       ld   e,(hl)       ;
       inc  hl           ; get start of requested error
       ld   d,(hl)       ; message in DE
       call L057d        ; print error message
       jr   L03a2        ; jump ahead
L039c  ld   de,$1391     ; Position of the error messages in ROM 1
       rst  28h          ;
      .word $0c0a        ; PO-MSG, message printing
L03a2  xor  a            ; af
       ld   de,$1536     ; 11 36 15
       rst  28h          ; ef
      .word $0c0a        ; PO-MSG; print a comma followed by a space
       ld   bc,($5c45)   ; PPC, current line number
       rst  28h          ; ef
      .word $1a1b        ; OUT-NUM-1
       ld   a,$3a        ; ":"
       rst  10h          ;
       ld   c,(iy+$0d)   ; SUBPPC
       ld   b,$00        ;
       rst  28h          ;
      .word $1a1b        ; OUT-NUM-1
       rst  28h          ;
      .word $1097 ; CLEAR-SP  ; tidy up
       ld   a,($5c3a)    ; ERR NR
       inc  a
       jr   z,L03df      ; Jump ahead for 0 OK
       cp   $09          ; 
       jr   z,L03cc      ; Jump for A Invalid argument
       cp   $15          ; 
       jr   nz,L03cf     ; Jump unless M Ramtop no good
L03cc  inc  (iy+$0d)     ; SUBPPC
L03cf  ld   bc,$0003     ; 01 03 00
       ld   de,$5c70     ; 11 70 5c
       ld   hl,$5c44     ; 21 44 5c
       bit  7,(hl)       ; cb 7e
       jr   z,L03dd      ; 28 01
       add  hl,bc        ; 09
L03dd  lddr              ; ed b8
L03df  ld   (iy+$0a),$ff ; fd 36 0a ff
       res  3,(iy+$01)   ; fd cb 01 9e
       ld   hl,$5b66     ; 21 66 5b
       res  0,(hl)       ; cb 86
       jp   L25cb        ; c3 cb 25
L03ef  ld   a,$10        ; 3e 10
       ld   bc,$0000     ; 01 00 00
       jp   L034e        ; c3 4e 03
L03f7  ld   ($5c49),bc   ; ed 43 49 5c
       call L1f45        ; cd 45 1f
       ld   a,b          ; 78
       or   c            ; b1
       jr   z,L040a      ; 28 08
       ld   ($5c49),bc   ; ed 43 49 5c
       ld   ($ec08),bc   ; ed 43 08 ec
L040a  call L1f20        ; cd 20 1f
       ld   hl,($5c5d)   ; 2a 5d 5c
       ex   de,hl        ; eb
       ld   hl,$03ef     ; 21 ef 03
       push hl           ; e5
       ld   hl,($5c61)   ; 2a 61 5c
       scf               ; 37
       sbc  hl,de        ; ed 52
       push hl           ; e5
       ld   h,b          ; 60
       ld   l,c          ; 69
       rst  28h          ; ef
       .word $196e ; LINE-ADDR
       jr   nz,L0429     ; 20 06
       rst  28h          ; ef
       .word $19b8 ; NEXT-ONE
       rst  28h          ; ef
      .word $19e8 ; RECLAIM-2
L0429  pop  bc           ; c1
       ld   a,c          ; 79
       dec  a            ; 3d
       or   b            ; b0
       jr   nz,L0442     ; 20 13
       call L1f45        ; cd 45 1f
       push hl           ; e5
       ld   hl,($5c49)   ; 2a 49 5c
       call L334a        ; cd 4a 33
       ld   ($5c49),hl   ; 22 49 5c
       pop  hl           ; e1
       call L1f20        ; cd 20 1f
       jr   L046a        ; 18 28
L0442  push bc           ; c5
       inc  bc           ; 03
       inc  bc           ; 03
       inc  bc           ; 03
       inc  bc           ; 03
       dec  hl           ; 2b
       ld   de,($5c53)   ; ed 5b 53 5c
       push de           ; d5
       rst  28h          ; ef
       .word $1655 ; MAKE-ROOM
       pop hl
       ld   ($5c53),hl   ; 22 53 5c
       pop  bc           ; c1
       push bc           ; c5
       inc  de           ; 13
       ld   hl,($5c61)   ; 2a 61 5c
       dec  hl           ; 2b
       dec  hl           ; 2b
       lddr              ; ed b8
       ld   hl,($5c49)   ; 2a 49 5c
       ex   de,hl        ; eb
       pop  bc           ; c1
       ld   (hl),b       ; 70
       dec  hl           ; 2b
       ld   (hl),c       ; 71
       dec  hl           ; 2b
       ld   (hl),e       ; 73
       dec  hl           ; 2b
       ld   (hl),d       ; 72
L046a  pop  af           ; f1
       ret               ; c9


; Pointers into the new error message table
L046c .word $048c, $0497, $04a6, $04b0, $04c1
      .word $04d4, $04e0, $04e0, $04f3, $0501
      .word $0512, $0523, $0531, $0542, $054e, $0561

L048c .text "MERGE erro"
      .byte 'r'+$80
      .text "Wrong file typ"
      .byte 'e'+$80
      .text "CODE erro"
      .byte 'r'+$80
      .text "Too many bracket"
      .byte 's'+$80
      .text "File already exist"
      .byte 's'+$80
      .text "Invalid nam"
      .byte 'e'+$80
      .text "File does not exis"
      .byte 't'+$80
      .text "Invalid devic"
      .byte 'e'+$80
      .text "Invalid baud rat"
      .byte 'e'+$80
      .text "Invalid note nam"
      .byte 'e'+$80
      .text "Number too bi"
      .byte 'g'+$80
      .text "Note out of rang"
      .byte 'e'+$80
      .text "Out of rang"
      .byte 'e'+$80
      .text "Too many tied note"
      .byte 's'+$80
L0561 .byte $7f ; copyright sign
      .text " 1986 Sinclair Research Lt"
      .byte 'd'+$80

; Print a message which is terminated by having bit 7 set
L057d  ld   a,(de)       ;
       and  $7f          ;
       push de           ;
       rst  10h          ;
       pop  de           ;
       ld   a,(de)       ;
       inc  de           ;
       add  a,a          ;
       jr   nc,L057d     ;
       ret               ;

; 21-byte table used at 01dd (channel information)
L0589 .byte $f4,$09,$a8,$10,$4b,$f4,$09,$c4
      .byte $15,$53,$81,$0f,$c4,$15,$52,$34
      .byte $5b,$2f,$5b,$50,$80

; 14-byte table used at L0226 (stream information)
L059e .byte $01,$00,$06,$00,$0b,$00,$01,$00
      .byte $01,$00,$06,$00,$10,$00

; Cause error report
L05ac  pop  hl           ; e1
       ld   bc,$7ffd     ; 01 fd 7f
       xor  a            ; af
       di                ; f3
       ld   ($5b5c),a    ; 32 5c 5b
       out  (c),a        ; ed 79
       ei                ; fb
       ld   sp,($5c3d)   ; ed 7b 3d 5c
       ld   a,(hl)       ; 7e
       ld   ($5b5e),a    ; 32 5e 5b
       inc  a            ; 3c
       cp   $1e          ; fe 1e
       jr   nc,L05c8     ; 30 03
       rst  28h          ; ef
       .word $5b5d
L05c8  dec  a            ; 3d
       ld   (iy+$00),a   ; fd 77 00
       ld   hl,($5c5d)   ; 2a 5d 5c
       ld   ($5c5f),hl   ; 22 5f 5c
       rst  28h          ; ef
       .word $16c5 ; SET-STK
       ret

; Check for BREAK
L05d6  ld   a,$7f        ; 3e 7f
       in   a,($fe)      ; db fe
       rra               ; 1f
       ret  c            ; d8
       ld   a,$fe        ; 3e fe
       in   a,($fe)      ; db fe
       rra               ; 1f
       ret  c            ; d8
       call L05ac        ; cd ac 05
       .byte $14         ; "L Break into program"
L05e6  ei                ; fb
       ex   af,af'       ; 08
       ld   de,$5b4a     ; 11 4a 5b
       push de           ; d5
       res  3,(iy+$02)   ; fd cb 02 9e
       push hl           ; e5
       ld   hl,($5c3d)   ; ERR SP
       ld   e,(hl)       ;
       inc  hl           ;
       ld   d,(hl)       ; DE = current error address
       and  a            ;
       ld   hl,$107f     ; HL= ED-ERROR
       sbc  hl,de        ; 
       jr   nz,L0637     ; 
       pop  hl           ; 
       ld   sp,($5c3d)   ; 
       pop  de           ;
       pop  de           ;
       ld   ($5c3d),de   ;
L060a  push hl           ;
       ld   de,$0610     ; Address to return to
       push de           ; Stack address
       jp   (hl)         ; Jump to ... ?
L0610  jr   c,L061b      ; 38 09
       jr   z,L0618      ; 28 04
L0614  call L05ac        ; 
      .byte $07          ; "8 End of file"
L0618  pop  hl           ; e1
       jr   L060a        ; 18 ef
L061b  cp   $0d          ; fe 0d
       jr   z,L062d      ; 28 0e
       ld   hl,($5b5a)   ; 2a 5a 5b
       push hl           ; e5
       rst  28h          ; ef
       add  a,l          ; 85
       rrca              ; 0f
       pop  hl           ; e1
       ld   ($5b5a),hl   ; 22 5a 5b
       pop  hl           ; e1
       jr   L060a        ; 18 dd
L062d  pop  hl           ; e1
       ld   a,($5b5c)    ; 3a 5c 5b
       or   $10          ; f6 10
       push af           ; f5
       jp   $5b4a        ; c3 4a 5b
L0637  pop  hl           ; e1
       ld   de,$063d     ; Continuation address
       push de           ; Stack address
       jp   (hl)         ; 
L063d  ret  c            ;
       ret  z            ;
       jr   L0614        ; Report "8 End of file"

; FORMAT routine
L0641  rst  28h          ; [Could just RST 18]
       .word $0018
       rst  28h          ; Get an expression
       .word EXPT_EXP
       bit  7,(iy+$01)   ;
       jr   z,L0661      ; Jump ahead if syntax checking
       rst  28h          ;
       .word STK_FETCH
       ld   a,c          ;
       dec  a            ;
       or   b            ;
       jr   z,L0659      ; Jump ahead if string is 1 character long
       call L05ac        ; Otherwise, error
       .byte $24         ; "i Invalid device"
L0659  ld   a,(de)       ; Get character
       and  $df          ; Convert to upper case
       cp   $50          ; Is it channel "P"?
       jp   nz,L1912     ; Error "C Nonsense in BASIC" if not
L0661  ld   hl,($5c5d)   ; (CH ADD), next character
       ld   a,(hl)       ;
       cp   $3b          ; Next character must be ";"
       jp   nz,L1912     ; Otherwise error C
       rst  28h          ; Skip past the ; character
       .word $0020       ; [Could just do RST 20] 
       rst  28h          ; Get a numeric expression from the line
       .word $1c82       ; EXPT-1NUM
       bit  7,(iy+$01)   ; Jump ahead if syntax checking
       jr   z,L067d      ;
       rst  28h          ; Get the result as an integer
       .word $1e99       ; FIND-INT2
       ld   ($5b71),bc   ; Store the result in the system variables
L067d  rst  28h          ; [Could just do RST 18]
       .word $0018       ; Get the next character in the BASIC line;
       cp   $0d          ; should be ENTER...
       jr   z,L0689      ; 
       cp   $3a          ; or ":",
       jp   nz,L1912     ; otherwise error C
L0689  call L18a1        ; Check for end of line
       ld   bc,($5b71)   ; Get the baud rate
       ld   a,b          ; Is it zero?
       or   c            ;
       jr   nz,L0698     ;
       call L05ac        ; If so, then report error
       .byte $25         ; "j invalid baud rate"
L0698  ld   hl,L06b8     ; Table of known baud rates
L069b  ld   e,(hl)       ;
       inc  hl           ;
       ld   d,(hl)       ;
       inc  hl           ; 
       ex   de,hl        ; HL = known baud rate
       ld   a,h          ; If we have reached the last item in the table without
       cp   $25          ; using a baud rate, then use this one (9600)
       jr   nc,L06af     ; 
       and  a            ; 
       sbc  hl,bc        ; Use this baud rate?
       jr   nc,L06af     ;
       ex   de,hl        ;
       inc  hl           ; Skip past the internal value used
       inc  hl           ; for the baud rate
       jr   L069b        ;
L06af  ex   de,hl        ; HL points to internal representation 
       ld   e,(hl)       ; 
       inc  hl           ;
       ld   d,(hl)       ; DE holds internal representation (T states/26 according to +3 manual)
       ld   ($5b5f),de   ; Store new value in BAUD SYS_VAR
       ret               ; Finish

; BAUD_RATE_TABLE
L06b8 .word $0032,$0aa5
      .word $006e,$04d4
      .word $012c,$01c3
      .word $0258,$00e0
      .word $04b0,$006e
      .word $0960,$0036
      .word $12c0,$0019
      .word $2580,$000b

; RS232 input
L06d8  ld   hl,$5b61     ; hl= SERFL SYS_VAR  keeps second char that can be received
       ld   a,(hl)       ; Is the second-character received flag set,
       and  a            ; i.e. have we already received data?
       jr   z,L06e5      ; Jump ahead if not.
       ld   (hl),$00     ; Otherwise clear the flag
       inc  hl           ; 
       ld   a,(hl)       ; and return the data which we received earlier.
       scf               ; Set carry flag to indicate success
       ret               ; 


; BAUD system variable: 23391 ,$5b5f
; Value = (3500000/(25.7*BaudRate))-3
;REC-BYTE  routine that handles the receiving of a byte              
L06e5  call L05d6         ; Check for BREAK    
       di                
       exx               
       ld   de,($5b5f)   ;Get BAUD
       ld   hl,($5b5f)   
       srl  h            ;  0 -> 76543210 -> C  Halve the value 
       rr   l            ;  C -> 76543210 -> C 
                         ; HL=1/2 BAUD
       or   a            
       ld   b,$fa        ;waiting time for start bit
       exx               
       ld   c,$fd        
       ld   d,$ff        
       ld   e,$bf        
       ld   b,d          
       ld   a,$0e        
       out  (c),a        ;selects register 14, port I/O of AY
       in   a,(c)        
       or   $f0          ;%11110000
       and  $fb          ;%11111011
                         ;result=%1111x0xx  
       ld   b,e          
       out  (c),a        ; Make CTS (Clear To Send) 
       ld   h,a          
L070e  ld   b,d          
       in   a,(c)        
       and  $80           ;%10000000 ;bit 7- RS232 pin 5 (TXD in)
       jr   z,L071e       ;First test for START BIT - test if it's zero 
L0715  exx               
       dec  b            
       exx               
       jr   nz,L070e     
       xor  a            
       push af            ;(*) Save the zero failure flag 
       jr   L0757         ;  time out waiting for START BIT

L071e  in   a,(c)         ;2. Second test - test again to see if it's zero -  START BIT
       and  $80          
       jr   nz,L0715     
       in   a,(c)        
       and  $80          ;3. third test - test again to see if it's zero -  START BIT
       jr   nz,L0715     

  ; ---
  ;   The branch is executed when TXdata was high for 3 tests.

       exx               
       ld   bc,$fffd     
       ld   a,$80        ;A stays with START BIT  
       ex   af,af'       
L0731  add  hl,de        ; HL=BAUD +1/2 BAUD  
       nop               ; (4) timing value  
       nop               
       nop               
       nop   
;BD-DELAY             
L0736  dec  hl            ; ( 6) Delay for 26 * BAUD 
       ld   a,h           ; ( 4) 
       or   l             ; ( 4)  
       jr   nz,L0736      ; (12) back to BD-DELAY

       in   a,(c)          ; Read a BIT  
       and  $80          
       jp   z,L074b      
       ex   af,af'         ;received one 1
       scf                 ;set  carry  
       rra                 ; C->76543210->C  
       jr   c,L0754        ;When we reach START BIT it ends 
  
       ex   af,af'       
       jp   L0731        ;Go read next bit

L074b  ex   af,af'        ;received one 0
       or   a             ;clear carry
       rra                ; C->76543210->C  
       jr   c,L0754       ;When we reach START BIT it ends
       ex   af,af'       
       jp   L0731         ;Go read next bit

;   After looping eight times, the start bit will pass through and A will
;   contain a received byte.

L0754  scf               ; signal success.
       push af            ; (*) push success flag  
       exx               

 ;   The success and failure (TIME OUT START BIT) paths converge here 
L0757  ld   a,h          
       or   $04      

   ;result=%1111x1xx
    
       ld   b,e           ;e=$bf  
       out  (c),a         ;reset CTS line 
       exx               
       ld   h,d
       ld   l,e          ; HL = (BAUD)
       ld   bc,$0007
       or   a
       sbc  hl,bc        ; HL = (BAUD) - 7

L0766  dec  hl         ;Delay for stop bit
       ld   a,h
       or   l
       jr   nz,L0766
                        ;hl=0

       ld   bc,$fffd     
       add  hl,de        
       add  hl,de        
       add  hl,de        ;HL = 3 * BAUD  

;   The device at the other end of the cable may send a second byte even though
;   CTS is low. So now repeat the procedure to read another byte

L0771  in   a,(c)         ;test START BIT
       and  $80          
       jr   z,L077f      
       dec  hl           
       ld   a,h          
       or   l            
       jr   nz,L0771     
       pop  af            ; restore byte and flags
       ei                 ; (either 0 and NC or received byte and carry).
       ret               

L077f  in   a,(c)         ;performs again  3 tests to START BIT
       and  $80          
       jr   nz,L0771     
       in   a,(c)        
       and  $80          
       jr   nz,L0771     

;   A second byte is on its way and is received exactly as before.
       ld   h,d          
       ld   l,e          
       ld   bc,$0002     
       srl  h            
       rr   l            
       or   a            
       sbc  hl,bc        
       ld   bc,$fffd     
       ld   a,$80        
       ex   af,af'       
L079d  nop               
       nop               
       nop               
       nop               
       add  hl,de        
L07a2  dec  hl           
       ld   a,h          
       or   l            
       jr   nz,L07a2     
       in   a,(c)        
       and  $80          
       jp   z,L07b7      
       ex   af,af'       
       scf               
       rra               
       jr   c,L07c0      
       ex   af,af'       
       jp   L079d        
L07b7  ex   af,af'       
       or   a            
       rra               
       jr   c,L07c0      
       ex   af,af'       
       jp   L079d        
L07c0  ld   hl,$5b61      ; SERFL:   second char ;flag e data
       ld   (hl),$01     
       inc  hl           
       ld   (hl),a       
       pop  af           
       ei                
       ret               


; The following has something to do with the LPRINT CHR$ 16; CHR$ 1; "ABC" bug
; (getting here from 063C)
L07ca  push af           ; A = character to print
       ld   a,($5b65)    ; TVPARS, #parameters expected
       or   a            ;
       jr   z,L07e0      ;
       dec  a            ;
       ld   ($5b65),a    ;
       jr   nz,L07db     ; Jump ahead if we have not processed all parameters
       pop  af           ; 
       jp   L0872        ; Otherwise...
L07db  pop  af           ;
       ld   ($5c0f),a    ; TVDATA + 1
       ret               ;
L07e0  pop  af           ;
       cp   $a3          ; "SPECTRUM"
       jr   c,L07f2      ;
       ld   hl,($5b5a)   ; Save RETADDR temporarily
       push hl           ;
       rst  28h          ;
      .word $0b52 ; PO-T&UDG
       pop  hl           ;
       ld   ($5b5a),hl   ;
       scf               ;
       ret               ;
L07f2  ld   hl,$5c3b     ; FLAGS
       res  0,(hl)       ;
       cp   $20          ;
       jr   nz,L07fd     ;
       set  0,(hl)       ;
L07fd  cp   $7f          ;
       jr   c,L0803      ; 38 02
       ld   a,$3f        ; 3e 3f
L0803  cp   $20          ; fe 20
       jr   c,L081e      ; 38 17
L0807  push af           ; f5
       ld   hl,$5b63     ; COL, column number
       inc  (hl)         ; 34
       ld   a,($5b64)    ; WIDTH
       cp   (hl)         ; be
       jr   nc,L081a     ; 30 08
       call L0822        ; cd 22 08
       ld   a,$01        ; 3e 01
       ld   ($5b63),a    ; 32 63 5b
L081a  pop  af           ; f1
       jp   L08a3        ; c3 a3 08
L081e  cp   $0d          ; fe 0d
       jr   nz,L0830     ; 20 0e
L0822  xor  a            ; af
       ld   ($5b63),a    ; 32 63 5b
       ld   a,$0d        ; 3e 0d
       call L08a3        ; cd a3 08
       ld   a,$0a        ; 3e 0a
       jp   L08a3        ; c3 a3 08
L0830  cp   $06          ; fe 06
       jr   nz,L0853     ; 20 1f
       ld   bc,($5b63)   ; ed 4b 63 5b
       ld   e,$00        ; 1e 00
L083a  inc  e            ; 1c
       inc  c            ; 0c
       ld   a,c          ; 79
       cp   b            ; b8
       jr   z,L0848      ; 28 08
L0840  sub  $08        ; d6 08
       jr   z,L0848      ; 28 04
       jr   nc,L0840     ; 30 fa
       jr   L083a        ; 18 f2
L0848  push de           ; d5
       ld   a,$20        ; 3e 20
       call L07ca        ; cd ca 07
       pop  de           ; d1
       dec  e            ; 1d
       ret  z            ; c8
       jr   L0848        ; 18 f5
L0853  cp   $16          ; AT
       jr   z,L0860      ; 
       cp   $17          ; TAB
       jr   z,L0860      ;
       cp   $10          ; fe 10
       ret  c            ; d8
       jr   L0869        ; 18 09
L0860  ld   ($5c0e),a    ; 32 0e 5c
       ld   a,$02        ; 3e 02
       ld   ($5b65),a    ; TV_PARS
       ret               ; c9
L0869  ld   ($5c0e),a    ;
       ld   a,$02        ; Should be 1
       ld   ($5b65),a    ; 
       ret               ; 

L0872  ld   d,a          ; D = character to print
       ld   a,($5c0e)    ; TV DATA
       cp   $16          ;
       jr   z,L0882      ; 
       cp   $17          ;
       ccf               ;
       ret  nz           ;
       ld   a,($5c0f)    ; TV DATA + 1
       ld   d,a          ;
L0882  ld   a,($5b64)    ; WIDTH
       cp   d            ; ba
       jr   z,L088a      ; 28 02
       jr   nc,L0890     ; 30 06
L088a  ld   b,a          ; 47
       ld   a,d          ; 7a
       sub  b            ; 90
       ld   d,a          ; 57
       jr   L0882        ; 18 f2
L0890  ld   a,d          ; 7a
       or   a            ; b7
       jp   z,L0822      ; ca 22 08
L0895  ld   a,($5b63)    ; 3a 63 5b
       cp   d            ; ba
       ret  z            ; c8
       push de           ; d5
       ld   a,$20        ; 3e 20
       call L07ca        ; cd ca 07
       pop  de           ; d1
       jr   L0895        ; 18 f2

; Talk to printer ;OUTPUT SERVICE   RS232
L08a3  push af           ;A=value to send

       ld   c,$fd        
       ld   d,$ff       

       ld   e,$bf        
       ld   b,d          ;FFFD = Address of the
       ld   a,$0e        ;command register  do AY
       out  (c),a        ;chose reg 14 do AY <=> porta I/O
                        

L08af  call L05d6         ; Check for BREAK

       in   a,(c)         ;Read  status of data register 
       and  $40           ; test DTR - %01000000   
       jr   nz,L08af     

       ld   hl,($5b5f)   ;HL = SYS_VAR BAUD
       ld   de,$0002     
       or   a            
       sbc  hl,de        
       ex   de,hl        ;DE=BAUD-2
       pop  af           
       cpl                ; Invert the bits in the character. (RS232 logic is inverted)
       scf                ;Carry is used to send START BIT
       ld   b,$0b         ;B= bits= 1 start + 8 data + 2 stop
       di    

;SEND BITS RS232            
L08c8  push bc           
       push af           
       ld   a,$fe        
       ld   h,d          
       ld   l,e          
L08ce  ld   bc,$bffd     ;AY data register
       jp   nc,L08da     ;jp nc,Send_one

;Send_zero   
       and  $f7          
       out  (c),a        
       jr   L08e0     

;Send_one   
L08da  or   $08          
       out  (c),a        
       jr   L08e0    ;??????

;Delay Loop BD-DEL     Wait 26 * BAUD cycles
L08e0  dec  hl         ; ( 6)  
       ld   a,h        ; ( 4)  
       or   l          ; ( 4)  
       jr   nz,L08e0   ; (12)
       nop               
       nop               
       nop               
       pop  af           
       pop  bc           
       or   a           ;clear carry      
       rra              ;C->7xxxxxx0->C 
       djnz L08c8       ;loops B bits 
       ei                
       ret               

; COPY routine (continuation)
L08f0  ld   hl,$5b72     ; 21 72 5b
       ld   (hl),$2b     ; 36 2b
L08f5  ld   hl,L0979     ; Point to data table
       call L095f        ; Send data to printer (?)
       call L0915        ; cd 15 09
       ld   hl,$0980     ; Point to data table
       call L095f        ; Send data to printer (?)
       ld   hl,$5b72     ; 21 72 5b
       xor  a            ; af
       cp   (hl)         ; be
       jr   z,L090e      ; 28 03
       dec  (hl)         ; 35
       jr   L08f5        ; 18 e7
L090e  ld   hl,L0982     ; 21 82 09
       call L095f        ; cd 5f 09
       ret               ; c9

L0915  ld   hl,$5b71     ; 21 71 5b
       ld   (hl),$ff     ; 36 ff
L091a  call L0926        ; cd 26 09
       ld   hl,$5b71     ; 21 71 5b
       xor  a            ; af
       cp   (hl)         ; be
       ret  z            ; c8
       dec  (hl)         ; 35
       jr   L091a        ; 18 f4

L0926  ld   de,$c000     ; 11 00 c0
       ld   bc,($5b71)   ; ed 4b 71 5b
       scf               ; 37
       rl   b            ; cb 10
       scf               ; 37
       rl   b            ; cb 10
       ld   a,c          ; 79
       cpl               ; 2f
       ld   c,a          ; 4f
       xor  a            ; af
       push af           ; f5
       push de           ; d5
       push bc           ; c5
L093a  call L096d        ; Test whether pixel (B,C) is set
       pop  bc           ; c1
       pop  de           ; d1
       ld   e,$00        ; 1e 00
       jr   z,L0944      ; 28 01
       ld   e,d          ; 5a
L0944  pop  af           ; f1
       or   e            ; b3
       push af           ; f5
       dec  b            ; 05
       srl  d            ; cb 3a
       srl  d            ; cb 3a
       push de           ; d5
       push bc           ; c5
       jr   nc,L093a     ; 30 ea
       pop  bc           ; c1
       pop  de           ; d1
       pop  af           ; f1
       ld   b,$03        ; 06 03
L0955  push bc           ; c5
       push af           ; f5
       call L08a3        ; cd a3 08
       pop  af           ; f1
       pop  bc           ; c1
       djnz L0955        ; 10 f7
       ret               ; c9

L095f  ld   b,(hl)       ; Get number of bytes
       inc  hl           ; 
L0961  ld   a,(hl)       ; Retrieve value
       push hl           ; 
       push bc           ; 
       call L08a3        ; Send to printer?
       pop  bc           ; c1
       pop  hl           ; e1
       inc  hl           ; 23
       djnz L0961        ; 10 f5
       ret               ; c9

; Test whether the pixel (B,C) is set or not
; If the pixel is reset, returns with A=0
; If the pixel is set, returns with A>0
;   (actually the value of the bit corresponding to the pixel within the byte)
L096d  rst  28h          ; Get address of (B,C) pixel into HL/A
       .word $22aa ; PIXEL-ADDR
       ld   b,a          ; B=pixel position within byte (0-7)
       inc  b            ;
       xor  a            ; 
       scf               ; Set bit to be rotated into A
L0974  rra               ; Rotate...
       djnz L0974        ; ... and repeat
       and  (hl)         ; Isolate this pixel from A
       ret               ;

; Some data used in COPY
L0979 .byte $06,$1b,$31,$1b,$4c,$00,$03
; Some more data
L0980 .byte $01,$0a
; A bit more data
L0982  .byte $02,$1b,$32

; ** THE PLAY SUBROUTINES **

; Reserve and intialise space for PLAY data. B = the number of strings
; in the PLAY command. There is a block of $003c bytes allocated (IY
; points to this) plus $0037 bytes for each string used
; (IX is used to point to the current channel).
;

; IY data block:
; (IY+$00, IY+$01) points to data for channel 0
; (IY+$02, IY+$03) points to data for channel 1
; ...
; (IY+$10) gets initialised to 0ffh and RLed for each string;
; i.e. it ends up with the least-significant 'n' bits reset
; if there are n strings provided to the PLAY command
; ...
; (IY+$27;$28) holds the tempo
; (IY+$29) effect value
; (IY+$2B...$37) (for 13d bytes) gets initialised to values from L0a31

; When referring to a channel, the following values are used:
; (ix+$01) = MIDI channel
; (ix+$02) = index of string within PLAY command
; (ix+$03) = 12 * current octave number
; (ix+$04) = current volume
; (ix+$06,$07) = current position in string
; (ix+$08,$09) = 1 after end position
; (ix+$0a) = flags (only lowest bit used?)
; (ix+$0b) = current bracket nesting level
; (ix+$0e,$0f) = stored bracket return positions
; (ix+$10,$11) = stored bracket return positions
; (ix+$12,$13) = stored bracket return positions
; (ix+$14,$15) = stored bracket return positions
; (ix+$16) = ??? initialised to FF
; (ix+$17) = ??? initialised to 00
; (ix+$18) = ??? initialised to 00
; ... ?
; (ix+$21) = counter of tied notes

L0985  di
       push bc
       ld   de,$0037     ; Calculate HL = $003C + $0037 * B
       ld   hl,$003c     ;
L098d  add  hl,de        ;
       djnz L098d        ;
       ld   c,l          ;
       ld   b,h          ; BC = space required
       rst  28h          ; 
       .word $0030       ; Make BC bytes of space in the workspace.
       di                ;
       push de           ; 
       pop  iy           ; IY = first new byte
       push hl           ; 
       pop  ix           ; IX = last new byte
       ld   (iy+$10),$ff ; Initial value meaning 'zero strings'

; Loop over each string to be played
L09a0  ld   bc,$ffc9     ; $-37
       add  ix,bc        ; IX points to start of space for last channel
       ld   (ix+$03),$3c ; Default octave is 4
       ld   (ix+$01),$ff ;
       ld   (ix+$04),$0f ; Default volume is 15
       ld   (ix+$05),$05 ;
       ld   (ix+$21),$00 ;
       ld   (ix+$0a),$00 ;
       ld   (ix+$0b),$00 ; Initial bracket nesting level
       ld   (ix+$16),$ff ;
       ld   (ix+$17),$00 ;
       ld   (ix+$18),$00 ;
       rst  28h          ; Get the details of the string from the stack
       .word STK_FETCH
       di                ;
       ld   (ix+$06),e   ; Store the start of the string as
       ld   (ix+$07),d   ; the current position
       ld   (ix+$0c),e   ;
       ld   (ix+$0d),d   ;
       ex   de,hl        ;
       add  hl,bc        ;
       ld   (ix+$08),l   ; Store the address of the character just
       ld   (ix+$09),h   ; after the string
       pop  bc           ; Restore B=current string index
       push bc           ; and save it again
       dec  b            ;
       ld   c,b          ;
       ld   b,$00        ; 
       sla  c            ; BC=string index*2
       push iy           ;
       pop  hl           ; 
       add  hl,bc        ; HL 
       push ix           ;
       pop  bc           ; BC=pointer to data for this channel
       ld   (hl),c       ; Store point
       inc  hl           ;
       ld   (hl),b       ;
       or   a            ;
       rl   (iy+$10)     ; Rotate one zero-bit into the least significant bit of
                         ; (iy+$10). Once this loop is over, this byte is one
                         ; zero bit for each string parameter to the PLAY command.
       pop  bc           ; Restore B=current string index
       dec  b            ; Decrement string index
       push bc           ; and save it for future use
       ld   (ix+$02),b   ; Set index of string
       jr   nz,L09a0     ; Jump back while more channels
       pop  bc           ; 
L0a05  ld   (iy+$27),$1a ; Initialise tempo
       ld   (iy+$28),$0b ;
       push iy           ;
       pop  hl           ; 
       ld   bc,$002b     ; 
       add  hl,bc        ; 
       ex   de,hl        ; DE=main data area + $2b bytes
       ld   hl,L0a31     ; data area in ROM
       ld   bc,$000d     ;
       ldir              ; Copy 13 bytes
       ld   d,$07        ; Set sound chip register 07 to $f8
       ld   e,$f8        ; ("Mixer")
       call L0e7c        ; 
       ld   d,$0b        ; Set register $0b to $ff
       ld   e,$ff        ; ("Envelope fine duration")
       call L0e7c        ;
       inc  d            ; Set register $0c to $ff
       call L0e7c        ; ("Envelope coarse duration")
       jr   L0a7d        ; Jump forwards

; 13 bytes of data (initial PLAY data)
L0a31 .byte $ef,$a4,$01,$05,$34,$df,$75,$f4
      .byte $38,$75,$05,$38,$c9

; Test for BREAK (returns with carry clear if BREAK is pressed)
L0a3e  ld   a,$7f        ;
       in   a,($fe)      ;
       rra               ;
       ret  c            ; Return with C set if SPACE not pressed
       ld   a,$fe        ;
       in   a,($fe)      ; 
       rra               ;
       ret               ; Return with C set if CAPS not pressed

L0a4a  ld   bc,$0011     ; 01 11 00
       jr   L0a52        ; 18 03

; Set up some PLAY data ??
L0a4f  ld   bc,$0000     ; 01 00 00
L0a52  push iy           ; fd e5
       pop  hl           ; e1
       add  hl,bc        ; 09
       ld   (iy+$23),l   ; fd 75 23
       ld   (iy+$24),h   ; fd 74 24
       ld   a,(iy+$10)   ; fd 7e 10
       ld   (iy+$22),a   ; fd 77 22
       ld   (iy+$21),$01 ; fd 36 21 01
       ret               ; c9

; Get IX (channel data pointer) from the bytes at (HL, HL+1)
L0a67  ld   e,(hl)       ;
       inc  hl           ;
       ld   d,(hl)       ;
       push de           ;
       pop  ix           ;
       ret               ;

; Increase the pointer at (iy+$23;iy+$24) by two
; (??? What is this pointer?)
L0a6e  ld   l,(iy+$23)   ; fd 6e 23
       ld   h,(iy+$24)   ; fd 66 24
       inc  hl           ; 23
       inc  hl           ; 23
       ld   (iy+$23),l   ; fd 75 23
       ld   (iy+$24),h   ; fd 74 24
       ret               ; c9

; Continuation of the PLAY code
L0a7d  call L0a4f        ; Set up some data (leaves with HL=IY)
L0a80  rr   (iy+$22)     ; fd cb 22 1e
       jr   c,L0a8c      ; 38 06
       call L0a67        ; Get IX from (HL;HL+1)
       call L0b5c        ; Process the PLAY string for this channel
L0a8c  sla  (iy+$21)     ; fd cb 21 26
       jr   c,L0a97      ; 38 05
       call L0a6e        ; cd 6e 0a
       jr   L0a80        ; 18 e9
L0a97  call L0f91        ; cd 91 0f
       push de           ; d5
       call L0f42        ; cd 42 0f
       pop  de           ; d1
L0a9f  ld   a,(iy+$10)   ; 
       cp   $ff          ; $ff means nothing to PLAY
       jr   nz,L0aab     ; 20 05
       call L0e93        ; cd 93 0e
       ei                ; fb
       ret               ; c9
L0aab  dec  de           ; 1b
       call L0f76        ; cd 76 0f
       call L0fc1        ; cd c1 0f
       call L0f91        ; cd 91 0f
       jr   L0a9f        ; 18 e8

; Recognised characters in PLAY commands
L0ab7  .text "HZYXWUVMT)(NO!"

; Get the current character from the PLAY string and increment the pointer
L0ac5  call L0ee3        ; Get the current character
       ret  c            ; Return if error condition
       inc  (ix+$06)     ; Increment the low byte of the pointer
       ret  nz           ;
       inc  (ix+$07)     ; ... and the high byte if necessary
       ret               ;

; Return A=number of semitones above C for the next note in the string,
; or A=$80 for a rest
L0ad1  push hl           ; Save HL
       ld   c,$00        ; Default is for a 'natural' note; ie no adjustment
L0ad4  call L0ac5        ; Get the current character from the PLAY string
       jr   c,L0ae1      ; Jump if error condition
       cp   $26          ; "&" (rest)
       jr   nz,L0aec     ; Jump ahead if not
       ld   a,$80        ;
L0adf  pop  hl           ; Restore HL
       ret               ; and return
L0ae1  ld   a,(iy+$21)   ; fd 7e 21
       or   (iy+$10)     ; fd b6 10
       ld   (iy+$10),a   ; fd 77 10
       jr   L0adf        ; 18 f3
L0aec  cp   $23          ; "#" (sharpen)
       jr   nz,L0af3     ;
       inc  c            ; +1 semitone
       jr   L0ad4        ;
L0af3  cp   $24          ; "$" (flatten)
       jr   nz,L0afa     ;
       dec  c            ; -1 semitone
       jr   L0ad4        ;
L0afa  bit  5,a          ;
       jr   nz,L0b04     ; Jump ahead if lower case
       push af           ; 
       ld   a,$0c        ; Increase A by an octave
       add  a,c          ; by adding 12 semitones to C
       ld   c,a          ;
       pop  af           ;
L0b04  and  $df          ; Make sure upper-case
       sub  $41          ; Convert "A" -> 0, "G"->6
       jp   c,L0f22      ; jump if error
       cp   $07          ; 
       jp   nc,L0f22     ; jump if error
       push bc           ; 
       ld   b,$00        ; 
       ld   c,a          ; BC represents the note, 0="a", 6="g"
       ld   hl,L0df9     ; Lookup table
       add  hl,bc        ; HL=pointer to look up table
       ld   a,(hl)       ; Get A=number of semitones above the note C
       pop  bc           ; Restore BC
       add  a,c          ; Adjust for sharp/flat
       pop  hl           ; Restore HL
       ret               ; 

; Get a numeric value from a PLAY string into BC
L0b1d  push hl           ;
       push de           ;
       ld   l,(ix+$06)   ; Get the pointer into
       ld   h,(ix+$07)   ; the PLAY string
       ld   de,$0000     ; Initialise result to 0
L0b28  ld   a,(hl)       ;
       cp   $30          ; Is character numeric?
       jr   c,L0b45      ; 
       cp   $3a          ;
       jr   nc,L0b45     ;
       inc  hl           ; Got a numeric digit
       push hl           ;
       call L0b50        ; Multiply result so far by 10
       sub  $30          ; Convert ASCII digit to numeric value
       ld   h,$00        ; 
       ld   l,a          ; 
       add  hl,de        ; Increase result so far by the value
       jr   c,L0b42      ; Error on overflow
       ex   de,hl        ; Result into DE
       pop  hl           ; Retrieve pointer into string
       jr   L0b28        ; Loop back

L0b42  jp   L0f1a        ; Jump to generate error "l number too big"

L0b45  ld   (ix+$06),l   ; Update pointer into
       ld   (ix+$07),h   ; PLAY string
       push de           ; Result into BC
       pop  bc           ; 
       pop  de           ; Restore DE, HL
       pop  hl           ;
       ret               ;

; Multiply DE by 10
L0b50  ld   hl,$0000     ; Do HL=10*DE
       ld   b,$0a        ;
L0b55  add  hl,de        ;
       jr   c,L0b42      ; Error if overflow
       djnz L0b55        ;
       ex   de,hl        ; Result into DE
       ret               ; 

L0b5c  call L0a3e        ; Test for BREAK
       jr   c,L0b69      ; Jump ahead if not pressed
       call L0e93        ; Reset sound registers
       ei                ; 
       call L05ac        ; Generate error
       .byte $14         ; "L Break into program"
L0b69  call L0ac5        ; get next character from PLAY string
       jp   c,L0da2      ; jump if error
       call L0df0        ; Test for a recognised PLAY control character
       ld   b,$00        ;
       sla  c            ; Double the return value
       ld   hl,L0dca     ; Start of lookup table
       add  hl,bc        ; HL points to address for this commmand code
       ld   e,(hl)       ; 
       inc  hl           ;
       ld   d,(hl)       ;
       ex   de,hl        ; HL holds address for this command code
       call L0b84        ; Call this code
       jr   L0b5c        ; Loop back
       ret               ; Finish
L0b84  jp   (hl)         ;

; "!" (comment) command for PLAY
L0b85  call L0ac5        ; get next character from PLAY string
       jp   c,L0da1      ; error condition
       cp   $21          ; "!", end-of-comment character
       ret  z            ;
       jr   L0b85        ;

; "O" (octave) command for PLAY
L0b90  call L0b1d        ; Get a numeric value from the string
       ld   a,c          ; There is no check on the high value
       cp   $09          ; of the value, so O256 works
       jp   nc,L0f12     ; Error for 9 and above
       sla  a            ; Multiply A by 12
       sla  a            ;
       ld   b,a          ;
       sla  a            ;
       add  a,b          ;
       ld   (ix+$03),a   ; ... and store it
       ret               ;

; "N" (separator) command for PLAY
L0ba5  ret               ; Nothing to do

; "(" command for PLAY
L0ba6  ld   a,(ix+$0b)   ; Current level of bracket nesting
       inc  a            ;
       cp   $05          ;
       jp   z,L0f2a      ; "Too many brackets" error
       ld   (ix+$0b),a   ; Store new nesting level
       ld   de,$000c     ;
       call L0c27        ; Fetch HL = IX + L000C + 2*A
       ld   a,(ix+$06)   ; Store current position
       ld   (hl),a       ;
       inc  hl           ;
       ld   a,(ix+$07)   ;
       ld   (hl),a       ;
       ret               ;

; ")" command for PLAY
L0bc2  ld   a,(ix+$16)   ; dd 7e 16
       ld   de,$0017     ; 11 17 00
       or   a            ; b7
       jp   m,L0bf0      ; jump if negative (80..ff)
       call L0c27        ; Fetch HL = IX + L0017 + 2*A
       ld   a,(ix+$06)   ; Current position (low byte)
       cp   (hl)         ; 
       jr   nz,L0bf0     ;
       inc  hl           ;
       ld   a,(ix+$07)   ; Current position (high byte)
       cp   (hl)         ; be
       jr   nz,L0bf0     ; 20 14
       dec  (ix+$16)     ; dd 35 16
       ld   a,(ix+$16)   ; dd 7e 16
       or   a            ; b7
       ret  p            ; f0
       bit  0,(ix+$0a)   ; dd cb 0a 46
       ret  z            ; c8
       ld   (ix+$16),$00 ; dd 36 16 00
       xor  a            ; af
       jr   L0c0b        ; 18 1b
L0bf0  ld   a,(ix+$16)   ; dd 7e 16
       inc  a            ; 3c
       cp   $05          ; fe 05
       jp   z,L0f2a      ; "d too many brackets"
       ld   (ix+$16),a   ; dd 77 16
       call L0c27        ; cd 27 0c
       ld   a,(ix+$06)   ; dd 7e 06
       ld   (hl),a       ; 77
       inc  hl           ; 23
       ld   a,(ix+$07)   ; dd 7e 07
       ld   (hl),a       ; 77
       ld   a,(ix+$0b)   ; Level of bracket nesting
L0c0b  ld   de,$000c     ;
       call L0c27        ; HL = IX + L000c + 2*A
       ld   a,(hl)       ; Retrieve low byte of stored position
       ld   (ix+$06),a   ; and set the current position
       inc  hl           ; 
       ld   a,(hl)       ; Same for the high byte
       ld   (ix+$07),a   ;
       dec  (ix+$0b)     ; Decrement level of bracket nesting
       ret  p            ; f0
       ld   (ix+$0b),$00 ; dd 36 0b 00
       set  0,(ix+$0a)   ; dd cb 0a c6
       ret               ; c9

; Get HL = IX + DE + 2*A
L0c27  push ix           ; dd e5
       pop  hl           ; e1
       add  hl,de        ; 19
       ld   b,$00        ; 06 00
       ld   c,a          ; 4f
       sla  c            ; cb 21
       add  hl,bc        ; 09
       ret               ; c9

; "T" (tempo) command for PLAY
L0c32  call L0b1d        ; Get numeric value into BC
       ld   a,b          ;
       or   a            ;
       jp   nz,L0f12     ; Error if 256 or above
       ld   a,c          ; 
       cp   $3c          ;
       jp   c,L0f12      ; Error if 59 or below
       cp   $f1          ; 
       jp   nc,L0f12     ; Jump if 241 or above
       ld   a,(ix+$02)   ; Index of current string
       or   a            ; 
       ret  nz           ; T commands have to be specified in string 0
       ld   b,$00        ; [B is already zero]
       push bc           ;
       pop  hl           ;
       add  hl,hl        ;
       add  hl,hl        ; HL = tempo * 4
       push hl           ;
       pop  bc           ; BC = tempo * 4
       push iy           ;
       rst  28h          ;
       .word $2d2b       ; STACK-BC
       di                ;
       pop  iy           ; 
       push iy           ;
       push iy           ;
       pop  hl           ; HL = IY
       ld   bc,$002b     ;
       add  hl,bc        ; HL = IY + $002B
       ld   iy,$5c3a     ; Restore IY
       push hl           ; 
       ld   hl,L0c76     ;
       ld   ($5b5a),hl   ; RETADDR
       ld   hl,$5b14     ;
       ex   (sp),hl      ;
       push hl           ;
       jp   $5b00        ; Eh?
L0c76  di                ;
       rst  28h          ;
       .word $2da2       ; FP-TO-BC
       di                ;
       pop  iy           ;
       ld   (iy+$27),c   ; Store tempo
L0c80  ld   (iy+$28),b   ;
       ret               ;

; "M" (channel) command for play
L0c84  call L0b1d        ; Get numeric value into BC
       ld   a,c          ; A=(low byte of) value
       cp   $40          ;
       jp   nc,L0f12     ; Error n out of range
       cpl               ;
       ld   e,a          ;
       ld   d,$07        ; Register 7
       call L0e7c        ; Value E
       ret               ;

; V command for PLAY
L0c95  call L0b1d        ; Get numeric value
       ld   a,c          ;
       cp   $10          ; Test against 16
       jp   nc,L0f12     ; Error for 16 and above
       ld   (ix+$04),a   ; Store volume
       ld   e,(ix+$02)   ; Get index of string
       ld   a,$08        ;
       add  a,e          ; A = number of string + 8
       ld   d,a          ; D = register to write to
       ld   e,c          ; E = value to write = volume
       call L0e7c        ; set register
       ret               ;

; "U" (use volume effect) command for PLAY
L0cad  ld   e,(ix+$02)   ; Get index of string
       ld   a,$08        ;
       add  a,e          ;
       ld   d,a          ; Register (8+index)
       ld   e,$1f        ;
       ld   (ix+$04),e   ; Store volume of 15
       ret               ;

; "W" (volume effect specifier) command for PLAY
L0cba  call L0b1d        ; Get numeric value into BC
       ld   a,c          ; (Discard high byte)
       cp   $08          ;
       jp   nc,L0f12     ; Error n out of range
       ld   b,$00        ; 
       ld   hl,L0de8     ; Lookup table
       add  hl,bc        ; HL points to the value in the table
       ld   a,(hl)       ;
       ld   (iy+$29),a   ; Store new effect value
       ret               ;

; "X" (duration of volume effect) command for PLAY
L0cce  call L0b1d        ; Get numeric value into BC
       ld   d,$0b        ;
       ld   e,c          ;
       call L0e7c        ; Set register 0B to the low byte of the value
       inc  d            ;
       ld   e,b          ;
       call L0e7c        ; Set register 0C to the high byte of the value
       ret               ;

; "Y" (MIDI channel) command for PLAY
L0cdd  call L0b1d        ; Get numeric parameter
       ld   a,c          ;
       dec  a            ; (No check on high byte)
       jp   m,L0f12      ; Error
       cp   $10          ; 
       jp   nc,L0f12     ; Error
       ld   (ix+$01),a   ; Store MIDI channel
       ret               ;

; "Z" (MIDI programming code) command for PLAY
L0cee  call L0b1d        ; Get numeric value
       ld   a,c          ; A=(low byte of) value
       call L11a3        ;
       ret               ;

; "H" (stop) command for PLAY
L0cf6  ld   (iy+$10),$ff ; Indicate 'nothing left to play'
       ret               ;

; any other command for PLAY (a..g, A..G, 1..12, &, _)
L0cfb  call L0e19        ; Test for digit
       jp   c,L0d81      ; Jump if not digit
       call L0dac        ; Get HL = IX + L0022
       call L0db4        ; Store HL
       xor  a            ;
       ld   (ix+$21),a   ;
       call L0ec8        ; Get the previous character
       call L0b1d        ; Get numeric value
       ld   a,c          ;
       or   a            ;
       jp   z,L0f12      ; Error if zero
       cp   $0d          ; 
       jp   nc,L0f12     ; Error if 13 or above
       cp   $0a          ; 
       jr   c,L0d32      ; Jump if 1..9
       call L0e00        ; Otherwise it's a triplet semi-quaver (10),
                         ; triplet quaver (11) or triplet crotchet (12).
                         ; Look up length (into DE) from table
       call L0d74        ; Increment the counter of tied notes
       ld   (hl),e       ; Store the duration value
       inc  hl           ; into (IX+$22, IX+$23)
       ld   (hl),d       ; 
L0d28  call L0d74        ; Increment the counter of tied notes
       inc  hl           ; 
       ld   (hl),e       ; 73
       inc  hl           ; 23
       ld   (hl),d       ; 72
       inc  hl           ; 23
       jr   L0d38        ; Jump ahead

L0d32  ld   (ix+$05),c   ; C=1..9 for the duration of note
       call L0e00        ; DE=duration of this note (from lookup table)

L0d38  call L0d74        ; Increment counter of tied notes
L0d3b  call L0ee3        ; Get character from this PLAY string
       cp   $5f          ; Is it "_" (indicating a tied note)?
       jr   nz,L0d6e     ; Jump ahead if not
       call L0ac5        ; Get next character from the PLAY string
       call L0b1d        ; then get numeric value
       ld   a,c          ; Fetch the value into A
       cp   $0a          ; Compare with 10d
       jr   c,L0d5f      ; Jump ahead for 1..9 (semiquaver .. semibreve)
L0d4d  push hl           ; e5
       push de           ; d5
       call L0e00        ; cd 00 0e
       pop  hl           ; e1
       add  hl,de        ; 19
       ld   c,e          ; 4b
       ld   b,d          ; 42
       ex   de,hl        ; eb
       pop  hl           ; e1
       ld   (hl),e       ; 73
       inc  hl           ; 23
       ld   (hl),d       ; 72
       ld   e,c          ; 59
       ld   d,b          ; 50
       jr   L0d28        ; 18 c9
L0d5f  ld   (ix+$05),c   ; dd 71 05
       push hl           ; e5
       push de           ; d5
       call L0e00        ; cd 00 0e
       pop  hl           ; e1
       add  hl,de        ; 19
       ex   de,hl        ; eb
       pop  hl           ; e1
L0d6b  jp   L0d3b        ; c3 3b 0d
L0d6e  ld   (hl),e       ; 73
       inc  hl           ; 23
       ld   (hl),d       ; 72
       jp   L0d9c        ; c3 9c 0d

L0d74  ld   a,(ix+$21)   ; Increment counter of tied notes
       inc  a            ;
       cp   $0b          ;
       jp   z,L0f3a      ; Error "o too many tied notes" 
       ld   (ix+$21),a   ; Store incremented counter
       ret               ;

L0d81  call L0ec8        ; Get the previous character from the string
       ld   (ix+$21),$01 ; 
       call L0dac        ; Get HL=IX+L0022
       call L0db4        ; Store HL
       ld   c,(ix+$05)   ; C = ?
       push hl           ; [Not necessary]
       call L0e00        ; Look up the C'th element of a table
       pop  hl           ; [Not necessary]
       ld   (hl),e       ; 73
       inc  hl           ; 23
       ld   (hl),d       ; 72
       jp   L0d9c        ; c3 9c 0d

L0d9c  pop  hl           ;
       inc  hl           ; 
       inc  hl           ;
       push hl           ;
       ret               ;

; error
L0da1  pop  hl           ; e1
L0da2  ld   a,(iy+$21)   ; fd 7e 21
       or   (iy+$10)     ; fd b6 10
       ld   (iy+$10),a   ; fd 77 10
       ret               ; c9

; GET HL = IX+$0022 (point to information for next PLAY parameter)
L0dac  push ix           ; dd e5
       pop  hl           ; e1
       ld   bc,$0022     ; 01 22 00
       add  hl,bc        ; 09
       ret               ; c9

; Store HL in (IY + $0011 + 2 * (IX+$02))
L0db4  push hl           ; e5
       push iy           ; fd e5
       pop  hl           ; e1
       ld   bc,$0011     ; 01 11 00
       add  hl,bc        ; 09
       ld   b,$00        ; 06 00
       ld   c,(ix+$02)   ; = index of string
       sla  c            ; cb 21
       add  hl,bc        ; HL = IY + $0011 + 2 * (IX+$02)
       pop  de           ; d1
       ld   (hl),e       ; 73
       inc  hl           ; 23
       ld   (hl),d       ; 72
       ex   de,hl        ; eb
       ret               ; c9

; Addresses for PLAY commands
L0dca .word L0cfb, L0b85, L0b90, L0ba5   ;   ! O N
      .word L0ba6, L0bc2, L0c32, L0c84   ; ( ) T M
      .word L0c95, L0cad, L0cba, L0cce   ; V U W X
      .word L0cdd, L0cee, L0cf6          ; Y Z H

; Lookup table when using the "W" command in PLAY
L0de8  .byte $00,$04,$0b,$0d
       .byte $08,$0c,$0e,$0a

; Test for command characters in PLAY
L0df0  ld   bc,$000f     ; Number of characters in lookup table
       ld   hl,L0ab7     ; Start of lookup table
       cpir              ; Test for character
       ret               ; 

; Data table for PLAY
; Each entry is equivalent to a note of the scale, A...G
; and is the number of semitones above (the note) C
L0df9  .byte $09, $0b, $00, $02, $04, $05, $07

; Get the C'th entry in the table from 0E0C into E
L0e00  push hl           ;
       ld   b,$00        ;
       ld   hl,$0e0c     ;
       add  hl,bc        ;
       ld   d,$00        ;
       ld   e,(hl)       ;
       pop  hl           ;
       ret               ;

L0e0c .byte $80,$06,$09,$0c,$12,$18,$24,$30
      .byte $48,$60,$04,$08,$10

; Test for a digit; returns with C flag false for a digit
L0e19  cp   $30          ; '0' or less?
       ret  c
       cp   $3a          ; More than '9'?
       ccf               ; 
       ret               ;

; Play the note A at the current octave
; (A = 0 corresponds to C; A=2 corresponds to D etc.)
L0e20  ld   c,a          ;
       ld   a,(ix+$03)   ; Octave number * 12
       add  a,c          ;
       cp   $80          ; fe 80
       jp   nc,L0f32     ; d2 32 0f
       ld   c,a          ; C = note value
       ld   a,(ix+$02)   ; dd 7e 02
       or   a            ; b7
       jr   nz,L0e3f     ; 20 0e
       ld   a,c          ; 79
       cpl               ; 2f
       and  $7f          ; e6 7f
       srl  a            ; cb 3f
       srl  a            ; cb 3f
       ld   d,$06        ; 16 06
       ld   e,a          ; 5f
       call L0e7c        ; 
L0e3f  ld   (ix+$00),c   ; dd 71 00
       ld   a,(ix+$02)   ; dd 7e 02
       cp   $03          ; fe 03
       ret  nc           ; d0
       ld   hl,$1096     ; Start of lookup table
       ld   b,$00        ; 
       ld   a,c          ; 
       sub  $15        ; 
       jr   nc,L0e57     ; 
       ld   de,$0fbf     ; If 0..$14, use values 0f,bf [the lowest note]
       jr   L0e5e        ;
L0e57  ld   c,a          ; If $15+...
       sla  c            ; 
       add  hl,bc        ; Lookup DE from 1096 + 2 * C
       ld   e,(hl)       ;
       inc  hl           ;
       ld   d,(hl)       ;
L0e5e  ex   de,hl        ; HL = value looked up
       ld   d,(ix+$02)   ; index of string in PLAY command
       sla  d            ; D = 2 * index
       ld   e,l          ; E = 1st byte looked up
       call L0e7c        ; Set register D to value E
       inc  d            ; Next register
       ld   e,h          ; 2nd byte looked up
       call L0e7c        ; Set register D to value E
       bit  4,(ix+$04)   ; dd cb 04 66
       ret  z            ;
       ld   d,$0d        ; Register 13
       ld   a,(iy+$29)   ; Effect value
       ld   e,a          ; 
       call L0e7c        ; Set register
       ret               ;

; Set sound chip register D to value E
L0e7c  push bc           ; 
       ld   bc,$fffd     ;
       out  (c),d        ;
       ld   bc,$bffd     ;
       out  (c),e        ;
       pop  bc           ;
       ret               ;

L0e89  push bc           ; c5
       ld   bc,$fffd     ; 01 fd ff
       out  (c),a        ; ed 79
       in   a,(c)        ; ed 78
       pop  bc           ; c1
       ret               ; c9

; Set sound chip register 7 to FF and 8,9,10 to 0
; (resets the registers to their default state)
L0e93  ld   d,$07        ; 16 07
       ld   e,$ff        ; 1e ff
       call L0e7c        ; cd 7c 0e
       ld   d,$08        ; 16 08
       ld   e,$00        ; 1e 00
       call L0e7c        ; cd 7c 0e
       inc  d            ; 14
       call L0e7c        ; cd 7c 0e
       inc  d            ; 14
       call L0e7c        ; cd 7c 0e
       call L0a4f        ; cd 4f 0a
L0eac  rr   (iy+$22)     ; fd cb 22 1e
       jr   c,L0eb8      ; 38 06
       call L0a67        ; cd 67 0a
       call L118d        ; cd 8d 11
L0eb8  sla  (iy+$21)     ; fd cb 21 26
       jr   c,L0ec3      ; 38 05
       call L0a6e        ; cd 6e 0a
       jr   L0eac        ; 18 e9
L0ec3  ld   iy,$5c3a     ; fd 21 3a 5c
       ret               ; c9

; Get the previous character from the PLAY string (excluding SPACE/ENTER)
L0ec8  push hl           ;
       push de           ;
       ld   l,(ix+$06)   ; HL points to PLAY string
       ld   h,(ix+$07)   ; 
L0ed0  dec  hl           ; Point to previous character
       ld   a,(hl)       ; 
       cp   $20          ;
       jr   z,L0ed0      ; Back again if SPACE...
       cp   $0d          ; 
       jr   z,L0ed0      ; ... or ENTER
       ld   (ix+$06),l   ; Store decremented pointer
       ld   (ix+$07),h   ;
       pop  de           ;
       pop  hl           ;
       ret               ;

; Get the current character from the PLAY string (skipping SPACE and ENTER)
L0ee3  push hl           ;
       push de           ;
       push bc           ;
       ld   l,(ix+$06)   ; Get pointer to PLAY string
       ld   h,(ix+$07)   ;
L0eec  ld   a,h          ;
       cp   (ix+$09)     ; Reached end-of-string high byte?
       jr   nz,L0efb     ; 
       ld   a,l          ;
       cp   (ix+$08)     ; Reached end-of-string low byte?
       jr   nz,L0efb     ; 
       scf               ; Indicate error
       jr   L0f05        ; 
L0efb  ld   a,(hl)       ; Get character
       cp   $20          ;
       jr   z,L0f09      ; Jump ahead to get next character for SPACE...
       cp   $0d          ;
       jr   z,L0f09      ; ... or for an ENTER character
       or   a            ; Otherwise with Z reset
                         ;  (apart from CHR$ 0)
L0f05  pop  bc           ;
       pop  de           ;
       pop  hl           ;
       ret               ;

L0f09  inc  hl           ; 23
       ld   (ix+$06),l   ; dd 75 06
       ld   (ix+$07),h   ; dd 74 07
       jr   L0eec        ; 18 da

L0f12  call L0e93        ; Reset sound registers
       ei                ; 
       call L05ac        ; Generate error
       .byte $29         ; "n Out of range"

L0f1a  call L0e93        ; Reset sound chip registers
       ei                ;
       call L05ac        ; Generate error
       .byte $27         ; "l Number too big"

L0f22  call L0e93        ; Reset sound registers
       ei                ;
       call L05ac        ; Generate error
       .byte $26         ; "k Invalid note name"

L0f2a  call L0e93        ; Reset sound registers
       ei                ;
       call L05ac        ; Generate error
       .byte $1f         ; "d Too many brackets" 

L0f32  call L0e93        ; Reset sound registers
       ei                ;
       call L05ac        ; Generate error
       .byte $28         ; "m Note out of range"

L0f3a  call L0e93        ; Reset sound registers
       ei                ;
       call L05ac        ; Generate error
       .byte $2a         ; "o Too many tied notes"

L0f42  call L0a4f        ; ??
L0f45  rr   (iy+$22)     ; fd cb 22 1e
       jr   c,L0f6c      ; 38 21
       call L0a67        ; cd 67 0a
       call L0ad1        ; Get the next note in the string
       cp   $80          ; Is it a rest?
       jr   z,L0f6c      ; Jump ahead if so
       call L0e20        ; Otherwise play the note
       ld   a,(ix+$02)   ; Get string index (channel)
       cp   $03          ; Only set volume for channels 0-2
       jr   nc,L0f69     ;
       ld   d,$08        ; Find register number
       add  a,d          ;
       ld   d,a          ; D = register = 8 + string index
       ld   e,(ix+$04)   ; Current volume
       call L0e7c        ; Output volume control
L0f69  call L116e        ; cd 6e 11
L0f6c  sla  (iy+$21)     ; fd cb 21 26
       ret  c            ; d8
       call L0a6e        ; cd 6e 0a
       jr   L0f45        ; 18 cf

; Wait (during the PLAY command). The duration of the \
; pause is based on the current tempo and the \
; value in DE.
L0f76  push hl           ; Save HL
       ld   l,(iy+$27)   ; Get tempo
       ld   h,(iy+$28)   ; 
       ld   bc,$0064     ; BC=100d
       or   a            ;
       sbc  hl,bc        ; HL=tempo-100d
       push hl           ;
       pop  bc           ; BC=tempo-100d
       pop  hl           ; Restore HL
L0f86  dec  bc           ; Wait for 'tempo-100' loops
       ld   a,b          ;
       or   c            ;
       jr   nz,L0f86     ;
       dec  de           ; Repeat 'DE' times
       ld   a,d          ;
       or   e            ;
       jr   nz,L0f76     ;
       ret               ;

L0f91  ld   de,$ffff     ; 11 ff ff
       call L0a4a        ; cd 4a 0a
L0f97  rr   (iy+$22)     ; fd cb 22 1e
       jr   c,L0faf      ; 38 12
       push de           ; d5
       ld   e,(hl)       ; 5e
       inc  hl           ; 23
       ld   d,(hl)       ; 56
       ex   de,hl        ; eb
       ld   e,(hl)       ; 5e
       inc  hl           ; 23
       ld   d,(hl)       ; 56
       push de           ; d5
       pop  hl           ; e1
       pop  bc           ; c1
       or   a            ; b7
       sbc  hl,bc        ; ed 42
       jr   c,L0faf      ; 38 02
       push bc           ; c5
       pop  de           ; d1
L0faf  sla  (iy+$21)     ; fd cb 21 26
       jr   c,L0fba      ; 38 05
       call L0a6e        ; cd 6e 0a
       jr   L0f97        ; 18 dd
L0fba  ld   (iy+$25),e   ; fd 73 25
       ld   (iy+$26),d   ; fd 72 26
       ret               ; c9

L0fc1  xor  a            ; af
       ld   (iy+$2a),a   ; fd 77 2a
       call L0a4f        ; cd 4f 0a
L0fc8  rr   (iy+$22)     ; fd cb 22 1e
       jp   c,L105a      ; da 5a 10
       call L0a67        ; cd 67 0a
       push iy           ; fd e5
       pop  hl           ; e1
       ld   bc,$0011     ; 01 11 00
       add  hl,bc        ; 09
       ld   b,$00        ; 06 00
       ld   c,(ix+$02)   ; dd 4e 02
       sla  c            ; cb 21
       add  hl,bc        ; 09
       ld   e,(hl)       ; 5e
       inc  hl           ; 23
       ld   d,(hl)       ; 56
       ex   de,hl        ; eb
       push hl           ; e5
       ld   e,(hl)       ; 5e
       inc  hl           ; 23
       ld   d,(hl)       ; 56
       ex   de,hl        ; eb
       ld   e,(iy+$25)   ; fd 5e 25
       ld   d,(iy+$26)   ; fd 56 26
       or   a            ; b7
       sbc  hl,de        ; ed 52
       ex   de,hl        ; eb
       pop  hl           ; e1
       jr   z,L0ffc      ; 28 05
       ld   (hl),e       ; 73
       inc  hl           ; 23
       ld   (hl),d       ; 72
       jr   L105a        ; 18 5e
L0ffc  ld   a,(ix+$02)   ; dd 7e 02
       cp   $03          ; fe 03
       jr   nc,L100c     ; 30 09
       ld   d,$08        ; 16 08
       add  a,d          ; 82
       ld   d,a          ; 57
       ld   e,$00        ; 1e 00
       call L0e7c        ; cd 7c 0e
L100c  call L118d        ; cd 8d 11
       push ix           ; dd e5
       pop  hl           ; e1
       ld   bc,$0021     ; 01 21 00
       add  hl,bc        ; 09
       dec  (hl)         ; 35
       jr   nz,L1026     ; 20 0d
       call L0b5c        ; cd 5c 0b
       ld   a,(iy+$21)   ; fd 7e 21
       and  (iy+$10)     ; fd a6 10
       jr   nz,L105a     ; 20 36
       jr   L103d        ; 18 17
L1026  push iy           ; fd e5
       pop  hl           ; e1
       ld   bc,$0011     ; 01 11 00
       add  hl,bc        ; 09
       ld   b,$00        ; 06 00
       ld   c,(ix+$02)   ; dd 4e 02
       sla  c            ; cb 21
       add  hl,bc        ; 09
       ld   e,(hl)       ; 5e
       inc  hl           ; 23
       ld   d,(hl)       ; 56
       inc  de           ; 13
       inc  de           ; 13
       ld   (hl),d       ; 72
       dec  hl           ; 2b
       ld   (hl),e       ; 73
L103d  call L0ad1        ; cd d1 0a
       ld   c,a          ; 4f
       ld   a,(iy+$21)   ; fd 7e 21
       and  (iy+$10)     ; fd a6 10
       jr   nz,L105a     ; 20 11
       ld   a,c          ; 79
       cp   $80          ; fe 80
       jr   z,L105a      ; 28 0c
       call L0e20        ; cd 20 0e
       ld   a,(iy+$21)   ; fd 7e 21
       or   (iy+$2a)     ; fd b6 2a
       ld   (iy+$2a),a   ; fd 77 2a
L105a  sla  (iy+$21)     ; fd cb 21 26
       jr   c,L1066      ; 38 06
       call L0a6e        ; cd 6e 0a
       jp   L0fc8        ; c3 c8 0f
L1066  ld   de,$0001     ; 11 01 00
       call L0f76        ; cd 76 0f
       call L0a4f        ; cd 4f 0a
L106f  rr   (iy+$2a)     ; fd cb 2a 1e
       jr   nc,L108c     ; 30 17
       call L0a67        ; cd 67 0a
       ld   a,(ix+$02)   ; String index (channel)
       cp   $03          ; Only set volume
       jr   nc,L1089     ;  for channels 0-2
L107f  ld   d,$08        ; Get register number
       add  a,d          ;  = 8 + channel
       ld   d,a          ; 
       ld   e,(ix+$04)   ; Current volume
       call L0e7c        ; Set register
L1089  call L116e        ; cd 6e 11
L108c  sla  (iy+$21)     ; fd cb 21 26
       ret  c            ; d8
       call L0a6e        ; cd 6e 0a
       jr   L106f        ; 18 d9

; Lookup table for PLAY; each pair of bytes gives the values of the
; registers for a given note
L1096 .byte $bf,$0f,$dc,$0e,$07,$0e,$3d,$0d,$7f,$0c,$cc,$0b,$22,$0b,$82,$0a
      .byte $eb,$09,$5d,$09,$d6,$08,$57,$08,$df,$07,$6e,$07,$03,$07,$9f,$06
      .byte $40,$06,$e6,$05,$91,$05,$41,$05,$f6,$04,$ae,$04,$6b,$04,$2c,$04
      .byte $f0,$03,$b7,$03,$82,$03,$4f,$03,$20,$03,$f3,$02,$c8,$02,$a1,$02
      .byte $7b,$02,$57,$02,$36,$02,$16,$02,$f8,$01,$dc,$01,$c1,$01,$a8,$01
      .byte $90,$01,$79,$01,$64,$01,$50,$01,$3d,$01,$2c,$01,$1b,$01,$0b,$01
      .byte $fc,$00,$ee,$00,$e0,$00,$d4,$00,$c8,$00,$bd,$00,$b2,$00,$a8,$00
      .byte $9f,$00,$96,$00,$8d,$00,$85,$00,$7e,$00,$77,$00,$70,$00,$6a,$00
      .byte $64,$00,$5e,$00,$59,$00,$54,$00,$4f,$00,$4b,$00,$47,$00,$43,$00
      .byte $3f,$00,$3b,$00,$38,$00,$35,$00,$32,$00,$2f,$00,$2d,$00,$2a,$00
      .byte $28,$00,$25,$00,$23,$00,$21,$00,$1f,$00,$1e,$00,$1c,$00,$1a,$00
      .byte $19,$00,$18,$00,$16,$00,$15,$00,$14,$00,$13,$00,$12,$00,$11,$00
      .byte $10,$00,$0f,$00,$0e,$00,$0d,$00,$0c,$00,$0c,$00,$0b,$00,$0b,$00
      .byte $0a,$00,$09,$00,$09,$00,$08,$00

L116e  ld   a,(ix+$01)   ; dd 7e 01
       or   a            ; b7
       ret  m            ; f8
       or   $90          ; f6 90
       call L11a3        ; cd a3 11
       ld   a,(ix+$00)   ; dd 7e 00
       call L11a3        ; cd a3 11
       ld   a,(ix+$04)   ; dd 7e 04
       res  4,a          ; cb a7
       sla  a            ; cb 27
       sla  a            ; cb 27
       sla  a            ; cb 27
       call L11a3        ; cd a3 11
       ret               ; c9

L118d  ld   a,(ix+$01)   ; dd 7e 01
       or   a            ; b7
       ret  m            ; f8
       or   $80          ; f6 80
       call L11a3        ; cd a3 11
       ld   a,(ix+$00)   ; dd 7e 00
       call L11a3        ; cd a3 11
       ld   a,$40        ; 3e 40
       call L11a3        ; cd a3 11
       ret               ; c9

L11a3  ld   l,a          ; 6f
       ld   bc,$fffd     ; 01 fd ff
       ld   a,$0e        ; 3e 0e
       out  (c),a        ; ed 79
       ld   bc,$bffd     ; 01 fd bf
       ld   a,$fa        ; 3e fa
       out  (c),a        ; ed 79
       ld   e,$03        ; 1e 03
L11b4  dec  e            ; 1d
       jr   nz,L11b4     ; 20 fd
       nop               ; 00
       nop               ; 00
       nop               ; 00
       nop               ; 00
       ld   a,l          ; 7d
       ld   d,$08        ; 16 08
L11be  rra               ; 1f
       ld   l,a          ; 6f
       jp   nc,L11c9     ; d2 c9 11
       ld   a,$fe        ; 3e fe
       out  (c),a        ; ed 79
       jr   L11cf        ; 18 06
L11c9  ld   a,$fa        ; 3e fa
       out  (c),a        ; ed 79
       jr   L11cf        ; 18 00
L11cf  ld   e,$02        ; 1e 02
L11d1  dec  e            ; 1d
       jr   nz,L11d1     ; 20 fd
       nop               ; 00
       add  a,$00        ; c6 00
       ld   a,l          ; 7d
       dec  d            ; 15
       jr   nz,L11be     ; 20 e3
       nop               ; 00
       nop               ; 00
       add  a,$00        ; c6 00
       nop               ; 00
       nop               ; 00
       ld   a,$fe        ; 3e fe
       out  (c),a        ; ed 79
       ld   e,$06        ; 1e 06
L11e7  dec  e            ; 1d
       jr   nz,L11e7     ; 20 fd
       ret               ; c9

; ** THE TAPE AND RAMDISK OPERATIONS **

; SAVE
L11eb  ld   hl,$5b66
       set  5,(hl)       ; Indicate SAVE
       jr   L1205

; LOAD
L11f2  ld   hl,$5b66
       set  4,(hl)       ; Indicate LOAD
       jr   L1205

; VERIFY
L11f9  ld   hl,$5b66
       set  7,(hl)       ; Indicate VERIFY
       jr   L1205

; MERGE
L1200  ld   hl,$5b66
       set  6,(hl)       ; Indicate MERGE

L1205  ld   hl,$5b66     ; 
       res  3,(hl)       ; Reset RAMdisk flag
       rst  18h          ; Get current character
       cp   $21          ; "!"
       jp   nz,L13be     ;
       ld   hl,$5b66     ; 
       set  3,(hl)       ; Set RAMdisk flag
       rst  20h          ; Move on to next character
       jp   L13be        ;

L1219  call L05ac        ;
       .byte $0b         ; "C Nonsense in BASIC"

; RAMDisk operation.
; The information relating to the file is copied into memory in 5B66... \
; to ensure that it is available once other RAM pages are switched in
L121d  ld   ($5b74),hl   ;
       ld   a,(ix+$00)   ; File type
       ld   ($5b71),a    ;
       ld   l,(ix+$0b)   ; HL=length
       ld   h,(ix+$0c)   ; 
       ld   ($5b72),hl   ;
       ld   l,(ix+$0d)   ; HL=start address
       ld   h,(ix+$0e)   ; 
L1235  ld   ($5b78),hl   ;
       ld   l,(ix+$0f)   ;
       ld   h,(ix+$10)   ;
       ld   ($5b76),hl   ;
       or   a            ; Test file type
       jr   z,L124e      ; Jump ahead for a BASIC file
       cp   $03          ; 
       jr   z,L124e      ; Jump ahead for a CODE file
       ld   a,(ix+$0e)   ;
       ld   ($5b76),a    ;
L124e  push ix           ; IX points to file header
       pop  hl           ; Retrieve into HL
       inc  hl           ; HL points to filename
       ld   de,$5b67     ; Copy to 5B67
       ld   bc,$000a     ;
       ldir              ;
       ld   hl,$5b66     ;
       bit  5,(hl)       ; Set for SAVE
       jp   nz,L1bad     ; Jump ahead if SAVE
       ld   hl,$5b71     ; Copy the expected details to 5b7a
       ld   de,$5b7a     ;
       ld   bc,$0007     ;
       ldir              ;
       call L1c2e        ; Load header to 5b71
       ld   a,($5b7a)    ; Check that file types match
       ld   b,a          ;
       ld   a,($5b71)    ;
       cp   b            ;
       jr   nz,L1280     ; Error b if not
       cp   $03          ; Check for type 3 (CODE)
       jr   z,L1290      ;
       jr   c,L1284      ; Only file types 00-02 are OK
L1280  call L05ac        ;
       .byte $1d         ; "b Wrong file type"
L1284  ld   a,($5b66)    ; 
       bit  6,a          ; Set for MERGE
       jr   nz,L12c5     ; Jump for MERGE
       bit  7,a          ; Set for VERIFY
       jp   z,L12db      ; 
L1290  ld   a,($5b66)    ; Flags
       bit  6,a          ; Set for MERGE
       jr   z,L129b      ; Jump if not MERGE
       call L05ac        ;
       .byte $1c         ; "a MERGE error"
L129b  ld   hl,($5b7b)   ; Length requested
       ld   de,($5b72)   ; Length of actual file (don't know when this was set up?)
       ld   a,h          ;
       or   l            ;
       jr   z,L12ae      ; Jump ahead if requested length is 0 (= not specified?)
       sbc  hl,de        ;
       jr   nc,L12ae     ; Jump ahead if requested length is OK
       call L05ac        ;
       .byte $1e         ; "c CODE error"
L12ae  ld   hl,($5b7d)
       ld   a,h          ; 7c
       or   l            ; b5
       jr   nz,L12b8     ; 20 03
       ld   hl,($5b74)   ; 2a 74 5b
L12b8  ld   a,($5b71)    ; 3a 71 5b
       and  a            ; a7
       jr   nz,L12c1     ; 20 03
       ld   hl,($5c53)   ; 2a 53 5c
L12c1  call L137e        ; cd 7e 13
       ret               ; c9
L12c5  ld   bc,($5b72)   ; ed 4b 72 5b
       push bc           ; c5
       inc  bc           ; 03
       rst  28h          ; ef
       .word $0030
       ld   (hl),$80     ; 36 80
       ex   de,hl        ; eb
       pop  de           ; d1
       push hl           ; e5
       call L137e        ; cd 7e 13
       pop  hl           ; e1
       rst  28h          ; ef
       .word $08ce ; ME-CONTRL + ?
       ret               ; c9

L12db  ld   de,($5b72)   ; DE = length
       ld   hl,($5b7d)   ; 2a 7d 5b
       push hl           ; e5
       ld   a,h          ; 7c
       or   l            ; b5
       jr   nz,L12ed     ; 20 06
       inc  de           ; 13
       inc  de           ; 13
       inc  de           ; 13
       ex   de,hl        ; eb
       jr   L12f6        ; 18 09
L12ed  ld   hl,($5b7b)   ; 2a 7b 5b
       ex   de,hl        ; eb
       scf               ; 37
       sbc  hl,de        ; ed 52
       jr   c,L12ff      ; 38 09
L12f6  ld   de,$0005     ; 11 05 00
       add  hl,de        ; 19
       ld   b,h          ; 44
       ld   c,l          ; 4d
       rst  28h          ; ef
       .word $1f05 ; TEST-ROOM
L12ff  pop  hl           ; e1
       ld   a,($5b71)    ; 3a 71 5b
L1303  and  a            ; a7
       jr   z,L1335      ; 28 2f
       ld   a,h          ; 7c
       or   l            ; b5
       jr   z,L1315      ; 28 0b
       dec  hl           ; 2b
       ld   b,(hl)       ; 46
       dec  hl           ; 2b
       ld   c,(hl)       ; 4e
       dec  hl           ; 2b
       inc  bc           ; 03
       inc  bc           ; 03
       inc  bc           ; 03
       rst  28h          ; ef
       .word $19e8 ; RECLAIM-2
L1315  ld   hl,($5c59)   ; 2a 59 5c
       dec  hl           ; 2b
       ld   bc,($5b72)   ; ed 4b 72 5b
       push bc           ; c5
       inc  bc           ; 03
       inc  bc           ; 03
       inc  bc           ; 03
       ld   a,($5b7f)    ; 3a 7f 5b
       push af           ; f5
       rst  28h          ; ef
       .word $1655 ; MAKE-ROOM
       inc hl
       pop  af           ; f1
       ld   (hl),a       ; 77
       pop  de           ; d1
       inc  hl           ; 23
       ld   (hl),e       ; 73
       inc  hl           ; 23
       ld   (hl),d       ; 72
       inc  hl           ; 23
L1331  call L137e        ; cd 7e 13
       ret               ; c9
L1335  ld   hl,$5b66     ; 21 66 5b
       res  1,(hl)       ; cb 8e
       ld   de,($5c53)   ; ed 5b 53 5c
       ld   hl,($5c59)   ; 2a 59 5c
       dec  hl           ; 2b
       rst  28h          ; ef
       .word $19e5 ; RECLAIM
       ld   bc,($5b72)   ; ed 4b 72 5b
       ld   hl,($5c53)   ; 2a 53 5c
       rst  28h          ; ef
       .word $1655 ; MAKE-ROOM
       inc hl
       ld   bc,($5b76)   ; ed 4b 76 5b
       add  hl,bc        ; 09
       ld   ($5c4b),hl   ; 22 4b 5c
       ld   a,($5b79)    ; 3a 79 5b
       ld   h,a          ; 67
       and  $c0          ; e6 c0
       jr   nz,L1370     ; 20 10
       ld   a,($5b78)    ; 3a 78 5b
       ld   l,a          ; 6f
       ld   ($5c42),hl   ; 22 42 5c
       ld   (iy+$0a),$00 ; fd 36 0a 00
       ld   hl,$5b66     ; 21 66 5b
       set  1,(hl)       ; cb ce
L1370  ld   hl,($5c53)   ; 2a 53 5c
       ld   de,($5b72)   ; ed 5b 72 5b
       dec  hl           ; 2b
       ld   ($5c57),hl   ; 22 57 5c
       inc  hl           ; 23
       jr   L1331        ; 18 b3
L137e  ld   a,d          ; 7a
       or   e            ; b3
       ret  z            ; c8
       call L1c4b        ; Load bytes
       ret               ; c9

L1385  rst  28h          ; Expecting an expression on the BASIC line
       .word EXPT_EXP
       bit  7,(iy+$01)   ; Return early if syntax-checking
       ret  z            ;
       push af           ; Get the item off the calculator stack
       rst  28h          ; 
       .word STK_FETCH
       pop  af           ; 
       ret               ;

; Called to check a filename for validity and to copy it into a buffer
; starting at 5B67
L1393  rst  20h          ; Advance the pointer into the BASIC line
       call L1385        ; Get expression from BASIC line
       ret  z            ; Return if syntax checking
       push af           ; 
       ld   a,c          ; Check for zero length
       or   b            ;
       jr   z,L13ba      ; Error f if so
       ld   hl,$000a     ; Check for length &gt; 10
       sbc  hl,bc        ; 
       jr   c,L13ba      ; Error f if so
       push de           ; Stack the filename start...
       push bc           ; ... and length
       ld   hl,$5b67     ; HL points to where we will store the filename
       ld   b,$0a        ; Fill it with 10 spaces
       ld   a,$20        ;
L13ad  ld   (hl),a       ;
       inc  hl           ;
       djnz L13ad        ;
       pop  bc           ; Restore filename length...
       pop  hl           ; ... and start
       ld   de,$5b67     ; DE points to where we will store the filename
       ldir              ; Perform the copy
       pop  af           ; Restore flags
       ret               ; 

L13ba  call L05ac        ; cd ac 05
      .byte $21          ; "f Invalid name"

; SAVE, LOAD, MERGE, VERIFY
L13be  rst 28h
       .word EXPT_EXP
       bit  7,(iy+$01)   ;
       jr   z,L1407      ; Jump ahead if checking syntax
       ld   bc,$0011     ; Size of header, 17d bytes
       ld   a,($5c74)    ; Effectively the BASIC command
       and  a            ; Is it SAVE?
       jr   z,L13d2      ; Jump ahead if so
       ld   c,$22        ; Otherwise need 34d bytes
L13d2  rst  28h          ;
       .word $0030       ; Create memory in workspace
       push de           ; Get start of the created memory into IX
       pop  ix           ; 
       ld   b,$0b        ; Clear the filename
       ld   a,$20        ; ' '
L13dc  ld   (de),a       ; 
       inc  de           ;
       djnz L13dc        ;
       ld   (ix+$01),$ff ;
       rst  28h          ; Get value from calculator stack
       .word STK_FETCH
       ld   hl,$fff6     ; = -10
       dec  bc           ; 0b
       add  hl,bc        ; 09
       inc  bc           ; 03
       jr   nc,L1400     ; 30 11
       ld   a,($5c74)    ; Indicates which BASIC command
       and  a            ; Is it SAVE?
       jr   nz,L13f9     ; Jump ahead if not
       call L05ac        ; Error report
       .byte $0e         ; "F Invalid filename"
L13f9  ld   a,b
       or   c            ; b1
       jr   z,L1407      ; 28 0a
       ld   bc,$000a     ; 01 0a 00
L1400  push ix           ; dd e5
       pop  hl           ; e1
       inc  hl           ; 23
       ex   de,hl        ; eb
       ldir              ; ed b0
L1407  rst  18h          ; Get character from BASIC line
       cp   $e4          ; "DATA"
       jr   nz,L145f     ; Jump if not DATA
       ld   a,($5c74)    ; Check the BASIC command
       cp   $03          ; Is it MERGE?
       jp   z,L1219      ; "C Nonsense in BASIC" if so
       rst  20h          ; Get next character from BASIC line
       rst  28h          ;
       .word $28b2       ; LOOK_VARS
       jr nc,L142f
       ld   hl,$0000     ; 21 00 00
       bit  6,(iy+$01)   ; fd cb 01 76
       jr   z,L1425      ; 28 02
       set  7,c          ; cb f9
L1425  ld   a,($5c74)    ; 3a 74 5c
       dec  a            ; 3d
       jr   z,L1444      ; 28 19
       call L05ac        ; Error report
       .byte $01          ; "2 Variable not found"

L142f  jp   nz,L1219     ; "C Nonsense in BASIC"
       bit  7,(iy+$01)   ; fd cb 01 7e
       jr   z,L1451      ; 28 19
       ld   c,(hl)       ; 4e
       inc  hl           ; 23
       ld   a,(hl)       ; 7e
       ld   (ix+$0b),a   ; dd 77 0b
       inc  hl           ; 23
       ld   a,(hl)       ; 7e
       ld   (ix+$0c),a   ; dd 77 0c
       inc  hl           ; 23
L1444  ld   (ix+$0e),c   ; dd 71 0e
       ld   a,$01        ; 3e 01
       bit  6,c          ; cb 71
       jr   z,L144e      ; 28 01
       inc  a            ; 3c
L144e  ld   (ix+$00),a   ; dd 77 00
L1451  ex   de,hl        ; eb
       rst  20h          ; e7
       cp   $29          ; fe 29
       jr   nz,L142f     ; 20 d8
       rst  20h          ; e7
       call L18a1        ; cd a1 18
       ex   de,hl        ; eb
       jp   L1519        ; c3 19 15
L145f  cp   $aa          ; 'SCREEN$' ?
       jr   nz,L1482     ; Jump ahead if not
       ld   a,($5c74)    ; Check the BASIC command
       cp   $03          ; Is it MERGE?
       jp   z,L1219      ; "C Nonsense in BASIC" if so
       rst  20h          ; Advance pointer into BASIC line
       call L18a1        ; Ensure end of statement 
       ld   (ix+$0b),$00 ; Set up length...
       ld   (ix+$0c),$1b ; 
       ld   hl,$4000     ; ... and start of CODE block
       ld   (ix+$0d),l   ;
       ld   (ix+$0e),h   ;
       jr   L14cf        ;
L1482  cp   $af          ; 'CODE'?
       jr   nz,L14d5     ; Jump ahead if not
       ld   a,($5c74)    ; Check the BASIC command
       cp   $03          ; Is it MERGE?
       jp   z,L1219      ; "C Nonsense in BASIC" if so
       rst  20h          ;
       rst  28h          ;
       .word $2048       ; PR-ST-END
       jr   nz,L14a0
       ld   a,($5c74)    ; 3a 74 5c
       and  a            ; a7
       jp   z,L1219      ; "C Nonsense in BASIC"
       rst  28h          ; ef
       .word $1ce6       ; USE-ZERO
       jr   L14af        ; 18 0f
L14a0  rst  28h          ; ef
       .word $1c82       ; EXPT-1NUM
       rst  18h          ; df
       cp   $2c          ; fe 2c
       jr   z,L14b4      ; 28 0c
       ld   a,($5c74)    ; 3a 74 5c
       and  a            ; a7
       jp   z,L1219      ; "C Nonsense in BASIC"
L14af  rst  28h          ; ef
       .word $1ce6 ; USE-ZERO
       jr   L14b8        ; 18 04
L14b4  rst  20h          ; e7
       rst  28h          ; ef
       .word $1c82 ; EXPT-1NUM
L14b8  call L18a1        ; cd a1 18
       rst  28h          ;
       .word $1e99 ; FIND-INT2
       ld   (ix+$0b),c   ; Store the length of the CODE block
       ld   (ix+$0c),b   ;
       rst  28h          ;
       .word $1e99 ; FIND-INT2
       ld   (ix+$0d),c   ; Store the start address of the CODE block
       ld   (ix+$0e),b   ; 
       ld   h,b          ; 60
       ld   l,c          ; 69
L14cf  ld   (ix+$00),$03 ; Store file type = 03 (CODE)
       jr   L1519        ;
L14d5  cp   $ca          ; 'LINE'?
       jr   z,L14e2      ; Jump ahead if so
       call L18a1        ; Check for end of statement
       ld   (ix+$0e),$80 ; Indicate no LINE number
       jr   L14f9        ; 
L14e2  ld   a,($5c74)    ; Check the BASIC command
       and  a            ; Is it SAVE?
       jp   nz,L1219     ; "C Nonsense in BASIC" if not
       rst  20h          ; Advance pointer into BASIC line
       rst  28h          ; Get LINE number onto calculator stack
       .word $1c82 ; EXPT-1NUM
       call L18a1        ; Ensure end-of-statement
       rst  28h          ; Retrieve LINE number from calculator stack
       .word $1e99 ; FIND-INT2
       ld   (ix+$0d),c   ; Store LINE number
       ld   (ix+$0e),b   ;
L14f9  ld   (ix+$00),$00 ; Store file type = 00
       ld   hl,($5c59)   ; 2a 59 5c
L1500  ld   de,($5c53)   ; ed 5b 53 5c
       scf               ; 37
       sbc  hl,de        ; ed 52
       ld   (ix+$0b),l   ; dd 75 0b
       ld   (ix+$0c),h   ; dd 74 0c
       ld   hl,($5c4b)   ; 2a 4b 5c
       sbc  hl,de        ; ed 52
       ld   (ix+$0f),l   ; dd 75 0f
       ld   (ix+$10),h   ; dd 74 10
       ex   de,hl        ; eb
L1519  ld   a,($5b66)    ; Flags byte
       bit  3,a          ; RAMdisk bit
       jp   nz,L121d     ; Jump if the operation is on the RAMdisk
       ld   a,($5c74)    ; Otherwise get the BASIC command
       and  a            ; Test for SAVE
       jr   nz,L152b     ; Jump ahead if not
       rst  28h          ; 
       .word $0970 ; SA-CONTROL
       ret               ;
L152b  rst  28h          ;
       .word $0761 ; SA-ALL + ?
       ret               ;

; called when a line is entered?
L152f  ld   hl,$eef5     ; 
       res  0,(hl)       ; flag ?
       set  1,(hl)       ; flag ?
L1536  ld   hl,($5c49)   ; E PPC - current line number
       ld   a,h          ; 
       or   l            ;
       jr   nz,L1540     ; Jump ahead if not zero
       ld   ($ec06),hl   ; Store in ???
L1540  ld   a,($f9db)    ;
       push af           ; 
       ld   hl,($fc9a)   ; First line on screen (or 0)
       call L334a        ; Get address of line number in BASIC,
                         ; or 0 if no such line
       ld   ($f9d7),hl   ;
       call L3222        ; copy some bytes
       call L30d6        ; around
       pop  af           ;
L1554  or   a            ; b7
       jr   z,L1563      ; 28 0c
       push af           ; f5
       call L30df        ; cd df 30
       ex   de,hl        ; eb
       call L326a        ; cd 6a 32
       pop  af           ; f1
       dec  a            ; 3d
       jr   L1554        ; 18 f1
L1563  ld   c,$00        ; first line on screen
       call L30b4        ; DE = start of editing line C
       ld   b,c          ; currently indexed editing line
       ld   a,($ec15)    ;
       ld   c,a          ; C=#editing lines on screen
       push bc           ; 
       push de           ;
L156f  call L30df        ; cd df 30
       ld   a,($eef5)    ; 3a f5 ee
       bit  1,a          ; cb 4f
       jr   z,L1596      ; 28 1d
       push de           ; d5
       push hl           ; e5
       ld   de,$0020     ; 11 20 00
       add  hl,de        ; 19
       bit  0,(hl)       ; cb 46
       jr   z,L1594      ; 28 11
       inc  hl           ;
       ld   d,(hl)       ; Get line number into DE
       inc  hl           ; 
       ld   e,(hl)       ;
       or   a            ;
       ld   hl,($5c49)   ; E PPC, number of current line
       sbc  hl,de        ;
       jr   nz,L1594     ; Jump ahead unless this is the current line
       ld   hl,$eef5     ; 
       set  0,(hl)       ;
L1594  pop  hl           ; e1
       pop  de           ; d1
L1596  push bc           ; c5
       push hl           ; e5
       ld   bc,$0023     ; 01 23 00
       ldir              ; [ this is where the IF n1>n2 corruption initally
                         ;   occurs ]
       pop  hl           ; e1
       pop  bc           ; c1
       push de           ; d5
       push bc           ; c5
       ex   de,hl        ; eb
       ld   hl,$eef5     ; 21 f5 ee
       bit  0,(hl)       ; cb 46
       jr   z,L15d3      ; 28 2a
       ld   b,$00        ; 06 00
L15ab  ld   hl,($ec06)   ; 2a 06 ec
       ld   a,h          ; 7c
       or   l            ; b5
       jr   z,L15c0      ; 28 0e
       push hl           ; e5
       call L2e41        ; cd 41 2e
       pop  hl           ; e1
       jr   nc,L15cb     ; 30 12
       dec  hl           ; 2b
       inc  b            ; 04
       ld   ($ec06),hl   ; 22 06 ec
       jr   L15ab        ; 18 eb
L15c0  call L2e41        ; cd 41 2e
       call nc,L2e63     ; d4 63 2e
       ld   hl,$eef5     ; 21 f5 ee
       ld   (hl),$00     ; 36 00
L15cb  ld   a,b          ; 78
       pop  bc           ; c1
       push bc           ; c5
       ld   c,b          ; 48
       ld   b,a          ; 47
       call L2a11        ; cd 11 2a
L15d3  pop  bc           ; c1
       pop  de           ; d1
       ld   a,c          ; 79
       inc  b            ; 04
       cp   b            ; b8
       jr   nc,L156f     ; 30 95
       ld   a,($eef5)    ; 3a f5 ee
       bit  1,a          ; cb 4f
       jr   z,L1602      ; 28 21
       bit  0,a          ; cb 47
       jr   nz,L1602     ; 20 1d
       ld   hl,($5c49)   ; 2a 49 5c       current line number
       ld   a,h          ; 7c
       or   l            ; b5
       jr   z,L15f4      ; 28 08
       ld   ($fc9a),hl   ; 22 9a fc
L15ef  call L3222        ; cd 22 32
       jr   L15fd        ; 18 09
L15f4  ld   ($fc9a),hl   ; 22 9a fc
       call L3352        ; cd 52 33
       ld   ($5c49),hl   ; 22 49 5c
L15fd  pop  de           ; d1
       pop  bc           ; c1
       jp   L1536        ; c3 36 15
L1602  pop  de           ; d1
       pop  bc           ; c1
       cp   a            ; Set Z flag
L1605  push af           ; f5
       ld   a,c          ; 79
       ld   c,b          ; 48
       call L30b4        ; Get address of start of line in editing area
       ex   de,hl        ; ... into HL
L160c  push af           ; 
       call L3604        ;
       pop  af           ;
       ld   de,$0023     ; next line
       add  hl,de        ;
L1615  inc  c            ;
       cp   c            ;
       jr   nc,L160c     ;
       pop  af           ;
       ret  z            ;
       call L2a07        ; cd 07 2a
L161e  call L2b78        ; cd 78 2b
       ld   hl,($ec06)   ; 2a 06 ec
       dec  hl           ; 2b
       ld   a,h          ; 7c
       or   l            ; b5
       ld   ($ec06),hl   ; 22 06 ec
       jr   nz,L161e     ; 20 f2
       jp   L2a11        ; c3 11 2a
       ret               ; c9

L1630  ld   b,$00        ; 
       ld   a,($ec15)    ; 
       ld   d,a          ; D=#editing lines available
       jp   L3b5e        ;

L1639  ld   b,$00        ; 06 00
       push hl           ; e5
       ld   c,b          ; 48
       call L30b4        ; DE =  start of editing line C
       call L326a        ; cd 6a 32
       pop  hl           ; e1
       ret  nc           ; d0
       call L30df        ; cd df 30
L1648  push bc           ; c5
       push hl           ; e5
       ld   hl,$0023     ; 21 23 00
       add  hl,de        ; 19
       ld   a,($ec15)    ; 3a 15 ec
       ld   c,a          ; 4f
       cp   b            ; b8
       jr   z,L1663      ; 28 0e
L1655  push bc           ; c5
L1656  push bc           ; c5
       ld   bc,$0023     ; 01 23 00
       ldir              ; ed b0
       pop  bc           ; c1
       ld   a,c          ; 79
       inc  b            ; 04
       cp   b            ; b8
       jr   nz,L1656     ; 20 f4
       pop  bc           ; c1
L1663  pop  hl           ; e1
L1664  call L3618        ; cd 18 36
       ld   bc,$0023     ; 01 23 00
       ldir              ; ed b0
       scf               ; 37
       pop  bc           ; c1
       ret               ; c9

L166f  ld   b,$00        ; 06 00
       call L322b        ; cd 2b 32
       ret  nc           ; d0
L1675  push bc           ; c5
       push hl           ; e5
       ld   a,($ec15)    ; 3a 15 ec
       ld   c,a          ; 4f
       call L30b4        ; DE = start of editing line C
       call L311e        ; cd 1e 31
       jr   nc,L16a9     ; 30 26
       dec  de           ; 1b
       ld   hl,$0023     ; 21 23 00
       add  hl,de        ; 19
       ex   de,hl        ; eb
       push bc           ;