    ; ===========================================================
    ; An Assembly Listing of the Operating System of the ZX81 ROM
    ; ===========================================================
    ; -------------------------
    ; Last updated: 13-DEC-2004
    ; -------------------------
    ;
    ; Work in progress.
    ; This file will cross-assemble an original version of the "Improved"
    ; ZX81 ROM.  The file can be modified to change the behaviour of the ROM
    ; when used in emulators although there is no spare space available.
    ;
    ; The documentation is incomplete and if you can find a copy
    ; of "The Complete Spectrum ROM Disassembly" then many routines
    ; such as POINTERS and most of the mathematical routines are
    ; similar and often identical.
    ;
    ; I've used the labels from the above book in this file and also
    ; some from the more elusive Complete ZX81 ROM Disassembly
    ; by the same publishers, Melbourne House.

    #define DEFB .BYTE      ; TASM cross-assembler definitions
    #define DEFW .WORD
    #define EQU  .EQU

    ;*****************************************
    ;** Part 1. RESTART ROUTINES AND TABLES **
    ;*****************************************

    ; -----------
    ; THE 'START'
    ; -----------
    ; All Z80 chips start at location zero.
    ; At start-up the Interrupt Mode is 0, ZX computers use Interrupt Mode 1.
    ; Interrupts are disabled .

    ;; START
    L0000:  OUT     ($FD),A         ; Turn off the NMI generator if this ROM is
                                    ; running in ZX81 hardware. This does nothing
                                    ; if this ROM is running within an upgraded
                                    ; ZX80.
            LD      BC,$7FFF        ; Set BC to the top of possible RAM.
                                    ; The higher unpopulated addresses are used for
                                    ; video generation.
            JP      L03CB           ; Jump forward to RAM-CHECK.

    ; -------------------
    ; THE 'ERROR' RESTART
    ; -------------------
    ; The error restart deals immediately with an error. ZX computers execute the
    ; same code in runtime as when checking syntax. If the error occurred while
    ; running a program then a brief report is produced. If the error occurred
    ; while entering a BASIC line or in input etc., then the error marker indicates
    ; the exact point at which the error lies.

    ;; ERROR-1
    L0008:  LD      HL,($4016)      ; fetch character address from CH_ADD.
            LD      ($4018),HL      ; and set the error pointer X_PTR.
            JR      L0056           ; forward to continue at ERROR-2.

    ; -------------------------------
    ; THE 'PRINT A CHARACTER' RESTART
    ; -------------------------------
    ; This restart prints the character in the accumulator using the alternate
    ; register set so there is no requirement to save the main registers.
    ; There is sufficient room available to separate a space (zero) from other
    ; characters as leading spaces need not be considered with a space.

    ;; PRINT-A
    L0010:  AND     A               ; test for zero - space.
            JP      NZ,L07F1        ; jump forward if not to PRINT-CH.

            JP      L07F5           ; jump forward to PRINT-SP.

    ; ---

            DEFB    $FF             ; unused location.

    ; ---------------------------------
    ; THE 'COLLECT A CHARACTER' RESTART
    ; ---------------------------------
    ; The character addressed by the system variable CH_ADD is fetched and if it
    ; is a non-space, non-cursor character it is returned else CH_ADD is
    ; incremented and the new addressed character tested until it is not a space.

    ;; GET-CHAR
    L0018:  LD      HL,($4016)      ; set HL to character address CH_ADD.
            LD      A,(HL)          ; fetch addressed character to A.

    ;; TEST-SP
    L001C:  AND     A               ; test for space.
            RET     NZ              ; return if not a space

            NOP                     ; else trickle through
            NOP                     ; to the next routine.

    ; ------------------------------------
    ; THE 'COLLECT NEXT CHARACTER' RESTART
    ; ------------------------------------
    ; The character address in incremented and the new addressed character is
    ; returned if not a space, or cursor, else the process is repeated.

    ;; NEXT-CHAR
    L0020:  CALL    L0049           ; routine CH-ADD+1 gets next immediate
                                    ; character.
            JR      L001C           ; back to TEST-SP.

    ; ---

            DEFB    $FF, $FF, $FF   ; unused locations.

    ; ---------------------------------------
    ; THE 'FLOATING POINT CALCULATOR' RESTART
    ; ---------------------------------------
    ; this restart jumps to the recursive floating-point calculator.
    ; the ZX81's internal, FORTH-like, stack-based language.
    ;
    ; In the five remaining bytes there is, appropriately, enough room for the
    ; end-calc literal - the instruction which exits the calculator.

    ;; FP-CALC
    L0028:  JP      L199D           ; jump immediately to the CALCULATE routine.

    ; ---

    ;; end-calc
    L002B:  POP     AF              ; drop the calculator return address RE-ENTRY
            EXX                     ; switch to the other set.

            EX      (SP),HL         ; transfer H'L' to machine stack for the
                                    ; return address.
                                    ; when exiting recursion then the previous
                                    ; pointer is transferred to H'L'.

            EXX                     ; back to main set.
            RET                     ; return.

    ; -----------------------------
    ; THE 'MAKE BC SPACES'  RESTART
    ; -----------------------------
    ; This restart is used eight times to create, in workspace, the number of
    ; spaces passed in the BC register.

    ;; BC-SPACES
    L0030:  PUSH    BC              ; push number of spaces on stack.
            LD      HL,($4014)      ; fetch edit line location from E_LINE.
            PUSH    HL              ; save this value on stack.
            JP      L1488           ; jump forward to continue at RESERVE.

    ; -----------------------
    ; THE 'INTERRUPT' RESTART
    ; -----------------------
    ;   The Mode 1 Interrupt routine is concerned solely with generating the central
    ;   television picture.
    ;   On the ZX81 interrupts are enabled only during the interrupt routine,
    ;   although the interrupt
    ;   This Interrupt Service Routine automatically disables interrupts at the
    ;   outset and the last interrupt in a cascade exits before the interrupts are
    ;   enabled.
    ;   There is no DI instruction in the ZX81 ROM.
    ;   An maskable interrupt is triggered when bit 6 of the Z80's Refresh register
    ;   changes from set to reset.
    ;   The Z80 will always be executing a HALT (NEWLINE) when the interrupt occurs.
    ;   A HALT instruction repeatedly executes NOPS but the seven lower bits
    ;   of the Refresh register are incremented each time as they are when any
    ;   simple instruction is executed. (The lower 7 bits are incremented twice for
    ;   a prefixed instruction)
    ;   This is controlled by the Sinclair Computer Logic Chip - manufactured from
    ;   a Ferranti Uncommitted Logic Array.
    ;
    ;   When a Mode 1 Interrupt occurs the Program Counter, which is the address in
    ;   the upper echo display following the NEWLINE/HALT instruction, goes on the
    ;   machine stack.  193 interrupts are required to generate the last part of
    ;   the 56th border line and then the 192 lines of the central TV picture and,
    ;   although each interrupt interrupts the previous one, there are no stack
    ;   problems as the 'return address' is discarded each time.
    ;
    ;   The scan line counter in C counts down from 8 to 1 within the generation of
    ;   each text line. For the first interrupt in a cascade the initial value of
    ;   C is set to 1 for the last border line.
    ;   Timing is of the utmost importance as the RH border, horizontal retrace
    ;   and LH border are mostly generated in the 58 clock cycles this routine
    ;   takes .

    ;; INTERRUPT
    L0038:  DEC     C               ; (4)  decrement C - the scan line counter.
            JP      NZ,L0045        ; (10/10) JUMP forward if not zero to SCAN-LINE

            POP     HL              ; (10) point to start of next row in display
                                    ;      file.

            DEC     B               ; (4)  decrement the row counter. (4)
            RET     Z               ; (11/5) return when picture complete to L028B
                                    ;      with interrupts disabled.

            SET     3,C             ; (8)  Load the scan line counter with eight.
                                    ;      Note. LD C,$08 is 7 clock cycles which
                                    ;      is way too fast.

    ; ->

    ;; WAIT-INT
    L0041:  LD      R,A             ; (9) Load R with initial rising value $DD.

            EI                      ; (4) Enable Interrupts.  [ R is now $DE ].

            JP      (HL)            ; (4) jump to the echo display file in upper
                                    ;     memory and execute characters $00 - $3F
                                    ;     as NOP instructions.  The video hardware
                                    ;     is able to read these characters and,
                                    ;     with the I register is able to convert
                                    ;     the character bitmaps in this ROM into a
                                    ;     line of bytes. Eventually the NEWLINE/HALT
                                    ;     will be encountered before R reaches $FF.
                                    ;     It is however the transition from $FF to
                                    ;     $80 that triggers the next interrupt.
                                    ;     [ The Refresh register is now $DF ]

    ; ---

    ;; SCAN-LINE
    L0045:  POP     DE              ; (10) discard the address after NEWLINE as the
                                    ;      same text line has to be done again
                                    ;      eight times.

            RET     Z               ; (5)  Harmless Nonsensical Timing.
                                    ;      (condition never met)

            JR      L0041           ; (12) back to WAIT-INT

    ;   Note. that a computer with less than 4K or RAM will have a collapsed
    ;   display file and the above mechanism deals with both types of display.
    ;
    ;   With a full display, the 32 characters in the line are treated as NOPS
    ;   and the Refresh register rises from $E0 to $FF and, at the next instruction
    ;   - HALT, the interrupt occurs.
    ;   With a collapsed display and an initial NEWLINE/HALT, it is the NOPs
    ;   generated by the HALT that cause the Refresh value to rise from $E0 to $FF,
    ;   triggering an Interrupt on the next transition.
    ;   This works happily for all display lines between these extremes and the
    ;   generation of the 32 character, 1 pixel high, line will always take 128
    ;   clock cycles.

    ; ---------------------------------
    ; THE 'INCREMENT CH-ADD' SUBROUTINE
    ; ---------------------------------
    ; This is the subroutine that increments the character address system variable
    ; and returns if it is not the cursor character. The ZX81 has an actual
    ; character at the cursor position rather than a pointer system variable
    ; as is the case with prior and subsequent ZX computers.

    ;; CH-ADD+1
    L0049:  LD      HL,($4016)      ; fetch character address to CH_ADD.

    ;; TEMP-PTR1
    L004C:  INC     HL              ; address next immediate location.

    ;; TEMP-PTR2
    L004D:  LD      ($4016),HL      ; update system variable CH_ADD.

            LD      A,(HL)          ; fetch the character.
            CP      $7F             ; compare to cursor character.
            RET     NZ              ; return if not the cursor.

            JR      L004C           ; back for next character to TEMP-PTR1.

    ; --------------------
    ; THE 'ERROR-2' BRANCH
    ; --------------------
    ; This is a continuation of the error restart.
    ; If the error occurred in runtime then the error stack pointer will probably
    ; lead to an error report being printed unless it occurred during input.
    ; If the error occurred when checking syntax then the error stack pointer
    ; will be an editing routine and the position of the error will be shown
    ; when the lower screen is reprinted.

    ;; ERROR-2
    L0056:  POP     HL              ; pop the return address which points to the
                                    ; DEFB, error code, after the RST 08.
            LD      L,(HL)          ; load L with the error code. HL is not needed
                                    ; anymore.

    ;; ERROR-3
    L0058:  LD      (IY+$00),L      ; place error code in system variable ERR_NR
            LD      SP,($4002)      ; set the stack pointer from ERR_SP
            CALL    L0207           ; routine SLOW/FAST selects slow mode.
            JP      L14BC           ; exit to address on stack via routine SET-MIN.

    ; ---

            DEFB    $FF             ; unused.

    ; ------------------------------------
    ; THE 'NON MASKABLE INTERRUPT' ROUTINE
    ; ------------------------------------
    ;   Jim Westwood's technical dodge using Non-Maskable Interrupts solved the
    ;   flicker problem of the ZX80 and gave the ZX81 a multi-tasking SLOW mode
    ;   with a steady display.  Note that the AF' register is reserved for this
    ;   function and its interaction with the display routines.  When counting
    ;   TV lines, the NMI makes no use of the main registers.
    ;   The circuitry for the NMI generator is contained within the SCL (Sinclair
    ;   Computer Logic) chip.
    ;   ( It takes 32 clock cycles while incrementing towards zero ).

    ;; NMI
    L0066:  EX      AF,AF'          ; (4) switch in the NMI's copy of the
                                    ;     accumulator.
            INC     A               ; (4) increment.
            JP      M,L006D         ; (10/10) jump, if minus, to NMI-RET as this is
                                    ;     part of a test to see if the NMI
                                    ;     generation is working or an intermediate
                                    ;     value for the ascending negated blank
                                    ;     line counter.

            JR      Z,L006F         ; (12) forward to NMI-CONT
                                    ;      when line count has incremented to zero.

    ; Note. the synchronizing NMI when A increments from zero to one takes this
    ; 7 clock cycle route making 39 clock cycles in all.

    ;; NMI-RET
    L006D:  EX      AF,AF'          ; (4)  switch out the incremented line counter
                                    ;      or test result $80
            RET                     ; (10) return to User application for a while.

    ; ---

    ;   This branch is taken when the 55 (or 31) lines have been drawn.

    ;; NMI-CONT
    L006F:  EX      AF,AF'          ; (4) restore the main accumulator.

            PUSH    AF              ; (11) *             Save Main Registers
            PUSH    BC              ; (11) **
            PUSH    DE              ; (11) ***
            PUSH    HL              ; (11) ****

    ;   the next set-up procedure is only really applicable when the top set of
    ;   blank lines have been generated.

            LD      HL,($400C)      ; (16) fetch start of Display File from D_FILE
                                    ;      points to the HALT at beginning.
            SET     7,H             ; (8) point to upper 32K 'echo display file'

            HALT                    ; (1) HALT synchronizes with NMI.
                                    ; Used with special hardware connected to the
                                    ; Z80 HALT and WAIT lines to take 1 clock cycle.

    ; ----------------------------------------------------------------------------
    ;   the NMI has been generated - start counting. The cathode ray is at the RH
    ;   side of the TV.
    ;   First the NMI servicing, similar to CALL            =  17 clock cycles.
    ;   Then the time taken by the NMI for zero-to-one path =  39 cycles
    ;   The HALT above                                      =  01 cycles.
    ;   The two instructions below                          =  19 cycles.
    ;   The code at L0281 up to and including the CALL      =  43 cycles.
    ;   The Called routine at L02B5                         =  24 cycles.
    ;   --------------------------------------                ---
    ;   Total Z80 instructions                              = 143 cycles.
    ;
    ;   Meanwhile in TV world,
    ;   Horizontal retrace                                  =  15 cycles.
    ;   Left blanking border 8 character positions          =  32 cycles
    ;   Generation of 75% scanline from the first NEWLINE   =  96 cycles
    ;   ---------------------------------------               ---
    ;                                                         143 cycles
    ;
    ;   Since at the time the first JP (HL) is encountered to execute the echo
    ;   display another 8 character positions have to be put out, then the
    ;   Refresh register need to hold $F8. Working back and counteracting
    ;   the fact that every instruction increments the Refresh register then
    ;   the value that is loaded into R needs to be $F5.      :-)
    ;
    ;
            OUT     ($FD),A         ; (11) Stop the NMI generator.

            JP      (IX)            ; (8) forward to L0281 (after top) or L028F

    ; ****************
    ; ** KEY TABLES **
    ; ****************

    ; -------------------------------
    ; THE 'UNSHIFTED' CHARACTER CODES
    ; -------------------------------

    ;; K-UNSHIFT
    L007E:  DEFB    $3F             ; Z
            DEFB    $3D             ; X
            DEFB    $28             ; C
            DEFB    $3B             ; V
            DEFB    $26             ; A
            DEFB    $38             ; S
            DEFB    $29             ; D
            DEFB    $2B             ; F
            DEFB    $2C             ; G
            DEFB    $36             ; Q
            DEFB    $3C             ; W
            DEFB    $2A             ; E
            DEFB    $37             ; R
            DEFB    $39             ; T
            DEFB    $1D             ; 1
            DEFB    $1E             ; 2
            DEFB    $1F             ; 3
            DEFB    $20             ; 4
            DEFB    $21             ; 5
            DEFB    $1C             ; 0
            DEFB    $25             ; 9
            DEFB    $24             ; 8
            DEFB    $23             ; 7
            DEFB    $22             ; 6
            DEFB    $35             ; P
            DEFB    $34             ; O
            DEFB    $2E             ; I
            DEFB    $3A             ; U
            DEFB    $3E             ; Y
            DEFB    $76             ; NEWLINE
            DEFB    $31             ; L
            DEFB    $30             ; K
            DEFB    $2F             ; J
            DEFB    $2D             ; H
            DEFB    $00             ; SPACE
            DEFB    $1B             ; .
            DEFB    $32             ; M
            DEFB    $33             ; N
            DEFB    $27             ; B

    ; -----------------------------
    ; THE 'SHIFTED' CHARACTER CODES
    ; -----------------------------

    ;; K-SHIFT
    L00A5:  DEFB    $0E             ; :
            DEFB    $19             ; ;
            DEFB    $0F             ; ?
            DEFB    $18             ; /
            DEFB    $E3             ; STOP
            DEFB    $E1             ; LPRINT
            DEFB    $E4             ; SLOW
            DEFB    $E5             ; FAST
            DEFB    $E2             ; LLIST
            DEFB    $C0             ; ""
            DEFB    $D9             ; OR
            DEFB    $E0             ; STEP
            DEFB    $DB             ; <=
            DEFB    $DD             ; <>
            DEFB    $75             ; EDIT
            DEFB    $DA             ; AND
            DEFB    $DE             ; THEN
            DEFB    $DF             ; TO
            DEFB    $72             ; cursor-left
            DEFB    $77             ; RUBOUT
            DEFB    $74             ; GRAPHICS
            DEFB    $73             ; cursor-right
            DEFB    $70             ; cursor-up
            DEFB    $71             ; cursor-down
            DEFB    $0B             ; "
            DEFB    $11             ; )
            DEFB    $10             ; (
            DEFB    $0D             ; $
            DEFB    $DC             ; >=
            DEFB    $79             ; FUNCTION
            DEFB    $14             ; =
            DEFB    $15             ; +
            DEFB    $16             ; -
            DEFB    $D8             ; **
            DEFB    $0C             ;  £
            DEFB    $1A             ; ,
            DEFB    $12             ; >
            DEFB    $13             ; <
            DEFB    $17             ; *

    ; ------------------------------
    ; THE 'FUNCTION' CHARACTER CODES
    ; ------------------------------

    ;; K-FUNCT
    L00CC:  DEFB    $CD             ; LN
            DEFB    $CE             ; EXP
            DEFB    $C1             ; AT
            DEFB    $78             ; KL
            DEFB    $CA             ; ASN
            DEFB    $CB             ; ACS
            DEFB    $CC             ; ATN
            DEFB    $D1             ; SGN
            DEFB    $D2             ; ABS
            DEFB    $C7             ; SIN
            DEFB    $C8             ; COS
            DEFB    $C9             ; TAN
            DEFB    $CF             ; INT
            DEFB    $40             ; RND
            DEFB    $78             ; KL
            DEFB    $78             ; KL
            DEFB    $78             ; KL
            DEFB    $78             ; KL
            DEFB    $78             ; KL
            DEFB    $78             ; KL
            DEFB    $78             ; KL
            DEFB    $78             ; KL
            DEFB    $78             ; KL
            DEFB    $78             ; KL
            DEFB    $C2             ; TAB
            DEFB    $D3             ; PEEK
            DEFB    $C4             ; CODE
            DEFB    $D6             ; CHR$
            DEFB    $D5             ; STR$
            DEFB    $78             ; KL
            DEFB    $D4             ; USR
            DEFB    $C6             ; LEN
            DEFB    $C5             ; VAL
            DEFB    $D0             ; SQR
            DEFB    $78             ; KL
            DEFB    $78             ; KL
            DEFB    $42             ; PI
            DEFB    $D7             ; NOT
            DEFB    $41             ; INKEY$

    ; -----------------------------
    ; THE 'GRAPHIC' CHARACTER CODES
    ; -----------------------------

    ;; K-GRAPH
    L00F3:  DEFB    $08             ; graphic
            DEFB    $0A             ; graphic
            DEFB    $09             ; graphic
            DEFB    $8A             ; graphic
            DEFB    $89             ; graphic
            DEFB    $81             ; graphic
            DEFB    $82             ; graphic
            DEFB    $07             ; graphic
            DEFB    $84             ; graphic
            DEFB    $06             ; graphic
            DEFB    $01             ; graphic
            DEFB    $02             ; graphic
            DEFB    $87             ; graphic
            DEFB    $04             ; graphic
            DEFB    $05             ; graphic
            DEFB    $77             ; RUBOUT
            DEFB    $78             ; KL
            DEFB    $85             ; graphic
            DEFB    $03             ; graphic
            DEFB    $83             ; graphic
            DEFB    $8B             ; graphic
            DEFB    $91             ; inverse )
            DEFB    $90             ; inverse (
            DEFB    $8D             ; inverse $
            DEFB    $86             ; graphic
            DEFB    $78             ; KL
            DEFB    $92             ; inverse >
            DEFB    $95             ; inverse +
            DEFB    $96             ; inverse -
            DEFB    $88             ; graphic

    ; ------------------
    ; THE 'TOKEN' TABLES
    ; ------------------

    ;; TOKENS
    L0111:  DEFB    $0F+$80                         ; '?'+$80
            DEFB    $0B,$0B+$80                     ; ""
            DEFB    $26,$39+$80                     ; AT
            DEFB    $39,$26,$27+$80                 ; TAB
            DEFB    $0F+$80                         ; '?'+$80
            DEFB    $28,$34,$29,$2A+$80             ; CODE
            DEFB    $3B,$26,$31+$80                 ; VAL
            DEFB    $31,$2A,$33+$80                 ; LEN
            DEFB    $38,$2E,$33+$80                 ; SIN
            DEFB    $28,$34,$38+$80                 ; COS
            DEFB    $39,$26,$33+$80                 ; TAN
            DEFB    $26,$38,$33+$80                 ; ASN
            DEFB    $26,$28,$38+$80                 ; ACS
            DEFB    $26,$39,$33+$80                 ; ATN
            DEFB    $31,$33+$80                     ; LN
            DEFB    $2A,$3D,$35+$80                 ; EXP
            DEFB    $2E,$33,$39+$80                 ; INT
            DEFB    $38,$36,$37+$80                 ; SQR
            DEFB    $38,$2C,$33+$80                 ; SGN
            DEFB    $26,$27,$38+$80                 ; ABS
            DEFB    $35,$2A,$2A,$30+$80             ; PEEK
            DEFB    $3A,$38,$37+$80                 ; USR
            DEFB    $38,$39,$37,$0D+$80             ; STR$
            DEFB    $28,$2D,$37,$0D+$80             ; CHR$
            DEFB    $33,$34,$39+$80                 ; NOT
            DEFB    $17,$17+$80                     ; **
            DEFB    $34,$37+$80                     ; OR
            DEFB    $26,$33,$29+$80                 ; AND
            DEFB    $13,$14+$80                     ; <=
            DEFB    $12,$14+$80                     ; >=
            DEFB    $13,$12+$80                     ; <>
            DEFB    $39,$2D,$2A,$33+$80             ; THEN
            DEFB    $39,$34+$80                     ; TO
            DEFB    $38,$39,$2A,$35+$80             ; STEP
            DEFB    $31,$35,$37,$2E,$33,$39+$80     ; LPRINT
            DEFB    $31,$31,$2E,$38,$39+$80         ; LLIST
            DEFB    $38,$39,$34,$35+$80             ; STOP
            DEFB    $38,$31,$34,$3C+$80             ; SLOW
            DEFB    $2B,$26,$38,$39+$80             ; FAST
            DEFB    $33,$2A,$3C+$80                 ; NEW
            DEFB    $38,$28,$37,$34,$31,$31+$80     ; SCROLL
            DEFB    $28,$34,$33,$39+$80             ; CONT
            DEFB    $29,$2E,$32+$80                 ; DIM
            DEFB    $37,$2A,$32+$80                 ; REM
            DEFB    $2B,$34,$37+$80                 ; FOR
            DEFB    $2C,$34,$39,$34+$80             ; GOTO
            DEFB    $2C,$34,$38,$3A,$27+$80         ; GOSUB
            DEFB    $2E,$33,$35,$3A,$39+$80         ; INPUT
            DEFB    $31,$34,$26,$29+$80             ; LOAD
            DEFB    $31,$2E,$38,$39+$80             ; LIST
            DEFB    $31,$2A,$39+$80                 ; LET
            DEFB    $35,$26,$3A,$38,$2A+$80         ; PAUSE
            DEFB    $33,$2A,$3D,$39+$80             ; NEXT
            DEFB    $35,$34,$30,$2A+$80             ; POKE
            DEFB    $35,$37,$2E,$33,$39+$80         ; PRINT
            DEFB    $35,$31,$34,$39+$80             ; PLOT
            DEFB    $37,$3A,$33+$80                 ; RUN
            DEFB    $38,$26,$3B,$2A+$80             ; SAVE
            DEFB    $37,$26,$33,$29+$80             ; RAND
            DEFB    $2E,$2B+$80                     ; IF
            DEFB    $28,$31,$38+$80                 ; CLS
            DEFB    $3A,$33,$35,$31,$34,$39+$80     ; UNPLOT
            DEFB    $28,$31,$2A,$26,$37+$80         ; CLEAR
            DEFB    $37,$2A,$39,$3A,$37,$33+$80     ; RETURN
            DEFB    $28,$34,$35,$3E+$80             ; COPY
            DEFB    $37,$33,$29+$80                 ; RND
            DEFB    $2E,$33,$30,$2A,$3E,$0D+$80     ; INKEY$
            DEFB    $35,$2E+$80                     ; PI

    ; ------------------------------
    ; THE 'LOAD-SAVE UPDATE' ROUTINE
    ; ------------------------------
    ;
    ;

    ;; LOAD/SAVE
    L01FC:  INC     HL              ;
            EX      DE,HL           ;
            LD      HL,($4014)      ; system variable edit line E_LINE.
            SCF                     ; set carry flag
            SBC     HL,DE           ;
            EX      DE,HL           ;
            RET     NC              ; return if more bytes to load/save.

            POP     HL              ; else drop return address

    ; ----------------------
    ; THE 'DISPLAY' ROUTINES
    ; ----------------------
    ;
    ;

    ;; SLOW/FAST
    L0207:  LD      HL,$403B        ; Address the system variable CDFLAG.
            LD      A,(HL)          ; Load value to the accumulator.
            RLA                     ; rotate bit 6 to position 7.
            XOR     (HL)            ; exclusive or with original bit 7.
            RLA                     ; rotate result out to carry.
            RET     NC              ; return if both bits were the same.

    ;   Now test if this really is a ZX81 or a ZX80 running the upgraded ROM.
    ;   The standard ZX80 did not have an NMI generator.

            LD      A,$7F           ; Load accumulator with %011111111
            EX      AF,AF'          ; save in AF'

            LD      B,$11           ; A counter within which an NMI should occur
                                    ; if this is a ZX81.
            OUT     ($FE),A         ; start the NMI generator.

    ;  Note that if this is a ZX81 then the NMI will increment AF'.

    ;; LOOP-11
    L0216:  DJNZ    L0216           ; self loop to give the NMI a chance to kick in.
                                    ; = 16*13 clock cycles + 8 = 216 clock cycles.

            OUT     ($FD),A         ; Turn off the NMI generator.
            EX      AF,AF'          ; bring back the AF' value.
            RLA                     ; test bit 7.
            JR      NC,L0226        ; forward, if bit 7 is still reset, to NO-SLOW.

    ;   If the AF' was incremented then the NMI generator works and SLOW mode can
    ;   be set.

            SET     7,(HL)          ; Indicate SLOW mode - Compute and Display.

            PUSH    AF              ; *             Save Main Registers
            PUSH    BC              ; **
            PUSH    DE              ; ***
            PUSH    HL              ; ****

            JR      L0229           ; skip forward - to DISPLAY-1.

    ; ---

    ;; NO-SLOW
    L0226:  RES     6,(HL)          ; reset bit 6 of CDFLAG.
            RET                     ; return.

    ; -----------------------
    ; THE 'MAIN DISPLAY' LOOP
    ; -----------------------
    ; This routine is executed once for every frame displayed.

    ;; DISPLAY-1
    L0229:  LD      HL,($4034)      ; fetch two-byte system variable FRAMES.
            DEC     HL              ; decrement frames counter.

    ;; DISPLAY-P
    L022D:  LD      A,$7F           ; prepare a mask
            AND     H               ; pick up bits 6-0 of H.
            OR      L               ; and any bits of L.
            LD      A,H             ; reload A with all bits of H for PAUSE test.

    ;   Note both branches must take the same time.

            JR      NZ,L0237        ; (12/7) forward if bits 14-0 are not zero
                                    ; to ANOTHER

            RLA                     ; (4) test bit 15 of FRAMES.
            JR      L0239           ; (12) forward with result to OVER-NC

    ; ---

    ;; ANOTHER
    L0237:  LD      B,(HL)          ; (7) Note. Harmless Nonsensical Timing weight.
            SCF                     ; (4) Set Carry Flag.

    ; Note. the branch to here takes either (12)(7)(4) cyles or (7)(4)(12) cycles.

    ;; OVER-NC
    L0239:  LD      H,A             ; (4)  set H to zero
            LD      ($4034),HL      ; (16) update system variable FRAMES
            RET     NC              ; (11/5) return if FRAMES is in use by PAUSE
                                    ; command.

    ;; DISPLAY-2
    L023E:  CALL    L02BB           ; routine KEYBOARD gets the key row in H and
                                    ; the column in L. Reading the ports also starts
                                    ; the TV frame synchronization pulse. (VSYNC)

            LD      BC,($4025)      ; fetch the last key values read from LAST_K
            LD      ($4025),HL      ; update LAST_K with new values.

            LD      A,B             ; load A with previous column - will be $FF if
                                    ; there was no key.
            ADD     A,$02           ; adding two will set carry if no previous key.

            SBC     HL,BC           ; subtract with the carry the two key values.

    ; If the same key value has been returned twice then HL will be zero.

            LD      A,($4027)       ; fetch system variable DEBOUNCE
            OR      H               ; and OR with both bytes of the difference
            OR      L               ; setting the zero flag for the upcoming branch.

            LD      E,B             ; transfer the column value to E
            LD      B,$0B           ; and load B with eleven

            LD      HL,$403B        ; address system variable CDFLAG
            RES     0,(HL)          ; reset the rightmost bit of CDFLAG
            JR      NZ,L0264        ; skip forward if debounce/diff >0 to NO-KEY

            BIT     7,(HL)          ; test compute and display bit of CDFLAG
            SET     0,(HL)          ; set the rightmost bit of CDFLAG.
            RET     Z               ; return if bit 7 indicated fast mode.

            DEC     B               ; (4) decrement the counter.
            NOP                     ; (4) Timing - 4 clock cycles. ??
            SCF                     ; (4) Set Carry Flag

    ;; NO-KEY
    L0264:  LD      HL,$4027        ; sv DEBOUNCE
            CCF                     ; Complement Carry Flag
            RL      B               ; rotate left B picking up carry
                                    ;  C<-76543210<-C

    ;; LOOP-B
    L026A:  DJNZ    L026A           ; self-loop while B>0 to LOOP-B

            LD      B,(HL)          ; fetch value of DEBOUNCE to B
            LD      A,E             ; transfer column value
            CP      $FE             ;
            SBC     A,A             ;
            LD      B,$1F           ;
            OR      (HL)            ;
            AND     B               ;
            RRA                     ;
            LD      (HL),A          ;

            OUT     ($FF),A         ; end the TV frame synchronization pulse.

            LD      HL,($400C)      ; (12) set HL to the Display File from D_FILE
            SET     7,H             ; (8) set bit 15 to address the echo display.

            CALL    L0292           ; (17) routine DISPLAY-3 displays the top set
                                    ; of blank lines.

    ; ---------------------
    ; THE 'VIDEO-1' ROUTINE
    ; ---------------------

    ;; R-IX-1
    L0281:  LD      A,R             ; (9)  Harmless Nonsensical Timing or something
                                    ;      very clever?
            LD      BC,$1901        ; (10) 25 lines, 1 scanline in first.
            LD      A,$F5           ; (7)  This value will be loaded into R and
                                    ; ensures that the cycle starts at the right
                                    ; part of the display  - after 32nd character
                                    ; position.

            CALL    L02B5           ; (17) routine DISPLAY-5 completes the current
                                    ; blank line and then generates the display of
                                    ; the live picture using INT interrupts
                                    ; The final interrupt returns to the next
                                    ; address.

    L028B:  DEC     HL              ; point HL to the last NEWLINE/HALT.

            CALL    L0292           ; routine DISPLAY-3 displays the bottom set of
                                    ; blank lines.

    ; ---

    ;; R-IX-2
    L028F:  JP      L0229           ; JUMP back to DISPLAY-1

    ; ---------------------------------
    ; THE 'DISPLAY BLANK LINES' ROUTINE
    ; ---------------------------------
    ;   This subroutine is called twice (see above) to generate first the blank
    ;   lines at the top of the television display and then the blank lines at the
    ;   bottom of the display.

    ;; DISPLAY-3
    L0292:  POP     IX              ; pop the return address to IX register.
                                    ; will be either L0281 or L028F - see above.

            LD      C,(IY+$28)      ; load C with value of system constant MARGIN.
            BIT     7,(IY+$3B)      ; test CDFLAG for compute and display.
            JR      Z,L02A9         ; forward, with FAST mode, to DISPLAY-4

            LD      A,C             ; move MARGIN to A  - 31d or 55d.
            NEG                     ; Negate
            INC     A               ;
            EX      AF,AF'          ; place negative count of blank lines in A'

            OUT     ($FE),A         ; enable the NMI generator.

            POP     HL              ; ****
            POP     DE              ; ***
            POP     BC              ; **
            POP     AF              ; *             Restore Main Registers

            RET                     ; return - end of interrupt.  Return is to
                                    ; user's program - BASIC or machine code.
                                    ; which will be interrupted by every NMI.

    ; ------------------------
    ; THE 'FAST MODE' ROUTINES
    ; ------------------------

    ;; DISPLAY-4
    L02A9:  LD      A,$FC           ; (7)  load A with first R delay value
            LD      B,$01           ; (7)  one row only.

            CALL    L02B5           ; (17) routine DISPLAY-5

            DEC     HL              ; (6)  point back to the HALT.
            EX      (SP),HL         ; (19) Harmless Nonsensical Timing if paired.
            EX      (SP),HL         ; (19) Harmless Nonsensical Timing.
            JP      (IX)            ; (8)  to L0281 or L028F

    ; --------------------------
    ; THE 'DISPLAY-5' SUBROUTINE
    ; --------------------------
    ;   This subroutine is called from SLOW mode and FAST mode to generate the
    ;   central TV picture. With SLOW mode the R register is incremented, with
    ;   each instruction, to $F7 by the time it completes.  With fast mode, the
    ;   final R value will be $FF and an interrupt will occur as soon as the
    ;   Program Counter reaches the HALT.  (24 clock cycles)

    ;; DISPLAY-5
    L02B5:  LD      R,A             ; (9) Load R from A.    R = slow: $F5 fast: $FC
            LD      A,$DD           ; (7) load future R value.        $F6       $FD

            EI                      ; (4) Enable Interrupts           $F7       $FE

            JP      (HL)            ; (4) jump to the echo display.   $F8       $FF

    ; ----------------------------------
    ; THE 'KEYBOARD SCANNING' SUBROUTINE
    ; ----------------------------------
    ; The keyboard is read during the vertical sync interval while no video is
    ; being displayed.  Reading a port with address bit 0 low i.e. $FE starts the
    ; vertical sync pulse.

    ;; KEYBOARD
    L02BB:  LD      HL,$FFFF        ; (16) prepare a buffer to take key.
            LD      BC,$FEFE        ; (20) set BC to port $FEFE. The B register,
                                    ;      with its single reset bit also acts as
                                    ;      an 8-counter.
            IN      A,(C)           ; (11) read the port - all 16 bits are put on
                                    ;      the address bus.  Start VSYNC pulse.
            OR      $01             ; (7)  set the rightmost bit so as to ignore
                                    ;      the SHIFT key.

    ;; EACH-LINE
    L02C5:  OR      $E0             ; [7] OR %11100000
            LD      D,A             ; [4] transfer to D.
            CPL                     ; [4] complement - only bits 4-0 meaningful now.
            CP      $01             ; [7] sets carry if A is zero.
            SBC     A,A             ; [4] $FF if $00 else zero.
            OR      B               ; [7] $FF or port FE,FD,FB....
            AND     L               ; [4] unless more than one key, L will still be
                                    ;     $FF. if more than one key is pressed then A is
                                    ;     now invalid.
            LD      L,A             ; [4] transfer to L.

    ; now consider the column identifier.

            LD      A,H             ; [4] will be $FF if no previous keys.
            AND     D               ; [4] 111xxxxx
            LD      H,A             ; [4] transfer A to H

    ; since only one key may be pressed, H will, if valid, be one of
    ; 11111110, 11111101, 11111011, 11110111, 11101111
    ; reading from the outer column, say Q, to the inner column, say T.

            RLC     B               ; [8]  rotate the 8-counter/port address.
                                    ;      sets carry if more to do.
            IN      A,(C)           ; [10] read another half-row.
                                    ;      all five bits this time.

            JR      C,L02C5         ; [12](7) loop back, until done, to EACH-LINE

    ;   The last row read is SHIFT,Z,X,C,V  for the second time.

            RRA                     ; (4) test the shift key - carry will be reset
                                    ;     if the key is pressed.
            RL      H               ; (8) rotate left H picking up the carry giving
                                    ;     column values -
                                    ;        $FD, $FB, $F7, $EF, $DF.
                                    ;     or $FC, $FA, $F6, $EE, $DE if shifted.

    ;   We now have H identifying the column and L identifying the row in the
    ;   keyboard matrix.

    ;   This is a good time to test if this is an American or British machine.
    ;   The US machine has an extra diode that causes bit 6 of a byte read from
    ;   a port to be reset.

            RLA                     ; (4) compensate for the shift test.
            RLA                     ; (4) rotate bit 7 out.
            RLA                     ; (4) test bit 6.

            SBC     A,A             ; (4)           $FF or $00 {USA}
            AND     $18             ; (7)           $18 or $00
            ADD     A,$1F           ; (7)           $37 or $1F

    ;   result is either 31 (USA) or 55 (UK) blank lines above and below the TV
    ;   picture.

            LD      ($4028),A       ; (13) update system variable MARGIN

            RET                     ; (10) return

    ; ------------------------------
    ; THE 'SET FAST MODE' SUBROUTINE
    ; ------------------------------
    ;
    ;

    ;; SET-FAST
    L02E7:  BIT     7,(IY+$3B)      ; sv CDFLAG
            RET     Z               ;

            HALT                    ; Wait for Interrupt
            OUT     ($FD),A         ;
            RES     7,(IY+$3B)      ; sv CDFLAG
            RET                     ; return.

    ; --------------
    ; THE 'REPORT-F'
    ; --------------

    ;; REPORT-F
    L02F4:  RST     08H             ; ERROR-1
            DEFB    $0E             ; Error Report: No Program Name supplied.

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

    ;; SAVE
    L02F6:  CALL    L03A8           ; routine NAME
            JR      C,L02F4         ; back with null name to REPORT-F above.

            EX      DE,HL           ;
            LD      DE,$12CB        ; five seconds timing value

    ;; HEADER
    L02FF:  CALL    L0F46           ; routine BREAK-1
            JR      NC,L0332        ; to BREAK-2

    ;; DELAY-1
    L0304:  DJNZ    L0304           ; to DELAY-1

            DEC     DE              ;
            LD      A,D             ;
            OR      E               ;
            JR      NZ,L02FF        ; back for delay to HEADER

    ;; OUT-NAME
    L030B:  CALL    L031E           ; routine OUT-BYTE
            BIT     7,(HL)          ; test for inverted bit.
            INC     HL              ; address next character of name.
            JR      Z,L030B         ; back if not inverted to OUT-NAME

    ; now start saving the system variables onwards.

            LD      HL,$4009        ; set start of area to VERSN thereby
                                    ; preserving RAMTOP etc.

    ;; OUT-PROG
    L0316:  CALL    L031E           ; routine OUT-BYTE

            CALL    L01FC           ; routine LOAD/SAVE                     >>
            JR      L0316           ; loop back to OUT-PROG

    ; -------------------------
    ; THE 'OUT-BYTE' SUBROUTINE
    ; -------------------------
    ; This subroutine outputs a byte a bit at a time to a domestic tape recorder.

    ;; OUT-BYTE
    L031E:  LD      E,(HL)          ; fetch byte to be saved.
            SCF                     ; set carry flag - as a marker.

    ;; EACH-BIT
    L0320:  RL      E               ;  C < 76543210 < C
            RET     Z               ; return when the marker bit has passed
                                    ; right through.                        >>

            SBC     A,A             ; $FF if set bit or $00 with no carry.
            AND     $05             ; $05               $00
            ADD     A,$04           ; $09               $04
            LD      C,A             ; transfer timer to C. a set bit has a longer
                                    ; pulse than a reset bit.

    ;; PULSES
    L0329:  OUT     ($FF),A         ; pulse to cassette.
            LD      B,$23           ; set timing constant

    ;; DELAY-2
    L032D:  DJNZ    L032D           ; self-loop to DELAY-2

            CALL    L0F46           ; routine BREAK-1 test for BREAK key.

    ;; BREAK-2
    L0332:  JR      NC,L03A6        ; forward with break to REPORT-D

            LD      B,$1E           ; set timing value.

    ;; DELAY-3
    L0336:  DJNZ    L0336           ; self-loop to DELAY-3

            DEC     C               ; decrement counter
            JR      NZ,L0329        ; loop back to PULSES

    ;; DELAY-4
    L033B:  AND     A               ; clear carry for next bit test.
            DJNZ    L033B           ; self loop to DELAY-4 (B is zero - 256)

            JR      L0320           ; loop back to EACH-BIT

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

    ;; LOAD
    L0340:  CALL    L03A8           ; routine NAME

    ; DE points to start of name in RAM.

            RL      D               ; pick up carry
            RRC     D               ; carry now in bit 7.

    ;; NEXT-PROG
    L0347:  CALL    L034C           ; routine IN-BYTE
            JR      L0347           ; loop to NEXT-PROG

    ; ------------------------
    ; THE 'IN-BYTE' SUBROUTINE
    ; ------------------------

    ;; IN-BYTE
    L034C:  LD      C,$01           ; prepare an eight counter 00000001.

    ;; NEXT-BIT
    L034E:  LD      B,$00           ; set counter to 256

    ;; BREAK-3
    L0350:  LD      A,$7F           ; read the keyboard row
            IN      A,($FE)         ; with the SPACE key.

            OUT     ($FF),A         ; output signal to screen.

            RRA                     ; test for SPACE pressed.
            JR      NC,L03A2        ; forward if so to BREAK-4

            RLA                     ; reverse above rotation
            RLA                     ; test tape bit.
            JR      C,L0385         ; forward if set to GET-BIT

            DJNZ    L0350           ; loop back to BREAK-3

            POP     AF              ; drop the return address.
            CP      D               ; ugh.

    ;; RESTART
    L0361:  JP      NC,L03E5        ; jump forward to INITIAL if D is zero
                                    ; to reset the system
                                    ; if the tape signal has timed out for example
                                    ; if the tape is stopped. Not just a simple
                                    ; report as some system variables will have
                                    ; been overwritten.

            LD      H,D             ; else transfer the start of name
            LD      L,E             ; to the HL register

    ;; IN-NAME
    L0366:  CALL    L034C           ; routine IN-BYTE is sort of recursion for name
                                    ; part. received byte in C.
            BIT     7,D             ; is name the null string ?
            LD      A,C             ; transfer byte to A.
            JR      NZ,L0371        ; forward with null string to MATCHING

            CP      (HL)            ; else compare with string in memory.
            JR      NZ,L0347        ; back with mis-match to NEXT-PROG
                                    ; (seemingly out of subroutine but return
                                    ; address has been dropped).

    ;; MATCHING
    L0371:  INC     HL              ; address next character of name
            RLA                     ; test for inverted bit.
            JR      NC,L0366        ; back if not to IN-NAME

    ; the name has been matched in full.
    ; proceed to load the data but first increment the high byte of E_LINE, which
    ; is one of the system variables to be loaded in. Since the low byte is loaded
    ; before the high byte, it is possible that, at the in-between stage, a false
    ; value could cause the load to end prematurely - see  LOAD/SAVE check.

            INC     (IY+$15)        ; increment system variable E_LINE_hi.
            LD      HL,$4009        ; start loading at system variable VERSN.

    ;; IN-PROG
    L037B:  LD      D,B             ; set D to zero as indicator.
            CALL    L034C           ; routine IN-BYTE loads a byte
            LD      (HL),C          ; insert assembled byte in memory.
            CALL    L01FC           ; routine LOAD/SAVE                     >>
            JR      L037B           ; loop back to IN-PROG

    ; ---

    ; this branch assembles a full byte before exiting normally
    ; from the IN-BYTE subroutine.

    ;; GET-BIT
    L0385:  PUSH    DE              ; save the
            LD      E,$94           ; timing value.

    ;; TRAILER
    L0388:  LD      B,$1A           ; counter to twenty six.

    ;; COUNTER
    L038A:  DEC     E               ; decrement the measuring timer.
            IN      A,($FE)         ; read the
            RLA                     ;
            BIT     7,E             ;
            LD      A,E             ;
            JR      C,L0388         ; loop back with carry to TRAILER

            DJNZ    L038A           ; to COUNTER

            POP     DE              ;
            JR      NZ,L039C        ; to BIT-DONE

            CP      $56             ;
            JR      NC,L034E        ; to NEXT-BIT

    ;; BIT-DONE
    L039C:  CCF                     ; complement carry flag
            RL      C               ;
            JR      NC,L034E        ; to NEXT-BIT

            RET                     ; return with full byte.

    ; ---

    ; if break is pressed while loading data then perform a reset.
    ; if break pressed while waiting for program on tape then OK to break.

    ;; BREAK-4
    L03A2:  LD      A,D             ; transfer indicator to A.
            AND     A               ; test for zero.
            JR      Z,L0361         ; back if so to RESTART

    ;; REPORT-D
    L03A6:  RST     08H             ; ERROR-1
            DEFB    $0C             ; Error Report: BREAK - CONT repeats

    ; -----------------------------
    ; THE 'PROGRAM NAME' SUBROUTINE
    ; -----------------------------
    ;
    ;

    ;; NAME
    L03A8:  CALL    L0F55           ; routine SCANNING
            LD      A,($4001)       ; sv FLAGS
            ADD     A,A             ;
            JP      M,L0D9A         ; to REPORT-C

            POP     HL              ;
            RET     NC              ;

            PUSH    HL              ;
            CALL    L02E7           ; routine SET-FAST
            CALL    L13F8           ; routine STK-FETCH
            LD      H,D             ;
            LD      L,E             ;
            DEC     C               ;
            RET     M               ;

            ADD     HL,BC           ;
            SET     7,(HL)          ;
            RET                     ;

    ; -------------------------
    ; THE 'NEW' COMMAND ROUTINE
    ; -------------------------
    ;
    ;

    ;; NEW
    L03C3:  CALL    L02E7           ; routine SET-FAST
            LD      BC,($4004)      ; fetch value of system variable RAMTOP
            DEC     BC              ; point to last system byte.

    ; -----------------------
    ; THE 'RAM CHECK' ROUTINE
    ; -----------------------
    ;
    ;

    ;; RAM-CHECK
    L03CB:  LD      H,B             ;
            LD      L,C             ;
            LD      A,$3F           ;

    ;; RAM-FILL
    L03CF:  LD      (HL),$02        ;
            DEC     HL              ;
            CP      H               ;
            JR      NZ,L03CF        ; to RAM-FILL

    ;; RAM-READ
    L03D5:  AND     A               ;
            SBC     HL,BC           ;
            ADD     HL,BC           ;
            INC     HL              ;
            JR      NC,L03E2        ; to SET-TOP

            DEC     (HL)            ;
            JR      Z,L03E2         ; to SET-TOP

            DEC     (HL)            ;
            JR      Z,L03D5         ; to RAM-READ

    ;; SET-TOP
    L03E2:  LD      ($4004),HL      ; set system variable RAMTOP to first byte
                                    ; above the BASIC system area.

    ; ----------------------------
    ; THE 'INITIALIZATION' ROUTINE
    ; ----------------------------
    ;
    ;

    ;; INITIAL
    L03E5:  LD      HL,($4004)      ; fetch system variable RAMTOP.
            DEC     HL              ; point to last system byte.
            LD      (HL),$3E        ; make GO SUB end-marker $3E - too high for
                                    ; high order byte of line number.
                                    ; (was $3F on ZX80)
            DEC     HL              ; point to unimportant low-order byte.
            LD      SP,HL           ; and initialize the stack-pointer to this
                                    ; location.
            DEC     HL              ; point to first location on the machine stack
            DEC     HL              ; which will be filled by next CALL/PUSH.
            LD      ($4002),HL      ; set the error stack pointer ERR_SP to
                                    ; the base of the now empty machine stack.

    ; Now set the I register so that the video hardware knows where to find the
    ; character set. This ROM only uses the character set when printing to
    ; the ZX Printer. The TV picture is formed by the external video hardware.
    ; Consider also, that this 8K ROM can be retro-fitted to the ZX80 instead of
    ; its original 4K ROM so the video hardware could be on the ZX80.

            LD      A,$1E           ; address for this ROM is $1E00.
            LD      I,A             ; set I register from A.
            IM      1               ; select Z80 Interrupt Mode 1.

            LD      IY,$4000        ; set IY to the start of RAM so that the
                                    ; system variables can be indexed.
            LD      (IY+$3B),$40    ; set CDFLAG 0100 0000. Bit 6 indicates
                                    ; Compute nad Display required.

            LD      HL,$407D        ; The first location after System Variables -
                                    ; 16509 decimal.
            LD      ($400C),HL      ; set system variable D_FILE to this value.
            LD      B,$19           ; prepare minimal screen of 24 NEWLINEs
                                    ; following an initial NEWLINE.

    ;; LINE
    L0408:  LD      (HL),$76        ; insert NEWLINE (HALT instruction)
            INC     HL              ; point to next location.
            DJNZ    L0408           ; loop back for all twenty five to LINE

            LD      ($4010),HL      ; set system variable VARS to next location

            CALL    L149A           ; routine CLEAR sets $80 end-marker and the
                                    ; dynamic memory pointers E_LINE, STKBOT and
                                    ; STKEND.

    ;; N/L-ONLY
    L0413:  CALL    L14AD           ; routine CURSOR-IN inserts the cursor and
                                    ; end-marker in the Edit Line also setting
                                    ; size of lower display to two lines.

            CALL    L0207           ; routine SLOW/FAST selects COMPUTE and DISPLAY

    ; ---------------------------
    ; THE 'BASIC LISTING' SECTION
    ; ---------------------------
    ;
    ;

    ;; UPPER
    L0419:  CALL    L0A2A           ; routine CLS
            LD      HL,($400A)      ; sv E_PPC_lo
            LD      DE,($4023)      ; sv S_TOP_lo
            AND     A               ;
            SBC     HL,DE           ;
            EX      DE,HL           ;
            JR      NC,L042D        ; to ADDR-TOP

            ADD     HL,DE           ;
            LD      ($4023),HL      ; sv S_TOP_lo

    ;; ADDR-TOP
    L042D:  CALL    L09D8           ; routine LINE-ADDR
            JR      Z,L0433         ; to LIST-TOP

            EX      DE,HL           ;

    ;; LIST-TOP
    L0433:  CALL    L073E           ; routine LIST-PROG
            DEC     (IY+$1E)        ; sv BERG
            JR      NZ,L0472        ; to LOWER

            LD      HL,($400A)      ; sv E_PPC_lo
            CALL    L09D8           ; routine LINE-ADDR
            LD      HL,($4016)      ; sv CH_ADD_lo
            SCF                     ; Set Carry Flag
            SBC     HL,DE           ;
            LD      HL,$4023        ; sv S_TOP_lo
            JR      NC,L0457        ; to INC-LINE

            EX      DE,HL           ;
            LD      A,(HL)          ;
            INC     HL              ;
            LDI                     ;
            LD      (DE),A          ;
            JR       L0419          ; to UPPER

    ; ---

    ;; DOWN-KEY
    L0454:  LD      HL,$400A        ; sv E_PPC_lo

    ;; INC-LINE
    L0457:  LD      E,(HL)          ;
            INC     HL              ;
            LD      D,(HL)          ;
            PUSH    HL              ;
            EX      DE,HL           ;
            INC     HL              ;
            CALL    L09D8           ; routine LINE-ADDR
            CALL    L05BB           ; routine LINE-NO
            POP     HL              ;

    ;; KEY-INPUT
    L0464:  BIT     5,(IY+$2D)      ; sv FLAGX
            JR      NZ,L0472        ; forward to LOWER

            LD      (HL),D          ;
            DEC     HL              ;
            LD      (HL),E          ;
            JR      L0419           ; to UPPER

    ; ----------------------------
    ; THE 'EDIT LINE COPY' SECTION
    ; ----------------------------
    ; This routine sets the edit line to just the cursor when
    ; 1) There is not enough memory to edit a BASIC line.
    ; 2) The edit key is used during input.
    ; The entry point LOWER

    ;; EDIT-INP
    L046F:  CALL    L14AD           ; routine CURSOR-IN sets cursor only edit line.

    ; ->

    ;; LOWER
    L0472:  LD      HL,($4014)      ; fetch edit line start from E_LINE.

    ;; EACH-CHAR
    L0475:  LD      A,(HL)          ; fetch a character from edit line.
            CP      $7E             ; compare to the number marker.
            JR      NZ,L0482        ; forward if not to END-LINE

            LD      BC,$0006        ; else six invisible bytes to be removed.
            CALL    L0A60           ; routine RECLAIM-2
            JR      L0475           ; back to EACH-CHAR

    ; ---

    ;; END-LINE
    L0482:  CP      $76             ;
            INC     HL              ;
            JR      NZ,L0475        ; to EACH-CHAR

    ;; EDIT-LINE
    L0487:  CALL    L0537           ; routine CURSOR sets cursor K or L.

    ;; EDIT-ROOM
    L048A:  CALL    L0A1F           ; routine LINE-ENDS
            LD      HL,($4014)      ; sv E_LINE_lo
            LD      (IY+$00),$FF    ; sv ERR_NR
            CALL    L0766           ; routine COPY-LINE
            BIT     7,(IY+$00)      ; sv ERR_NR
            JR      NZ,L04C1        ; to DISPLAY-6

            LD      A,($4022)       ; sv DF_SZ
            CP      $18             ;
            JR      NC,L04C1        ; to DISPLAY-6

            INC     A               ;
            LD      ($4022),A       ; sv DF_SZ
            LD      B,A             ;
            LD      C,$01           ;
            CALL    L0918           ; routine LOC-ADDR
            LD      D,H             ;
            LD      E,L             ;
            LD      A,(HL)          ;

    ;; FREE-LINE
    L04B1:  DEC     HL              ;
            CP      (HL)            ;
            JR      NZ,L04B1        ; to FREE-LINE

            INC     HL              ;
            EX      DE,HL           ;
            LD      A,($4005)       ; sv RAMTOP_hi
            CP      $4D             ;
            CALL    C,L0A5D         ; routine RECLAIM-1
            JR      L048A           ; to EDIT-ROOM

    ; --------------------------
    ; THE 'WAIT FOR KEY' SECTION
    ; --------------------------
    ;
    ;

    ;; DISPLAY-6
    L04C1:  LD      HL,$0000        ;
            LD      ($4018),HL      ; sv X_PTR_lo

            LD      HL,$403B        ; system variable CDFLAG
            BIT     7,(HL)          ;

            CALL    Z,L0229         ; routine DISPLAY-1

    ;; SLOW-DISP
    L04CF:  BIT     0,(HL)          ;
            JR      Z,L04CF         ; to SLOW-DISP

            LD      BC,($4025)      ; sv LAST_K
            CALL    L0F4B           ; routine DEBOUNCE
            CALL    L07BD           ; routine DECODE

            JR      NC,L0472        ; back to LOWER

    ; -------------------------------
    ; THE 'KEYBOARD DECODING' SECTION
    ; -------------------------------
    ;   The decoded key value is in E and HL points to the position in the
    ;   key table. D contains zero.

    ;; K-DECODE
    L04DF:  LD      A,($4006)       ; Fetch value of system variable MODE
            DEC     A               ; test the three values together

            JP      M,L0508         ; forward, if was zero, to FETCH-2

            JR      NZ,L04F7        ; forward, if was 2, to FETCH-1

    ;   The original value was one and is now zero.

            LD      ($4006),A       ; update the system variable MODE

            DEC     E               ; reduce E to range $00 - $7F
            LD      A,E             ; place in A
            SUB     $27             ; subtract 39 setting carry if range 00 - 38
            JR      C,L04F2         ; forward, if so, to FUNC-BASE

            LD      E,A             ; else set E to reduced value

    ;; FUNC-BASE
    L04F2:  LD      HL,L00CC        ; address of K-FUNCT table for function keys.
            JR      L0505           ; forward to TABLE-ADD

    ; ---

    ;; FETCH-1
    L04F7:  LD      A,(HL)          ;
            CP      $76             ;
            JR      Z,L052B         ; to K/L-KEY

            CP      $40             ;
            SET     7,A             ;
            JR      C,L051B         ; to ENTER

            LD      HL,$00C7        ; (expr reqd)

    ;; TABLE-ADD
    L0505:  ADD     HL,DE           ;
            JR      L0515           ; to FETCH-3

    ; ---

    ;; FETCH-2
    L0508:  LD      A,(HL)          ;
            BIT     2,(IY+$01)      ; sv FLAGS  - K or L mode ?
            JR      NZ,L0516        ; to TEST-CURS

            ADD     A,$C0           ;
            CP      $E6             ;
            JR      NC,L0516        ; to TEST-CURS

    ;; FETCH-3
    L0515:  LD      A,(HL)          ;

    ;; TEST-CURS
    L0516:  CP      $F0             ;
            JP      PE,L052D        ; to KEY-SORT

    ;; ENTER
    L051B:  LD      E,A             ;
            CALL    L0537           ; routine CURSOR

            LD      A,E             ;
            CALL    L0526           ; routine ADD-CHAR

    ;; BACK-NEXT
    L0523:  JP      L0472           ; back to LOWER

    ; ------------------------------
    ; THE 'ADD CHARACTER' SUBROUTINE
    ; ------------------------------
    ;
    ;

    ;; ADD-CHAR
    L0526:  CALL    L099B           ; routine ONE-SPACE
            LD      (DE),A          ;
            RET                     ;

    ; -------------------------
    ; THE 'CURSOR KEYS' ROUTINE
    ; -------------------------
    ;
    ;

    ;; K/L-KEY
    L052B:  LD      A,$78           ;

    ;; KEY-SORT
    L052D:  LD      E,A             ;
            LD      HL,$0482        ; base address of ED-KEYS (exp reqd)
            ADD     HL,DE           ;
            ADD     HL,DE           ;
            LD      C,(HL)          ;
            INC     HL              ;
            LD      B,(HL)          ;
            PUSH    BC              ;

    ;; CURSOR
    L0537:  LD      HL,($4014)      ; sv E_LINE_lo
            BIT     5,(IY+$2D)      ; sv FLAGX
            JR      NZ,L0556        ; to L-MODE

    ;; K-MODE
    L0540:  RES     2,(IY+$01)      ; sv FLAGS  - Signal use K mode

    ;; TEST-CHAR
    L0544:  LD      A,(HL)          ;
            CP      $7F             ;
            RET     Z               ; return

            INC     HL              ;
            CALL    L07B4           ; routine NUMBER
            JR      Z,L0544         ; to TEST-CHAR

            CP      $26             ;
            JR      C,L0544         ; to TEST-CHAR

            CP      $DE             ;
            JR      Z,L0540         ; to K-MODE

    ;; L-MODE
    L0556:  SET     2,(IY+$01)      ; sv FLAGS  - Signal use L mode
            JR      L0544           ; to TEST-CHAR

    ; --------------------------
    ; THE 'CLEAR-ONE' SUBROUTINE
    ; --------------------------
    ;
    ;

    ;; CLEAR-ONE
    L055C:  LD      BC,$0001        ;
            JP      L0A60           ; to RECLAIM-2

    ; ------------------------
    ; THE 'EDITING KEYS' TABLE
    ; ------------------------
    ;
    ;

    ;; ED-KEYS
    L0562:  DEFW    L059F           ; Address: $059F; Address: UP-KEY
            DEFW    L0454           ; Address: $0454; Address: DOWN-KEY
            DEFW    L0576           ; Address: $0576; Address: LEFT-KEY
            DEFW    L057F           ; Address: $057F; Address: RIGHT-KEY
            DEFW    L05AF           ; Address: $05AF; Address: FUNCTION
            DEFW    L05C4           ; Address: $05C4; Address: EDIT-KEY
            DEFW    L060C           ; Address: $060C; Address: N/L-KEY
            DEFW    L058B           ; Address: $058B; Address: RUBOUT
            DEFW    L05AF           ; Address: $05AF; Address: FUNCTION
            DEFW    L05AF           ; Address: $05AF; Address: FUNCTION

    ; -------------------------
    ; THE 'CURSOR LEFT' ROUTINE
    ; -------------------------
    ;
    ;

    ;; LEFT-KEY
    L0576:  CALL    L0593           ; routine LEFT-EDGE
            LD      A,(HL)          ;
            LD      (HL),$7F        ;
            INC     HL              ;
            JR      L0588           ; to GET-CODE

    ; --------------------------
    ; THE 'CURSOR RIGHT' ROUTINE
    ; --------------------------
    ;
    ;

    ;; RIGHT-KEY
    L057F:  INC     HL              ;
            LD      A,(HL)          ;
            CP      $76             ;
            JR      Z,L059D         ; to ENDED-2

            LD      (HL),$7F        ;
            DEC     HL              ;

    ;; GET-CODE
    L0588:  LD      (HL),A          ;

    ;; ENDED-1
    L0589:  JR      L0523           ; to BACK-NEXT

    ; --------------------
    ; THE 'RUBOUT' ROUTINE
    ; --------------------
    ;
    ;

    ;; RUBOUT
    L058B:  CALL    L0593           ; routine LEFT-EDGE
            CALL    L055C           ; routine CLEAR-ONE
            JR      L0589           ; to ENDED-1

    ; ------------------------
    ; THE 'ED-EDGE' SUBROUTINE
    ; ------------------------
    ;
    ;

    ;; LEFT-EDGE
    L0593:  DEC     HL              ;
            LD      DE,($4014)      ; sv E_LINE_lo
            LD      A,(DE)          ;
            CP      $7F             ;
            RET     NZ              ;

            POP     DE              ;

    ;; ENDED-2
    L059D:  JR      L0589           ; to ENDED-1

    ; -----------------------
    ; THE 'CURSOR UP' ROUTINE
    ; -----------------------
    ;
    ;

    ;; UP-KEY
    L059F:  LD      HL,($400A)      ; sv E_PPC_lo
            CALL    L09D8           ; routine LINE-ADDR
            EX      DE,HL           ;
            CALL    L05BB           ; routine LINE-NO
            LD      HL,$400B        ; point to system variable E_PPC_hi
            JP      L0464           ; jump back to KEY-INPUT

    ; --------------------------
    ; THE 'FUNCTION KEY' ROUTINE
    ; --------------------------
    ;
    ;

    ;; FUNCTION
    L05AF:  LD      A,E             ;
            AND     $07             ;
            LD      ($4006),A       ; sv MODE
            JR      L059D           ; back to ENDED-2

    ; ------------------------------------
    ; THE 'COLLECT LINE NUMBER' SUBROUTINE
    ; ------------------------------------
    ;
    ;

    ;; ZERO-DE
    L05B7:  EX      DE,HL           ;
            LD      DE,L04C1 + 1    ; $04C2 - a location addressing two zeros.

    ; ->

    ;; LINE-NO
    L05BB:  LD      A,(HL)          ;
            AND     $C0             ;
            JR      NZ,L05B7        ; to ZERO-DE

            LD      D,(HL)          ;
            INC     HL              ;
            LD      E,(HL)          ;
            RET                     ;

    ; ----------------------
    ; THE 'EDIT KEY' ROUTINE
    ; ----------------------
    ;
    ;

    ;; EDIT-KEY
    L05C4:  CALL    L0A1F           ; routine LINE-ENDS clears lower display.

            LD      HL,L046F        ; Address: EDIT-INP
            PUSH    HL              ; ** is pushed as an error looping address.

            BIT     5,(IY+$2D)      ; test FLAGX
            RET     NZ              ; indirect jump if in input mode
                                    ; to L046F, EDIT-INP (begin again).

    ;

            LD      HL,($4014)      ; fetch E_LINE
            LD      ($400E),HL      ; and use to update the screen cursor DF_CC

    ; so now RST $10 will print the line numbers to the edit line instead of screen.
    ; first make sure that no newline/out of screen can occur while sprinting the
    ; line numbers to the edit line.

            LD      HL,$1821        ; prepare line 0, column 0.
            LD      ($4039),HL      ; update S_POSN with these dummy values.

            LD      HL,($400A)      ; fetch current line from E_PPC may be a
                                    ; non-existent line e.g. last line deleted.
            CALL    L09D8           ; routine LINE-ADDR gets address or that of
                                    ; the following line.
            CALL    L05BB           ; routine LINE-NO gets line number if any in DE
                                    ; leaving HL pointing at second low byte.

            LD      A,D             ; test the line number for zero.
            OR      E               ;
            RET     Z               ; return if no line number - no program to edit.

            DEC     HL              ; point to high byte.
            CALL    L0AA5           ; routine OUT-NO writes number to edit line.

            INC     HL              ; point to length bytes.
            LD      C,(HL)          ; low byte to C.
            INC     HL              ;
            LD      B,(HL)          ; high byte to B.

            INC     HL              ; point to first character in line.
            LD      DE,($400E)      ; fetch display file cursor DF_CC

            LD      A,$7F           ; prepare the cursor character.
            LD      (DE),A          ; and insert in edit line.
            INC     DE              ; increment intended destination.

            PUSH    HL              ; * save start of BASIC.

            LD      HL,$001D        ; set an overhead of 29 bytes.
            ADD     HL,DE           ; add in the address of cursor.
            ADD     HL,BC           ; add the length of the line.
            SBC     HL,SP           ; subtract the stack pointer.

            POP     HL              ; * restore pointer to start of BASIC.

            RET     NC              ; return if not enough room to L046F EDIT-INP.
                                    ; the edit key appears not to work.

            LDIR                    ; else copy bytes from program to edit line.
                                    ; Note. hidden floating point forms are also
                                    ; copied to edit line.

            EX      DE,HL           ; transfer free location pointer to HL

            POP     DE              ; ** remove address EDIT-INP from stack.

            CALL    L14A6           ; routine SET-STK-B sets STKEND from HL.

            JR      L059D           ; back to ENDED-2 and after 3 more jumps
                                    ; to L0472, LOWER.
                                    ; Note. The LOWER routine removes the hidden
                                    ; floating-point numbers from the edit line.

    ; -------------------------
    ; THE 'NEWLINE KEY' ROUTINE
    ; -------------------------
    ;
    ;

    ;; N/L-KEY
    L060C:  CALL    L0A1F           ; routine LINE-ENDS

            LD      HL,L0472        ; prepare address: LOWER

            BIT     5,(IY+$2D)      ; sv FLAGX
            JR      NZ,L0629        ; to NOW-SCAN

            LD      HL,($4014)      ; sv E_LINE_lo
            LD      A,(HL)          ;
            CP      $FF             ;
            JR      Z,L0626         ; to STK-UPPER

            CALL    L08E2           ; routine CLEAR-PRB
            CALL    L0A2A           ; routine CLS

    ;; STK-UPPER
    L0626:  LD      HL,L0419        ; Address: UPPER

    ;; NOW-SCAN
    L0629:  PUSH    HL              ; push routine address (LOWER or UPPER).
            CALL    L0CBA           ; routine LINE-SCAN
            POP     HL              ;
            CALL    L0537           ; routine CURSOR
            CALL    L055C           ; routine CLEAR-ONE
            CALL    L0A73           ; routine E-LINE-NO
            JR      NZ,L064E        ; to N/L-INP

            LD      A,B             ;
            OR      C               ;
            JP      NZ,L06E0        ; to N/L-LINE

            DEC     BC              ;
            DEC     BC              ;
            LD      ($4007),BC      ; sv PPC_lo
            LD      (IY+$22),$02    ; sv DF_SZ
            LD      DE,($400C)      ; sv D_FILE_lo

            JR      L0661           ; forward to TEST-NULL

    ; ---

    ;; N/L-INP
    L064E:  CP      $76             ;
            JR      Z,L0664         ; to N/L-NULL

            LD      BC,($4030)      ; sv T_ADDR_lo
            CALL    L0918           ; routine LOC-ADDR
            LD      DE,($4029)      ; sv NXTLIN_lo
            LD      (IY+$22),$02    ; sv DF_SZ

    ;; TEST-NULL
    L0661:  RST     18H             ; GET-CHAR
            CP      $76             ;

    ;; N/L-NULL
    L0664:  JP      Z,L0413         ; to N/L-ONLY

            LD      (IY+$01),$80    ; sv FLAGS
            EX      DE,HL           ;

    ;; NEXT-LINE
    L066C:  LD      ($4029),HL      ; sv NXTLIN_lo
            EX      DE,HL           ;
            CALL    L004D           ; routine TEMP-PTR-2
            CALL    L0CC1           ; routine LINE-RUN
            RES     1,(IY+$01)      ; sv FLAGS  - Signal printer not in use
            LD      A,$C0           ;
            LD      (IY+$19),A      ; sv X_PTR_lo
            CALL    L14A3           ; routine X-TEMP
            RES     5,(IY+$2D)      ; sv FLAGX
            BIT     7,(IY+$00)      ; sv ERR_NR
            JR      Z,L06AE         ; to STOP-LINE

            LD      HL,($4029)      ; sv NXTLIN_lo
            AND     (HL)            ;
            JR       NZ,L06AE       ; to STOP-LINE

            LD      D,(HL)          ;
            INC     HL              ;
            LD      E,(HL)          ;
            LD      ($4007),DE      ; sv PPC_lo
            INC     HL              ;
            LD      E,(HL)          ;
            INC     HL              ;
            LD      D,(HL)          ;
            INC     HL              ;
            EX      DE,HL           ;
            ADD     HL,DE           ;
            CALL    L0F46           ; routine BREAK-1
            JR      C,L066C         ; to NEXT-LINE

            LD      HL,$4000        ; sv ERR_NR
            BIT     7,(HL)          ;
            JR      Z,L06AE         ; to STOP-LINE

            LD      (HL),$0C        ;

    ;; STOP-LINE
    L06AE:  BIT     7,(IY+$38)      ; sv PR_CC
            CALL    Z,L0871         ; routine COPY-BUFF
            LD      BC,$0121        ;
            CALL    L0918           ; routine LOC-ADDR
            LD      A,($4000)       ; sv ERR_NR
            LD      BC,($4007)      ; sv PPC_lo
            INC     A               ;
            JR      Z,L06D1         ; to REPORT

            CP      $09             ;
            JR      NZ,L06CA        ; to CONTINUE

            INC     BC              ;

    ;; CONTINUE
    L06CA:  LD      ($402B),BC      ; sv OLDPPC_lo
            JR      NZ,L06D1        ; to REPORT

            DEC     BC              ;

    ;; REPORT
    L06D1:  CALL    L07EB           ; routine OUT-CODE
            LD      A,$18           ;

            RST     10H             ; PRINT-A
            CALL    L0A98           ; routine OUT-NUM
            CALL    L14AD           ; routine CURSOR-IN
            JP      L04C1           ; to DISPLAY-6

    ; ---

    ;; N/L-LINE
    L06E0:  LD      ($400A),BC      ; sv E_PPC_lo
            LD      HL,($4016)      ; sv CH_ADD_lo
            EX      DE,HL           ;
            LD      HL,L0413        ; Address: N/L-ONLY
            PUSH    HL              ;
            LD      HL,($401A)      ; sv STKBOT_lo
            SBC     HL,DE           ;
            PUSH    HL              ;
            PUSH    BC              ;
            CALL    L02E7           ; routine SET-FAST
            CALL    L0A2A           ; routine CLS
            POP     HL              ;
            CALL    L09D8           ; routine LINE-ADDR
            JR      NZ,L0705        ; to COPY-OVER

            CALL    L09F2           ; routine NEXT-ONE
            CALL    L0A60           ; routine RECLAIM-2

    ;; COPY-OVER
    L0705:  POP     BC              ;
            LD      A,C             ;
            DEC     A               ;
            OR      B               ;
            RET     Z               ;

            PUSH    BC              ;
            INC     BC              ;
            INC     BC              ;
            INC     BC              ;
            INC     BC              ;
            DEC     HL              ;
            CALL    L099E           ; routine MAKE-ROOM
            CALL    L0207           ; routine SLOW/FAST
            POP     BC              ;
            PUSH    BC              ;
            INC     DE              ;
            LD      HL,($401A)      ; sv STKBOT_lo
            DEC     HL              ;
            LDDR                    ; copy bytes
            LD      HL,($400A)      ; sv E_PPC_lo
            EX      DE,HL           ;
            POP     BC              ;
            LD      (HL),B          ;
            DEC     HL              ;
            LD      (HL),C          ;
            DEC     HL              ;
            LD      (HL),E          ;
            DEC     HL              ;
            LD      (HL),D          ;

            RET                     ; return.

    ; ---------------------------------------
    ; THE 'LIST' AND 'LLIST' COMMAND ROUTINES
    ; ---------------------------------------
    ;
    ;

    ;; LLIST
    L072C:  SET     1,(IY+$01)      ; sv FLAGS  - signal printer in use

    ;; LIST
    L0730:  CALL    L0EA7           ; routine FIND-INT

            LD      A,B             ; fetch high byte of user-supplied line number.
            AND     $3F             ; and crudely limit to range 1-16383.

            LD      H,A             ;
            LD      L,C             ;
            LD      ($400A),HL      ; sv E_PPC_lo
            CALL    L09D8           ; routine LINE-ADDR

    ;; LIST-PROG
    L073E:  LD      E,$00           ;

    ;; UNTIL-END
    L0740:  CALL    L0745           ; routine OUT-LINE lists one line of BASIC
                                    ; making an early return when the screen is
                                    ; full or the end of program is reached.    >>
            JR      L0740           ; loop back to UNTIL-END

    ; -----------------------------------
    ; THE 'PRINT A BASIC LINE' SUBROUTINE
    ; -----------------------------------
    ;
    ;

    ;; OUT-LINE
    L0745:  LD      BC,($400A)      ; sv E_PPC_lo
            CALL    L09EA           ; routine CP-LINES
            LD      D,$92           ;
            JR      Z,L0755         ; to TEST-END

            LD      DE,$0000        ;
            RL      E               ;

    ;; TEST-END
    L0755:  LD      (IY+$1E),E      ; sv BERG
            LD      A,(HL)          ;
            CP      $40             ;
            POP     BC              ;
            RET     NC              ;

            PUSH    BC              ;
            CALL    L0AA5           ; routine OUT-NO
            INC     HL              ;
            LD      A,D             ;

            RST     10H             ; PRINT-A
            INC     HL              ;
            INC     HL              ;

    ;; COPY-LINE
    L0766:  LD      ($4016),HL      ; sv CH_ADD_lo
            SET     0,(IY+$01)      ; sv FLAGS  - Suppress leading space

    ;; MORE-LINE
    L076D:  LD      BC,($4018)      ; sv X_PTR_lo
            LD      HL,($4016)      ; sv CH_ADD_lo
            AND      A              ;
            SBC     HL,BC           ;
            JR      NZ,L077C        ; to TEST-NUM

            LD      A,$B8           ;

            RST     10H             ; PRINT-A

    ;; TEST-NUM
    L077C:  LD      HL,($4016)      ; sv CH_ADD_lo
            LD      A,(HL)          ;
            INC     HL              ;
            CALL    L07B4           ; routine NUMBER
            LD      ($4016),HL      ; sv CH_ADD_lo
            JR      Z,L076D         ; to MORE-LINE

            CP      $7F             ;
            JR      Z,L079D         ; to OUT-CURS

            CP      $76             ;
            JR      Z,L07EE         ; to OUT-CH

            BIT     6,A             ;
            JR      Z,L079A         ; to NOT-TOKEN

            CALL    L094B           ; routine TOKENS
            JR      L076D           ; to MORE-LINE

    ; ---

    ;; NOT-TOKEN
    L079A:  RST     10H             ; PRINT-A
            JR      L076D           ; to MORE-LINE

    ; ---

    ;; OUT-CURS
    L079D:  LD      A,($4006)       ; Fetch value of system variable MODE
            LD      B,$AB           ; Prepare an inverse [F] for function cursor.

            AND     A               ; Test for zero -
            JR      NZ,L07AA        ; forward if not to FLAGS-2

            LD      A,($4001)       ; Fetch system variable FLAGS.
            LD      B,$B0           ; Prepare an inverse [K] for keyword cursor.

    ;; FLAGS-2
    L07AA:  RRA                     ; 00000?00 -> 000000?0
            RRA                     ; 000000?0 -> 0000000?
            AND     $01             ; 0000000?    0000000x

            ADD     A,B             ; Possibly [F] -> [G]  or  [K] -> [L]

            CALL    L07F5           ; routine PRINT-SP prints character
            JR      L076D           ; back to MORE-LINE

    ; -----------------------
    ; THE 'NUMBER' SUBROUTINE
    ; -----------------------
    ;
    ;

    ;; NUMBER
    L07B4:  CP      $7E             ;
            RET     NZ              ;

            INC     HL              ;
            INC     HL              ;
            INC     HL              ;
            INC     HL              ;
            INC     HL              ;
            RET                     ;

    ; --------------------------------
    ; THE 'KEYBOARD DECODE' SUBROUTINE
    ; --------------------------------
    ;
    ;

    ;; DECODE
    L07BD:  LD      D,$00           ;
            SRA     B               ;
            SBC     A,A             ;
            OR      $26             ;
            LD      L,$05           ;
            SUB     L               ;

    ;; KEY-LINE
    L07C7:  ADD     A,L             ;
            SCF                     ; Set Carry Flag
            RR      C               ;
            JR      C,L07C7         ; to KEY-LINE

            INC     C               ;
            RET      NZ             ;

            LD      C,B             ;
            DEC     L               ;
            LD      L,$01           ;
            JR      NZ,L07C7        ; to KEY-LINE

            LD      HL,$007D        ; (expr reqd)
            LD      E,A             ;
            ADD     HL,DE           ;
            SCF                     ; Set Carry Flag
            RET                     ;

    ; -------------------------
    ; THE 'PRINTING' SUBROUTINE
    ; -------------------------
    ;
    ;

    ;; LEAD-SP
    L07DC:  LD      A,E             ;
            AND     A               ;
            RET     M               ;

            JR      L07F1           ; to PRINT-CH

    ; ---

    ;; OUT-DIGIT
    L07E1:  XOR     A               ;

    ;; DIGIT-INC
    L07E2:  ADD     HL,BC           ;
            INC     A               ;
            JR      C,L07E2         ; to DIGIT-INC

            SBC     HL,BC           ;
            DEC     A               ;
            JR      Z,L07DC         ; to LEAD-SP

    ;; OUT-CODE
    L07EB:  LD      E,$1C           ;
            ADD     A,E             ;

    ;; OUT-CH
    L07EE:  AND     A               ;
            JR      Z,L07F5         ; to PRINT-SP

    ;; PRINT-CH
    L07F1:  RES     0,(IY+$01)      ; update FLAGS - signal leading space permitted

    ;; PRINT-SP
    L07F5:  EXX                     ;
            PUSH    HL              ;
            BIT     1,(IY+$01)      ; test FLAGS - is printer in use ?
            JR      NZ,L0802        ; to LPRINT-A

            CALL    L0808           ; routine ENTER-CH
            JR      L0805           ; to PRINT-EXX

    ; ---

    ;; LPRINT-A
    L0802:  CALL    L0851           ; routine LPRINT-CH

    ;; PRINT-EXX
    L0805:  POP     HL              ;
            EXX                     ;
            RET                     ;

    ; ---

    ;; ENTER-CH
    L0808:  LD      D,A             ;
            LD      BC,($4039)      ; sv S_POSN_x
            LD      A,C             ;
            CP      $21             ;
            JR      Z,L082C         ; to TEST-LOW

    ;; TEST-N/L
    L0812:  LD      A,$76           ;
            CP      D               ;
            JR      Z,L0847         ; to WRITE-N/L

            LD      HL,($400E)      ; sv DF_CC_lo
            CP      (HL)            ;
            LD      A,D             ;
            JR      NZ,L083E        ; to WRITE-CH

            DEC     C               ;
            JR      NZ,L083A        ; to EXPAND-1

            INC     HL              ;
            LD       ($400E),HL     ; sv DF_CC_lo
            LD      C,$21           ;
            DEC     B               ;
            LD      ($4039),BC      ; sv S_POSN_x

    ;; TEST-LOW
    L082C:  LD      A,B             ;
            CP      (IY+$22)        ; sv DF_SZ
            JR      Z,L0835         ; to REPORT-5

            AND     A               ;
            JR      NZ,L0812        ; to TEST-N/L

    ;; REPORT-5
    L0835:  LD      L,$04           ; 'No more room on screen'
            JP      L0058           ; to ERROR-3

    ; ---

    ;; EXPAND-1
    L083A:  CALL    L099B           ; routine ONE-SPACE
            EX      DE,HL           ;

    ;; WRITE-CH
    L083E:  LD      (HL),A          ;
            INC     HL              ;
            LD      ($400E),HL      ; sv DF_CC_lo
            DEC     (IY+$39)        ; sv S_POSN_x
            RET                     ;

    ; ---

    ;; WRITE-N/L
    L0847:  LD      C,$21           ;
            DEC     B               ;
            SET     0,(IY+$01)      ; sv FLAGS  - Suppress leading space
            JP      L0918           ; to LOC-ADDR

    ; --------------------------
    ; THE 'LPRINT-CH' SUBROUTINE
    ; --------------------------
    ; This routine sends a character to the ZX-Printer placing the code for the
    ; character in the Printer Buffer.
    ; Note. PR-CC contains the low byte of the buffer address. The high order byte
    ; is always constant.

    ;; LPRINT-CH
    L0851:  CP      $76             ; compare to NEWLINE.
            JR      Z,L0871         ; forward if so to COPY-BUFF

            LD      C,A             ; take a copy of the character in C.
            LD      A,($4038)       ; fetch print location from PR_CC
            AND     $7F             ; ignore bit 7 to form true position.
            CP      $5C             ; compare to 33rd location

            LD      L,A             ; form low-order byte.
            LD      H,$40           ; the high-order byte is fixed.

            CALL    Z,L0871         ; routine COPY-BUFF to send full buffer to
                                    ; the printer if first 32 bytes full.
                                    ; (this will reset HL to start.)

            LD      (HL),C          ; place character at location.
            INC     L               ; increment - will not cross a 256 boundary.
            LD      (IY+$38),L      ; update system variable PR_CC
                                    ; automatically resetting bit 7 to show that
                                    ; the buffer is not empty.
            RET                     ; return.

    ; --------------------------
    ; THE 'COPY' COMMAND ROUTINE
    ; --------------------------
    ; The full character-mapped screen is copied to the ZX-Printer.
    ; All twenty-four text/graphic lines are printed.

    ;; COPY
    L0869:  LD      D,$16           ; prepare to copy twenty four text lines.
            LD      HL,($400C)      ; set HL to start of display file from D_FILE.
            INC     HL              ;
            JR      L0876           ; forward to COPY*D

    ; ---

    ; A single character-mapped printer buffer is copied to the ZX-Printer.

    ;; COPY-BUFF
    L0871:  LD      D,$01           ; prepare to copy a single text line.
            LD      HL,$403C        ; set HL to start of printer buffer PRBUFF.

    ; both paths converge here.

    ;; COPY*D
    L0876:  CALL    L02E7           ; routine SET-FAST

            PUSH    BC              ; *** preserve BC throughout.
                                    ; a pending character may be present
                                    ; in C from LPRINT-CH

    ;; COPY-LOOP
    L087A:  PUSH    HL              ; save first character of line pointer. (*)
            XOR     A               ; clear accumulator.
            LD      E,A             ; set pixel line count, range 0-7, to zero.

    ; this inner loop deals with each horizontal pixel line.

    ;; COPY-TIME
    L087D:  OUT     ($FB),A         ; bit 2 reset starts the printer motor
                                    ; with an inactive stylus - bit 7 reset.
            POP     HL              ; pick up first character of line pointer (*)
                                    ; on inner loop.

    ;; COPY-BRK
    L0880:  CALL    L0F46           ; routine BREAK-1
            JR      C,L088A         ; forward with no keypress to COPY-CONT

    ; else A will hold 11111111 0

            RRA                     ; 0111 1111
            OUT     ($FB),A         ; stop ZX printer motor, de-activate stylus.

    ;; REPORT-D2
    L0888:  RST     08H             ; ERROR-1
            DEFB    $0C             ; Error Report: BREAK - CONT repeats

    ; ---

    ;; COPY-CONT
    L088A:  IN      A,($FB)         ; read from printer port.
            ADD     A,A             ; test bit 6 and 7
            JP      M,L08DE         ; jump forward with no printer to COPY-END

            JR      NC,L0880        ; back if stylus not in position to COPY-BRK

            PUSH    HL              ; save first character of line pointer (*)
            PUSH    DE              ; ** preserve character line and pixel line.

            LD      A,D             ; text line count to A?
            CP      $02             ; sets carry if last line.
            SBC     A,A             ; now $FF if last line else zero.

    ; now cleverly prepare a printer control mask setting bit 2 (later moved to 1)
    ; of D to slow printer for the last two pixel lines ( E = 6 and 7)

            AND     E               ; and with pixel line offset 0-7
            RLCA                    ; shift to left.
            AND     E               ; and again.
            LD      D,A             ; store control mask in D.

    ;; COPY-NEXT
    L089C:  LD      C,(HL)          ; load character from screen or buffer.
            LD      A,C             ; save a copy in C for later inverse test.
            INC     HL              ; update pointer for next time.
            CP      $76             ; is character a NEWLINE ?
            JR      Z,L08C7         ; forward, if so, to COPY-N/L

            PUSH    HL              ; * else preserve the character pointer.

            SLA     A               ; (?) multiply by two
            ADD     A,A             ; multiply by four
            ADD     A,A             ; multiply by eight

            LD      H,$0F           ; load H with half the address of character set.
            RL      H               ; now $1E or $1F (with carry)
            ADD     A,E             ; add byte offset 0-7
            LD      L,A             ; now HL addresses character source byte

            RL      C               ; test character, setting carry if inverse.
            SBC     A,A             ; accumulator now $00 if normal, $FF if inverse.

            XOR     (HL)            ; combine with bit pattern at end or ROM.
            LD      C,A             ; transfer the byte to C.
            LD      B,$08           ; count eight bits to output.

    ;; COPY-BITS
    L08B5:  LD      A,D             ; fetch speed control mask from D.
            RLC     C               ; rotate a bit from output byte to carry.
            RRA                     ; pick up in bit 7, speed bit to bit 1
            LD      H,A             ; store aligned mask in H register.

    ;; COPY-WAIT
    L08BA:  IN      A,($FB)         ; read the printer port
            RRA                     ; test for alignment signal from encoder.
            JR      NC,L08BA        ; loop if not present to COPY-WAIT

            LD      A,H             ; control byte to A.
            OUT     ($FB),A         ; and output to printer port.
            DJNZ    L08B5           ; loop for all eight bits to COPY-BITS

            POP     HL              ; * restore character pointer.
            JR      L089C           ; back for adjacent character line to COPY-NEXT

    ; ---

    ; A NEWLINE has been encountered either following a text line or as the
    ; first character of the screen or printer line.

    ;; COPY-N/L
    L08C7:  IN      A,($FB)         ; read printer port.
            RRA                     ; wait for encoder signal.
            JR      NC,L08C7        ; loop back if not to COPY-N/L

            LD      A,D             ; transfer speed mask to A.
            RRCA                    ; rotate speed bit to bit 1.
                                    ; bit 7, stylus control is reset.
            OUT     ($FB),A         ; set the printer speed.

            POP     DE              ; ** restore character line and pixel line.
            INC     E               ; increment pixel line 0-7.
            BIT     3,E             ; test if value eight reached.
            JR      Z,L087D         ; back if not to COPY-TIME

    ; eight pixel lines, a text line have been completed.

            POP     BC              ; lose the now redundant first character
                                    ; pointer
            DEC     D               ; decrease text line count.
            JR      NZ,L087A        ; back if not zero to COPY-LOOP

            LD      A,$04           ; stop the already slowed printer motor.
            OUT     ($FB),A         ; output to printer port.

    ;; COPY-END
    L08DE:  CALL    L0207           ; routine SLOW/FAST
            POP     BC              ; *** restore preserved BC.

    ; -------------------------------------
    ; THE 'CLEAR PRINTER BUFFER' SUBROUTINE
    ; -------------------------------------
    ; This subroutine sets 32 bytes of the printer buffer to zero (space) and
    ; the 33rd character is set to a NEWLINE.
    ; This occurs after the printer buffer is sent to the printer but in addition
    ; after the 24 lines of the screen are sent to the printer.
    ; Note. This is a logic error as the last operation does not involve the
    ; buffer at all. Logically one should be able to use
    ; 10 LPRINT "HELLO ";
    ; 20 COPY
    ; 30 LPRINT ; "WORLD"
    ; and expect to see the entire greeting emerge from the printer.
    ; Surprisingly this logic error was never discovered and although one can argue
    ; if the above is a bug, the repetition of this error on the Spectrum was most
    ; definitely a bug.
    ; Since the printer buffer is fixed at the end of the system variables, and
    ; the print position is in the range $3C - $5C, then bit 7 of the system
    ; variable is set to show the buffer is empty and automatically reset when
    ; the variable is updated with any print position - neat.

    ;; CLEAR-PRB
    L08E2:  LD      HL,$405C        ; address fixed end of PRBUFF
            LD      (HL),$76        ; place a newline at last position.
            LD      B,$20           ; prepare to blank 32 preceding characters.

    ;; PRB-BYTES
    L08E9:  DEC     HL              ; decrement address - could be DEC L.
            LD      (HL),$00        ; place a zero byte.
            DJNZ    L08E9           ; loop for all thirty-two to PRB-BYTES

            LD      A,L             ; fetch character print position.
            SET     7,A             ; signal the printer buffer is clear.
            LD      ($4038),A       ; update one-byte system variable PR_CC
            RET                     ; return.

    ; -------------------------
    ; THE 'PRINT AT' SUBROUTINE
    ; -------------------------
    ;
    ;

    ;; PRINT-AT
    L08F5:  LD      A,$17           ;
            SUB     B               ;
            JR      C,L0905         ; to WRONG-VAL

    ;; TEST-VAL
    L08FA:  CP      (IY+$22)        ; sv DF_SZ
            JP      C,L0835         ; to REPORT-5

            INC     A               ;
            LD      B,A             ;
            LD      A,$1F           ;
            SUB     C               ;

    ;; WRONG-VAL
    L0905:  JP      C,L0EAD         ; to REPORT-B

            ADD     A,$02           ;
            LD      C,A             ;

    ;; SET-FIELD
    L090B:  BIT     1,(IY+$01)      ; sv FLAGS  - Is printer in use
            JR      Z,L0918         ; to LOC-ADDR

            LD      A,$5D           ;
            SUB     C               ;
            LD      ($4038),A       ; sv PR_CC
            RET                     ;

    ; ----------------------------
    ; THE 'LOCATE ADDRESS' ROUTINE
    ; ----------------------------
    ;
    ;

    ;; LOC-ADDR
    L0918:  LD      ($4039),BC      ; sv S_POSN_x
            LD      HL,($4010)      ; sv VARS_lo
            LD      D,C             ;
            LD      A,$22           ;
            SUB     C               ;
            LD      C,A             ;
            LD      A,$76           ;
            INC     B               ;

    ;; LOOK-BACK
    L0927:  DEC     HL              ;
            CP      (HL)            ;
            JR      NZ,L0927        ; to LOOK-BACK

            DJNZ    L0927           ; to LOOK-BACK

            INC     HL              ;
            CPIR                    ;
            DEC     HL              ;
            LD      ($400E),HL      ; sv DF_CC_lo
            SCF                     ; Set Carry Flag
            RET     PO              ;

            DEC     D               ;
            RET     Z               ;

            PUSH    BC              ;
            CALL    L099E           ; routine MAKE-ROOM
            POP     BC              ;
            LD      B,C             ;
            LD      H,D             ;
            LD       L,E            ;

    ;; EXPAND-2
    L0940:  LD      (HL),$00        ;
            DEC     HL              ;
            DJNZ    L0940           ; to EXPAND-2

            EX      DE,HL           ;
            INC     HL              ;
            LD      ($400E),HL      ; sv DF_CC_lo
            RET                     ;

    ; ------------------------------
    ; THE 'EXPAND TOKENS' SUBROUTINE
    ; ------------------------------
    ;
    ;

    ;; TOKENS
    L094B:  PUSH    AF              ;
            CALL    L0975           ; routine TOKEN-ADD
            JR      NC,L0959        ; to ALL-CHARS

            BIT     0,(IY+$01)      ; sv FLAGS  - Leading space if set
            JR      NZ,L0959        ; to ALL-CHARS

            XOR     A               ;

            RST     10H             ; PRINT-A

    ;; ALL-CHARS
    L0959:  LD      A,(BC)          ;
            AND     $3F             ;

            RST     10H             ; PRINT-A
            LD      A,(BC)          ;
            INC     BC              ;
            ADD     A,A             ;
            JR      NC,L0959        ; to ALL-CHARS

            POP     BC              ;
            BIT     7,B             ;
            RET     Z               ;

            CP      $1A             ;
            JR      Z,L096D         ; to TRAIL-SP

            CP      $38             ;
            RET     C               ;

    ;; TRAIL-SP
    L096D:  XOR     A               ;
            SET     0,(IY+$01)      ; sv FLAGS  - Suppress leading space
            JP      L07F5           ; to PRINT-SP

    ; ---

    ;; TOKEN-ADD
    L0975:  PUSH    HL              ;
            LD      HL,L0111        ; Address of TOKENS
            BIT     7,A             ;
            JR      Z,L097F         ; to TEST-HIGH

            AND     $3F             ;

    ;; TEST-HIGH
    L097F:  CP      $43             ;
            JR      NC,L0993        ; to FOUND

            LD      B,A             ;
            INC     B               ;

    ;; WORDS
    L0985:  BIT     7,(HL)          ;
            INC     HL              ;
            JR      Z,L0985         ; to WORDS

            DJNZ    L0985           ; to WORDS

            BIT     6,A             ;
            JR      NZ,L0992        ; to COMP-FLAG

            CP      $18             ;

    ;; COMP-FLAG
    L0992:  CCF                     ; Complement Carry Flag

    ;; FOUND
    L0993:  LD      B,H             ;
            LD       C,L            ;
            POP     HL              ;
            RET     NC              ;

            LD      A,(BC)          ;
            ADD     A,$E4           ;
            RET                     ;

    ; --------------------------
    ; THE 'ONE SPACE' SUBROUTINE
    ; --------------------------
    ;
    ;

    ;; ONE-SPACE
    L099B:  LD      BC,$0001        ;

    ; --------------------------
    ; THE 'MAKE ROOM' SUBROUTINE
    ; --------------------------
    ;
    ;

    ;; MAKE-ROOM
    L099E:  PUSH    HL              ;
            CALL    L0EC5           ; routine TEST-ROOM
            POP     HL              ;
            CALL    L09AD           ; routine POINTERS
            LD      HL,($401C)      ; sv STKEND_lo
            EX      DE,HL           ;
            LDDR                    ; Copy Bytes
            RET                     ;

    ; -------------------------
    ; THE 'POINTERS' SUBROUTINE
    ; -------------------------
    ;
    ;

    ;; POINTERS
    L09AD:  PUSH    AF              ;
            PUSH    HL              ;
            LD      HL,$400C        ; sv D_FILE_lo
            LD      A,$09           ;

    ;; NEXT-PTR
    L09B4:  LD      E,(HL)          ;
            INC     HL              ;
            LD      D,(HL)          ;
            EX      (SP),HL         ;
            AND     A               ;
            SBC     HL,DE           ;
            ADD     HL,DE           ;
            EX      (SP),HL         ;
            JR      NC,L09C8        ; to PTR-DONE

            PUSH    DE              ;
            EX      DE,HL           ;
            ADD     HL,BC           ;
            EX      DE,HL           ;
            LD      (HL),D          ;
            DEC     HL              ;
            LD      (HL),E          ;
            INC     HL              ;
            POP     DE              ;

    ;; PTR-DONE
    L09C8:  INC     HL              ;
            DEC     A               ;
            JR      NZ,L09B4        ; to NEXT-PTR

            EX      DE,HL           ;
            POP     DE              ;
            POP     AF              ;
            AND     A               ;
            SBC     HL,DE           ;
            LD      B,H             ;
            LD      C,L             ;
            INC     BC              ;
            ADD     HL,DE           ;
            EX      DE,HL           ;
            RET                     ;

    ; -----------------------------
    ; THE 'LINE ADDRESS' SUBROUTINE
    ; -----------------------------
    ;
    ;

    ;; LINE-ADDR
    L09D8:  PUSH    HL              ;
            LD      HL,$407D        ;
            LD      D,H             ;
            LD      E,L             ;

    ;; NEXT-TEST
    L09DE:  POP     BC              ;
            CALL    L09EA           ; routine CP-LINES
            RET     NC              ;

            PUSH    BC              ;
            CALL     L09F2          ; routine NEXT-ONE
            EX      DE,HL           ;
            JR      L09DE           ; to NEXT-TEST

    ; -------------------------------------
    ; THE 'COMPARE LINE NUMBERS' SUBROUTINE
    ; -------------------------------------
    ;
    ;

    ;; CP-LINES
    L09EA:  LD      A,(HL)          ;
            CP      B               ;
            RET     NZ              ;

            INC     HL              ;
            LD      A,(HL)          ;
            DEC     HL              ;
            CP      C               ;
            RET                     ;

    ; --------------------------------------
    ; THE 'NEXT LINE OR VARIABLE' SUBROUTINE
    ; --------------------------------------
    ;
    ;

    ;; NEXT-ONE
    L09F2:  PUSH    HL              ;
            LD      A,(HL)          ;
            CP      $40             ;
            JR      C,L0A0F         ; to LINES

            BIT     5,A             ;
            JR      Z,L0A10         ; forward to NEXT-O-4

            ADD     A,A             ;
            JP      M,L0A01         ; to NEXT+FIVE

            CCF                     ; Complement Carry Flag

    ;; NEXT+FIVE
    L0A01:  LD      BC,$0005        ;
            JR      NC,L0A08        ; to NEXT-LETT

            LD      C,$11           ;

    ;; NEXT-LETT
    L0A08:  RLA                     ;
            INC     HL              ;
            LD      A,(HL)          ;
            JR      NC,L0A08        ; to NEXT-LETT

            JR      L0A15           ; to NEXT-ADD

    ; ---

    ;; LINES
    L0A0F:  INC     HL              ;

    ;; NEXT-O-4
    L0A10:  INC     HL              ;
            LD      C,(HL)          ;
            INC     HL              ;
            LD      B,(HL)          ;
            INC     HL              ;

    ;; NEXT-ADD
    L0A15:  ADD     HL,BC           ;
            POP     DE              ;

    ; ---------------------------
    ; THE 'DIFFERENCE' SUBROUTINE
    ; ---------------------------
    ;
    ;

    ;; DIFFER
    L0A17:  AND     A               ;
            SBC     HL,DE           ;
            LD      B,H             ;
            LD      C,L             ;
            ADD     HL,DE           ;
            EX      DE,HL           ;
            RET                     ;

    ; --------------------------
    ; THE 'LINE-ENDS' SUBROUTINE
    ; --------------------------
    ;
    ;

    ;; LINE-ENDS
    L0A1F:  LD      B,(IY+$22)      ; sv DF_SZ
            PUSH    BC              ;
            CALL    L0A2C           ; routine B-LINES
            POP     BC              ;
            DEC     B               ;
            JR      L0A2C           ; to B-LINES

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

    ;; CLS
    L0A2A:  LD      B,$18           ;

    ;; B-LINES
    L0A2C:  RES     1,(IY+$01)      ; sv FLAGS  - Signal printer not in use
            LD      C,$21           ;
            PUSH    BC              ;
            CALL    L0918           ; routine LOC-ADDR
            POP     BC              ;
            LD      A,($4005)       ; sv RAMTOP_hi
            CP      $4D             ;
            JR      C,L0A52         ; to COLLAPSED

            SET     7,(IY+$3A)      ; sv S_POSN_y

    ;; CLEAR-LOC
    L0A42:  XOR     A               ; prepare a space
            CALL    L07F5           ; routine PRINT-SP prints a space
            LD      HL,($4039)      ; sv S_POSN_x
            LD      A,L             ;
            OR      H               ;
            AND     $7E             ;
            JR      NZ,L0A42        ; to CLEAR-LOC

            JP      L0918           ; to LOC-ADDR

    ; ---

    ;; COLLAPSED
    L0A52:  LD      D,H             ;
            LD      E,L             ;
            DEC     HL              ;
            LD      C,B             ;
            LD      B,$00           ;
            LDIR                    ; Copy Bytes
            LD      HL,($4010)      ; sv VARS_lo

    ; ----------------------------
    ; THE 'RECLAIMING' SUBROUTINES
    ; ----------------------------
    ;
    ;

    ;; RECLAIM-1
    L0A5D:  CALL    L0A17           ; routine DIFFER

    ;; RECLAIM-2
    L0A60:  PUSH    BC              ;
            LD      A,B             ;
            CPL                     ;
            LD      B,A             ;
            LD      A,C             ;
            CPL                     ;
            LD      C,A             ;
            INC     BC              ;
            CALL    L09AD           ; routine POINTERS
            EX      DE,HL           ;
            POP     HL              ;
            ADD     HL,DE           ;
            PUSH    DE              ;
            LDIR                    ; Copy Bytes
            POP     HL              ;
            RET                     ;

    ; ------------------------------
    ; THE 'E-LINE NUMBER' SUBROUTINE
    ; ------------------------------
    ;
    ;

    ;; E-LINE-NO
    L0A73:  LD      HL,($4014)      ; sv E_LINE_lo
            CALL    L004D           ; routine TEMP-PTR-2

            RST     18H             ; GET-CHAR
            BIT     5,(IY+$2D)      ; sv FLAGX
            RET     NZ              ;

            LD      HL,$405D        ; sv MEM-0-1st
            LD      ($401C),HL      ; sv STKEND_lo
            CALL    L1548           ; routine INT-TO-FP
            CALL    L158A           ; routine FP-TO-BC
            JR      C,L0A91         ; to NO-NUMBER

            LD      HL,$D8F0        ; value '-10000'
            ADD     HL,BC           ;

    ;; NO-NUMBER
    L0A91:  JP      C,L0D9A         ; to REPORT-C

            CP      A               ;
            JP      L14BC           ; routine SET-MIN

    ; -------------------------------------------------
    ; THE 'REPORT AND LINE NUMBER' PRINTING SUBROUTINES
    ; -------------------------------------------------
    ;
    ;

    ;; OUT-NUM
    L0A98:  PUSH    DE              ;
            PUSH    HL              ;
            XOR     A               ;
            BIT     7,B             ;
            JR      NZ,L0ABF        ; to UNITS

            LD       H,B            ;
            LD      L,C             ;
            LD      E,$FF           ;
            JR      L0AAD           ; to THOUSAND

    ; ---

    ;; OUT-NO
    L0AA5:  PUSH    DE              ;
            LD      D,(HL)          ;
            INC     HL              ;
            LD      E,(HL)          ;
            PUSH    HL              ;
            EX      DE,HL           ;
            LD      E,$00           ; set E to leading space.

    ;; THOUSAND
    L0AAD:  LD      BC,$FC18        ;
            CALL    L07E1           ; routine OUT-DIGIT
            LD      BC,$FF9C        ;
            CALL    L07E1           ; routine OUT-DIGIT
            LD      C,$F6           ;
            CALL    L07E1           ; routine OUT-DIGIT
            LD      A,L             ;

    ;; UNITS
    L0ABF:  CALL    L07EB           ; routine OUT-CODE
            POP     HL              ;
            POP     DE              ;
            RET                     ;

    ; --------------------------
    ; THE 'UNSTACK-Z' SUBROUTINE
    ; --------------------------
    ; This subroutine is used to return early from a routine when checking syntax.
    ; On the ZX81 the same routines that execute commands also check the syntax
    ; on line entry. This enables precise placement of the error marker in a line
    ; that fails syntax.
    ; The sequence CALL SYNTAX-Z ; RET Z can be replaced by a call to this routine
    ; although it has not replaced every occurrence of the above two instructions.
    ; Even on the ZX-80 this routine was not fully utilized.

    ;; UNSTACK-Z
    L0AC5:  CALL    L0DA6           ; routine SYNTAX-Z resets the ZERO flag if
                                    ; checking syntax.
            POP     HL              ; drop the return address.
            RET     Z               ; return to previous calling routine if
                                    ; checking syntax.

            JP      (HL)            ; else jump to the continuation address in
                                    ; the calling routine as RET would have done.

    ; ----------------------------
    ; THE 'LPRINT' COMMAND ROUTINE
    ; ----------------------------
    ;
    ;

    ;; LPRINT
    L0ACB:  SET     1,(IY+$01)      ; sv FLAGS  - Signal printer in use

    ; ---------------------------
    ; THE 'PRINT' COMMAND ROUTINE
    ; ---------------------------
    ;
    ;

    ;; PRINT
    L0ACF:  LD      A,(HL)          ;
            CP      $76             ;
            JP      Z,L0B84         ; to PRINT-END

    ;; PRINT-1
    L0AD5:  SUB     $1A             ;
            ADC     A,$00           ;
            JR      Z,L0B44         ; to SPACING

            CP      $A7             ;
            JR      NZ,L0AFA        ; to NOT-AT

            RST     20H             ; NEXT-CHAR
            CALL    L0D92           ; routine CLASS-6
            CP      $1A             ;
            JP      NZ,L0D9A        ; to REPORT-C

            RST     20H             ; NEXT-CHAR
            CALL    L0D92           ; routine CLASS-6
            CALL    L0B4E           ; routine SYNTAX-ON

            RST     28H             ;; FP-CALC
            DEFB    $01             ;;exchange
            DEFB    $34             ;;end-calc

            CALL    L0BF5           ; routine STK-TO-BC
            CALL    L08F5           ; routine PRINT-AT
            JR      L0B37           ; to PRINT-ON

    ; ---

    ;; NOT-AT
    L0AFA:  CP      $A8             ;
            JR      NZ,L0B31        ; to NOT-TAB

            RST     20H             ; NEXT-CHAR
            CALL    L0D92           ; routine CLASS-6
            CALL    L0B4E           ; routine SYNTAX-ON
            CALL    L0C02           ; routine STK-TO-A
            JP      NZ,L0EAD        ; to REPORT-B

            AND     $1F             ;
            LD      C,A             ;
            BIT     1,(IY+$01)      ; sv FLAGS  - Is printer in use
            JR      Z,L0B1E         ; to TAB-TEST

            SUB     (IY+$38)        ; sv PR_CC
            SET     7,A             ;
            ADD     A,$3C           ;
            CALL    NC,L0871        ; routine COPY-BUFF

    ;; TAB-TEST
    L0B1E:  ADD     A,(IY+$39)      ; sv S_POSN_x
            CP      $21             ;
            LD      A,($403A)       ; sv S_POSN_y
            SBC     A,$01           ;
            CALL    L08FA           ; routine TEST-VAL
            SET     0,(IY+$01)      ; sv FLAGS  - Suppress leading space
            JR      L0B37           ; to PRINT-ON

    ; ---

    ;; NOT-TAB
    L0B31:  CALL    L0F55           ; routine SCANNING
            CALL    L0B55           ; routine PRINT-STK

    ;; PRINT-ON
    L0B37:  RST     18H             ; GET-CHAR
            SUB     $1A             ;
            ADC     A,$00           ;
            JR      Z,L0B44         ; to SPACING

            CALL    L0D1D           ; routine CHECK-END
            JP      L0B84           ;;; to PRINT-END

    ; ---

    ;; SPACING
    L0B44:  CALL    NC,L0B8B        ; routine FIELD

            RST     20H             ; NEXT-CHAR
            CP      $76             ;
            RET     Z               ;

            JP      L0AD5           ;;; to PRINT-1

    ; ---

    ;; SYNTAX-ON
    L0B4E:  CALL    L0DA6           ; routine SYNTAX-Z
            RET     NZ              ;

            POP     HL              ;
            JR      L0B37           ; to PRINT-ON

    ; ---

    ;; PRINT-STK
    L0B55:  CALL    L0AC5           ; routine UNSTACK-Z
            BIT     6,(IY+$01)      ; sv FLAGS  - Numeric or string result?
            CALL    Z,L13F8         ; routine STK-FETCH
            JR      Z,L0B6B         ; to PR-STR-4

            JP      L15DB           ; jump forward to PRINT-FP

    ; ---

    ;; PR-STR-1
    L0B64:  LD      A,$0B           ;

    ;; PR-STR-2
    L0B66:  RST     10H             ; PRINT-A

    ;; PR-STR-3
    L0B67:  LD      DE,($4018)      ; sv X_PTR_lo

    ;; PR-STR-4
    L0B6B:  LD      A,B             ;
            OR      C               ;
            DEC     BC              ;
            RET     Z               ;

            LD      A,(DE)          ;
            INC     DE              ;
            LD      ($4018),DE      ; sv X_PTR_lo
            BIT      6,A            ;
            JR      Z,L0B66         ; to PR-STR-2

            CP      $C0             ;
            JR      Z,L0B64         ; to PR-STR-1

            PUSH    BC              ;
            CALL    L094B           ; routine TOKENS
            POP     BC              ;
            JR      L0B67           ; to PR-STR-3

    ; ---

    ;; PRINT-END
    L0B84:  CALL    L0AC5           ; routine UNSTACK-Z
            LD      A,$76           ;

            RST     10H             ; PRINT-A
            RET                     ;

    ; ---

    ;; FIELD
    L0B8B:  CALL    L0AC5           ; routine UNSTACK-Z
            SET     0,(IY+$01)      ; sv FLAGS  - Suppress leading space
            XOR     A               ;

            RST     10H             ; PRINT-A
            LD      BC,($4039)      ; sv S_POSN_x
            LD      A,C             ;
            BIT     1,(IY+$01)      ; sv FLAGS  - Is printer in use
            JR      Z,L0BA4         ; to CENTRE

            LD      A,$5D           ;
            SUB     (IY+$38)        ; sv PR_CC

    ;; CENTRE
    L0BA4:  LD      C,$11           ;
            CP      C               ;
            JR      NC,L0BAB        ; to RIGHT

            LD      C,$01           ;

    ;; RIGHT
    L0BAB:  CALL    L090B           ; routine SET-FIELD
            RET                     ;

    ; --------------------------------------
    ; THE 'PLOT AND UNPLOT' COMMAND ROUTINES
    ; --------------------------------------
    ;
    ;

    ;; PLOT/UNP
    L0BAF:  CALL    L0BF5           ; routine STK-TO-BC
            LD      ($4036),BC      ; sv COORDS_x
            LD      A,$2B           ;
            SUB     B               ;
            JP      C,L0EAD         ; to REPORT-B

            LD      B,A             ;
            LD      A,$01           ;
            SRA     B               ;
            JR      NC,L0BC5        ; to COLUMNS

            LD      A,$04           ;

    ;; COLUMNS
    L0BC5:  SRA     C               ;
            JR      NC,L0BCA        ; to FIND-ADDR

            RLCA                    ;

    ;; FIND-ADDR
    L0BCA:  PUSH    AF              ;
            CALL    L08F5           ; routine PRINT-AT
            LD      A,(HL)          ;
            RLCA                    ;
            CP      $10             ;
            JR      NC,L0BDA        ; to TABLE-PTR

            RRCA                    ;
            JR      NC,L0BD9        ; to SQ-SAVED

            XOR     $8F             ;

    ;; SQ-SAVED
    L0BD9:  LD      B,A             ;

    ;; TABLE-PTR
    L0BDA:  LD      DE,L0C9E        ; Address: P-UNPLOT
            LD      A,($4030)       ; sv T_ADDR_lo
            SUB     E               ;
            JP      M,L0BE9         ; to PLOT

            POP     AF              ;
            CPL                     ;
            AND     B               ;
            JR      L0BEB           ; to UNPLOT

    ; ---

    ;; PLOT
    L0BE9:  POP     AF              ;
            OR      B               ;

    ;; UNPLOT
    L0BEB:  CP      $08             ;
            JR      C,L0BF1         ; to PLOT-END

            XOR     $8F             ;

    ;; PLOT-END
    L0BF1:  EXX                     ;

            RST     10H             ; PRINT-A
            EXX                     ;
            RET                     ;

    ; ----------------------------
    ; THE 'STACK-TO-BC' SUBROUTINE
    ; ----------------------------
    ;
    ;

    ;; STK-TO-BC
    L0BF5:  CALL    L0C02           ; routine STK-TO-A
            LD      B,A             ;
            PUSH    BC              ;
            CALL    L0C02           ; routine STK-TO-A
            LD      E,C             ;
            POP     BC              ;
            LD      D,C             ;
            LD      C,A             ;
            RET                     ;

    ; ---------------------------
    ; THE 'STACK-TO-A' SUBROUTINE
    ; ---------------------------
    ;
    ;

    ;; STK-TO-A
    L0C02:  CALL    L15CD           ; routine FP-TO-A
            JP      C,L0EAD         ; to REPORT-B

            LD      C,$01           ;
            RET     Z               ;

            LD      C,$FF           ;
            RET                     ;

    ; -----------------------
    ; THE 'SCROLL' SUBROUTINE
    ; -----------------------
    ;
    ;

    ;; SCROLL
    L0C0E:  LD      B,(IY+$22)      ; sv DF_SZ
            LD      C,$21           ;
            CALL    L0918           ; routine LOC-ADDR
            CALL    L099B           ; routine ONE-SPACE
            LD      A,(HL)          ;
            LD      (DE),A          ;
            INC     (IY+$3A)        ; sv S_POSN_y
            LD      HL,($400C)      ; sv D_FILE_lo
            INC     HL              ;
            LD      D,H             ;
            LD      E,L             ;
            CPIR                    ;
            JP      L0A5D           ; to RECLAIM-1

    ; -------------------
    ; THE 'SYNTAX' TABLES
    ; -------------------

    ; i) The Offset table

    ;; offset-t
    L0C29:  DEFB    L0CB4 - $       ; 8B offset to; Address: P-LPRINT
            DEFB    L0CB7 - $       ; 8D offset to; Address: P-LLIST
            DEFB    L0C58 - $       ; 2D offset to; Address: P-STOP
            DEFB    L0CAB - $       ; 7F offset to; Address: P-SLOW
            DEFB    L0CAE - $       ; 81 offset to; Address: P-FAST
            DEFB    L0C77 - $       ; 49 offset to; Address: P-NEW
            DEFB    L0CA4 - $       ; 75 offset to; Address: P-SCROLL
            DEFB    L0C8F - $       ; 5F offset to; Address: P-CONT
            DEFB    L0C71 - $       ; 40 offset to; Address: P-DIM
            DEFB    L0C74 - $       ; 42 offset to; Address: P-REM
            DEFB    L0C5E - $       ; 2B offset to; Address: P-FOR
            DEFB    L0C4B - $       ; 17 offset to; Address: P-GOTO
            DEFB    L0C54 - $       ; 1F offset to; Address: P-GOSUB
            DEFB    L0C6D - $       ; 37 offset to; Address: P-INPUT
            DEFB    L0C89 - $       ; 52 offset to; Address: P-LOAD
            DEFB    L0C7D - $       ; 45 offset to; Address: P-LIST
            DEFB    L0C48 - $       ; 0F offset to; Address: P-LET
            DEFB    L0CA7 - $       ; 6D offset to; Address: P-PAUSE
            DEFB    L0C66 - $       ; 2B offset to; Address: P-NEXT
            DEFB    L0C80 - $       ; 44 offset to; Address: P-POKE
            DEFB    L0C6A - $       ; 2D offset to; Address: P-PRINT
            DEFB    L0C98 - $       ; 5A offset to; Address: P-PLOT
            DEFB    L0C7A - $       ; 3B offset to; Address: P-RUN
            DEFB    L0C8C - $       ; 4C offset to; Address: P-SAVE
            DEFB    L0C86 - $       ; 45 offset to; Address: P-RAND
            DEFB    L0C4F - $       ; 0D offset to; Address: P-IF
            DEFB    L0C95 - $       ; 52 offset to; Address: P-CLS
            DEFB    L0C9E - $       ; 5A offset to; Address: P-UNPLOT
            DEFB    L0C92 - $       ; 4D offset to; Address: P-CLEAR
            DEFB    L0C5B - $       ; 15 offset to; Address: P-RETURN
            DEFB    L0CB1 - $       ; 6A offset to; Address: P-COPY

    ; ii) The parameter table.

    ;; P-LET
    L0C48:  DEFB    $01             ; Class-01 - A variable is required.
            DEFB    $14             ; Separator:  '='
            DEFB    $02             ; Class-02 - An expression, numeric or string,
                                    ; must follow.

    ;; P-GOTO
    L0C4B:  DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0E81           ; Address: $0E81; Address: GOTO

    ;; P-IF
    L0C4F:  DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $DE             ; Separator:  'THEN'
            DEFB    $05             ; Class-05 - Variable syntax checked entirely
                                    ; by routine.
            DEFW    L0DAB           ; Address: $0DAB; Address: IF

    ;; P-GOSUB
    L0C54:  DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0EB5           ; Address: $0EB5; Address: GOSUB

    ;; P-STOP
    L0C58:  DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0CDC           ; Address: $0CDC; Address: STOP

    ;; P-RETURN
    L0C5B:  DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0ED8           ; Address: $0ED8; Address: RETURN

    ;; P-FOR
    L0C5E:  DEFB    $04             ; Class-04 - A single character variable must
                                    ; follow.
            DEFB    $14             ; Separator:  '='
            DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $DF             ; Separator:  'TO'
            DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $05             ; Class-05 - Variable syntax checked entirely
                                    ; by routine.
            DEFW    L0DB9           ; Address: $0DB9; Address: FOR

    ;; P-NEXT
    L0C66:  DEFB    $04             ; Class-04 - A single character variable must
                                    ; follow.
            DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0E2E           ; Address: $0E2E; Address: NEXT

    ;; P-PRINT
    L0C6A:  DEFB    $05             ; Class-05 - Variable syntax checked entirely
                                    ; by routine.
            DEFW    L0ACF           ; Address: $0ACF; Address: PRINT

    ;; P-INPUT
    L0C6D:  DEFB    $01             ; Class-01 - A variable is required.
            DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0EE9           ; Address: $0EE9; Address: INPUT

    ;; P-DIM
    L0C71:  DEFB    $05             ; Class-05 - Variable syntax checked entirely
                                    ; by routine.
            DEFW    L1409           ; Address: $1409; Address: DIM

    ;; P-REM
    L0C74:  DEFB    $05             ; Class-05 - Variable syntax checked entirely
                                    ; by routine.
            DEFW    L0D6A           ; Address: $0D6A; Address: REM

    ;; P-NEW
    L0C77:  DEFB    $00             ; Class-00 - No further operands.
            DEFW    L03C3           ; Address: $03C3; Address: NEW

    ;; P-RUN
    L0C7A:  DEFB    $03             ; Class-03 - A numeric expression may follow
                                    ; else default to zero.
            DEFW    L0EAF           ; Address: $0EAF; Address: RUN

    ;; P-LIST
    L0C7D:  DEFB    $03             ; Class-03 - A numeric expression may follow
                                    ; else default to zero.
            DEFW    L0730           ; Address: $0730; Address: LIST

    ;; P-POKE
    L0C80:  DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $1A             ; Separator:  ','
            DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0E92           ; Address: $0E92; Address: POKE

    ;; P-RAND
    L0C86:  DEFB    $03             ; Class-03 - A numeric expression may follow
                                    ; else default to zero.
            DEFW    L0E6C           ; Address: $0E6C; Address: RAND

    ;; P-LOAD
    L0C89:  DEFB    $05             ; Class-05 - Variable syntax checked entirely
                                    ; by routine.
            DEFW    L0340           ; Address: $0340; Address: LOAD

    ;; P-SAVE
    L0C8C:  DEFB    $05             ; Class-05 - Variable syntax checked entirely
                                    ; by routine.
            DEFW    L02F6           ; Address: $02F6; Address: SAVE

    ;; P-CONT
    L0C8F:  DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0E7C           ; Address: $0E7C; Address: CONT

    ;; P-CLEAR
    L0C92:  DEFB    $00             ; Class-00 - No further operands.
            DEFW    L149A           ; Address: $149A; Address: CLEAR

    ;; P-CLS
    L0C95:  DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0A2A           ; Address: $0A2A; Address: CLS

    ;; P-PLOT
    L0C98:  DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $1A             ; Separator:  ','
            DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0BAF           ; Address: $0BAF; Address: PLOT/UNP

    ;; P-UNPLOT
    L0C9E:  DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $1A             ; Separator:  ','
            DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0BAF           ; Address: $0BAF; Address: PLOT/UNP

    ;; P-SCROLL
    L0CA4:  DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0C0E           ; Address: $0C0E; Address: SCROLL

    ;; P-PAUSE
    L0CA7:  DEFB    $06             ; Class-06 - A numeric expression must follow.
            DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0F32           ; Address: $0F32; Address: PAUSE

    ;; P-SLOW
    L0CAB:  DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0F2B           ; Address: $0F2B; Address: SLOW

    ;; P-FAST
    L0CAE:  DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0F23           ; Address: $0F23; Address: FAST

    ;; P-COPY
    L0CB1:  DEFB    $00             ; Class-00 - No further operands.
            DEFW    L0869           ; Address: $0869; Address: COPY

    ;; P-LPRINT
    L0CB4:  DEFB    $05             ; Class-05 - Variable syntax checked entirely
                                    ; by routine.
            DEFW    L0ACB           ; Address: $0ACB; Address: LPRINT

    ;; P-LLIST
    L0CB7:  DEFB    $03             ; Class-03 - A numeric expression may follow
                                    ; else default to zero.
            DEFW    L072C           ; Address: $072C; Address: LLIST

    ; ---------------------------
    ; THE 'LINE SCANNING' ROUTINE
    ; ---------------------------
    ;
    ;

    ;; LINE-SCAN
    L0CBA:  LD      (IY+$01),$01    ; sv FLAGS
            CALL    L0A73           ; routine E-LINE-NO

    ;; LINE-RUN
    L0CC1:  CALL    L14BC           ; routine SET-MIN
            LD      HL,$4000        ; sv ERR_NR
            LD      (HL),$FF        ;
            LD      HL,$402D        ; sv FLAGX
            BIT     5,(HL)          ;
            JR      Z,L0CDE         ; to LINE-NULL

            CP      $E3             ; 'STOP' ?
            LD      A,(HL)          ;
            JP      NZ,L0D6F        ; to INPUT-REP

            CALL    L0DA6           ; routine SYNTAX-Z
            RET     Z               ;

            RST     08H             ; ERROR-1
            DEFB    $0C             ; Error Report: BREAK - CONT repeats

    ; --------------------------
    ; THE 'STOP' COMMAND ROUTINE
    ; --------------------------
    ;
    ;

    ;; STOP
    L0CDC:  RST     08H             ; ERROR-1
            DEFB    $08             ; Error Report: STOP statement

    ; ---

    ; the interpretation of a line continues with a check for just spaces
    ; followed by a carriage return.
    ; The IF command also branches here with a true value to execute the
    ; statement after the THEN but the statement can be null so
    ; 10 IF 1 = 1 THEN
    ; passes syntax (on all ZX computers).

    ;; LINE-NULL
    L0CDE:  RST     18H             ; GET-CHAR
            LD      B,$00           ; prepare to index - early.
            CP      $76             ; compare to NEWLINE.
            RET     Z               ; return if so.

            LD      C,A             ; transfer character to C.

            RST     20H             ; NEXT-CHAR advances.
            LD      A,C             ; character to A
            SUB     $E1             ; subtract 'LPRINT' - lowest command.
            JR      C,L0D26         ; forward if less to REPORT-C2

            LD      C,A             ; reduced token to C
            LD      HL,L0C29        ; set HL to address of offset table.
            ADD     HL,BC           ; index into offset table.
            LD      C,(HL)          ; fetch offset
            ADD     HL,BC           ; index into parameter table.
            JR      L0CF7           ; to GET-PARAM

    ; ---

    ;; SCAN-LOOP
    L0CF4:  LD      HL,($4030)      ; sv T_ADDR_lo

    ; -> Entry Point to Scanning Loop

    ;; GET-PARAM
    L0CF7:  LD      A,(HL)          ;
            INC     HL              ;
            LD      ($4030),HL      ; sv T_ADDR_lo

            LD      BC,L0CF4        ; Address: SCAN-LOOP
            PUSH    BC              ; is pushed on machine stack.

            LD      C,A             ;
            CP      $0B             ;
            JR      NC,L0D10        ; to SEPARATOR

            LD      HL,L0D16        ; class-tbl - the address of the class table.
            LD      B,$00           ;
            ADD     HL,BC           ;
            LD      C,(HL)          ;
            ADD     HL,BC           ;
            PUSH    HL              ;

            RST     18H             ; GET-CHAR
            RET                     ; indirect jump to class routine and
                                    ; by subsequent RET to SCAN-LOOP.

    ; -----------------------
    ; THE 'SEPARATOR' ROUTINE
    ; -----------------------

    ;; SEPARATOR
    L0D10:  RST     18H             ; GET-CHAR
            CP      C               ;
            JR      NZ,L0D26        ; to REPORT-C2
                                    ; 'Nonsense in BASIC'

            RST     20H             ; NEXT-CHAR
            RET                     ; return

    ; -------------------------
    ; THE 'COMMAND CLASS' TABLE
    ; -------------------------
    ;

    ;; class-tbl
    L0D16:  DEFB    L0D2D - $       ; 17 offset to; Address: CLASS-0
            DEFB    L0D3C - $       ; 25 offset to; Address: CLASS-1
            DEFB    L0D6B - $       ; 53 offset to; Address: CLASS-2
            DEFB    L0D28 - $       ; 0F offset to; Address: CLASS-3
            DEFB    L0D85 - $       ; 6B offset to; Address: CLASS-4
            DEFB    L0D2E - $       ; 13 offset to; Address: CLASS-5
            DEFB    L0D92 - $       ; 76 offset to; Address: CLASS-6

    ; --------------------------
    ; THE 'CHECK END' SUBROUTINE
    ; --------------------------
    ; Check for end of statement and that no spurious characters occur after
    ; a correctly parsed statement. Since only one statement is allowed on each
    ; line, the only character that may follow a statement is a NEWLINE.
    ;

    ;; CHECK-END
    L0D1D:  CALL    L0DA6           ; routine SYNTAX-Z
            RET     NZ              ; return in runtime.

            POP     BC              ; else drop return address.

    ;; CHECK-2
    L0D22:  LD      A,(HL)          ; fetch character.
            CP      $76             ; compare to NEWLINE.
            RET     Z               ; return if so.

    ;; REPORT-C2
    L0D26:  JR      L0D9A           ; to REPORT-C
                                    ; 'Nonsense in BASIC'

    ; --------------------------
    ; COMMAND CLASSES 03, 00, 05
    ; --------------------------
    ;
    ;

    ;; CLASS-3
    L0D28:  CP      $76             ;
            CALL    L0D9C           ; routine NO-TO-STK

    ;; CLASS-0
    L0D2D:  CP      A               ;

    ;; CLASS-5
    L0D2E:  POP     BC              ;
            CALL    Z,L0D1D         ; routine CHECK-END
            EX      DE,HL           ;
            LD      HL,($4030)      ; sv T_ADDR_lo
            LD      C,(HL)          ;
            INC     HL              ;
            LD      B,(HL)          ;
            EX      DE,HL           ;

    ;; CLASS-END
    L0D3A:  PUSH    BC              ;
            RET                     ;

    ; ------------------------------
    ; COMMAND CLASSES 01, 02, 04, 06
    ; ------------------------------
    ;
    ;

    ;; CLASS-1
    L0D3C:  CALL    L111C           ; routine LOOK-VARS

    ;; CLASS-4-2
    L0D3F:  LD      (IY+$2D),$00    ; sv FLAGX
            JR      NC,L0D4D        ; to SET-STK

            SET     1,(IY+$2D)      ; sv FLAGX
            JR      NZ,L0D63        ; to SET-STRLN

    ;; REPORT-2
    L0D4B:  RST     08H             ; ERROR-1
            DEFB    $01             ; Error Report: Variable not found

    ; ---

    ;; SET-STK
    L0D4D:  CALL    Z,L11A7         ; routine STK-VAR
            BIT     6,(IY+$01)      ; sv FLAGS  - Numeric or string result?
            JR      NZ,L0D63        ; to SET-STRLN

            XOR     A               ;
            CALL    L0DA6           ; routine SYNTAX-Z
            CALL    NZ,L13F8        ; routine STK-FETCH
            LD      HL,$402D        ; sv FLAGX
            OR      (HL)            ;
            LD      (HL),A          ;
            EX      DE,HL           ;

    ;; SET-STRLN
    L0D63:  LD      ($402E),BC      ; sv STRLEN_lo
            LD      ($4012),HL      ; sv DEST-lo

    ; THE 'REM' COMMAND ROUTINE

    ;; REM
    L0D6A:  RET                     ;

    ; ---

    ;; CLASS-2
    L0D6B:  POP     BC              ;
            LD      A,($4001)       ; sv FLAGS

    ;; INPUT-REP
    L0D6F:  PUSH    AF              ;
            CALL    L0F55           ; routine SCANNING
            POP     AF              ;
            LD      BC,L1321        ; Address: LET
            LD      D,(IY+$01)      ; sv FLAGS
            XOR     D               ;
            AND     $40             ;
            JR      NZ,L0D9A        ; to REPORT-C

            BIT     7,D             ;
            JR      NZ,L0D3A        ; to CLASS-END

            JR      L0D22           ; to CHECK-2

    ; ---

    ;; CLASS-4
    L0D85:  CALL    L111C           ; routine LOOK-VARS
            PUSH    AF              ;
            LD      A,C             ;
            OR      $9F             ;
            INC     A               ;
            JR       NZ,L0D9A       ; to REPORT-C

            POP     AF              ;
            JR      L0D3F           ; to CLASS-4-2

    ; ---

    ;; CLASS-6
    L0D92:  CALL    L0F55           ; routine SCANNING
            BIT     6,(IY+$01)      ; sv FLAGS  - Numeric or string result?
            RET     NZ              ;

    ;; REPORT-C
    L0D9A:  RST     08H             ; ERROR-1
            DEFB    $0B             ; Error Report: Nonsense in BASIC

    ; --------------------------------
    ; THE 'NUMBER TO STACK' SUBROUTINE
    ; --------------------------------
    ;
    ;

    ;; NO-TO-STK
    L0D9C:  JR      NZ,L0D92        ; back to CLASS-6 with a non-zero number.

            CALL    L0DA6           ; routine SYNTAX-Z
            RET     Z               ; return if checking syntax.

    ; in runtime a zero default is placed on the calculator stack.

            RST     28H             ;; FP-CALC
            DEFB    $A0             ;;stk-zero
            DEFB    $34             ;;end-calc

            RET                     ; return.

    ; -------------------------
    ; THE 'SYNTAX-Z' SUBROUTINE
    ; -------------------------
    ; This routine returns with zero flag set if checking syntax.
    ; Calling this routine uses three instruction bytes compared to four if the
    ; bit test is implemented inline.

    ;; SYNTAX-Z
    L0DA6:  BIT     7,(IY+$01)      ; test FLAGS  - checking syntax only?
            RET                     ; return.

    ; ------------------------
    ; THE 'IF' COMMAND ROUTINE
    ; ------------------------
    ; In runtime, the class routines have evaluated the test expression and
    ; the result, true or false, is on the stack.

    ;; IF
    L0DAB:  CALL    L0DA6           ; routine SYNTAX-Z
            JR      Z,L0DB6         ; forward if checking syntax to IF-END

    ; else delete the Boolean value on the calculator stack.

            RST     28H             ;; FP-CALC
            DEFB    $02             ;;delete
            DEFB    $34             ;;end-calc

    ; register DE points to exponent of floating point value.

            LD      A,(DE)          ; fetch exponent.
            AND     A               ; test for zero - FALSE.
            RET     Z               ; return if so.

    ;; IF-END
    L0DB6:  JP      L0CDE           ; jump back to LINE-NULL

    ; -------------------------
    ; THE 'FOR' COMMAND ROUTINE
    ; -------------------------
    ;
    ;

    ;; FOR
    L0DB9:  CP      $E0             ; is current character 'STEP' ?
            JR      NZ,L0DC6        ; forward if not to F-USE-ONE

            RST     20H             ; NEXT-CHAR
            CALL    L0D92           ; routine CLASS-6 stacks the number
            CALL    L0D1D           ; routine CHECK-END
            JR      L0DCC           ; forward to F-REORDER

    ; ---

    ;; F-USE-ONE
    L0DC6:  CALL    L0D1D           ; routine CHECK-END

            RST     28H             ;; FP-CALC
            DEFB    $A1             ;;stk-one
            DEFB    $34             ;;end-calc

    ;; F-REORDER
    L0DCC:  RST     28H             ;; FP-CALC      v, l, s.
            DEFB    $C0             ;;st-mem-0      v, l, s.
            DEFB    $02             ;;delete        v, l.
            DEFB    $01             ;;exchange      l, v.
            DEFB    $E0             ;;get-mem-0     l, v, s.
            DEFB    $01             ;;exchange      l, s, v.
            DEFB    $34             ;;end-calc      l, s, v.

            CALL    L1321           ; routine LET

            LD      ($401F),HL      ; set MEM to address variable.
            DEC     HL              ; point to letter.
            LD      A,(HL)          ;
            SET     7,(HL)          ;
            LD      BC,$0006        ;
            ADD     HL,BC           ;
            RLCA                    ;
            JR      C,L0DEA         ; to F-LMT-STP

            SLA     C               ;
            CALL    L099E           ; routine MAKE-ROOM
            INC     HL              ;

    ;; F-LMT-STP
    L0DEA:  PUSH    HL              ;

            RST     28H             ;; FP-CALC
            DEFB    $02             ;;delete
            DEFB    $02             ;;delete
            DEFB    $34             ;;end-calc

            POP     HL              ;
            EX      DE,HL           ;

            LD      C,$0A           ; ten bytes to be moved.
            LDIR                    ; copy bytes

            LD      HL,($4007)      ; set HL to system variable PPC current line.
            EX      DE,HL           ; transfer to DE, variable pointer to HL.
            INC     DE              ; loop start will be this line + 1 at least.
            LD      (HL),E          ;
            INC     HL              ;
            LD      (HL),D          ;
            CALL    L0E5A           ; routine NEXT-LOOP considers an initial pass.
            RET     NC              ; return if possible.

    ; else program continues from point following matching NEXT.

            BIT     7,(IY+$08)      ; test PPC_hi
            RET     NZ              ; return if over 32767 ???

            LD      B,(IY+$2E)      ; fetch variable name from STRLEN_lo
            RES     6,B             ; make a true letter.
            LD      HL,($4029)      ; set HL from NXTLIN

    ; now enter a loop to look for matching next.

    ;; NXTLIN-NO
    L0E0E:  LD      A,(HL)          ; fetch high byte of line number.
            AND     $C0             ; mask off low bits $3F
            JR      NZ,L0E2A        ; forward at end of program to FOR-END

            PUSH    BC              ; save letter
            CALL    L09F2           ; routine NEXT-ONE finds next line.
            POP     BC              ; restore letter

            INC     HL              ; step past low byte
            INC     HL              ; past the
            INC     HL              ; line length.
            CALL    L004C           ; routine TEMP-PTR1 sets CH_ADD

            RST     18H             ; GET-CHAR
            CP      $F3             ; compare to 'NEXT'.
            EX      DE,HL           ; next line to HL.
            JR      NZ,L0E0E        ; back with no match to NXTLIN-NO

    ;

            EX      DE,HL           ; restore pointer.

            RST     20H             ; NEXT-CHAR advances and gets letter in A.
            EX      DE,HL           ; save pointer
            CP      B               ; compare to variable name.
            JR      NZ,L0E0E        ; back with mismatch to NXTLIN-NO

    ;; FOR-END
    L0E2A:  LD      ($4029),HL      ; update system variable NXTLIN
            RET                     ; return.

    ; --------------------------
    ; THE 'NEXT' COMMAND ROUTINE
    ; --------------------------
    ;
    ;

    ;; NEXT
    L0E2E:  BIT     1,(IY+$2D)      ; sv FLAGX
            JP      NZ,L0D4B        ; to REPORT-2

            LD      HL,($4012)      ; DEST
            BIT     7,(HL)          ;
            JR      Z,L0E58         ; to REPORT-1

            INC     HL              ;
            LD      ($401F),HL      ; sv MEM_lo

            RST     28H             ;; FP-CALC
            DEFB    $E0             ;;get-mem-0
            DEFB    $E2             ;;get-mem-2
            DEFB    $0F             ;;addition
            DEFB    $C0             ;;st-mem-0
            DEFB    $02             ;;delete
            DEFB    $34             ;;end-calc

            CALL    L0E5A           ; routine NEXT-LOOP
            RET     C               ;

            LD      HL,($401F)      ; sv MEM_lo
            LD      DE,$000F        ;
            ADD     HL,DE           ;
            LD      E,(HL)          ;
            INC     HL              ;
            LD      D,(HL)          ;
            EX      DE,HL           ;
            JR      L0E86           ; to GOTO-2

    ; ---

    ;; REPORT-1
    L0E58:  RST     08H             ; ERROR-1
            DEFB    $00             ; Error Report: NEXT without FOR

    ; --------------------------
    ; THE 'NEXT-LOOP' SUBROUTINE
    ; --------------------------
    ;
    ;

    ;; NEXT-LOOP
    L0E5A:  RST     28H             ;; FP-CALC
            DEFB    $E1             ;;get-mem-1
            DEFB    $E0             ;;get-mem-0
            DEFB    $E2             ;;get-mem-2
            DEFB    $32             ;;less-0
            DEFB    $00             ;;jump-true
            DEFB    $02             ;;to L0E62, LMT-V-VAL

            DEFB    $01             ;;exchange

    ;; LMT-V-VAL
    L0E62:  DEFB    $03             ;;subtract
            DEFB    $33             ;;greater-0
            DEFB    $00             ;;jump-true
            DEFB    $04             ;;to L0E69, IMPOSS

            DEFB    $34             ;;end-calc

            AND     A               ; clear carry flag
            RET                     ; return.

    ; ---

    ;; IMPOSS
    L0E69:  DEFB    $34             ;;end-calc

            SCF                     ; set carry flag
            RET                     ; return.

    ; --------------------------
    ; THE 'RAND' COMMAND ROUTINE
    ; --------------------------
    ; The keyword was 'RANDOMISE' on the ZX80, is 'RAND' here on the ZX81 and
    ; becomes 'RANDOMIZE' on the ZX Spectrum.
    ; In all invocations the procedure is the same - to set the SEED system variable
    ; with a supplied integer value or to use a time-based value if no number, or
    ; zero, is supplied.

    ;; RAND
    L0E6C:  CALL    L0EA7           ; routine FIND-INT
            LD      A,B             ; test value
            OR      C               ; for zero
            JR      NZ,L0E77        ; forward if not zero to SET-SEED

            LD      BC,($4034)      ; fetch value of FRAMES system variable.

    ;; SET-SEED
    L0E77:  LD       ($4032),BC     ; update the SEED system variable.
            RET                     ; return.

    ; --------------------------
    ; THE 'CONT' COMMAND ROUTINE
    ; --------------------------
    ; Another abbreviated command. ROM space was really tight.
    ; CONTINUE at the line number that was set when break was pressed.
    ; Sometimes the current line, sometimes the next line.

    ;; CONT
    L0E7C:  LD      HL,($402B)      ; set HL from system variable OLDPPC
            JR      L0E86           ; forward to GOTO-2

    ; --------------------------
    ; THE 'GOTO' COMMAND ROUTINE
    ; --------------------------
    ; This token also suffered from the shortage of room and there is no space
    ; getween GO and TO as there is on the ZX80 and ZX Spectrum. The same also
    ; applies to the GOSUB keyword.

    ;; GOTO
    L0E81:  CALL    L0EA7           ; routine FIND-INT
            LD      H,B             ;
            LD      L,C             ;

    ;; GOTO-2
    L0E86:  LD      A,H             ;
            CP      $F0             ;
            JR      NC,L0EAD        ; to REPORT-B

            CALL    L09D8           ; routine LINE-ADDR
            LD      ($4029),HL      ; sv NXTLIN_lo
            RET                     ;

    ; --------------------------
    ; THE 'POKE' COMMAND ROUTINE
    ; --------------------------
    ;
    ;

    ;; POKE
    L0E92:  CALL    L15CD           ; routine FP-TO-A
            JR      C,L0EAD         ; forward, with overflow, to REPORT-B

            JR      Z,L0E9B         ; forward, if positive, to POKE-SAVE

            NEG                     ; negate

    ;; POKE-SAVE
    L0E9B:  PUSH    AF              ; preserve value.
            CALL    L0EA7           ; routine FIND-INT gets address in BC
                                    ; invoking the error routine with overflow
                                    ; or a negative number.
            POP     AF              ; restore value.

    ; Note. the next two instructions are legacy code from the ZX80 and
    ; inappropriate here.

            BIT     7,(IY+$00)      ; test ERR_NR - is it still $FF ?
            RET     Z               ; return with error.

            LD      (BC),A          ; update the address contents.
            RET                     ; return.

    ; -----------------------------
    ; THE 'FIND INTEGER' SUBROUTINE
    ; -----------------------------
    ;
    ;

    ;; FIND-INT
    L0EA7:  CALL    L158A           ; routine FP-TO-BC
            JR      C,L0EAD         ; forward with overflow to REPORT-B

            RET     Z               ; return if positive (0-65535).

    ;; REPORT-B
    L0EAD:  RST     08H             ; ERROR-1
            DEFB    $0A             ; Error Report: Integer out of range

    ; -------------------------
    ; THE 'RUN' COMMAND ROUTINE
    ; -------------------------
    ;
    ;

    ;; RUN
    L0EAF:  CALL    L0E81           ; routine GOTO
            JP      L149A           ; to CLEAR

    ; ---------------------------
    ; THE 'GOSUB' COMMAND ROUTINE
    ; ---------------------------
    ;
    ;

    ;; GOSUB
    L0EB5:  LD      HL,($4007)      ; sv PPC_lo
            INC     HL              ;
            EX      (SP),HL         ;
            PUSH    HL              ;
            LD      ($4002),SP      ; set the error stack pointer - ERR_SP
            CALL    L0E81           ; routine GOTO
            LD      BC,$0006        ;

    ; --------------------------
    ; THE 'TEST ROOM' SUBROUTINE
    ; --------------------------
    ;
    ;

    ;; TEST-ROOM
    L0EC5:  LD      HL,($401C)      ; sv STKEND_lo
            ADD     HL,BC           ;
            JR      C,L0ED3         ; to REPORT-4

            EX      DE,HL           ;
            LD      HL,$0024        ;
            ADD     HL,DE           ;
            SBC     HL,SP           ;
            RET     C               ;

    ;; REPORT-4
    L0ED3:  LD      L,$03           ;
            JP      L0058           ; to ERROR-3

    ; ----------------------------
    ; THE 'RETURN' COMMAND ROUTINE
    ; ----------------------------
    ;
    ;

    ;; RETURN
    L0ED8:  POP     HL              ;
            EX      (SP),HL         ;
            LD      A,H             ;
            CP      $3E             ;
            JR      Z,L0EE5         ; to REPORT-7

            LD      ($4002),SP      ; sv ERR_SP_lo
            JR      L0E86           ; back to GOTO-2

    ; ---

    ;; REPORT-7
    L0EE5:  EX      (SP),HL         ;
            PUSH    HL              ;

            RST     08H             ; ERROR-1
            DEFB    $06             ; Error Report: RETURN without GOSUB

    ; ---------------------------
    ; THE 'INPUT' COMMAND ROUTINE
    ; ---------------------------
    ;
    ;

    ;; INPUT
    L0EE9:  BIT     7,(IY+$08)      ; sv PPC_hi
            JR      NZ,L0F21        ; to REPORT-8

            CALL    L14A3           ; routine X-TEMP
            LD      HL,$402D        ; sv FLAGX
            SET     5,(HL)          ;
            RES     6,(HL)          ;
            LD      A,($4001)       ; sv FLAGS
            AND     $40             ;
            LD      BC,$0002        ;
            JR      NZ,L0F05        ; to PROMPT

            LD      C,$04           ;

    ;; PROMPT
    L0F05:  OR      (HL)            ;
            LD      (HL),A          ;

            RST     30H             ; BC-SPACES
            LD      (HL),$76        ;
            LD      A,C             ;
            RRCA                    ;
            RRCA                    ;
            JR      C,L0F14         ; to ENTER-CUR

            LD      A,$0B           ;
            LD      (DE),A          ;
            DEC     HL              ;
            LD      (HL),A          ;

    ;; ENTER-CUR
    L0F14:  DEC     HL              ;
            LD      (HL),$7F        ;
            LD      HL,($4039)      ; sv S_POSN_x
            LD      ($4030),HL      ; sv T_ADDR_lo
            POP     HL              ;
            JP      L0472           ; to LOWER

    ; ---

    ;; REPORT-8
    L0F21:  RST     08H             ; ERROR-1
            DEFB    $07             ; Error Report: End of file

    ; ---------------------------
    ; THE 'PAUSE' COMMAND ROUTINE
    ; ---------------------------
    ;
    ;

    ;; FAST
    L0F23:  CALL    L02E7           ; routine SET-FAST
            RES     6,(IY+$3B)      ; sv CDFLAG
            RET                     ; return.

    ; --------------------------
    ; THE 'SLOW' COMMAND ROUTINE
    ; --------------------------
    ;
    ;

    ;; SLOW
    L0F2B:  SET     6,(IY+$3B)      ; sv CDFLAG
            JP      L0207           ; to SLOW/FAST

    ; ---------------------------
    ; THE 'PAUSE' COMMAND ROUTINE
    ; ---------------------------

    ;; PAUSE
    L0F32:  CALL    L0EA7           ; routine FIND-INT
            CALL    L02E7           ; routine SET-FAST
            LD      H,B             ;
            LD      L,C             ;
            CALL    L022D           ; routine DISPLAY-P

            LD      (IY+$35),$FF    ; sv FRAMES_hi

            CALL    L0207           ; routine SLOW/FAST
            JR      L0F4B           ; routine DEBOUNCE

    ; ----------------------
    ; THE 'BREAK' SUBROUTINE
    ; ----------------------
    ;
    ;

    ;; BREAK-1
    L0F46:  LD      A,$7F           ; read port $7FFE - keys B,N,M,.,SPACE.
            IN      A,($FE)         ;
            RRA                     ; carry will be set if space not pressed.

    ; -------------------------
    ; THE 'DEBOUNCE' SUBROUTINE
    ; -------------------------
    ;
    ;

    ;; DEBOUNCE
    L0F4B:  RES     0,(IY+$3B)      ; update system variable CDFLAG
            LD      A,$FF           ;
            LD      ($4027),A       ; update system variable DEBOUNCE
            RET                     ; return.

    ; -------------------------
    ; THE 'SCANNING' SUBROUTINE
    ; -------------------------
    ; This recursive routine is where the ZX81 gets its power. Provided there is
    ; enough memory it can evaluate an expression of unlimited complexity.
    ; Note. there is no unary plus so, as on the ZX80, PRINT +1 gives a syntax error.
    ; PRINT +1 works on the Spectrum but so too does PRINT + "STRING".

    ;; SCANNING
    L0F55:  RST     18H             ; GET-CHAR
            LD      B,$00           ; set B register to zero.
            PUSH    BC              ; stack zero as a priority end-marker.

    ;; S-LOOP-1
    L0F59:  CP      $40             ; compare to the 'RND' character
            JR      NZ,L0F8C        ; forward, if not, to S-TEST-PI

    ; ------------------
    ; THE 'RND' FUNCTION
    ; ------------------

            CALL    L0DA6           ; routine SYNTAX-Z
            JR      Z,L0F8A         ; forward if checking syntax to S-JPI-END

            LD      BC,($4032)      ; sv SEED_lo
            CALL    L1520           ; routine STACK-BC

            RST     28H             ;; FP-CALC
            DEFB    $A1             ;;stk-one
            DEFB    $0F             ;;addition
            DEFB    $30             ;;stk-data
            DEFB    $37             ;;Exponent: $87, Bytes: 1
            DEFB    $16             ;;(+00,+00,+00)
            DEFB    $04             ;;multiply
            DEFB    $30             ;;stk-data
            DEFB    $80             ;;Bytes: 3
            DEFB    $41             ;;Exponent $91
            DEFB    $00,$00,$80     ;;(+00)
            DEFB    $2E             ;;n-mod-m
            DEFB    $02             ;;delete
            DEFB    $A1             ;;stk-one
            DEFB    $03             ;;subtract
            DEFB    $2D             ;;duplicate
            DEFB    $34             ;;end-calc

            CALL    L158A           ; routine FP-TO-BC
            LD      ($4032),BC      ; update the SEED system variable.
            LD      A,(HL)          ; HL addresses the exponent of the last value.
            AND     A               ; test for zero
            JR      Z,L0F8A         ; forward, if so, to S-JPI-END

            SUB     $10             ; else reduce exponent by sixteen
            LD      (HL),A          ; thus dividing by 65536 for last value.

    ;; S-JPI-END
    L0F8A:  JR      L0F99           ; forward to S-PI-END

    ; ---

    ;; S-TEST-PI
    L0F8C:  CP      $42             ; the 'PI' character
            JR      NZ,L0F9D        ; forward, if not, to S-TST-INK

    ; -------------------
    ; THE 'PI' EVALUATION
    ; -------------------

            CALL    L0DA6           ; routine SYNTAX-Z
            JR      Z,L0F99         ; forward if checking syntax to S-PI-END

            RST     28H             ;; FP-CALC
            DEFB    $A3             ;;stk-pi/2
            DEFB    $34             ;;end-calc

            INC     (HL)            ; double the exponent giving PI on the stack.

    ;; S-PI-END
    L0F99:  RST     20H             ; NEXT-CHAR advances character pointer.

            JP      L1083           ; jump forward to S-NUMERIC to set the flag
                                    ; to signal numeric result before advancing.

    ; ---

    ;; S-TST-INK
    L0F9D:  CP      $41             ; compare to character 'INKEY$'
            JR      NZ,L0FB2        ; forward, if not, to S-ALPHANUM

    ; -----------------------
    ; THE 'INKEY$' EVALUATION
    ; -----------------------

            CALL    L02BB           ; routine KEYBOARD
            LD      B,H             ;
            LD      C,L             ;
            LD      D,C             ;
            INC     D               ;
            CALL    NZ,L07BD        ; routine DECODE
            LD      A,D             ;
            ADC     A,D             ;
            LD      B,D             ;
            LD      C,A             ;
            EX      DE,HL           ;
            JR      L0FED           ; forward to S-STRING

    ; ---

    ;; S-ALPHANUM
    L0FB2:  CALL    L14D2           ; routine ALPHANUM
            JR      C,L1025         ; forward, if alphanumeric to S-LTR-DGT

            CP      $1B             ; is character a '.' ?
            JP      Z,L1047         ; jump forward if so to S-DECIMAL

            LD      BC,$09D8        ; prepare priority 09, operation 'subtract'
            CP      $16             ; is character unary minus '-' ?
            JR      Z,L1020         ; forward, if so, to S-PUSH-PO

            CP      $10             ; is character a '(' ?
            JR      NZ,L0FD6        ; forward if not to S-QUOTE

            CALL    L0049           ; routine CH-ADD+1 advances character pointer.

            CALL    L0F55           ; recursively call routine SCANNING to
                                    ; evaluate the sub-expression.

            CP      $11             ; is subsequent character a ')' ?
            JR      NZ,L0FFF        ; forward if not to S-RPT-C

            CALL    L0049           ; routine CH-ADD+1  advances.
            JR      L0FF8           ; relative jump to S-JP-CONT3 and then S-CONT3

    ; ---

    ; consider a quoted string e.g. PRINT "Hooray!"
    ; Note. quotes are not allowed within a string.

    ;; S-QUOTE
    L0FD6:  CP      $0B             ; is character a quote (") ?
            JR      NZ,L1002        ; forward, if not, to S-FUNCTION

            CALL    L0049           ; routine CH-ADD+1 advances
            PUSH    HL              ; * save start of string.
            JR      L0FE3           ; forward to S-QUOTE-S

    ; ---

    ;; S-Q-AGAIN
    L0FE0:  CALL    L0049           ; routine CH-ADD+1

    ;; S-QUOTE-S
    L0FE3:  CP      $0B             ; is character a '"' ?
            JR      NZ,L0FFB        ; forward if not to S-Q-NL

            POP     DE              ; * retrieve start of string
            AND     A               ; prepare to subtract.
            SBC     HL,DE           ; subtract start from current position.
            LD      B,H             ; transfer this length
            LD      C,L             ; to the BC register pair.

    ;; S-STRING
    L0FED:  LD      HL,$4001        ; address system variable FLAGS
            RES     6,(HL)          ; signal string result
            BIT     7,(HL)          ; test if checking syntax.

            CALL    NZ,L12C3        ; in run-time routine STK-STO-$ stacks the
                                    ; string descriptor - start DE, length BC.

            RST     20H             ; NEXT-CHAR advances pointer.

    ;; S-J-CONT-3
    L0FF8:  JP      L1088           ; jump to S-CONT-3

    ; ---

    ; A string with no terminating quote has to be considered.

    ;; S-Q-NL
    L0FFB:  CP      $76             ; compare to NEWLINE
            JR      NZ,L0FE0        ; loop back if not to S-Q-AGAIN

    ;; S-RPT-C
    L0FFF:  JP      L0D9A           ; to REPORT-C

    ; ---

    ;; S-FUNCTION
    L1002:  SUB     $C4             ; subtract 'CODE' reducing codes
                                    ; CODE thru '<>' to range $00 - $XX
            JR      C,L0FFF         ; back, if less, to S-RPT-C

    ; test for NOT the last function in character set.

            LD      BC,$04EC        ; prepare priority $04, operation 'not'
            CP      $13             ; compare to 'NOT'  ( - CODE)
            JR      Z,L1020         ; forward, if so, to S-PUSH-PO

            JR      NC,L0FFF        ; back with anything higher to S-RPT-C

    ; else is a function 'CODE' thru 'CHR$'

            LD      B,$10           ; priority sixteen binds all functions to
                                    ; arguments removing the need for brackets.

            ADD     A,$D9           ; add $D9 to give range $D9 thru $EB
                                    ; bit 6 is set to show numeric argument.
                                    ; bit 7 is set to show numeric result.

    ; now adjust these default argument/result indicators.

            LD      C,A             ; save code in C

            CP      $DC             ; separate 'CODE', 'VAL', 'LEN'
            JR      NC,L101A        ; skip forward if string operand to S-NO-TO-$

            RES     6,C             ; signal string operand.

    ;; S-NO-TO-$
    L101A:  CP      $EA             ; isolate top of range 'STR$' and 'CHR$'
            JR      C,L1020         ; skip forward with others to S-PUSH-PO

            RES     7,C             ; signal string result.

    ;; S-PUSH-PO
    L1020:  PUSH    BC              ; push the priority/operation

            RST     20H             ; NEXT-CHAR
            JP      L0F59           ; jump back to S-LOOP-1

    ; ---

    ;; S-LTR-DGT
    L1025:  CP      $26             ; compare to 'A'.
            JR      C,L1047         ; forward if less to S-DECIMAL

            CALL    L111C           ; routine LOOK-VARS
            JP      C,L0D4B         ; back if not found to REPORT-2
                                    ; a variable is always 'found' when checking
                                    ; syntax.

            CALL    Z,L11A7         ; routine STK-VAR stacks string parameters or
                                    ; returns cell location if numeric.

            LD      A,($4001)       ; fetch FLAGS
            CP      $C0             ; compare to numeric result/numeric operand
            JR      C,L1087         ; forward if not numeric to S-CONT-2

            INC     HL              ; address numeric contents of variable.
            LD      DE,($401C)      ; set destination to STKEND
            CALL    L19F6           ; routine MOVE-FP stacks the five bytes
            EX      DE,HL           ; transfer new free location from DE to HL.
            LD      ($401C),HL      ; update STKEND system variable.
            JR      L1087           ; forward to S-CONT-2

    ; ---

    ; The Scanning Decimal routine is invoked when a decimal point or digit is
    ; found in the expression.
    ; When checking syntax, then the 'hidden floating point' form is placed
    ; after the number in the BASIC line.
    ; In run-time, the digits are skipped and the floating point number is picked
    ; up.

    ;; S-DECIMAL
    L1047:  CALL    L0DA6           ; routine SYNTAX-Z
            JR      NZ,L106F        ; forward in run-time to S-STK-DEC

            CALL    L14D9           ; routine DEC-TO-FP

            RST     18H             ; GET-CHAR advances HL past digits
            LD      BC,$0006        ; six locations are required.
            CALL    L099E           ; routine MAKE-ROOM
            INC     HL              ; point to first new location
            LD      (HL),$7E        ; insert the number marker 126 decimal.
            INC     HL              ; increment
            EX      DE,HL           ; transfer destination to DE.
            LD      HL,($401C)      ; set HL from STKEND which points to the
                                    ; first location after the 'last value'
            LD      C,$05           ; five bytes to move.
            AND     A               ; clear carry.
            SBC     HL,BC           ; subtract five pointing to 'last value'.
            LD      ($401C),HL      ; update STKEND thereby 'deleting the value.

            LDIR                    ; copy the five value bytes.

            EX      DE,HL           ; basic pointer to HL which may be white-space
                                    ; following the number.
            DEC     HL              ; now points to last of five bytes.
            CALL    L004C           ; routine TEMP-PTR1 advances the character
                                    ; address skipping any white-space.
            JR      L1083           ; forward to S-NUMERIC
                                    ; to signal a numeric result.

    ; ---

    ; In run-time the branch is here when a digit or point is encountered.

    ;; S-STK-DEC
    L106F:  RST     20H             ; NEXT-CHAR
            CP      $7E             ; compare to 'number marker'
            JR      NZ,L106F        ; loop back until found to S-STK-DEC
                                    ; skipping all the digits.

            INC     HL              ; point to first of five hidden bytes.
            LD      DE,($401C)      ; set destination from STKEND system variable
            CALL    L19F6           ; routine MOVE-FP stacks the number.
            LD      ($401C),DE      ; update system variable STKEND.
            LD      ($4016),HL      ; update system variable CH_ADD.

    ;; S-NUMERIC
    L1083:  SET     6,(IY+$01)      ; update FLAGS  - Signal numeric result

    ;; S-CONT-2
    L1087:  RST     18H             ; GET-CHAR

    ;; S-CONT-3
    L1088:  CP      $10             ; compare to opening bracket '('
            JR      NZ,L1098        ; forward if not to S-OPERTR

            BIT     6,(IY+$01)      ; test FLAGS  - Numeric or string result?
            JR      NZ,L10BC        ; forward if numeric to S-LOOP

    ; else is a string

            CALL    L1263           ; routine SLICING

            RST     20H             ; NEXT-CHAR
            JR      L1088           ; back to S-CONT-3

    ; ---

    ; the character is now manipulated to form an equivalent in the table of
    ; calculator literals. This is quite cumbersome and in the ZX Spectrum a
    ; simple look-up table was introduced at this point.

    ;; S-OPERTR
    L1098:  LD      BC,$00C3        ; prepare operator 'subtract' as default.
                                    ; also set B to zero for later indexing.

            CP      $12             ; is character '>' ?
            JR      C,L10BC         ; forward if less to S-LOOP as
                                    ; we have reached end of meaningful expression

            SUB     $16             ; is character '-' ?
            JR      NC,L10A7        ; forward with - * / and '**' '<>' to SUBMLTDIV

            ADD     A,$0D           ; increase others by thirteen
                                    ; $09 '>' thru $0C '+'
            JR      L10B5           ; forward to GET-PRIO

    ; ---

    ;; SUBMLTDIV
    L10A7:  CP      $03             ; isolate $00 '-', $01 '*', $02 '/'
            JR      C,L10B5         ; forward if so to GET-PRIO

    ; else possibly originally $D8 '**' thru $DD '<>' already reduced by $16

            SUB     $C2             ; giving range $00 to $05
            JR      C,L10BC         ; forward if less to S-LOOP

            CP      $06             ; test the upper limit for nonsense also
            JR      NC,L10BC        ; forward if so to S-LOOP

            ADD     A,$03           ; increase by 3 to give combined operators of

                                    ; $00 '-'
                                    ; $01 '*'
                                    ; $02 '/'

                                    ; $03 '**'
                                    ; $04 'OR'
                                    ; $05 'AND'
                                    ; $06 '<='
                                    ; $07 '>='
                                    ; $08 '<>'

                                    ; $09 '>'
                                    ; $0A '<'
                                    ; $0B '='
                                    ; $0C '+'

    ;; GET-PRIO
    L10B5:  ADD     A,C             ; add to default operation 'sub' ($C3)
            LD      C,A             ; and place in operator byte - C.

            LD      HL,L110F - $C3  ; theoretical base of the priorities table.
            ADD     HL,BC           ; add C ( B is zero)
            LD      B,(HL)          ; pick up the priority in B

    ;; S-LOOP
    L10BC:  POP     DE              ; restore previous
            LD      A,D             ; load A with priority.
            CP      B               ; is present priority higher
            JR      C,L10ED         ; forward if so to S-TIGHTER

            AND     A               ; are both priorities zero
            JP      Z,L0018         ; exit if zero via GET-CHAR

            PUSH    BC              ; stack present values
            PUSH    DE              ; stack last values
            CALL    L0DA6           ; routine SYNTAX-Z
            JR      Z,L10D5         ; forward is checking syntax to S-SYNTEST

            LD      A,E             ; fetch last operation
            AND     $3F             ; mask off the indicator bits to give true
                                    ; calculator literal.
            LD      B,A             ; place in the B register for BREG

    ; perform the single operation

            RST     28H             ;; FP-CALC
            DEFB    $37             ;;fp-calc-2
            DEFB    $34             ;;end-calc

            JR      L10DE           ; forward to S-RUNTEST

    ; ---

    ;; S-SYNTEST
    L10D5:  LD      A,E             ; transfer masked operator to A
            XOR     (IY+$01)        ; XOR with FLAGS like results will reset bit 6
            AND     $40             ; test bit 6

    ;; S-RPORT-C
    L10DB:  JP      NZ,L0D9A        ; back to REPORT-C if results do not agree.

    ; ---

    ; in run-time impose bit 7 of the operator onto bit 6 of the FLAGS

    ;; S-RUNTEST
    L10DE:  POP     DE              ; restore last operation.
            LD      HL,$4001        ; address system variable FLAGS
            SET     6,(HL)          ; presume a numeric result
            BIT     7,E             ; test expected result in operation
            JR      NZ,L10EA        ; forward if numeric to S-LOOPEND

            RES     6,(HL)          ; reset to signal string result

    ;; S-LOOPEND
    L10EA:  POP     BC              ; restore present values
            JR      L10BC           ; back to S-LOOP

    ; ---

    ;; S-TIGHTER
    L10ED:  PUSH    DE              ; push last values and consider these

            LD      A,C             ; get the present operator.
            BIT     6,(IY+$01)      ; test FLAGS  - Numeric or string result?
            JR      NZ,L110A        ; forward if numeric to S-NEXT

            AND     $3F             ; strip indicator bits to give clear literal.
            ADD     A,$08           ; add eight - augmenting numeric to equivalent
                                    ; string literals.
            LD      C,A             ; place plain literal back in C.
            CP      $10             ; compare to 'AND'
            JR      NZ,L1102        ; forward if not to S-NOT-AND

            SET     6,C             ; set the numeric operand required for 'AND'
            JR      L110A           ; forward to S-NEXT

    ; ---

    ;; S-NOT-AND
    L1102:  JR      C,L10DB         ; back if less than 'AND' to S-RPORT-C
                                    ; Nonsense if '-', '*' etc.

            CP      $17             ; compare to 'strs-add' literal
            JR      Z,L110A         ; forward if so signaling string result

            SET     7,C             ; set bit to numeric (Boolean) for others.

    ;; S-NEXT
    L110A:  PUSH    BC              ; stack 'present' values

            RST     20H             ; NEXT-CHAR
            JP      L0F59           ; jump back to S-LOOP-1

    ; -------------------------
    ; THE 'TABLE OF PRIORITIES'
    ; -------------------------
    ;
    ;

    ;; tbl-pri
    L110F:  DEFB    $06             ;       '-'
            DEFB    $08             ;       '*'
            DEFB    $08             ;       '/'
            DEFB    $0A             ;       '**'
            DEFB    $02             ;       'OR'
            DEFB    $03             ;       'AND'
            DEFB    $05             ;       '<='
            DEFB    $05             ;       '>='
            DEFB    $05             ;       '<>'
            DEFB    $05             ;       '>'
            DEFB    $05             ;       '<'
            DEFB    $05             ;       '='
            DEFB    $06             ;       '+'

    ; --------------------------
    ; THE 'LOOK-VARS' SUBROUTINE
    ; --------------------------
    ;
    ;

    ;; LOOK-VARS
    L111C:  SET     6,(IY+$01)      ; sv FLAGS  - Signal numeric result

            RST     18H             ; GET-CHAR
            CALL    L14CE           ; routine ALPHA
            JP      NC,L0D9A        ; to REPORT-C

            PUSH    HL              ;
            LD      C,A             ;

            RST     20H             ; NEXT-CHAR
            PUSH    HL              ;
            RES     5,C             ;
            CP      $10             ;
            JR      Z,L1148         ; to V-SYN/RUN

            SET     6,C             ;
            CP      $0D             ;
            JR      Z,L1143         ; forward to V-STR-VAR

            SET     5,C             ;

    ;; V-CHAR
    L1139:  CALL    L14D2           ; routine ALPHANUM
            JR      NC,L1148        ; forward when not to V-RUN/SYN

            RES     6,C             ;

            RST     20H             ; NEXT-CHAR
            JR      L1139           ; loop back to V-CHAR

    ; ---

    ;; V-STR-VAR
    L1143:  RST     20H             ; NEXT-CHAR
            RES     6,(IY+$01)      ; sv FLAGS  - Signal string result

    ;; V-RUN/SYN
    L1148:  LD      B,C             ;
            CALL    L0DA6           ; routine SYNTAX-Z
            JR      NZ,L1156        ; forward to V-RUN

            LD      A,C             ;
            AND     $E0             ;
            SET     7,A             ;
            LD      C,A             ;
            JR      L118A           ; forward to V-SYNTAX

    ; ---

    ;; V-RUN
    L1156:  LD      HL,($4010)      ; sv VARS

    ;; V-EACH
    L1159:  LD      A,(HL)          ;
            AND     $7F             ;
            JR      Z,L1188         ; to V-80-BYTE

            CP      C               ;
            JR      NZ,L1180        ; to V-NEXT

            RLA                     ;
            ADD     A,A             ;
            JP      P,L1195         ; to V-FOUND-2

            JR      C,L1195         ; to V-FOUND-2

            POP     DE              ;
            PUSH    DE              ;
            PUSH    HL              ;

    ;; V-MATCHES
    L116B:  INC     HL              ;

    ;; V-SPACES
    L116C:  LD      A,(DE)          ;
            INC     DE              ;
            AND     A               ;
            JR      Z,L116C         ; back to V-SPACES

            CP      (HL)            ;
            JR      Z,L116B         ; back to V-MATCHES

            OR      $80             ;
            CP      (HL)            ;
            JR       NZ,L117F       ; forward to V-GET-PTR

            LD      A,(DE)          ;
            CALL    L14D2           ; routine ALPHANUM
            JR      NC,L1194        ; forward to V-FOUND-1

    ;; V-GET-PTR
    L117F:  POP     HL              ;

    ;; V-NEXT
    L1180:  PUSH    BC              ;
            CALL    L09F2           ; routine NEXT-ONE
            EX      DE,HL           ;
            POP     BC              ;
            JR      L1159           ; back to V-EACH

    ; ---

    ;; V-80-BYTE
    L1188:  SET     7,B             ;

    ;; V-SYNTAX
    L118A:  POP     DE              ;

            RST     18H             ; GET-CHAR
            CP      $10             ;
            JR      Z,L1199         ; forward to V-PASS

            SET     5,B             ;
            JR      L11A1           ; forward to V-END

    ; ---

    ;; V-FOUND-1
    L1194:  POP     DE              ;

    ;; V-FOUND-2
    L1195:  POP     DE              ;
            POP     DE              ;
            PUSH    HL              ;

            RST     18H             ; GET-CHAR

    ;; V-PASS
    L1199:  CALL    L14D2           ; routine ALPHANUM
            JR      NC,L11A1        ; forward if not alphanumeric to V-END

            RST     20H             ; NEXT-CHAR
            JR      L1199           ; back to V-PASS

    ; ---

    ;; V-END
    L11A1:  POP     HL              ;
            RL      B               ;
            BIT     6,B             ;
            RET                     ;

    ; ------------------------
    ; THE 'STK-VAR' SUBROUTINE
    ; ------------------------
    ;
    ;

    ;; STK-VAR
    L11A7:  XOR     A               ;
            LD      B,A             ;
            BIT     7,C             ;
            JR      NZ,L11F8        ; forward to SV-COUNT

            BIT     7,(HL)          ;
            JR      NZ,L11BF        ; forward to SV-ARRAYS

            INC     A               ;

    ;; SV-SIMPLE$
    L11B2:  INC     HL              ;
            LD      C,(HL)          ;
            INC     HL              ;
            LD      B,(HL)          ;
            INC     HL              ;
            EX      DE,HL           ;
            CALL    L12C3           ; routine STK-STO-$

            RST     18H             ; GET-CHAR
            JP      L125A           ; jump forward to SV-SLICE?

    ; ---

    ;; SV-ARRAYS
    L11BF:  INC     HL              ;
            INC     HL              ;
            INC     HL              ;
            LD      B,(HL)          ;
            BIT     6,C             ;
            JR      Z,L11D1         ; forward to SV-PTR

            DEC     B               ;
            JR      Z,L11B2         ; forward to SV-SIMPLE$

            EX      DE,HL           ;

            RST     18H             ; GET-CHAR
            CP      $10             ;
            JR      NZ,L1231        ; forward to REPORT-3

            EX      DE,HL           ;

    ;; SV-PTR
    L11D1:  EX      DE,HL           ;
            JR      L11F8           ; forward to SV-COUNT

    ; ---

    ;; SV-COMMA
    L11D4:  PUSH    HL              ;

            RST     18H             ; GET-CHAR
            POP     HL              ;
            CP      $1A             ;
            JR      Z,L11FB         ; forward to SV-LOOP

            BIT     7,C             ;
            JR      Z,L1231         ; forward to REPORT-3

            BIT     6,C             ;
            JR      NZ,L11E9        ; forward to SV-CLOSE

            CP      $11             ;
            JR      NZ,L1223        ; forward to SV-RPT-C

            RST     20H             ; NEXT-CHAR
            RET                     ;

    ; ---

    ;; SV-CLOSE
    L11E9:  CP      $11             ;
            JR      Z,L1259         ; forward to SV-DIM

            CP      $DF             ;
            JR      NZ,L1223        ; forward to SV-RPT-C

    ;; SV-CH-ADD
    L11F1:  RST     18H             ; GET-CHAR
            DEC     HL              ;
            LD      ($4016),HL      ; sv CH_ADD
            JR      L1256           ; forward to SV-SLICE

    ; ---

    ;; SV-COUNT
    L11F8:  LD      HL,$0000        ;

    ;; SV-LOOP
    L11FB:  PUSH    HL              ;

            RST     20H             ; NEXT-CHAR
            POP     HL              ;
            LD      A,C             ;
            CP      $C0             ;
            JR      NZ,L120C        ; forward to SV-MULT

            RST     18H             ; GET-CHAR
            CP      $11             ;
            JR      Z,L1259         ; forward to SV-DIM

            CP      $DF             ;
            JR      Z,L11F1         ; back to SV-CH-ADD

    ;; SV-MULT
    L120C:  PUSH    BC              ;
            PUSH    HL              ;
            CALL    L12FF           ; routine DE,(DE+1)
            EX      (SP),HL         ;
            EX      DE,HL           ;
            CALL    L12DD           ; routine INT-EXP1
            JR      C,L1231         ; forward to REPORT-3

            DEC     BC              ;
            CALL    L1305           ; routine GET-HL*DE
            ADD     HL,BC           ;
            POP     DE              ;
            POP     BC              ;
            DJNZ    L11D4           ; loop back to SV-COMMA

            BIT     7,C             ;

    ;; SV-RPT-C
    L1223:  JR      NZ,L128B        ; relative jump to SL-RPT-C

            PUSH    HL              ;
            BIT     6,C             ;
            JR      NZ,L123D        ; forward to SV-ELEM$

            LD      B,D             ;
            LD      C,E             ;

            RST     18H             ; GET-CHAR
            CP      $11             ; is character a ')' ?
            JR      Z,L1233         ; skip forward to SV-NUMBER

    ;; REPORT-3
    L1231:  RST     08H             ; ERROR-1
            DEFB    $02             ; Error Report: Subscript wrong

    ;; SV-NUMBER
    L1233:  RST     20H             ; NEXT-CHAR
            POP     HL              ;
            LD      DE,$0005        ;
            CALL    L1305           ; routine GET-HL*DE
            ADD     HL,BC           ;
            RET                     ; return                            >>

    ; ---

    ;; SV-ELEM$
    L123D:  CALL    L12FF           ; routine DE,(DE+1)
            EX      (SP),HL         ;
            CALL    L1305           ; routine GET-HL*DE
            POP     BC              ;
            ADD     HL,BC           ;
            INC     HL              ;
            LD      B,D             ;
            LD      C,E             ;
            EX      DE,HL           ;
            CALL    L12C2           ; routine STK-ST-0

            RST     18H             ; GET-CHAR
            CP      $11             ; is it ')' ?
            JR      Z,L1259         ; forward if so to SV-DIM

            CP      $1A             ; is it ',' ?
            JR      NZ,L1231        ; back if not to REPORT-3

    ;; SV-SLICE
    L1256:  CALL    L1263           ; routine SLICING

    ;; SV-DIM
    L1259:  RST     20H             ; NEXT-CHAR

    ;; SV-SLICE?
    L125A:  CP      $10             ;
            JR      Z,L1256         ; back to SV-SLICE

            RES     6,(IY+$01)      ; sv FLAGS  - Signal string result
            RET                     ; return.

    ; ------------------------
    ; THE 'SLICING' SUBROUTINE
    ; ------------------------
    ;
    ;

    ;; SLICING
    L1263:  CALL    L0DA6           ; routine SYNTAX-Z
            CALL    NZ,L13F8        ; routine STK-FETCH

            RST     20H             ; NEXT-CHAR
            CP      $11             ; is it ')' ?
            JR      Z,L12BE         ; forward if so to SL-STORE

            PUSH    DE              ;
            XOR     A               ;
            PUSH    AF              ;
            PUSH    BC              ;
            LD      DE,$0001        ;

            RST     18H             ; GET-CHAR
            POP     HL              ;
            CP      $DF             ; is it 'TO' ?
            JR      Z,L1292         ; forward if so to SL-SECOND

            POP     AF              ;
            CALL    L12DE           ; routine INT-EXP2
            PUSH    AF              ;
            LD      D,B             ;
            LD      E,C             ;
            PUSH    HL              ;

            RST     18H             ; GET-CHAR
            POP     HL              ;
            CP      $DF             ; is it 'TO' ?
            JR      Z,L1292         ; forward if so to SL-SECOND

            CP      $11             ;

    ;; SL-RPT-C
    L128B:  JP      NZ,L0D9A        ; to REPORT-C

            LD      H,D             ;
            LD      L,E             ;
            JR      L12A5           ; forward to SL-DEFINE

    ; ---

    ;; SL-SECOND
    L1292:  PUSH    HL              ;

            RST     20H             ; NEXT-CHAR
            POP     HL              ;
            CP      $11             ; is it ')' ?
            JR      Z,L12A5         ; forward if so to SL-DEFINE

            POP     AF              ;
            CALL    L12DE           ; routine INT-EXP2
            PUSH    AF              ;

            RST     18H             ; GET-CHAR
            LD      H,B             ;
            LD      L,C             ;
            CP      $11             ; is it ')' ?
            JR      NZ,L128B        ; back if not to SL-RPT-C

    ;; SL-DEFINE
    L12A5:  POP     AF              ;
            EX      (SP),HL         ;
            ADD     HL,DE           ;
            DEC     HL              ;
            EX      (SP),HL         ;
            AND     A               ;
            SBC     HL,DE           ;
            LD      BC,$0000        ;
            JR      C,L12B9         ; forward to SL-OVER

            INC     HL              ;
            AND     A               ;
            JP      M,L1231         ; jump back to REPORT-3

            LD      B,H             ;
            LD      C,L             ;

    ;; SL-OVER
    L12B9:  POP     DE              ;
            RES     6,(IY+$01)      ; sv FLAGS  - Signal string result

    ;; SL-STORE
    L12BE:  CALL    L0DA6           ; routine SYNTAX-Z
            RET     Z               ; return if checking syntax.

    ; --------------------------
    ; THE 'STK-STORE' SUBROUTINE
    ; --------------------------
    ;
    ;

    ;; STK-ST-0
    L12C2:  XOR     A               ;

    ;; STK-STO-$
    L12C3:  PUSH    BC              ;
            CALL    L19EB           ; routine TEST-5-SP
            POP     BC              ;
            LD      HL,($401C)      ; sv STKEND
            LD      (HL),A          ;
            INC     HL              ;
            LD      (HL),E          ;
            INC     HL              ;
            LD      (HL),D          ;
            INC     HL              ;
            LD      (HL),C          ;
            INC     HL              ;
            LD      (HL),B          ;
            INC     HL              ;
            LD      ($401C),HL      ; sv STKEND
            RES     6,(IY+$01)      ; update FLAGS - signal string result
            RET                     ; return.

    ; -------------------------
    ; THE 'INT EXP' SUBROUTINES
    ; -------------------------
    ;
    ;

    ;; INT-EXP1
    L12DD:  XOR     A               ;

    ;; INT-EXP2
    L12DE:  PUSH    DE              ;
            PUSH    HL              ;
            PUSH    AF              ;
            CALL    L0D92           ; routine CLASS-6
            POP     AF              ;
            CALL    L0DA6           ; routine SYNTAX-Z
            JR      Z,L12FC         ; forward if checking syntax to I-RESTORE

            PUSH    AF              ;
            CALL    L0EA7           ; routine FIND-INT
            POP     DE              ;
            LD      A,B             ;
            OR      C               ;
            SCF                     ; Set Carry Flag
            JR      Z,L12F9         ; forward to I-CARRY

            POP     HL              ;
            PUSH    HL              ;
            AND     A               ;
            SBC     HL,BC           ;

    ;; I-CARRY
    L12F9:  LD      A,D             ;
            SBC     A,$00           ;

    ;; I-RESTORE
    L12FC:  POP     HL              ;
            POP     DE              ;
            RET                     ;

    ; --------------------------
    ; THE 'DE,(DE+1)' SUBROUTINE
    ; --------------------------
    ; INDEX and LOAD Z80 subroutine.
    ; This emulates the 6800 processor instruction LDX 1,X which loads a two-byte
    ; value from memory into the register indexing it. Often these are hardly worth
    ; the bother of writing as subroutines and this one doesn't save any time or
    ; memory. The timing and space overheads have to be offset against the ease of
    ; writing and the greater program readability from using such toolkit routines.

    ;; DE,(DE+1)
    L12FF:  EX      DE,HL           ; move index address into HL.
            INC     HL              ; increment to address word.
            LD      E,(HL)          ; pick up word low-order byte.
            INC     HL              ; index high-order byte and
            LD      D,(HL)          ; pick it up.
            RET                     ; return with DE = word.

    ; --------------------------
    ; THE 'GET-HL*DE' SUBROUTINE
    ; --------------------------
    ;

    ;; GET-HL*DE
    L1305:  CALL    L0DA6           ; routine SYNTAX-Z
            RET     Z               ;

            PUSH    BC              ;
            LD      B,$10           ;
            LD      A,H             ;
            LD      C,L             ;
            LD      HL,$0000        ;

    ;; HL-LOOP
    L1311:  ADD     HL,HL           ;
            JR      C,L131A         ; forward with carry to HL-END

            RL      C               ;
            RLA                     ;
            JR      NC,L131D        ; forward with no carry to HL-AGAIN

            ADD     HL,DE           ;

    ;; HL-END
    L131A:  JP      C,L0ED3         ; to REPORT-4

    ;; HL-AGAIN
    L131D:  DJNZ    L1311           ; loop back to HL-LOOP

            POP     BC              ;
            RET                     ; return.

    ; --------------------
    ; THE 'LET' SUBROUTINE
    ; --------------------
    ;
    ;

    ;; LET
    L1321:  LD      HL,($4012)      ; sv DEST-lo
            BIT     1,(IY+$2D)      ; sv FLAGX
            JR      Z,L136E         ; forward to L-EXISTS

            LD      BC,$0005        ;

    ;; L-EACH-CH
    L132D:  INC     BC              ;

    ; check

    ;; L-NO-SP
    L132E:  INC     HL              ;
            LD      A,(HL)          ;
            AND     A               ;
            JR      Z,L132E         ; back to L-NO-SP

            CALL    L14D2           ; routine ALPHANUM
            JR      C,L132D         ; back to L-EACH-CH

            CP      $0D             ; is it '$' ?
            JP      Z,L13C8         ; forward if so to L-NEW$

            RST     30H             ; BC-SPACES
            PUSH    DE              ;
            LD      HL,($4012)      ; sv DEST
            DEC     DE              ;
            LD      A,C             ;
            SUB     $06             ;
            LD      B,A             ;
            LD      A,$40           ;
            JR      Z,L1359         ; forward to L-SINGLE

    ;; L-CHAR
    L134B:  INC     HL              ;
            LD      A,(HL)          ;
            AND     A               ; is it a space ?
            JR      Z,L134B         ; back to L-CHAR

            INC     DE              ;
            LD      (DE),A          ;
            DJNZ    L134B           ; loop back to L-CHAR

            OR      $80             ;
            LD      (DE),A          ;
            LD      A,$80           ;

    ;; L-SINGLE
    L1359:  LD      HL,($4012)      ; sv DEST-lo
            XOR     (HL)            ;
            POP     HL              ;
            CALL    L13E7           ; routine L-FIRST

    ;; L-NUMERIC
    L1361:  PUSH    HL              ;

            RST     28H             ;; FP-CALC
            DEFB    $02             ;;delete
            DEFB    $34             ;;end-calc

            POP     HL              ;
            LD      BC,$0005        ;
            AND     A               ;
            SBC     HL,BC           ;
            JR      L13AE           ; forward to L-ENTER

    ; ---

    ;; L-EXISTS
    L136E:  BIT     6,(IY+$01)      ; sv FLAGS  - Numeric or string result?
            JR      Z,L137A         ; forward to L-DELETE$

            LD      DE,$0006        ;
            ADD     HL,DE           ;
            JR      L1361           ; back to L-NUMERIC

    ; ---

    ;; L-DELETE$
    L137A:  LD      HL,($4012)      ; sv DEST-lo
            LD      BC,($402E)      ; sv STRLEN_lo
            BIT     0,(IY+$2D)      ; sv FLAGX
            JR      NZ,L13B7        ; forward to L-ADD$

            LD      A,B             ;
            OR      C               ;
            RET     Z               ;

            PUSH    HL              ;

            RST     30H             ; BC-SPACES
            PUSH    DE              ;
            PUSH    BC              ;
            LD      D,H             ;
            LD      E,L             ;
            INC     HL              ;
            LD      (HL),$00        ;
            LDDR                    ; Copy Bytes
            PUSH    HL              ;
            CALL    L13F8           ; routine STK-FETCH
            POP     HL              ;
            EX      (SP),HL         ;
            AND     A               ;
            SBC     HL,BC           ;
            ADD     HL,BC           ;
            JR      NC,L13A3        ; forward to L-LENGTH

            LD      B,H             ;
            LD      C,L             ;

    ;; L-LENGTH
    L13A3:  EX      (SP),HL         ;
            EX      DE,HL           ;
            LD      A,B             ;
            OR      C               ;
            JR      Z,L13AB         ; forward if zero to L-IN-W/S

            LDIR                    ; Copy Bytes

    ;; L-IN-W/S
    L13AB:  POP     BC              ;
            POP     DE              ;
            POP     HL              ;

    ; ------------------------
    ; THE 'L-ENTER' SUBROUTINE
    ; ------------------------
    ;

    ;; L-ENTER
    L13AE:  EX      DE,HL           ;
            LD      A,B             ;
            OR      C               ;
            RET     Z               ;

            PUSH    DE              ;
            LDIR                    ; Copy Bytes
            POP     HL              ;
            RET                     ; return.

    ; ---

    ;; L-ADD$
    L13B7:  DEC     HL              ;
            DEC     HL              ;
            DEC     HL              ;
            LD      A,(HL)          ;
            PUSH    HL              ;
            PUSH    BC              ;

            CALL    L13CE           ; routine L-STRING

            POP     BC              ;
            POP     HL              ;
            INC     BC              ;
            INC     BC              ;
            INC     BC              ;
            JP      L0A60           ; jump back to exit via RECLAIM-2

    ; ---

    ;; L-NEW$
    L13C8:  LD      A,$60           ; prepare mask %01100000
            LD      HL,($4012)      ; sv DEST-lo
            XOR     (HL)            ;

    ; -------------------------
    ; THE 'L-STRING' SUBROUTINE
    ; -------------------------
    ;

    ;; L-STRING
    L13CE:  PUSH    AF              ;
            CALL    L13F8           ; routine STK-FETCH
            EX      DE,HL           ;
            ADD     HL,BC           ;
            PUSH    HL              ;
            INC     BC              ;
            INC     BC              ;
            INC     BC              ;

            RST     30H             ; BC-SPACES
            EX      DE,HL           ;
            POP     HL              ;
            DEC     BC              ;
            DEC     BC              ;
            PUSH    BC              ;
            LDDR                    ; Copy Bytes
            EX      DE,HL           ;
            POP     BC              ;
            DEC     BC              ;
            LD      (HL),B          ;
            DEC     HL              ;
            LD      (HL),C          ;
            POP     AF              ;

    ;; L-FIRST
    L13E7:  PUSH    AF              ;
            CALL    L14C7           ; routine REC-V80
            POP     AF              ;
            DEC     HL              ;
            LD      (HL),A          ;
            LD      HL,($401A)      ; sv STKBOT_lo
            LD      ($4014),HL      ; sv E_LINE_lo
            DEC     HL              ;
            LD      (HL),$80        ;
            RET                     ;

    ; --------------------------
    ; THE 'STK-FETCH' SUBROUTINE
    ; --------------------------
    ; This routine fetches a five-byte value from the calculator stack
    ; reducing the pointer to the end of the stack by five.
    ; For a floating-point number the exponent is in A and the mantissa
    ; is the thirty-two bits EDCB.
    ; For strings, the start of the string is in DE and the length in BC.
    ; A is unused.

    ;; STK-FETCH
    L13F8:  LD      HL,($401C)      ; load HL from system variable STKEND

            DEC     HL              ;
            LD      B,(HL)          ;
            DEC     HL              ;
            LD      C,(HL)          ;
            DEC     HL              ;
            LD      D,(HL)          ;
            DEC     HL              ;
            LD      E,(HL)          ;
            DEC     HL              ;
            LD      A,(HL)          ;

            LD      ($401C),HL      ; set system variable STKEND to lower value.
            RET                     ; return.

    ; -------------------------
    ; THE 'DIM' COMMAND ROUTINE
    ; -------------------------
    ; An array is created and initialized to zeros which is also the space
    ; character on the ZX81.

    ;; DIM
    L1409:  CALL    L111C           ; routine LOOK-VARS

    ;; D-RPORT-C
    L140C:  JP      NZ,L0D9A        ; to REPORT-C

            CALL    L0DA6           ; routine SYNTAX-Z
            JR      NZ,L141C        ; forward to D-RUN

            RES     6,C             ;
            CALL    L11A7           ; routine STK-VAR
            CALL    L0D1D           ; routine CHECK-END

    ;; D-RUN
    L141C:  JR      C,L1426         ; forward to D-LETTER

            PUSH    BC              ;
            CALL    L09F2           ; routine NEXT-ONE
            CALL    L0A60           ; routine RECLAIM-2
            POP     BC              ;

    ;; D-LETTER
    L1426:  SET     7,C             ;
            LD      B,$00           ;
            PUSH    BC              ;
            LD      HL,$0001        ;
            BIT     6,C             ;
            JR      NZ,L1434        ; forward to D-SIZE

            LD      L,$05           ;

    ;; D-SIZE
    L1434:  EX      DE,HL           ;

    ;; D-NO-LOOP
    L1435:  RST     20H             ; NEXT-CHAR
            LD      H,$40           ;
            CALL    L12DD           ; routine INT-EXP1
            JP      C,L1231         ; jump back to REPORT-3

            POP     HL              ;
            PUSH    BC              ;
            INC     H               ;
            PUSH    HL              ;
            LD      H,B             ;
            LD      L,C             ;
            CALL    L1305           ; routine GET-HL*DE
            EX      DE,HL           ;

            RST     18H             ; GET-CHAR
            CP      $1A             ;
            JR      Z,L1435         ; back to D-NO-LOOP

            CP      $11             ; is it ')' ?
            JR      NZ,L140C        ; back if not to D-RPORT-C

            RST     20H             ; NEXT-CHAR
            POP     BC              ;
            LD      A,C             ;
            LD      L,B             ;
            LD      H,$00           ;
            INC     HL              ;
            INC     HL              ;
            ADD     HL,HL           ;
            ADD     HL,DE           ;
            JP      C,L0ED3         ; jump to REPORT-4

            PUSH    DE              ;
            PUSH    BC              ;
            PUSH    HL              ;
            LD      B,H             ;
            LD      C,L             ;
            LD      HL,($4014)      ; sv E_LINE_lo
            DEC     HL              ;
            CALL    L099E           ; routine MAKE-ROOM
            INC     HL              ;
            LD       (HL),A         ;
            POP     BC              ;
            DEC     BC              ;
            DEC     BC              ;
            DEC     BC              ;
            INC     HL              ;
            LD      (HL),C          ;
            INC     HL              ;
            LD      (HL),B          ;
            POP     AF              ;
            INC     HL              ;
            LD      (HL),A          ;
            LD      H,D             ;
            LD      L,E             ;
            DEC     DE              ;
            LD      (HL),$00        ;
            POP     BC              ;
            LDDR                    ; Copy Bytes

    ;; DIM-SIZES
    L147F:  POP     BC              ;
            LD      (HL),B          ;
            DEC     HL              ;
            LD      (HL),C          ;
            DEC     HL              ;
            DEC     A               ;
            JR      NZ,L147F        ; back to DIM-SIZES

            RET                     ; return.

    ; ---------------------
    ; THE 'RESERVE' ROUTINE
    ; ---------------------
    ;
    ;

    ;; RESERVE
    L1488:  LD      HL,($401A)      ; address STKBOT
            DEC     HL              ; now last byte of workspace
            CALL    L099E           ; routine MAKE-ROOM
            INC     HL              ;
            INC     HL              ;
            POP     BC              ;
            LD      ($4014),BC      ; sv E_LINE_lo
            POP     BC              ;
            EX      DE,HL           ;
            INC     HL              ;
            RET                     ;

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

    ;; CLEAR
    L149A:  LD      HL,($4010)      ; sv VARS_lo
            LD      (HL),$80        ;
            INC     HL              ;
            LD      ($4014),HL      ; sv E_LINE_lo

    ; -----------------------
    ; THE 'X-TEMP' SUBROUTINE
    ; -----------------------
    ;
    ;

    ;; X-TEMP
    L14A3:  LD      HL,($4014)      ; sv E_LINE_lo

    ; ----------------------
    ; THE 'SET-STK' ROUTINES
    ; ----------------------
    ;
    ;

    ;; SET-STK-B
    L14A6:  LD      ($401A),HL      ; sv STKBOT

    ;

    ;; SET-STK-E
    L14A9:  LD      ($401C),HL      ; sv STKEND
            RET                     ;

    ; -----------------------
    ; THE 'CURSOR-IN' ROUTINE
    ; -----------------------
    ; This routine is called to set the edit line to the minimum cursor/newline
    ; and to set STKEND, the start of free space, at the next position.

    ;; CURSOR-IN
    L14AD:  LD      HL,($4014)      ; fetch start of edit line from E_LINE
            LD      (HL),$7F        ; insert cursor character

            INC     HL              ; point to next location.
            LD      (HL),$76        ; insert NEWLINE character
            INC     HL              ; point to next free location.

            LD      (IY+$22),$02    ; set lower screen display file size DF_SZ

            JR      L14A6           ; exit via SET-STK-B above

    ; ------------------------
    ; THE 'SET-MIN' SUBROUTINE
    ; ------------------------
    ;
    ;

    ;; SET-MIN
    L14BC:  LD      HL,$405D        ; normal location of calculator's memory area
            LD      ($401F),HL      ; update system variable MEM
            LD      HL,($401A)      ; fetch STKBOT
            JR      L14A9           ; back to SET-STK-E

    ; ------------------------------------
    ; THE 'RECLAIM THE END-MARKER' ROUTINE
    ; ------------------------------------

    ;; REC-V80
    L14C7:  LD      DE,($4014)      ; sv E_LINE_lo
            JP      L0A5D           ; to RECLAIM-1

    ; ----------------------
    ; THE 'ALPHA' SUBROUTINE
    ; ----------------------

    ;; ALPHA
    L14CE:  CP      $26             ;
            JR      L14D4           ; skip forward to ALPHA-2

    ; -------------------------
    ; THE 'ALPHANUM' SUBROUTINE
    ; -------------------------

    ;; ALPHANUM
    L14D2:  CP      $1C             ;

    ;; ALPHA-2
    L14D4:  CCF                     ; Complement Carry Flag
            RET     NC              ;

            CP      $40             ;
            RET                     ;

    ; ------------------------------------------
    ; THE 'DECIMAL TO FLOATING POINT' SUBROUTINE
    ; ------------------------------------------
    ;

    ;; DEC-TO-FP
    L14D9:  CALL    L1548           ; routine INT-TO-FP gets first part
            CP      $1B             ; is character a '.' ?
            JR      NZ,L14F5        ; forward if not to E-FORMAT

            RST     28H             ;; FP-CALC
            DEFB    $A1             ;;stk-one
            DEFB    $C0             ;;st-mem-0
            DEFB    $02             ;;delete
            DEFB    $34             ;;end-calc

    ;; NXT-DGT-1
    L14E5:  RST     20H             ; NEXT-CHAR
            CALL    L1514           ; routine STK-DIGIT
            JR      C,L14F5         ; forward to E-FORMAT

            RST     28H             ;; FP-CALC
            DEFB    $E0             ;;get-mem-0
            DEFB    $A4             ;;stk-ten
            DEFB    $05             ;;division
            DEFB    $C0             ;;st-mem-0
            DEFB    $04             ;;multiply
            DEFB    $0F             ;;addition
            DEFB    $34             ;;end-calc

            JR      L14E5           ; loop back till exhausted to NXT-DGT-1

    ; ---

    ;; E-FORMAT
    L14F5:  CP      $2A             ; is character 'E' ?
            RET     NZ              ; return if not

            LD      (IY+$5D),$FF    ; initialize sv MEM-0-1st to $FF TRUE

            RST     20H             ; NEXT-CHAR
            CP      $15             ; is character a '+' ?
            JR      Z,L1508         ; forward if so to SIGN-DONE

            CP      $16             ; is it a '-' ?
            JR      NZ,L1509        ; forward if not to ST-E-PART

            INC     (IY+$5D)        ; sv MEM-0-1st change to FALSE

    ;; SIGN-DONE
    L1508:  RST     20H             ; NEXT-CHAR

    ;; ST-E-PART
    L1509:  CALL    L1548           ; routine INT-TO-FP

            RST     28H             ;; FP-CALC              m, e.
            DEFB    $E0             ;;get-mem-0             m, e, (1/0) TRUE/FALSE
            DEFB    $00             ;;jump-true
            DEFB    $02             ;;to L1511, E-POSTVE
            DEFB    $18             ;;neg                   m, -e

    ;; E-POSTVE
    L1511:  DEFB    $38             ;;e-to-fp               x.
            DEFB    $34             ;;end-calc              x.

            RET                     ; return.

    ; --------------------------
    ; THE 'STK-DIGIT' SUBROUTINE
    ; --------------------------
    ;

    ;; STK-DIGIT
    L1514:  CP      $1C             ;
            RET     C               ;

            CP      $26             ;
            CCF                     ; Complement Carry Flag
            RET     C               ;

            SUB     $1C             ;

    ; ------------------------
    ; THE 'STACK-A' SUBROUTINE
    ; ------------------------
    ;

    ;; STACK-A
    L151D:  LD      C,A             ;
            LD      B,$00           ;

    ; -------------------------
    ; THE 'STACK-BC' SUBROUTINE
    ; -------------------------
    ; The ZX81 does not have an integer number format so the BC register contents
    ; must be converted to their full floating-point form.

    ;; STACK-BC
    L1520:  LD      IY,$4000        ; re-initialize the system variables pointer.
            PUSH    BC              ; save the integer value.

    ; now stack zero, five zero bytes as a starting point.

            RST     28H             ;; FP-CALC
            DEFB    $A0             ;;stk-zero                      0.
            DEFB    $34             ;;end-calc

            POP     BC              ; restore integer value.

            LD      (HL),$91        ; place $91 in exponent         65536.
                                    ; this is the maximum possible value

            LD      A,B             ; fetch hi-byte.
            AND     A               ; test for zero.
            JR      NZ,L1536        ; forward if not zero to STK-BC-2

            LD      (HL),A          ; else make exponent zero again
            OR      C               ; test lo-byte
            RET     Z               ; return if BC was zero - done.

    ; else  there has to be a set bit if only the value one.

            LD      B,C             ; save C in B.
            LD      C,(HL)          ; fetch zero to C
            LD      (HL),$89        ; make exponent $89             256.

    ;; STK-BC-2
    L1536:  DEC     (HL)            ; decrement exponent - halving number
            SLA     C               ;  C<-76543210<-0
            RL      B               ;  C<-76543210<-C
            JR      NC,L1536        ; loop back if no carry to STK-BC-2

            SRL     B               ;  0->76543210->C
            RR      C               ;  C->76543210->C

            INC     HL              ; address first byte of mantissa
            LD      (HL),B          ; insert B
            INC     HL              ; address second byte of mantissa
            LD      (HL),C          ; insert C

            DEC     HL              ; point to the
            DEC     HL              ; exponent again
            RET                     ; return.

    ; ------------------------------------------
    ; THE 'INTEGER TO FLOATING POINT' SUBROUTINE
    ; ------------------------------------------
    ;
    ;

    ;; INT-TO-FP
    L1548:  PUSH    AF              ;

            RST     28H             ;; FP-CALC
            DEFB    $A0             ;;stk-zero
            DEFB    $34             ;;end-calc

            POP     AF              ;

    ;; NXT-DGT-2
    L154D:  CALL    L1514           ; routine STK-DIGIT
            RET     C               ;

            RST     28H             ;; FP-CALC
            DEFB    $01             ;;exchange
            DEFB    $A4             ;;stk-ten
            DEFB    $04             ;;multiply
            DEFB    $0F             ;;addition
            DEFB    $34             ;;end-calc

            RST     20H             ; NEXT-CHAR
            JR      L154D           ; to NXT-DGT-2

    ; -------------------------------------------
    ; THE 'E-FORMAT TO FLOATING POINT' SUBROUTINE
    ; -------------------------------------------
    ; (Offset $38: 'e-to-fp')
    ; invoked from DEC-TO-FP and PRINT-FP.
    ; e.g. 2.3E4 is 23000.
    ; This subroutine evaluates xEm where m is a positive or negative integer.
    ; At a simple level x is multiplied by ten for every unit of m.
    ; If the decimal exponent m is negative then x is divided by ten for each unit.
    ; A short-cut is taken if the exponent is greater than seven and in this
    ; case the exponent is reduced by seven and the value is multiplied or divided
    ; by ten million.
    ; Note. for the ZX Spectrum an even cleverer method was adopted which involved
    ; shifting the bits out of the exponent so the result was achieved with six
    ; shifts at most. The routine below had to be completely re-written mostly
    ; in Z80 machine code.
    ; Although no longer operable, the calculator literal was retained for old
    ; times sake, the routine being invoked directly from a machine code CALL.
    ;
    ; On entry in the ZX81, m, the exponent, is the 'last value', and the
    ; floating-point decimal mantissa is beneath it.

    ;; e-to-fp
    L155A:  RST     28H             ;; FP-CALC              x, m.
            DEFB    $2D             ;;duplicate             x, m, m.
            DEFB    $32             ;;less-0                x, m, (1/0).
            DEFB    $C0             ;;st-mem-0              x, m, (1/0).
            DEFB    $02             ;;delete                x, m.
            DEFB    $27             ;;abs                   x, +m.

    ;; E-LOOP
    L1560:  DEFB    $A1             ;;stk-one               x, m,1.
            DEFB    $03             ;;subtract              x, m-1.
            DEFB    $2D             ;;duplicate             x, m-1,m-1.
            DEFB    $32             ;;less-0                x, m-1, (1/0).
            DEFB    $00             ;;jump-true             x, m-1.
            DEFB    $22             ;;to L1587, E-END       x, m-1.

            DEFB    $2D             ;;duplicate             x, m-1, m-1.
            DEFB    $30             ;;stk-data
            DEFB    $33             ;;Exponent: $83, Bytes: 1

            DEFB    $40             ;;(+00,+00,+00)         x, m-1, m-1, 6.
            DEFB    $03             ;;subtract              x, m-1, m-7.
            DEFB    $2D             ;;duplicate             x, m-1, m-7, m-7.
            DEFB    $32             ;;less-0                x, m-1, m-7, (1/0).
            DEFB    $00             ;;jump-true             x, m-1, m-7.
            DEFB    $0C             ;;to L157A, E-LOW

    ; but if exponent m is higher than 7 do a bigger chunk.
    ; multiplying (or dividing if negative) by 10 million - 1e7.

            DEFB    $01             ;;exchange              x, m-7, m-1.
            DEFB    $02             ;;delete                x, m-7.
            DEFB    $01             ;;exchange              m-7, x.
            DEFB    $30             ;;stk-data
            DEFB    $80             ;;Bytes: 3
            DEFB    $48             ;;Exponent $98
            DEFB    $18,$96,$80     ;;(+00)                 m-7, x, 10,000,000 (=f)
            DEFB    $2F             ;;jump
            DEFB    $04             ;;to L157D, E-CHUNK

    ; ---

    ;; E-LOW
    L157A:  DEFB    $02             ;;delete                x, m-1.
            DEFB    $01             ;;exchange              m-1, x.
            DEFB    $A4             ;;stk-ten               m-1, x, 10 (=f).

    ;; E-CHUNK
    L157D:  DEFB    $E0             ;;get-mem-0             m-1, x, f, (1/0)
            DEFB    $00             ;;jump-true             m-1, x, f
            DEFB    $04             ;;to L1583, E-DIVSN

            DEFB    $04             ;;multiply              m-1, x*f.
            DEFB    $2F             ;;jump
            DEFB    $02             ;;to L1584, E-SWAP

    ; ---

    ;; E-DIVSN
    L1583:  DEFB    $05             ;;division              m-1, x/f (= new x).

    ;; E-SWAP
    L1584:  DEFB    $01             ;;exchange              x, m-1 (= new m).
            DEFB    $2F             ;;jump                  x, m.
            DEFB    $DA             ;;to L1560, E-LOOP

    ; ---

    ;; E-END
    L1587:  DEFB    $02             ;;delete                x. (-1)
            DEFB    $34             ;;end-calc              x.

            RET                     ; return.

    ; -------------------------------------
    ; THE 'FLOATING-POINT TO BC' SUBROUTINE
    ; -------------------------------------
    ; The floating-point form on the calculator stack is compressed directly into
    ; the BC register rounding up if necessary.
    ; Valid range is 0 to 65535.4999

    ;; FP-TO-BC
    L158A:  CALL    L13F8           ; routine STK-FETCH - exponent to A
                                    ; mantissa to EDCB.
            AND     A               ; test for value zero.
            JR      NZ,L1595        ; forward if not to FPBC-NZRO

    ; else value is zero

            LD      B,A             ; zero to B
            LD      C,A             ; also to C
            PUSH    AF              ; save the flags on machine stack
            JR      L15C6           ; forward to FPBC-END

    ; ---

    ; EDCB  =>  BCE

    ;; FPBC-NZRO
    L1595:  LD      B,E             ; transfer the mantissa from EDCB
            LD      E,C             ; to BCE. Bit 7 of E is the 17th bit which
            LD      C,D             ; will be significant for rounding if the
                                    ; number is already normalized.

            SUB     $91             ; subtract 65536
            CCF                     ; complement carry flag
            BIT     7,B             ; test sign bit
            PUSH    AF              ; push the result

            SET     7,B             ; set the implied bit
            JR      C,L15C6         ; forward with carry from SUB/CCF to FPBC-END
                                    ; number is too big.

            INC     A               ; increment the exponent and
            NEG                     ; negate to make range $00 - $0F

            CP      $08             ; test if one or two bytes
            JR      C,L15AF         ; forward with two to BIG-INT

            LD      E,C             ; shift mantissa
            LD      C,B             ; 8 places right
            LD      B,$00           ; insert a zero in B
            SUB     $08             ; reduce exponent by eight

    ;; BIG-INT
    L15AF:  AND     A               ; test the exponent
            LD      D,A             ; save exponent in D.

            LD      A,E             ; fractional bits to A
            RLCA                    ; rotate most significant bit to carry for
                                    ; rounding of an already normal number.

            JR      Z,L15BC         ; forward if exponent zero to EXP-ZERO
                                    ; the number is normalized

    ;; FPBC-NORM
    L15B5:  SRL     B               ;   0->76543210->C
            RR      C               ;   C->76543210->C

            DEC     D               ; decrement exponent

            JR      NZ,L15B5        ; loop back till zero to FPBC-NORM

    ;; EXP-ZERO
    L15BC:  JR      NC,L15C6        ; forward without carry to NO-ROUND

            INC     BC              ; round up.
            LD      A,B             ; test result
            OR      C               ; for zero
            JR      NZ,L15C6        ; forward if not to GRE-ZERO

            POP     AF              ; restore sign flag
            SCF                     ; set carry flag to indicate overflow
            PUSH    AF              ; save combined flags again

    ;; FPBC-END
    L15C6:  PUSH    BC              ; save BC value

    ; set HL and DE to calculator stack pointers.

            RST     28H             ;; FP-CALC
            DEFB    $34             ;;end-calc

            POP     BC              ; restore BC value
            POP     AF              ; restore flags
            LD      A,C             ; copy low byte to A also.
            RET                     ; return

    ; ------------------------------------
    ; THE 'FLOATING-POINT TO A' SUBROUTINE
    ; ------------------------------------
    ;
    ;

    ;; FP-TO-A
    L15CD:  CALL    L158A           ; routine FP-TO-BC
            RET     C               ;

            PUSH    AF              ;
            DEC     B               ;
            INC     B               ;
            JR      Z,L15D9         ; forward if in range to FP-A-END

            POP     AF              ; fetch result
            SCF                     ; set carry flag signaling overflow
            RET                     ; return

    ;; FP-A-END
    L15D9:  POP     AF              ;
            RET                     ;

    ; ----------------------------------------------
    ; THE 'PRINT A FLOATING-POINT NUMBER' SUBROUTINE
    ; ----------------------------------------------
    ; prints 'last value' x on calculator stack.
    ; There are a wide variety of formats see Chapter 4.
    ; e.g.
    ; PI            prints as       3.1415927
    ; .123          prints as       0.123
    ; .0123         prints as       .0123
    ; 999999999999  prints as       1000000000000
    ; 9876543210123 prints as       9876543200000

    ; Begin by isolating zero and just printing the '0' character
    ; for that case. For negative numbers print a leading '-' and
    ; then form the absolute value of x.

    ;; PRINT-FP
    L15DB:  RST     28H             ;; FP-CALC              x.
            DEFB    $2D             ;;duplicate             x, x.
            DEFB    $32             ;;less-0                x, (1/0).
            DEFB    $00             ;;jump-true
            DEFB    $0B             ;;to L15EA, PF-NGTVE    x.

            DEFB    $2D             ;;duplicate             x, x
            DEFB    $33             ;;greater-0             x, (1/0).
            DEFB    $00             ;;jump-true
            DEFB    $0D             ;;to L15F0, PF-POSTVE   x.

            DEFB    $02             ;;delete                .
            DEFB    $34             ;;end-calc              .

            LD      A,$1C           ; load accumulator with character '0'

            RST     10H             ; PRINT-A
            RET                     ; return.                               >>

    ; ---

    ;; PF-NEGTVE
    L15EA:  DEFB    $27             ; abs                   +x.
            DEFB    $34             ;;end-calc              x.

            LD      A,$16           ; load accumulator with '-'

            RST     10H             ; PRINT-A

            RST     28H             ;; FP-CALC              x.

    ;; PF-POSTVE
    L15F0:  DEFB    $34             ;;end-calc              x.

    ; register HL addresses the exponent of the floating-point value.
    ; if positive, and point floats to left, then bit 7 is set.

            LD      A,(HL)          ; pick up the exponent byte
            CALL    L151D           ; routine STACK-A places on calculator stack.

    ; now calculate roughly the number of digits, n, before the decimal point by
    ; subtracting a half from true exponent and multiplying by log to
    ; the base 10 of 2.
    ; The true number could be one higher than n, the integer result.

            RST     28H             ;; FP-CALC              x, e.
            DEFB    $30             ;;stk-data
            DEFB    $78             ;;Exponent: $88, Bytes: 2
            DEFB    $00,$80         ;;(+00,+00)             x, e, 128.5.
            DEFB    $03             ;;subtract              x, e -.5.
            DEFB    $30             ;;stk-data
            DEFB    $EF             ;;Exponent: $7F, Bytes: 4
            DEFB    $1A,$20,$9A,$85 ;;                      .30103 (log10 2)
            DEFB    $04             ;;multiply              x,
            DEFB    $24             ;;int
            DEFB    $C1             ;;st-mem-1              x, n.

            DEFB    $30             ;;stk-data
            DEFB    $34             ;;Exponent: $84, Bytes: 1
            DEFB    $00             ;;(+00,+00,+00)         x, n, 8.

            DEFB    $03             ;;subtract              x, n-8.
            DEFB    $18             ;;neg                   x, 8-n.
            DEFB    $38             ;;e-to-fp               x * (10^n)

    ; finally the 8 or 9 digit decimal is rounded.
    ; a ten-digit integer can arise in the case of, say, 999999999.5
    ; which gives 1000000000.

            DEFB    $A2             ;;stk-half
            DEFB    $0F             ;;addition
            DEFB    $24             ;;int                   i.
            DEFB    $34             ;;end-calc

    ; If there were 8 digits then final rounding will take place on the calculator
    ; stack above and the next two instructions insert a masked zero so that
    ; no further rounding occurs. If the result is a 9 digit integer then
    ; rounding takes place within the buffer.

            LD      HL,$406B        ; address system variable MEM-2-5th
                                    ; which could be the 'ninth' digit.
            LD      (HL),$90        ; insert the value $90  10010000

    ; now starting from lowest digit lay down the 8, 9 or 10 digit integer
    ; which represents the significant portion of the number
    ; e.g. PI will be the nine-digit integer 314159265

            LD      B,$0A           ; count is ten digits.

    ;; PF-LOOP
    L1615:  INC     HL              ; increase pointer

            PUSH    HL              ; preserve buffer address.
            PUSH    BC              ; preserve counter.

            RST     28H             ;; FP-CALC              i.
            DEFB    $A4             ;;stk-ten               i, 10.
            DEFB    $2E             ;;n-mod-m               i mod 10, i/10
            DEFB    $01             ;;exchange              i/10, remainder.
            DEFB    $34             ;;end-calc

            CALL    L15CD           ; routine FP-TO-A  $00-$09

            OR      $90             ; make left hand nibble 9

            POP     BC              ; restore counter
            POP     HL              ; restore buffer address.

            LD      (HL),A          ; insert masked digit in buffer.
            DJNZ    L1615           ; loop back for all ten to PF-LOOP

    ; the most significant digit will be last but if the number is exhausted then
    ; the last one or two positions will contain zero ($90).

    ; e.g. for 'one' we have zero as estimate of leading digits.
    ; 1*10^8 100000000 as integer value
    ; 90 90 90 90 90   90 90 90 91 90 as buffer mem3/mem4 contents.

            INC     HL              ; advance pointer to one past buffer
            LD      BC,$0008        ; set C to 8 ( B is already zero )
            PUSH    HL              ; save pointer.

    ;; PF-NULL
    L162C:  DEC     HL              ; decrease pointer
            LD      A,(HL)          ; fetch masked digit
            CP      $90             ; is it a leading zero ?
            JR      Z,L162C         ; loop back if so to PF-NULL

    ; at this point a significant digit has been found. carry is reset.

            SBC     HL,BC           ; subtract eight from the address.
            PUSH    HL              ; ** save this pointer too
            LD      A,(HL)          ; fetch addressed byte
            ADD     A,$6B           ; add $6B - forcing a round up ripple
                                    ; if  $95 or over.
            PUSH    AF              ; save the carry result.

    ; now enter a loop to round the number. After rounding has been considered
    ; a zero that has arisen from rounding or that was present at that position
    ; originally is changed from $90 to $80.

    ;; PF-RND-LP
    L1639:  POP     AF              ; retrieve carry from machine stack.
            INC     HL              ; increment address
            LD      A,(HL)          ; fetch new byte
            ADC     A,$00           ; add in any carry

            DAA                     ; decimal adjust accumulator
                                    ; carry will ripple through the '9'

            PUSH    AF              ; save carry on machine stack.
            AND     $0F             ; isolate character 0 - 9 AND set zero flag
                                    ; if zero.
            LD      (HL),A          ; place back in location.
            SET     7,(HL)          ; set bit 7 to show printable.
                                    ; but not if trailing zero after decimal point.
            JR      Z,L1639         ; back if a zero to PF-RND-LP
                                    ; to consider further rounding and/or trailing
                                    ; zero identification.

            POP     AF              ; balance stack
            POP     HL              ; ** retrieve lower pointer

    ; now insert 6 trailing zeros which are printed if before the decimal point
    ; but mark the end of printing if after decimal point.
    ; e.g. 9876543210123 is printed as 9876543200000
    ; 123.456001 is printed as 123.456

            LD      B,$06           ; the count is six.

    ;; PF-ZERO-6
    L164B:  LD      (HL),$80        ; insert a masked zero
            DEC     HL              ; decrease pointer.
            DJNZ    L164B           ; loop back for all six to PF-ZERO-6

    ; n-mod-m reduced the number to zero and this is now deleted from the calculator
    ; stack before fetching the original estimate of leading digits.

            RST     28H             ;; FP-CALC              0.
            DEFB    $02             ;;delete                .
            DEFB    $E1             ;;get-mem-1             n.
            DEFB    $34             ;;end-calc              n.

            CALL    L15CD           ; routine FP-TO-A
            JR      Z,L165B         ; skip forward if positive to PF-POS

            NEG                     ; negate makes positive

    ;; PF-POS
    L165B:  LD      E,A             ; transfer count of digits to E
            INC     E               ; increment twice
            INC     E               ;
            POP     HL              ; * retrieve pointer to one past buffer.

    ;; GET-FIRST
    L165F:  DEC     HL              ; decrement address.
            DEC     E               ; decrement digit counter.
            LD      A,(HL)          ; fetch masked byte.
            AND     $0F             ; isolate right-hand nibble.
            JR      Z,L165F         ; back with leading zero to GET-FIRST

    ; now determine if E-format printing is needed

            LD      A,E             ; transfer now accurate number count to A.
            SUB     $05             ; subtract five
            CP      $08             ; compare with 8 as maximum digits is 13.
            JP      P,L1682         ; forward if positive to PF-E-FMT

            CP      $F6             ; test for more than four zeros after point.
            JP      M,L1682         ; forward if so to PF-E-FMT

            ADD     A,$06           ; test for zero leading digits, e.g. 0.5
            JR      Z,L16BF         ; forward if so to PF-ZERO-1

            JP      M,L16B2         ; forward if more than one zero to PF-ZEROS

    ; else digits before the decimal point are to be printed

            LD      B,A             ; count of leading characters to B.

    ;; PF-NIB-LP
    L167B:  CALL    L16D0           ; routine PF-NIBBLE
            DJNZ    L167B           ; loop back for counted numbers to PF-NIB-LP

            JR      L16C2           ; forward to consider decimal part to PF-DC-OUT

    ; ---

    ;; PF-E-FMT
    L1682:  LD      B,E             ; count to B
            CALL    L16D0           ; routine PF-NIBBLE prints one digit.
            CALL    L16C2           ; routine PF-DC-OUT considers fractional part.

            LD      A,$2A           ; prepare character 'E'
            RST     10H             ; PRINT-A

            LD      A,B             ; transfer exponent to A
            AND     A               ; test the sign.
            JP      P,L1698         ; forward if positive to PF-E-POS

            NEG                     ; negate the negative exponent.
            LD      B,A             ; save positive exponent in B.

            LD      A,$16           ; prepare character '-'
            JR      L169A           ; skip forward to PF-E-SIGN

    ; ---

    ;; PF-E-POS
    L1698:  LD      A,$15           ; prepare character '+'

    ;; PF-E-SIGN
    L169A:  RST     10H             ; PRINT-A

    ; now convert the integer exponent in B to two characters.
    ; it will be less than 99.

            LD      A,B             ; fetch positive exponent.
            LD      B,$FF           ; initialize left hand digit to minus one.

    ;; PF-E-TENS
    L169E:  INC     B               ; increment ten count
            SUB     $0A             ; subtract ten from exponent
            JR      NC,L169E        ; loop back if greater than ten to PF-E-TENS

            ADD     A,$0A           ; reverse last subtraction
            LD      C,A             ; transfer remainder to C

            LD      A,B             ; transfer ten value to A.
            AND     A               ; test for zero.
            JR      Z,L16AD         ; skip forward if so to PF-E-LOW

            CALL    L07EB           ; routine OUT-CODE prints as digit '1' - '9'

    ;; PF-E-LOW
    L16AD:  LD      A,C             ; low byte to A
            CALL    L07EB           ; routine OUT-CODE prints final digit of the
                                    ; exponent.
            RET                     ; return.                               >>

    ; ---

    ; this branch deals with zeros after decimal point.
    ; e.g.      .01 or .0000999

    ;; PF-ZEROS
    L16B2:  NEG                     ; negate makes number positive 1 to 4.
            LD      B,A             ; zero count to B.

            LD      A,$1B           ; prepare character '.'
            RST     10H             ; PRINT-A

            LD      A,$1C           ; prepare a '0'

    ;; PF-ZRO-LP
    L16BA:  RST     10H             ; PRINT-A
            DJNZ    L16BA           ; loop back to PF-ZRO-LP

            JR      L16C8           ; forward to PF-FRAC-LP

    ; ---

    ; there is  a need to print a leading zero e.g. 0.1 but not with .01

    ;; PF-ZERO-1
    L16BF:  LD      A,$1C           ; prepare character '0'.
            RST     10H             ; PRINT-A

    ; this subroutine considers the decimal point and any trailing digits.
    ; if the next character is a marked zero, $80, then nothing more to print.

    ;; PF-DC-OUT
    L16C2:  DEC     (HL)            ; decrement addressed character
            INC     (HL)            ; increment it again
            RET     PE              ; return with overflow  (was 128) >>
                                    ; as no fractional part

    ; else there is a fractional part so print the decimal point.

            LD      A,$1B           ; prepare character '.'
            RST     10H             ; PRINT-A

    ; now enter a loop to print trailing digits

    ;; PF-FRAC-LP
    L16C8:  DEC     (HL)            ; test for a marked zero.
            INC     (HL)            ;
            RET     PE              ; return when digits exhausted          >>

            CALL    L16D0           ; routine PF-NIBBLE
            JR      L16C8           ; back for all fractional digits to PF-FRAC-LP.

    ; ---

    ; subroutine to print right-hand nibble

    ;; PF-NIBBLE
    L16D0:  LD      A,(HL)          ; fetch addressed byte
            AND     $0F             ; mask off lower 4 bits
            CALL    L07EB           ; routine OUT-CODE
            DEC     HL              ; decrement pointer.
            RET                     ; return.

    ; -------------------------------
    ; THE 'PREPARE TO ADD' SUBROUTINE
    ; -------------------------------
    ; This routine is called twice to prepare each floating point number for
    ; addition, in situ, on the calculator stack.
    ; The exponent is picked up from the first byte which is then cleared to act
    ; as a sign byte and accept any overflow.
    ; If the exponent is zero then the number is zero and an early return is made.
    ; The now redundant sign bit of the mantissa is set and if the number is
    ; negative then all five bytes of the number are twos-complemented to prepare
    ; the number for addition.
    ; On the second invocation the exponent of the first number is in B.

    ;; PREP-ADD
    L16D8:  LD      A,(HL)          ; fetch exponent.
            LD      (HL),$00        ; make this byte zero to take any overflow and
                                    ; default to positive.
            AND     A               ; test stored exponent for zero.
            RET     Z               ; return with zero flag set if number is zero.

            INC     HL              ; point to first byte of mantissa.
            BIT     7,(HL)          ; test the sign bit.
            SET     7,(HL)          ; set it to its implied state.
            DEC     HL              ; set pointer to first byte again.
            RET     Z               ; return if bit indicated number is positive.>>

    ; if negative then all five bytes are twos complemented starting at LSB.

            PUSH    BC              ; save B register contents.
            LD      BC,$0005        ; set BC to five.
            ADD     HL,BC           ; point to location after 5th byte.
            LD      B,C             ; set the B counter to five.
            LD      C,A             ; store original exponent in C.
            SCF                     ; set carry flag so that one is added.

    ; now enter a loop to twos-complement the number.
    ; The first of the five bytes becomes $FF to denote a negative number.

    ;; NEG-BYTE
    L16EC:  DEC     HL              ; point to first or more significant byte.
            LD      A,(HL)          ; fetch to accumulator.
            CPL                     ; complement.
            ADC     A,$00           ; add in initial carry or any subsequent carry.
            LD      (HL),A          ; place number back.
            DJNZ    L16EC           ; loop back five times to NEG-BYTE

            LD      A,C             ; restore the exponent to accumulator.
            POP     BC              ; restore B register contents.

            RET                     ; return.

    ; ----------------------------------
    ; THE 'FETCH TWO NUMBERS' SUBROUTINE
    ; ----------------------------------
    ; This routine is used by addition, multiplication and division to fetch
    ; the two five-byte numbers addressed by HL and DE from the calculator stack
    ; into the Z80 registers.
    ; The HL register may no longer point to the first of the two numbers.
    ; Since the 32-bit addition operation is accomplished using two Z80 16-bit
    ; instructions, it is important that the lower two bytes of each mantissa are
    ; in one set of registers and the other bytes all in the alternate set.
    ;
    ; In: HL = highest number, DE= lowest number
    ;
    ;         : alt':   :
    ; Out:    :H,B-C:C,B: num1
    ;         :L,D-E:D-E: num2

    ;; FETCH-TWO
    L16F7:  PUSH    HL              ; save HL
            PUSH    AF              ; save A - result sign when used from division.

            LD      C,(HL)          ;
            INC     HL              ;
            LD      B,(HL)          ;
            LD      (HL),A          ; insert sign when used from multiplication.
            INC     HL              ;
            LD      A,C             ; m1
            LD      C,(HL)          ;
            PUSH    BC              ; PUSH m2 m3

            INC     HL              ;
            LD      C,(HL)          ; m4
            INC     HL              ;
            LD      B,(HL)          ; m5  BC holds m5 m4

            EX      DE,HL           ; make HL point to start of second number.

            LD      D,A             ; m1
            LD      E,(HL)          ;
            PUSH    DE              ; PUSH m1 n1

            INC     HL              ;
            LD      D,(HL)          ;
            INC     HL              ;
            LD      E,(HL)          ;
            PUSH    DE              ; PUSH n2 n3

            EXX                     ; - - - - - - -

            POP     DE              ; POP n2 n3
            POP     HL              ; POP m1 n1
            POP     BC              ; POP m2 m3

            EXX                     ; - - - - - - -

            INC     HL              ;
            LD      D,(HL)          ;
            INC     HL              ;
            LD      E,(HL)          ; DE holds n4 n5

            POP     AF              ; restore saved
            POP     HL              ; registers.
            RET                     ; return.

    ; -----------------------------
    ; THE 'SHIFT ADDEND' SUBROUTINE
    ; -----------------------------
    ; The accumulator A contains the difference between the two exponents.
    ; This is the lowest of the two numbers to be added

    ;; SHIFT-FP
    L171A:  AND     A               ; test difference between exponents.
            RET     Z               ; return if zero. both normal.

            CP      $21             ; compare with 33 bits.
            JR      NC,L1736        ; forward if greater than 32 to ADDEND-0

            PUSH    BC              ; preserve BC - part
            LD      B,A             ; shift counter to B.

    ; Now perform B right shifts on the addend  L'D'E'D E
    ; to bring it into line with the augend     H'B'C'C B

    ;; ONE-SHIFT
    L1722:  EXX                     ; - - -
            SRA     L               ;    76543210->C    bit 7 unchanged.
            RR      D               ; C->76543210->C
            RR      E               ; C->76543210->C
            EXX                     ; - - -
            RR      D               ; C->76543210->C
            RR      E               ; C->76543210->C
            DJNZ    L1722           ; loop back B times to ONE-SHIFT

            POP     BC              ; restore BC
            RET     NC              ; return if last shift produced no carry.   >>

    ; if carry flag was set then accuracy is being lost so round up the addend.

            CALL    L1741           ; routine ADD-BACK
            RET     NZ              ; return if not FF 00 00 00 00

    ; this branch makes all five bytes of the addend zero and is made during
    ; addition when the exponents are too far apart for the addend bits to
    ; affect the result.

    ;; ADDEND-0
    L1736:  EXX                     ; select alternate set for more significant
                                    ; bytes.
            XOR     A               ; clear accumulator.

    ; this entry point (from multiplication) sets four of the bytes to zero or if
    ; continuing from above, during addition, then all five bytes are set to zero.

    ;; ZEROS-4/5
    L1738:  LD      L,$00           ; set byte 1 to zero.
            LD      D,A             ; set byte 2 to A.
            LD      E,L             ; set byte 3 to zero.
            EXX                     ; select main set
            LD      DE,$0000        ; set lower bytes 4 and 5 to zero.
            RET                     ; return.

    ; -------------------------
    ; THE 'ADD-BACK' SUBROUTINE
    ; -------------------------
    ; Called from SHIFT-FP above during addition and after normalization from
    ; multiplication.
    ; This is really a 32-bit increment routine which sets the zero flag according
    ; to the 32-bit result.
    ; During addition, only negative numbers like FF FF FF FF FF,
    ; the twos-complement version of xx 80 00 00 01 say
    ; will result in a full ripple FF 00 00 00 00.
    ; FF FF FF FF FF when shifted right is unchanged by SHIFT-FP but sets the
    ; carry invoking this routine.

    ;; ADD-BACK
    L1741:  INC     E               ;
            RET     NZ              ;

            INC     D               ;
            RET     NZ              ;

            EXX                     ;
            INC     E               ;
            JR      NZ,L174A        ; forward if no overflow to ALL-ADDED

            INC     D               ;

    ;; ALL-ADDED
    L174A:  EXX                     ;
            RET                     ; return with zero flag set for zero mantissa.

    ; ---------------------------
    ; THE 'SUBTRACTION' OPERATION
    ; ---------------------------
    ; just switch the sign of subtrahend and do an add.

    ;; subtract
    L174C:  LD      A,(DE)          ; fetch exponent byte of second number the
                                    ; subtrahend.
            AND     A               ; test for zero
            RET     Z               ; return if zero - first number is result.

            INC     DE              ; address the first mantissa byte.
            LD      A,(DE)          ; fetch to accumulator.
            XOR     $80             ; toggle the sign bit.
            LD      (DE),A          ; place back on calculator stack.
            DEC     DE              ; point to exponent byte.
                                    ; continue into addition routine.

    ; ------------------------
    ; THE 'ADDITION' OPERATION
    ; ------------------------
    ; The addition operation pulls out all the stops and uses most of the Z80's
    ; registers to add two floating-point numbers.
    ; This is a binary operation and on entry, HL points to the first number
    ; and DE to the second.

    ;; addition
    L1755:  EXX                     ; - - -
            PUSH    HL              ; save the pointer to the next literal.
            EXX                     ; - - -

            PUSH    DE              ; save pointer to second number
            PUSH    HL              ; save pointer to first number - will be the
                                    ; result pointer on calculator stack.

            CALL    L16D8           ; routine PREP-ADD
            LD      B,A             ; save first exponent byte in B.
            EX      DE,HL           ; switch number pointers.
            CALL    L16D8           ; routine PREP-ADD
            LD      C,A             ; save second exponent byte in C.
            CP      B               ; compare the exponent bytes.
            JR      NC,L1769        ; forward if second higher to SHIFT-LEN

            LD      A,B             ; else higher exponent to A
            LD      B,C             ; lower exponent to B
            EX      DE,HL           ; switch the number pointers.

    ;; SHIFT-LEN
    L1769:  PUSH    AF              ; save higher exponent
            SUB     B               ; subtract lower exponent

            CALL    L16F7           ; routine FETCH-TWO
            CALL    L171A           ; routine SHIFT-FP

            POP     AF              ; restore higher exponent.
            POP     HL              ; restore result pointer.
            LD      (HL),A          ; insert exponent byte.
            PUSH    HL              ; save result pointer again.

    ; now perform the 32-bit addition using two 16-bit Z80 add instructions.

            LD      L,B             ; transfer low bytes of mantissa individually
            LD      H,C             ; to HL register

            ADD     HL,DE           ; the actual binary addition of lower bytes

    ; now the two higher byte pairs that are in the alternate register sets.

            EXX                     ; switch in set
            EX      DE,HL           ; transfer high mantissa bytes to HL register.

            ADC     HL,BC           ; the actual addition of higher bytes with
                                    ; any carry from first stage.

            EX      DE,HL           ; result in DE, sign bytes ($FF or $00) to HL

    ; now consider the two sign bytes

            LD      A,H             ; fetch sign byte of num1

            ADC     A,L             ; add including any carry from mantissa
                                    ; addition. 00 or 01 or FE or FF

            LD      L,A             ; result in L.

    ; possible outcomes of signs and overflow from mantissa are
    ;
    ;  H +  L + carry =  L    RRA  XOR L  RRA
    ; ------------------------------------------------------------
    ; 00 + 00         = 00    00   00
    ; 00 + 00 + carry = 01    00   01     carry
    ; FF + FF         = FE C  FF   01     carry
    ; FF + FF + carry = FF C  FF   00
    ; FF + 00         = FF    FF   00
    ; FF + 00 + carry = 00 C  80   80

            RRA                     ; C->76543210->C
            XOR     L               ; set bit 0 if shifting required.

            EXX                     ; switch back to main set
            EX      DE,HL           ; full mantissa result now in D'E'D E registers.
            POP     HL              ; restore pointer to result exponent on
                                    ; the calculator stack.

            RRA                     ; has overflow occurred ?
            JR      NC,L1790        ; skip forward if not to TEST-NEG

    ; if the addition of two positive mantissas produced overflow or if the
    ; addition of two negative mantissas did not then the result exponent has to
    ; be incremented and the mantissa shifted one place to the right.

            LD      A,$01           ; one shift required.
            CALL    L171A           ; routine SHIFT-FP performs a single shift
                                    ; rounding any lost bit
            INC     (HL)            ; increment the exponent.
            JR      Z,L17B3         ; forward to ADD-REP-6 if the exponent
                                    ; wraps round from FF to zero as number is too
                                    ; big for the system.

    ; at this stage the exponent on the calculator stack is correct.

    ;; TEST-NEG
    L1790:  EXX                     ; switch in the alternate set.
            LD      A,L             ; load result sign to accumulator.
            AND     $80             ; isolate bit 7 from sign byte setting zero
                                    ; flag if positive.
            EXX                     ; back to main set.

            INC     HL              ; point to first byte of mantissa
            LD      (HL),A          ; insert $00 positive or $80 negative at
                                    ; position on calculator stack.

            DEC     HL              ; point to exponent again.
            JR      Z,L17B9         ; forward if positive to GO-NC-MLT

    ; a negative number has to be twos-complemented before being placed on stack.

            LD      A,E             ; fetch lowest (rightmost) mantissa byte.
            NEG                     ; Negate
            CCF                     ; Complement Carry Flag
            LD      E,A             ; place back in register

            LD      A,D             ; ditto
            CPL                     ;
            ADC     A,$00           ;
            LD      D,A             ;

            EXX                     ; switch to higher (leftmost) 16 bits.

            LD      A,E             ; ditto
            CPL                     ;
            ADC     A,$00           ;
            LD      E,A             ;

            LD      A,D             ; ditto
            CPL                     ;
            ADC     A,$00           ;
            JR      NC,L17B7        ; forward without overflow to END-COMPL

    ; else entire mantissa is now zero.  00 00 00 00

            RRA                     ; set mantissa to 80 00 00 00
            EXX                     ; switch.
            INC     (HL)            ; increment the exponent.

    ;; ADD-REP-6
    L17B3:  JP      Z,L1880         ; jump forward if exponent now zero to REPORT-6
                                    ; 'Number too big'

            EXX                     ; switch back to alternate set.

    ;; END-COMPL
    L17B7:  LD      D,A             ; put first byte of mantissa back in DE.
            EXX                     ; switch to main set.

    ;; GO-NC-MLT
    L17B9:  XOR     A               ; clear carry flag and
                                    ; clear accumulator so no extra bits carried
                                    ; forward as occurs in multiplication.

            JR      L1828           ; forward to common code at TEST-NORM
                                    ; but should go straight to NORMALIZE.

    ; ----------------------------------------------
    ; THE 'PREPARE TO MULTIPLY OR DIVIDE' SUBROUTINE
    ; ----------------------------------------------
    ; this routine is called twice from multiplication and twice from division
    ; to prepare each of the two numbers for the operation.
    ; Initially the accumulator holds zero and after the second invocation bit 7
    ; of the accumulator will be the sign bit of the result.

    ;; PREP-M/D
    L17BC:  SCF                     ; set carry flag to signal number is zero.
            DEC     (HL)            ; test exponent
            INC     (HL)            ; for zero.
            RET     Z               ; return if zero with carry flag set.

            INC     HL              ; address first mantissa byte.
            XOR     (HL)            ; exclusive or the running sign bit.
            SET     7,(HL)          ; set the implied bit.
            DEC     HL              ; point to exponent byte.
            RET                     ; return.

    ; ------------------------------
    ; THE 'MULTIPLICATION' OPERATION
    ; ------------------------------
    ;
    ;

    ;; multiply
    L17C6:  XOR     A               ; reset bit 7 of running sign flag.
            CALL    L17BC           ; routine PREP-M/D
            RET     C               ; return if number is zero.
                                    ; zero * anything = zero.

            EXX                     ; - - -
            PUSH    HL              ; save pointer to 'next literal'
            EXX                     ; - - -

            PUSH    DE              ; save pointer to second number

            EX      DE,HL           ; make HL address second number.

            CALL    L17BC           ; routine PREP-M/D

            EX      DE,HL           ; HL first number, DE - second number
            JR      C,L1830         ; forward with carry to ZERO-RSLT
                                    ; anything * zero = zero.

            PUSH    HL              ; save pointer to first number.

            CALL    L16F7           ; routine FETCH-TWO fetches two mantissas from
                                    ; calc stack to B'C'C,B  D'E'D E
                                    ; (HL will be overwritten but the result sign
                                    ; in A is inserted on the calculator stack)

            LD      A,B             ; transfer low mantissa byte of first number
            AND     A               ; clear carry.
            SBC     HL,HL           ; a short form of LD HL,$0000 to take lower
                                    ; two bytes of result. (2 program bytes)
            EXX                     ; switch in alternate set
            PUSH    HL              ; preserve HL
            SBC     HL,HL           ; set HL to zero also to take higher two bytes
                                    ; of the result and clear carry.
            EXX                     ; switch back.

            LD      B,$21           ; register B can now be used to count thirty
                                    ; three shifts.
            JR      L17F8           ; forward to loop entry point STRT-MLT

    ; ---

    ; The multiplication loop is entered at  STRT-LOOP.

    ;; MLT-LOOP
    L17E7:  JR      NC,L17EE        ; forward if no carry to NO-ADD

                                    ; else add in the multiplicand.

            ADD     HL,DE           ; add the two low bytes to result
            EXX                     ; switch to more significant bytes.
            ADC     HL,DE           ; add high bytes of multiplicand and any carry.
            EXX                     ; switch to main set.

    ; in either case shift result right into B'C'C A

    ;; NO-ADD
    L17EE:  EXX                     ; switch to alternate set
            RR      H               ; C > 76543210 > C
            RR      L               ; C > 76543210 > C
            EXX                     ;
            RR      H               ; C > 76543210 > C
            RR      L               ; C > 76543210 > C

    ;; STRT-MLT
    L17F8:  EXX                     ; switch in alternate set.
            RR      B               ; C > 76543210 > C
            RR      C               ; C > 76543210 > C
            EXX                     ; now main set
            RR      C               ; C > 76543210 > C
            RRA                     ; C > 76543210 > C
            DJNZ    L17E7           ; loop back 33 times to MLT-LOOP

    ;

            EX      DE,HL           ;
            EXX                     ;
            EX      DE,HL           ;
            EXX                     ;
            POP     BC              ;
            POP     HL              ;
            LD      A,B             ;
            ADD     A,C             ;
            JR      NZ,L180E        ; forward to MAKE-EXPT

            AND     A               ;

    ;; MAKE-EXPT
    L180E:  DEC     A               ;
            CCF                     ; Complement Carry Flag

    ;; DIVN-EXPT
    L1810:  RLA                     ;
            CCF                     ; Complement Carry Flag
            RRA                     ;
            JP      P,L1819         ; forward to OFLW1-CLR

            JR      NC,L1880        ; forward to REPORT-6

            AND     A               ;

    ;; OFLW1-CLR
    L1819:  INC     A               ;
            JR      NZ,L1824        ; forward to OFLW2-CLR

            JR      C,L1824         ; forward to OFLW2-CLR

            EXX                     ;
            BIT     7,D             ;
            EXX                     ;
            JR      NZ,L1880        ; forward to REPORT-6

    ;; OFLW2-CLR
    L1824:  LD      (HL),A          ;
            EXX                     ;
            LD      A,B             ;
            EXX                     ;

    ; addition joins here with carry flag clear.

    ;; TEST-NORM
    L1828:  JR      NC,L183F        ; forward to NORMALIZE

            LD      A,(HL)          ;
            AND     A               ;

    ;; NEAR-ZERO
    L182C:  LD      A,$80           ; prepare to rescue the most significant bit
                                    ; of the mantissa if it is set.
            JR      Z,L1831         ; skip forward to SKIP-ZERO

    ;; ZERO-RSLT
    L1830:  XOR     A               ; make mask byte zero signaling set five
                                    ; bytes to zero.

    ;; SKIP-ZERO
    L1831:  EXX                     ; switch in alternate set
            AND     D               ; isolate most significant bit (if A is $80).

            CALL    L1738           ; routine ZEROS-4/5 sets mantissa without
                                    ; affecting any flags.

            RLCA                    ; test if MSB set. bit 7 goes to bit 0.
                                    ; either $00 -> $00 or $80 -> $01
            LD      (HL),A          ; make exponent $01 (lowest) or $00 zero
            JR      C,L1868         ; forward if first case to OFLOW-CLR

            INC     HL              ; address first mantissa byte on the
                                    ; calculator stack.
            LD      (HL),A          ; insert a zero for the sign bit.
            DEC     HL              ; point to zero exponent
            JR      L1868           ; forward to OFLOW-CLR

    ; ---

    ; this branch is common to addition and multiplication with the mantissa
    ; result still in registers D'E'D E .

    ;; NORMALIZE
    L183F:  LD      B,$20           ; a maximum of thirty-two left shifts will be
                                    ; needed.

    ;; SHIFT-ONE
    L1841:  EXX                     ; address higher 16 bits.
            BIT     7,D             ; test the leftmost bit
            EXX                     ; address lower 16 bits.

            JR      NZ,L1859        ; forward if leftmost bit was set to NORML-NOW

            RLCA                    ; this holds zero from addition, 33rd bit
                                    ; from multiplication.

            RL      E               ; C < 76543210 < C
            RL      D               ; C < 76543210 < C

            EXX                     ; address higher 16 bits.

            RL      E               ; C < 76543210 < C
            RL      D               ; C < 76543210 < C

            EXX                     ; switch to main set.

            DEC     (HL)            ; decrement the exponent byte on the calculator
                                    ; stack.

            JR      Z,L182C         ; back if exponent becomes zero to NEAR-ZERO
                                    ; it's just possible that the last rotation
                                    ; set bit 7 of D. We shall see.

            DJNZ    L1841           ; loop back to SHIFT-ONE

    ; if thirty-two left shifts were performed without setting the most significant
    ; bit then the result is zero.

            JR      L1830           ; back to ZERO-RSLT

    ; ---

    ;; NORML-NOW
    L1859:  RLA                     ; for the addition path, A is always zero.
                                    ; for the mult path, ...

            JR      NC,L1868        ; forward to OFLOW-CLR

    ; this branch is taken only with multiplication.

            CALL    L1741           ; routine ADD-BACK

            JR      NZ,L1868        ; forward to OFLOW-CLR

            EXX                     ;
            LD      D,$80           ;
            EXX                     ;
            INC     (HL)            ;
            JR      Z,L1880         ; forward to REPORT-6

    ; now transfer the mantissa from the register sets to the calculator stack
    ; incorporating the sign bit already there.

    ;; OFLOW-CLR
    L1868:  PUSH    HL              ; save pointer to exponent on stack.
            INC     HL              ; address first byte of mantissa which was
                                    ; previously loaded with sign bit $00 or $80.

            EXX                     ; - - -
            PUSH    DE              ; push the most significant two bytes.
            EXX                     ; - - -

            POP     BC              ; pop - true mantissa is now BCDE.

    ; now pick up the sign bit.

            LD      A,B             ; first mantissa byte to A
            RLA                     ; rotate out bit 7 which is set
            RL      (HL)            ; rotate sign bit on stack into carry.
            RRA                     ; rotate sign bit into bit 7 of mantissa.

    ; and transfer mantissa from main registers to calculator stack.

            LD      (HL),A          ;
            INC     HL              ;
            LD      (HL),C          ;
            INC     HL              ;
            LD      (HL),D          ;
            INC     HL              ;
            LD      (HL),E          ;

            POP     HL              ; restore pointer to num1 now result.
            POP     DE              ; restore pointer to num2 now STKEND.

            EXX                     ; - - -
            POP     HL              ; restore pointer to next calculator literal.
            EXX                     ; - - -

            RET                     ; return.

    ; ---

    ;; REPORT-6
    L1880:  RST     08H             ; ERROR-1
            DEFB    $05             ; Error Report: Arithmetic overflow.

    ; ------------------------
    ; THE 'DIVISION' OPERATION
    ; ------------------------
    ;   "Of all the arithmetic subroutines, division is the most complicated and
    ;   the least understood.  It is particularly interesting to note that the
    ;   Sinclair programmer himself has made a mistake in his programming ( or has
    ;   copied over someone else's mistake!) for
    ;   PRINT PEEK 6352 [ $18D0 ] ('unimproved' ROM, 6351 [ $18CF ] )
    ;   should give 218 not 225."
    ;   - Dr. Ian Logan, Syntax magazine Jul/Aug 1982.
    ;   [  i.e. the jump should be made to div-34th ]

    ;   First check for division by zero.

    ;; division
    L1882:  EX      DE,HL           ; consider the second number first.
            XOR     A               ; set the running sign flag.
            CALL    L17BC           ; routine PREP-M/D
            JR      C,L1880         ; back if zero to REPORT-6
                                    ; 'Arithmetic overflow'

            EX      DE,HL           ; now prepare first number and check for zero.
            CALL    L17BC           ; routine PREP-M/D
            RET     C               ; return if zero, 0/anything is zero.

            EXX                     ; - - -
            PUSH    HL              ; save pointer to the next calculator literal.
            EXX                     ; - - -

            PUSH    DE              ; save pointer to divisor - will be STKEND.
            PUSH    HL              ; save pointer to dividend - will be result.

            CALL    L16F7           ; routine FETCH-TWO fetches the two numbers
                                    ; into the registers H'B'C'C B
                                    ;                    L'D'E'D E
            EXX                     ; - - -
            PUSH    HL              ; save the two exponents.

            LD      H,B             ; transfer the dividend to H'L'H L
            LD      L,C             ;
            EXX                     ;
            LD      H,C             ;
            LD      L,B             ;

            XOR     A               ; clear carry bit and accumulator.
            LD      B,$DF           ; count upwards from -33 decimal
            JR      L18B2           ; forward to mid-loop entry point DIV-START

    ; ---

    ;; DIV-LOOP
    L18A2:  RLA                     ; multiply partial quotient by two
            RL      C               ; setting result bit from carry.
            EXX                     ;
            RL      C               ;
            RL      B               ;
            EXX                     ;

    ;; div-34th
    L18AB:  ADD     HL,HL           ;
            EXX                     ;
            ADC     HL,HL           ;
            EXX                     ;
            JR      C,L18C2         ; forward to SUBN-ONLY

    ;; DIV-START
    L18B2:  SBC     HL,DE           ; subtract divisor part.
            EXX                     ;
            SBC     HL,DE           ;
            EXX                     ;
            JR      NC,L18C9        ; forward if subtraction goes to NO-RSTORE

            ADD     HL,DE           ; else restore
            EXX                     ;
            ADC     HL,DE           ;
            EXX                     ;
            AND     A               ; clear carry
            JR      L18CA           ; forward to COUNT-ONE

    ; ---

    ;; SUBN-ONLY
    L18C2:  AND     A               ;
            SBC     HL,DE           ;
            EXX                     ;
            SBC     HL,DE           ;
            EXX                     ;

    ;; NO-RSTORE
    L18C9:  SCF                     ; set carry flag

    ;; COUNT-ONE
    L18CA:  INC     B               ; increment the counter
            JP      M,L18A2         ; back while still minus to DIV-LOOP

            PUSH    AF              ;
            JR      Z,L18B2         ; back to DIV-START

    ; "This jump is made to the wrong place. No 34th bit will ever be obtained
    ; without first shifting the dividend. Hence important results like 1/10 and
    ; 1/1000 are not rounded up as they should be. Rounding up never occurs when
    ; it depends on the 34th bit. The jump should be made to div-34th above."
    ; - Dr. Frank O'Hara, "The Complete Spectrum ROM Disassembly", 1983,
    ; published by Melbourne House.
    ; (Note. on the ZX81 this would be JR Z,L18AB)
    ;
    ; However if you make this change, then while (1/2=.5) will now evaluate as
    ; true, (.25=1/4), which did evaluate as true, no longer does.

            LD      E,A             ;
            LD      D,C             ;
            EXX                     ;
            LD      E,C             ;
            LD      D,B             ;

            POP     AF              ;
            RR      B               ;
            POP     AF              ;
            RR      B               ;

            EXX                     ;
            POP     BC              ;
            POP     HL              ;
            LD      A,B             ;
            SUB     C               ;
            JP      L1810           ; jump back to DIVN-EXPT

    ; ------------------------------------------------
    ; THE 'INTEGER TRUNCATION TOWARDS ZERO' SUBROUTINE
    ; ------------------------------------------------
    ;

    ;; truncate
    L18E4:  LD      A,(HL)          ; fetch exponent
            CP      $81             ; compare to +1
            JR      NC,L18EF        ; forward, if 1 or more, to T-GR-ZERO

    ; else the number is smaller than plus or minus 1 and can be made zero.

            LD      (HL),$00        ; make exponent zero.
            LD      A,$20           ; prepare to set 32 bits of mantissa to zero.
            JR      L18F4           ; forward to NIL-BYTES

    ; ---

    ;; T-GR-ZERO
    L18EF:  SUB     $A0             ; subtract +32 from exponent
            RET     P               ; return if result is positive as all 32 bits
                                    ; of the mantissa relate to the integer part.
                                    ; The floating point is somewhere to the right
                                    ; of the mantissa

            NEG                     ; else negate to form number of rightmost bits
                                    ; to be blanked.

    ; for instance, disregarding the sign bit, the number 3.5 is held as
    ; exponent $82 mantissa .11100000 00000000 00000000 00000000
    ; we need to set $82 - $A0 = $E2 NEG = $1E (thirty) bits to zero to form the
    ; integer.
    ; The sign of the number is never considered as the first bit of the mantissa
    ; must be part of the integer.

    ;; NIL-BYTES
    L18F4:  PUSH    DE              ; save pointer to STKEND
            EX      DE,HL           ; HL points at STKEND
            DEC     HL              ; now at last byte of mantissa.
            LD      B,A             ; Transfer bit count to B register.
            SRL     B               ; divide by
            SRL     B               ; eight
            SRL     B               ;
            JR      Z,L1905         ; forward if zero to BITS-ZERO

    ; else the original count was eight or more and whole bytes can be blanked.

    ;; BYTE-ZERO
    L1900:  LD      (HL),$00        ; set eight bits to zero.
            DEC     HL              ; point to more significant byte of mantissa.
            DJNZ    L1900           ; loop back to BYTE-ZERO

    ; now consider any residual bits.

    ;; BITS-ZERO
    L1905:  AND     $07             ; isolate the remaining bits
            JR      Z,L1912         ; forward if none to IX-END

            LD      B,A             ; transfer bit count to B counter.
            LD      A,$FF           ; form a mask 11111111

    ;; LESS-MASK
    L190C:  SLA     A               ; 1 <- 76543210 <- o     slide mask leftwards.
            DJNZ    L190C           ; loop back for bit count to LESS-MASK

            AND     (HL)            ; lose the unwanted rightmost bits
            LD      (HL),A          ; and place in mantissa byte.

    ;; IX-END
    L1912:  EX      DE,HL           ; restore result pointer from DE.
            POP     DE              ; restore STKEND from stack.
            RET                     ; return.

    ;********************************
    ;**  FLOATING-POINT CALCULATOR **
    ;********************************

    ; As a general rule the calculator avoids using the IY register.
    ; Exceptions are val and str$.
    ; So an assembly language programmer who has disabled interrupts to use IY
    ; for other purposes can still use the calculator for mathematical
    ; purposes.

    ; ------------------------
    ; THE 'TABLE OF CONSTANTS'
    ; ------------------------
    ; The ZX81 has only floating-point number representation.
    ; Both the ZX80 and the ZX Spectrum have integer numbers in some form.

    ;; stk-zero                                                 00 00 00 00 00
    L1915:  DEFB    $00             ;;Bytes: 1
            DEFB    $B0             ;;Exponent $00
            DEFB    $00             ;;(+00,+00,+00)

    ;; stk-one                                                  81 00 00 00 00
    L1918:  DEFB    $31             ;;Exponent $81, Bytes: 1
            DEFB    $00             ;;(+00,+00,+00)

    ;; stk-half                                                 80 00 00 00 00
    L191A:  DEFB    $30             ;;Exponent: $80, Bytes: 1
            DEFB    $00             ;;(+00,+00,+00)

    ;; stk-pi/2                                                 81 49 0F DA A2
    L191C:  DEFB    $F1             ;;Exponent: $81, Bytes: 4
            DEFB    $49,$0F,$DA,$A2 ;;

    ;; stk-ten                                                  84 20 00 00 00
    L1921:  DEFB    $34             ;;Exponent: $84, Bytes: 1
            DEFB    $20             ;;(+00,+00,+00)

    ; ------------------------
    ; THE 'TABLE OF ADDRESSES'
    ; ------------------------
    ;
    ; starts with binary operations which have two operands and one result.
    ; three pseudo binary operations first.

    ;; tbl-addrs
    L1923:  DEFW    L1C2F           ; $00 Address: $1C2F - jump-true
            DEFW    L1A72           ; $01 Address: $1A72 - exchange
            DEFW    L19E3           ; $02 Address: $19E3 - delete

    ; true binary operations.

            DEFW    L174C           ; $03 Address: $174C - subtract
            DEFW    L17C6           ; $04 Address: $176C - multiply
            DEFW    L1882           ; $05 Address: $1882 - division
            DEFW    L1DE2           ; $06 Address: $1DE2 - to-power
            DEFW    L1AED           ; $07 Address: $1AED - or

            DEFW    L1AF3           ; $08 Address: $1B03 - no-&-no
            DEFW    L1B03           ; $09 Address: $1B03 - no-l-eql
            DEFW    L1B03           ; $0A Address: $1B03 - no-gr-eql
            DEFW    L1B03           ; $0B Address: $1B03 - nos-neql
            DEFW    L1B03           ; $0C Address: $1B03 - no-grtr
            DEFW    L1B03           ; $0D Address: $1B03 - no-less
            DEFW    L1B03           ; $0E Address: $1B03 - nos-eql
            DEFW    L1755           ; $0F Address: $1755 - addition

            DEFW    L1AF8           ; $10 Address: $1AF8 - str-&-no
            DEFW    L1B03           ; $11 Address: $1B03 - str-l-eql
            DEFW    L1B03           ; $12 Address: $1B03 - str-gr-eql
            DEFW    L1B03           ; $13 Address: $1B03 - strs-neql
            DEFW    L1B03           ; $14 Address: $1B03 - str-grtr
            DEFW    L1B03           ; $15 Address: $1B03 - str-less
            DEFW    L1B03           ; $16 Address: $1B03 - strs-eql
            DEFW    L1B62           ; $17 Address: $1B62 - strs-add

    ; unary follow

            DEFW    L1AA0           ; $18 Address: $1AA0 - neg

            DEFW    L1C06           ; $19 Address: $1C06 - code
            DEFW    L1BA4           ; $1A Address: $1BA4 - val
            DEFW    L1C11           ; $1B Address: $1C11 - len
            DEFW    L1D49           ; $1C Address: $1D49 - sin
            DEFW    L1D3E           ; $1D Address: $1D3E - cos
            DEFW    L1D6E           ; $1E Address: $1D6E - tan
            DEFW    L1DC4           ; $1F Address: $1DC4 - asn
            DEFW    L1DD4           ; $20 Address: $1DD4 - acs
            DEFW    L1D76           ; $21 Address: $1D76 - atn
            DEFW    L1CA9           ; $22 Address: $1CA9 - ln
            DEFW    L1C5B           ; $23 Address: $1C5B - exp
            DEFW    L1C46           ; $24 Address: $1C46 - int
            DEFW    L1DDB           ; $25 Address: $1DDB - sqr
            DEFW    L1AAF           ; $26 Address: $1AAF - sgn
            DEFW    L1AAA           ; $27 Address: $1AAA - abs
            DEFW    L1ABE           ; $28 Address: $1A1B - peek
            DEFW    L1AC5           ; $29 Address: $1AC5 - usr-no
            DEFW    L1BD5           ; $2A Address: $1BD5 - str$
            DEFW    L1B8F           ; $2B Address: $1B8F - chrs
            DEFW    L1AD5           ; $2C Address: $1AD5 - not

    ; end of true unary

            DEFW    L19F6           ; $2D Address: $19F6 - duplicate
            DEFW    L1C37           ; $2E Address: $1C37 - n-mod-m

            DEFW    L1C23           ; $2F Address: $1C23 - jump
            DEFW    L19FC           ; $30 Address: $19FC - stk-data

            DEFW    L1C17           ; $31 Address: $1C17 - dec-jr-nz
            DEFW    L1ADB           ; $32 Address: $1ADB - less-0
            DEFW    L1ACE           ; $33 Address: $1ACE - greater-0
            DEFW    L002B           ; $34 Address: $002B - end-calc
            DEFW    L1D18           ; $35 Address: $1D18 - get-argt
            DEFW    L18E4           ; $36 Address: $18E4 - truncate
            DEFW    L19E4           ; $37 Address: $19E4 - fp-calc-2
            DEFW    L155A           ; $38 Address: $155A - e-to-fp

    ; the following are just the next available slots for the 128 compound literals
    ; which are in range $80 - $FF.

            DEFW    L1A7F           ; $39 Address: $1A7F - series-xx    $80 - $9F.
            DEFW    L1A51           ; $3A Address: $1A51 - stk-const-xx $A0 - $BF.
            DEFW    L1A63           ; $3B Address: $1A63 - st-mem-xx    $C0 - $DF.
            DEFW    L1A45           ; $3C Address: $1A45 - get-mem-xx   $E0 - $FF.

    ; Aside: 3D - 7F are therefore unused calculator literals.
    ;        39 - 7B would be available for expansion.

    ; -------------------------------
    ; THE 'FLOATING POINT CALCULATOR'
    ; -------------------------------
    ;
    ;

    ;; CALCULATE
    L199D:  CALL    L1B85           ; routine STK-PNTRS is called to set up the
                                    ; calculator stack pointers for a default
                                    ; unary operation. HL = last value on stack.
                                    ; DE = STKEND first location after stack.

    ; the calculate routine is called at this point by the series generator...

    ;; GEN-ENT-1
    L19A0:  LD      A,B             ; fetch the Z80 B register to A
            LD      ($401E),A       ; and store value in system variable BREG.
                                    ; this will be the counter for dec-jr-nz
                                    ; or if used from fp-calc2 the calculator
                                    ; instruction.

    ; ... and again later at this point

    ;; GEN-ENT-2
    L19A4:  EXX                     ; switch sets
            EX      (SP),HL         ; and store the address of next instruction,
                                    ; the return address, in H'L'.
                                    ; If this is a recursive call then the H'L'
                                    ; of the previous invocation goes on stack.
                                    ; c.f. end-calc.
            EXX                     ; switch back to main set.

    ; this is the re-entry looping point when handling a string of literals.

    ;; RE-ENTRY
    L19A7:  LD      ($401C),DE      ; save end of stack in system variable STKEND
            EXX                     ; switch to alt
            LD      A,(HL)          ; get next literal
            INC     HL              ; increase pointer'

    ; single operation jumps back to here

    ;; SCAN-ENT
    L19AE:  PUSH    HL              ; save pointer on stack   *
            AND     A               ; now test the literal
            JP      P,L19C2         ; forward to FIRST-3D if in range $00 - $3D
                                    ; anything with bit 7 set will be one of
                                    ; 128 compound literals.

    ; compound literals have the following format.
    ; bit 7 set indicates compound.
    ; bits 6-5 the subgroup 0-3.
    ; bits 4-0 the embedded parameter $00 - $1F.
    ; The subgroup 0-3 needs to be manipulated to form the next available four
    ; address places after the simple literals in the address table.

            LD      D,A             ; save literal in D
            AND     $60             ; and with 01100000 to isolate subgroup
            RRCA                    ; rotate bits
            RRCA                    ; 4 places to right
            RRCA                    ; not five as we need offset * 2
            RRCA                    ; 00000xx0
            ADD     A,$72           ; add ($39 * 2) to give correct offset.
                                    ; alter above if you add more literals.
            LD      L,A             ; store in L for later indexing.
            LD      A,D             ; bring back compound literal
            AND     $1F             ; use mask to isolate parameter bits
            JR      L19D0           ; forward to ENT-TABLE

    ; ---

    ; the branch was here with simple literals.

    ;; FIRST-3D
    L19C2:  CP      $18             ; compare with first unary operations.
            JR      NC,L19CE        ; to DOUBLE-A with unary operations

    ; it is binary so adjust pointers.

            EXX                     ;
            LD      BC,$FFFB        ; the value -5
            LD      D,H             ; transfer HL, the last value, to DE.
            LD      E,L             ;
            ADD     HL,BC           ; subtract 5 making HL point to second
                                    ; value.
            EXX                     ;

    ;; DOUBLE-A
    L19CE:  RLCA                    ; double the literal
            LD      L,A             ; and store in L for indexing

    ;; ENT-TABLE
    L19D0:  LD      DE,L1923        ; Address: tbl-addrs
            LD      H,$00           ; prepare to index
            ADD     HL,DE           ; add to get address of routine
            LD      E,(HL)          ; low byte to E
            INC     HL              ;
            LD      D,(HL)          ; high byte to D

            LD      HL,L19A7        ; Address: RE-ENTRY
            EX      (SP),HL         ; goes on machine stack
                                    ; address of next literal goes to HL. *

            PUSH    DE              ; now the address of routine is stacked.
            EXX                     ; back to main set
                                    ; avoid using IY register.
            LD      BC,($401D)      ; STKEND_hi
                                    ; nothing much goes to C but BREG to B
                                    ; and continue into next ret instruction
                                    ; which has a dual identity

    ; -----------------------
    ; THE 'DELETE' SUBROUTINE
    ; -----------------------
    ; offset $02: 'delete'
    ; A simple return but when used as a calculator literal this
    ; deletes the last value from the calculator stack.
    ; On entry, as always with binary operations,
    ; HL=first number, DE=second number
    ; On exit, HL=result, DE=stkend.
    ; So nothing to do

    ;; delete
    L19E3:  RET                     ; return - indirect jump if from above.

    ; ---------------------------------
    ; THE 'SINGLE OPERATION' SUBROUTINE
    ; ---------------------------------
    ; offset $37: 'fp-calc-2'
    ; this single operation is used, in the first instance, to evaluate most
    ; of the mathematical and string functions found in BASIC expressions.

    ;; fp-calc-2
    L19E4:  POP     AF              ; drop return address.
            LD      A,($401E)       ; load accumulator from system variable BREG
                                    ; value will be literal eg. 'tan'
            EXX                     ; switch to alt
            JR      L19AE           ; back to SCAN-ENT
                                    ; next literal will be end-calc in scanning

    ; ------------------------------
    ; THE 'TEST 5 SPACES' SUBROUTINE
    ; ------------------------------
    ; This routine is called from MOVE-FP, STK-CONST and STK-STORE to
    ; test that there is enough space between the calculator stack and the
    ; machine stack for another five-byte value. It returns with BC holding
    ; the value 5 ready for any subsequent LDIR.

    ;; TEST-5-SP
    L19EB:  PUSH    DE              ; save
            PUSH    HL              ; registers
            LD      BC,$0005        ; an overhead of five bytes
            CALL    L0EC5           ; routine TEST-ROOM tests free RAM raising
                                    ; an error if not.
            POP     HL              ; else restore
            POP     DE              ; registers.
            RET                     ; return with BC set at 5.

    ; ---------------------------------------------
    ; THE 'MOVE A FLOATING POINT NUMBER' SUBROUTINE
    ; ---------------------------------------------
    ; offset $2D: 'duplicate'
    ; This simple routine is a 5-byte LDIR instruction
    ; that incorporates a memory check.
    ; When used as a calculator literal it duplicates the last value on the
    ; calculator stack.
    ; Unary so on entry HL points to last value, DE to stkend

    ;; duplicate
    ;; MOVE-FP
    L19F6:  CALL    L19EB           ; routine TEST-5-SP test free memory
                                    ; and sets BC to 5.
            LDIR                    ; copy the five bytes.
            RET                     ; return with DE addressing new STKEND
                                    ; and HL addressing new last value.

    ; -------------------------------
    ; THE 'STACK LITERALS' SUBROUTINE
    ; -------------------------------
    ; offset $30: 'stk-data'
    ; When a calculator subroutine needs to put a value on the calculator
    ; stack that is not a regular constant this routine is called with a
    ; variable number of following data bytes that convey to the routine
    ; the floating point form as succinctly as is possible.

    ;; stk-data
    L19FC:  LD      H,D             ; transfer STKEND
            LD      L,E             ; to HL for result.

    ;; STK-CONST
    L19FE:  CALL    L19EB           ; routine TEST-5-SP tests that room exists
                                    ; and sets BC to $05.

            EXX                     ; switch to alternate set
            PUSH    HL              ; save the pointer to next literal on stack
            EXX                     ; switch back to main set

            EX      (SP),HL         ; pointer to HL, destination to stack.

            PUSH    BC              ; save BC - value 5 from test room ??.

            LD      A,(HL)          ; fetch the byte following 'stk-data'
            AND     $C0             ; isolate bits 7 and 6
            RLCA                    ; rotate
            RLCA                    ; to bits 1 and 0  range $00 - $03.
            LD      C,A             ; transfer to C
            INC     C               ; and increment to give number of bytes
                                    ; to read. $01 - $04
            LD      A,(HL)          ; reload the first byte
            AND     $3F             ; mask off to give possible exponent.
            JR      NZ,L1A14        ; forward to FORM-EXP if it was possible to
                                    ; include the exponent.

    ; else byte is just a byte count and exponent comes next.

            INC     HL              ; address next byte and
            LD      A,(HL)          ; pick up the exponent ( - $50).

    ;; FORM-EXP
    L1A14:  ADD     A,$50           ; now add $50 to form actual exponent
            LD      (DE),A          ; and load into first destination byte.
            LD      A,$05           ; load accumulator with $05 and
            SUB     C               ; subtract C to give count of trailing
                                    ; zeros plus one.
            INC     HL              ; increment source
            INC     DE              ; increment destination
            LD      B,$00           ; prepare to copy
            LDIR                    ; copy C bytes

            POP     BC              ; restore 5 counter to BC ??.

            EX      (SP),HL         ; put HL on stack as next literal pointer
                                    ; and the stack value - result pointer -
                                    ; to HL.

            EXX                     ; switch to alternate set.
            POP     HL              ; restore next literal pointer from stack
                                    ; to H'L'.
            EXX                     ; switch back to main set.

            LD      B,A             ; zero count to B
            XOR     A               ; clear accumulator

    ;; STK-ZEROS
    L1A27:  DEC     B               ; decrement B counter
            RET     Z               ; return if zero.          >>
                                    ; DE points to new STKEND
                                    ; HL to new number.

            LD      (DE),A          ; else load zero to destination
            INC     DE              ; increase destination
            JR      L1A27           ; loop back to STK-ZEROS until done.

    ; -------------------------------
    ; THE 'SKIP CONSTANTS' SUBROUTINE
    ; -------------------------------
    ; This routine traverses variable-length entries in the table of constants,
    ; stacking intermediate, unwanted constants onto a dummy calculator stack,
    ; in the first five bytes of the ZX81 ROM.

    ;; SKIP-CONS
    L1A2D:  AND     A               ; test if initially zero.

    ;; SKIP-NEXT
    L1A2E:  RET     Z               ; return if zero.          >>

            PUSH     AF             ; save count.
            PUSH    DE              ; and normal STKEND

            LD      DE,$0000        ; dummy value for STKEND at start of ROM
                                    ; Note. not a fault but this has to be
                                    ; moved elsewhere when running in RAM.
                                    ;
            CALL    L19FE           ; routine STK-CONST works through variable
                                    ; length records.

            POP     DE              ; restore real STKEND
            POP     AF              ; restore count
            DEC     A               ; decrease
            JR      L1A2E           ; loop back to SKIP-NEXT

    ; --------------------------------
    ; THE 'MEMORY LOCATION' SUBROUTINE
    ; --------------------------------
    ; This routine, when supplied with a base address in HL and an index in A,
    ; will calculate the address of the A'th entry, where each entry occupies
    ; five bytes. It is used for addressing floating-point numbers in the
    ; calculator's memory area.

    ;; LOC-MEM
    L1A3C:  LD      C,A             ; store the original number $00-$1F.
            RLCA                    ; double.
            RLCA                    ; quadruple.
            ADD     A,C             ; now add original value to multiply by five.

            LD      C,A             ; place the result in C.
            LD      B,$00           ; set B to 0.
            ADD     HL,BC           ; add to form address of start of number in HL.

            RET                     ; return.

    ; -------------------------------------
    ; THE 'GET FROM MEMORY AREA' SUBROUTINE
    ; -------------------------------------
    ; offsets $E0 to $FF: 'get-mem-0', 'get-mem-1' etc.
    ; A holds $00-$1F offset.
    ; The calculator stack increases by 5 bytes.

    ;; get-mem-xx
    L1A45:  PUSH    DE              ; save STKEND
            LD      HL,($401F)      ; MEM is base address of the memory cells.
            CALL    L1A3C           ; routine LOC-MEM so that HL = first byte
            CALL    L19F6           ; routine MOVE-FP moves 5 bytes with memory
                                    ; check.
                                    ; DE now points to new STKEND.
            POP     HL              ; the original STKEND is now RESULT pointer.
            RET                     ; return.

    ; ---------------------------------
    ; THE 'STACK A CONSTANT' SUBROUTINE
    ; ---------------------------------
    ; offset $A0: 'stk-zero'
    ; offset $A1: 'stk-one'
    ; offset $A2: 'stk-half'
    ; offset $A3: 'stk-pi/2'
    ; offset $A4: 'stk-ten'
    ; This routine allows a one-byte instruction to stack up to 32 constants
    ; held in short form in a table of constants. In fact only 5 constants are
    ; required. On entry the A register holds the literal ANDed with $1F.
    ; It isn't very efficient and it would have been better to hold the
    ; numbers in full, five byte form and stack them in a similar manner
    ; to that which would be used later for semi-tone table values.

    ;; stk-const-xx
    L1A51:  LD      H,D             ; save STKEND - required for result
            LD      L,E             ;
            EXX                     ; swap
            PUSH    HL              ; save pointer to next literal
            LD      HL,L1915        ; Address: stk-zero - start of table of
                                    ; constants
            EXX                     ;
            CALL    L1A2D           ; routine SKIP-CONS
            CALL    L19FE           ; routine STK-CONST
            EXX                     ;
            POP     HL              ; restore pointer to next literal.
            EXX                     ;
            RET                     ; return.

    ; ---------------------------------------
    ; THE 'STORE IN A MEMORY AREA' SUBROUTINE
    ; ---------------------------------------
    ; Offsets $C0 to $DF: 'st-mem-0', 'st-mem-1' etc.
    ; Although 32 memory storage locations can be addressed, only six
    ; $C0 to $C5 are required by the ROM and only the thirty bytes (6*5)
    ; required for these are allocated. ZX81 programmers who wish to
    ; use the floating point routines from assembly language may wish to
    ; alter the system variable MEM to point to 160 bytes of RAM to have
    ; use the full range available.
    ; A holds derived offset $00-$1F.
    ; Unary so on entry HL points to last value, DE to STKEND.

    ;; st-mem-xx
    L1A63:  PUSH    HL              ; save the result pointer.
            EX      DE,HL           ; transfer to DE.
            LD      HL,($401F)      ; fetch MEM the base of memory area.
            CALL    L1A3C           ; routine LOC-MEM sets HL to the destination.
            EX      DE,HL           ; swap - HL is start, DE is destination.
            CALL    L19F6           ; routine MOVE-FP.
                                    ; note. a short ld bc,5; ldir
                                    ; the embedded memory check is not required
                                    ; so these instructions would be faster!
            EX      DE,HL           ; DE = STKEND
            POP     HL              ; restore original result pointer
            RET                     ; return.

    ; -------------------------
    ; THE 'EXCHANGE' SUBROUTINE
    ; -------------------------
    ; offset $01: 'exchange'
    ; This routine exchanges the last two values on the calculator stack
    ; On entry, as always with binary operations,
    ; HL=first number, DE=second number
    ; On exit, HL=result, DE=stkend.

    ;; exchange
    L1A72:  LD      B,$05           ; there are five bytes to be swapped

    ; start of loop.

    ;; SWAP-BYTE
    L1A74:  LD      A,(DE)          ; each byte of second
            LD      C,(HL)          ; each byte of first
            EX      DE,HL           ; swap pointers
            LD      (DE),A          ; store each byte of first
            LD      (HL),C          ; store each byte of second
            INC     HL              ; advance both
            INC     DE              ; pointers.
            DJNZ    L1A74           ; loop back to SWAP-BYTE until all 5 done.

            EX      DE,HL           ; even up the exchanges
                                    ; so that DE addresses STKEND.
            RET                     ; return.

    ; ---------------------------------
    ; THE 'SERIES GENERATOR' SUBROUTINE
    ; ---------------------------------
    ; offset $86: 'series-06'
    ; offset $88: 'series-08'
    ; offset $8C: 'series-0C'
    ; The ZX81 uses Chebyshev polynomials to generate approximations for
    ; SIN, ATN, LN and EXP. These are named after the Russian mathematician
    ; Pafnuty Chebyshev, born in 1821, who did much pioneering work on numerical
    ; series. As far as calculators are concerned, Chebyshev polynomials have an
    ; advantage over other series, for example the Taylor series, as they can
    ; reach an approximation in just six iterations for SIN, eight for EXP and
    ; twelve for LN and ATN. The mechanics of the routine are interesting but
    ; for full treatment of how these are generated with demonstrations in
    ; Sinclair BASIC see "The Complete Spectrum ROM Disassembly" by Dr Ian Logan
    ; and Dr Frank O'Hara, published 1983 by Melbourne House.

    ;; series-xx
    L1A7F:  LD      B,A             ; parameter $00 - $1F to B counter
            CALL    L19A0           ; routine GEN-ENT-1 is called.
                                    ; A recursive call to a special entry point
                                    ; in the calculator that puts the B register
                                    ; in the system variable BREG. The return
                                    ; address is the next location and where
                                    ; the calculator will expect its first
                                    ; instruction - now pointed to by HL'.
                                    ; The previous pointer to the series of
                                    ; five-byte numbers goes on the machine stack.

    ; The initialization phase.

            DEFB    $2D             ;;duplicate       x,x
            DEFB    $0F             ;;addition        x+x
            DEFB    $C0             ;;st-mem-0        x+x
            DEFB    $02             ;;delete          .
            DEFB    $A0             ;;stk-zero        0
            DEFB    $C2             ;;st-mem-2        0

    ; a loop is now entered to perform the algebraic calculation for each of
    ; the numbers in the series

    ;; G-LOOP
    L1A89:  DEFB    $2D             ;;duplicate       v,v.
            DEFB    $E0             ;;get-mem-0       v,v,x+2
            DEFB    $04             ;;multiply        v,v*x+2
            DEFB    $E2             ;;get-mem-2       v,v*x+2,v
            DEFB    $C1             ;;st-mem-1
            DEFB    $03             ;;subtract
            DEFB    $34             ;;end-calc

    ; the previous pointer is fetched from the machine stack to H'L' where it
    ; addresses one of the numbers of the series following the series literal.

            CALL    L19FC           ; routine STK-DATA is called directly to
                                    ; push a value and advance H'L'.
            CALL    L19A4           ; routine GEN-ENT-2 recursively re-enters
                                    ; the calculator without disturbing
                                    ; system variable BREG
                                    ; H'L' value goes on the machine stack and is
                                    ; then loaded as usual with the next address.

            DEFB    $0F             ;;addition
            DEFB    $01             ;;exchange
            DEFB    $C2             ;;st-mem-2
            DEFB    $02             ;;delete

            DEFB    $31             ;;dec-jr-nz
            DEFB    $EE             ;;back to L1A89, G-LOOP

    ; when the counted loop is complete the final subtraction yields the result
    ; for example SIN X.

            DEFB    $E1             ;;get-mem-1
            DEFB    $03             ;;subtract
            DEFB    $34             ;;end-calc

            RET                     ; return with H'L' pointing to location
                                    ; after last number in series.

    ; -----------------------
    ; Handle unary minus (18)
    ; -----------------------
    ; Unary so on entry HL points to last value, DE to STKEND.

    ;; NEGATE
    ;; negate
    L1AA0:  LD A,  (HL)             ; fetch exponent of last value on the
                                    ; calculator stack.
            AND     A               ; test it.
            RET     Z               ; return if zero.

            INC     HL              ; address the byte with the sign bit.
            LD      A,(HL)          ; fetch to accumulator.
            XOR     $80             ; toggle the sign bit.
            LD      (HL),A          ; put it back.
            DEC     HL              ; point to last value again.
            RET                     ; return.

    ; -----------------------
    ; Absolute magnitude (27)
    ; -----------------------
    ; This calculator literal finds the absolute value of the last value,
    ; floating point, on calculator stack.

    ;; abs
    L1AAA:  INC     HL              ; point to byte with sign bit.
            RES     7,(HL)          ; make the sign positive.
            DEC     HL              ; point to last value again.
            RET                     ; return.

    ; -----------
    ; Signum (26)
    ; -----------
    ; This routine replaces the last value on the calculator stack,
    ; which is in floating point form, with one if positive and with -minus one
    ; if negative. If it is zero then it is left as such.

    ;; sgn
    L1AAF:  INC     HL              ; point to first byte of 4-byte mantissa.
            LD      A,(HL)          ; pick up the byte with the sign bit.
            DEC     HL              ; point to exponent.
            DEC     (HL)            ; test the exponent for
            INC     (HL)            ; the value zero.

            SCF                     ; set the carry flag.
            CALL    NZ,L1AE0        ; routine FP-0/1  replaces last value with one
                                    ; if exponent indicates the value is non-zero.
                                    ; in either case mantissa is now four zeros.

            INC HL                  ; point to first byte of 4-byte mantissa.
            RLCA                    ; rotate original sign bit to carry.
            RR      (HL)            ; rotate the carry into sign.
            DEC HL                  ; point to last value.
            RET                     ; return.

    ; -------------------------
    ; Handle PEEK function (28)
    ; -------------------------
    ; This function returns the contents of a memory address.
    ; The entire address space can be peeked including the ROM.

    ;; peek
    L1ABE:  CALL    L0EA7           ; routine FIND-INT puts address in BC.
            LD      A,(BC)          ; load contents into A register.

    ;; IN-PK-STK
    L1AC2:  JP      L151D           ; exit via STACK-A to put value on the
                                    ; calculator stack.

    ; ---------------
    ; USR number (29)
    ; ---------------
    ; The USR function followed by a number 0-65535 is the method by which
    ; the ZX81 invokes machine code programs. This function returns the
    ; contents of the BC register pair.
    ; Note. that STACK-BC re-initializes the IY register to $4000 if a user-written
    ; program has altered it.

    ;; usr-no
    L1AC5:  CALL    L0EA7           ; routine FIND-INT to fetch the
                                    ; supplied address into BC.

            LD      HL,L1520        ; address: STACK-BC is
            PUSH    HL              ; pushed onto the machine stack.
            PUSH    BC              ; then the address of the machine code
                                    ; routine.

            RET                     ; make an indirect jump to the routine
                                    ; and, hopefully, to STACK-BC also.

    ; -----------------------
    ; Greater than zero ($33)
    ; -----------------------
    ; Test if the last value on the calculator stack is greater than zero.
    ; This routine is also called directly from the end-tests of the comparison
    ; routine.

    ;; GREATER-0
    ;; greater-0
    L1ACE:  LD      A,(HL)          ; fetch exponent.
            AND     A               ; test it for zero.
            RET     Z               ; return if so.

            LD      A,$FF           ; prepare XOR mask for sign bit
            JR      L1ADC           ; forward to SIGN-TO-C
                                    ; to put sign in carry
                                    ; (carry will become set if sign is positive)
                                    ; and then overwrite location with 1 or 0
                                    ; as appropriate.

    ; ------------------------
    ; Handle NOT operator ($2C)
    ; ------------------------
    ; This overwrites the last value with 1 if it was zero else with zero
    ; if it was any other value.
    ;
    ; e.g. NOT 0 returns 1, NOT 1 returns 0, NOT -3 returns 0.
    ;
    ; The subroutine is also called directly from the end-tests of the comparison
    ; operator.

    ;; NOT
    ;; not
    L1AD5:  LD      A,(HL)          ; get exponent byte.
            NEG                     ; negate - sets carry if non-zero.
            CCF                     ; complement so carry set if zero, else reset.
            JR      L1AE0           ; forward to FP-0/1.

    ; -------------------
    ; Less than zero (32)
    ; -------------------
    ; Destructively test if last value on calculator stack is less than zero.
    ; Bit 7 of second byte will be set if so.

    ;; less-0
    L1ADB:  XOR     A               ; set xor mask to zero
                                    ; (carry will become set if sign is negative).

    ; transfer sign of mantissa to Carry Flag.

    ;; SIGN-TO-C
    L1ADC:  INC     HL              ; address 2nd byte.
            XOR     (HL)            ; bit 7 of HL will be set if number is negative.
            DEC     HL              ; address 1st byte again.
            RLCA                    ; rotate bit 7 of A to carry.

    ; -----------
    ; Zero or one
    ; -----------
    ; This routine places an integer value zero or one at the addressed location
    ; of calculator stack or MEM area. The value one is written if carry is set on
    ; entry else zero.

    ;; FP-0/1
    L1AE0:  PUSH    HL              ; save pointer to the first byte
            LD      B,$05           ; five bytes to do.

    ;; FP-loop
    L1AE3:  LD      (HL),$00        ; insert a zero.
            INC     HL              ;
            DJNZ    L1AE3           ; repeat.

            POP     HL              ;
            RET     NC              ;

            LD      (HL),$81        ; make value 1
            RET                     ; return.

    ; -----------------------
    ; Handle OR operator (07)
    ; -----------------------
    ; The Boolean OR operator. eg. X OR Y
    ; The result is zero if both values are zero else a non-zero value.
    ;
    ; e.g.    0 OR 0  returns 0.
    ;        -3 OR 0  returns -3.
    ;         0 OR -3 returns 1.
    ;        -3 OR 2  returns 1.
    ;
    ; A binary operation.
    ; On entry HL points to first operand (X) and DE to second operand (Y).

    ;; or
    L1AED:  LD      A,(DE)          ; fetch exponent of second number
            AND     A               ; test it.
            RET     Z               ; return if zero.

            SCF                     ; set carry flag
            JR      L1AE0           ; back to FP-0/1 to overwrite the first operand
                                    ; with the value 1.

    ; -----------------------------
    ; Handle number AND number (08)
    ; -----------------------------
    ; The Boolean AND operator.
    ;
    ; e.g.    -3 AND 2  returns -3.
    ;         -3 AND 0  returns 0.
    ;          0 and -2 returns 0.
    ;          0 and 0  returns 0.
    ;
    ; Compare with OR routine above.

    ;; no-&-no
    L1AF3:  LD      A,(DE)          ; fetch exponent of second number.
            AND     A               ; test it.
            RET     NZ              ; return if not zero.

            JR      L1AE0           ; back to FP-0/1 to overwrite the first operand
                                    ; with zero for return value.

    ; -----------------------------
    ; Handle string AND number (10)
    ; -----------------------------
    ; e.g. "YOU WIN" AND SCORE>99 will return the string if condition is true
    ; or the null string if false.

    ;; str-&-no
    L1AF8:  LD      A,(DE)          ; fetch exponent of second number.
            AND     A               ; test it.
            RET     NZ              ; return if number was not zero - the string
                                    ; is the result.

    ; if the number was zero (false) then the null string must be returned by
    ; altering the length of the string on the calculator stack to zero.

            PUSH    DE              ; save pointer to the now obsolete number
                                    ; (which will become the new STKEND)

            DEC     DE              ; point to the 5th byte of string descriptor.
            XOR     A               ; clear the accumulator.
            LD      (DE),A          ; place zero in high byte of length.
            DEC     DE              ; address low byte of length.
            LD      (DE),A          ; place zero there - now the null string.

            POP     DE              ; restore pointer - new STKEND.
            RET                     ; return.

    ; -----------------------------------
    ; Perform comparison ($09-$0E, $11-$16)
    ; -----------------------------------
    ; True binary operations.
    ;
    ; A single entry point is used to evaluate six numeric and six string
    ; comparisons. On entry, the calculator literal is in the B register and
    ; the two numeric values, or the two string parameters, are on the
    ; calculator stack.
    ; The individual bits of the literal are manipulated to group similar
    ; operations although the SUB 8 instruction does nothing useful and merely
    ; alters the string test bit.
    ; Numbers are compared by subtracting one from the other, strings are
    ; compared by comparing every character until a mismatch, or the end of one
    ; or both, is reached.
    ;
    ; Numeric Comparisons.
    ; --------------------
    ; The 'x>y' example is the easiest as it employs straight-thru logic.
    ; Number y is subtracted from x and the result tested for greater-0 yielding
    ; a final value 1 (true) or 0 (false).
    ; For 'x<y' the same logic is used but the two values are first swapped on the
    ; calculator stack.
    ; For 'x=y' NOT is applied to the subtraction result yielding true if the
    ; difference was zero and false with anything else.
    ; The first three numeric comparisons are just the opposite of the last three
    ; so the same processing steps are used and then a final NOT is applied.
    ;
    ; literal    Test   No  sub 8       ExOrNot  1st RRCA  exch sub  ?   End-Tests
    ; =========  ====   == ======== === ======== ========  ==== ===  =  === === ===
    ; no-l-eql   x<=y   09 00000001 dec 00000000 00000000  ---- x-y  ?  --- >0? NOT
    ; no-gr-eql  x>=y   0A 00000010 dec 00000001 10000000c swap y-x  ?  --- >0? NOT
    ; nos-neql   x<>y   0B 00000011 dec 00000010 00000001  ---- x-y  ?  NOT --- NOT
    ; no-grtr    x>y    0C 00000100  -  00000100 00000010  ---- x-y  ?  --- >0? ---
    ; no-less    x<y    0D 00000101  -  00000101 10000010c swap y-x  ?  --- >0? ---
    ; nos-eql    x=y    0E 00000110  -  00000110 00000011  ---- x-y  ?  NOT --- ---
    ;
    ;                                                           comp -> C/F
    ;                                                           ====    ===
    ; str-l-eql  x$<=y$ 11 00001001 dec 00001000 00000100  ---- x$y$ 0  !or >0? NOT
    ; str-gr-eql x$>=y$ 12 00001010 dec 00001001 10000100c swap y$x$ 0  !or >0? NOT
    ; strs-neql  x$<>y$ 13 00001011 dec 00001010 00000101  ---- x$y$ 0  !or >0? NOT
    ; str-grtr   x$>y$  14 00001100  -  00001100 00000110  ---- x$y$ 0  !or >0? ---
    ; str-less   x$<y$  15 00001101  -  00001101 10000110c swap y$x$ 0  !or >0? ---
    ; strs-eql   x$=y$  16 00001110  -  00001110 00000111  ---- x$y$ 0  !or >0? ---
    ;
    ; String comparisons are a little different in that the eql/neql carry flag
    ; from the 2nd RRCA is, as before, fed into the first of the end tests but
    ; along the way it gets modified by the comparison process. The result on the
    ; stack always starts off as zero and the carry fed in determines if NOT is
    ; applied to it. So the only time the greater-0 test is applied is if the
    ; stack holds zero which is not very efficient as the test will always yield
    ; zero. The most likely explanation is that there were once separate end tests
    ; for numbers and strings.

    ;; no-l-eql,etc.
    L1B03:  LD      A,B             ; transfer literal to accumulator.
            SUB     $08             ; subtract eight - which is not useful.

            BIT     2,A             ; isolate '>', '<', '='.

            JR      NZ,L1B0B        ; skip to EX-OR-NOT with these.

            DEC     A               ; else make $00-$02, $08-$0A to match bits 0-2.

    ;; EX-OR-NOT
    L1B0B:  RRCA                    ; the first RRCA sets carry for a swap.
            JR      NC,L1B16        ; forward to NU-OR-STR with other 8 cases

    ; for the other 4 cases the two values on the calculator stack are exchanged.

            PUSH    AF              ; save A and carry.
            PUSH    HL              ; save HL - pointer to first operand.
                                    ; (DE points to second operand).

            CALL    L1A72           ; routine exchange swaps the two values.
                                    ; (HL = second operand, DE = STKEND)

            POP     DE              ; DE = first operand
            EX      DE,HL           ; as we were.
            POP     AF              ; restore A and carry.

    ; Note. it would be better if the 2nd RRCA preceded the string test.
    ; It would save two duplicate bytes and if we also got rid of that sub 8
    ; at the beginning we wouldn't have to alter which bit we test.

    ;; NU-OR-STR
    L1B16:  BIT     2,A             ; test if a string comparison.
            JR      NZ,L1B21        ; forward to STRINGS if so.

    ; continue with numeric comparisons.

            RRCA                    ; 2nd RRCA causes eql/neql to set carry.
            PUSH    AF              ; save A and carry

            CALL    L174C           ; routine subtract leaves result on stack.
            JR      L1B54           ; forward to END-TESTS

    ; ---

    ;; STRINGS
    L1B21:  RRCA                    ; 2nd RRCA causes eql/neql to set carry.
            PUSH    AF              ; save A and carry.

            CALL    L13F8           ; routine STK-FETCH gets 2nd string params
            PUSH    DE              ; save start2 *.
            PUSH    BC              ; and the length.

            CALL    L13F8           ; routine STK-FETCH gets 1st string
                                    ; parameters - start in DE, length in BC.
            POP     HL              ; restore length of second to HL.

    ; A loop is now entered to compare, by subtraction, each corresponding character
    ; of the strings. For each successful match, the pointers are incremented and
    ; the lengths decreased and the branch taken back to here. If both string
    ; remainders become null at the same time, then an exact match exists.

    ;; BYTE-COMP
    L1B2C:  LD      A,H             ; test if the second string
            OR      L               ; is the null string and hold flags.

            EX      (SP),HL         ; put length2 on stack, bring start2 to HL *.
            LD      A,B             ; hi byte of length1 to A

            JR      NZ,L1B3D        ; forward to SEC-PLUS if second not null.

            OR      C               ; test length of first string.

    ;; SECND-LOW
    L1B33:  POP     BC              ; pop the second length off stack.
            JR      Z,L1B3A         ; forward to BOTH-NULL if first string is also
                                    ; of zero length.

    ; the true condition - first is longer than second (SECND-LESS)

            POP     AF              ; restore carry (set if eql/neql)
            CCF                     ; complement carry flag.
                                    ; Note. equality becomes false.
                                    ; Inequality is true. By swapping or applying
                                    ; a terminal 'not', all comparisons have been
                                    ; manipulated so that this is success path.
            JR      L1B50           ; forward to leave via STR-TEST

    ; ---
    ; the branch was here with a match

    ;; BOTH-NULL
    L1B3A:  POP     AF              ; restore carry - set for eql/neql
            JR      L1B50           ; forward to STR-TEST

    ; ---
    ; the branch was here when 2nd string not null and low byte of first is yet
    ; to be tested.

    ;; SEC-PLUS
    L1B3D:  OR      C               ; test the length of first string.
            JR      Z,L1B4D         ; forward to FRST-LESS if length is zero.

    ; both strings have at least one character left.

            LD      A,(DE)          ; fetch character of first string.
            SUB     (HL)            ; subtract with that of 2nd string.
            JR      C,L1B4D         ; forward to FRST-LESS if carry set

            JR      NZ,L1B33        ; back to SECND-LOW and then STR-TEST
                                    ; if not exact match.

            DEC     BC              ; decrease length of 1st string.
            INC     DE              ; increment 1st string pointer.

            INC     HL              ; increment 2nd string pointer.
            EX      (SP),HL         ; swap with length on stack
            DEC     HL              ; decrement 2nd string length
            JR      L1B2C           ; back to BYTE-COMP

    ; ---
    ;   the false condition.

    ;; FRST-LESS
    L1B4D:  POP     BC              ; discard length
            POP     AF              ; pop A
            AND     A               ; clear the carry for false result.

    ; ---
    ;   exact match and x$>y$ rejoin here

    ;; STR-TEST
    L1B50:  PUSH    AF              ; save A and carry

            RST     28H             ;; FP-CALC
            DEFB    $A0             ;;stk-zero      an initial false value.
            DEFB    $34             ;;end-calc

    ;   both numeric and string paths converge here.

    ;; END-TESTS
    L1B54:  POP     AF              ; pop carry  - will be set if eql/neql
            PUSH    AF              ; save it again.

            CALL    C,L1AD5         ; routine NOT sets true(1) if equal(0)
                                    ; or, for strings, applies true result.
            CALL    L1ACE           ; greater-0  ??????????

            POP     AF              ; pop A
            RRCA                    ; the third RRCA - test for '<=', '>=' or '<>'.
            CALL    NC,L1AD5        ; apply a terminal NOT if so.
            RET                     ; return.

    ; -------------------------
    ; String concatenation ($17)
    ; -------------------------
    ;   This literal combines two strings into one e.g. LET A$ = B$ + C$
    ;   The two parameters of the two strings to be combined are on the stack.

    ;; strs-add
    L1B62:  CALL    L13F8           ; routine STK-FETCH fetches string parameters
                                    ; and deletes calculator stack entry.
            PUSH    DE              ; save start address.
            PUSH    BC              ; and length.

            CALL    L13F8           ; routine STK-FETCH for first string
            POP     HL              ; re-fetch first length
            PUSH    HL              ; and save again
            PUSH    DE              ; save start of second string
            PUSH    BC              ; and its length.

            ADD     HL,BC           ; add the two lengths.
            LD      B,H             ; transfer to BC
            LD      C,L             ; and create
            RST     30H             ; BC-SPACES in workspace.
                                    ; DE points to start of space.

            CALL    L12C3           ; routine STK-STO-$ stores parameters
                                    ; of new string updating STKEND.

            POP     BC              ; length of first
            POP     HL              ; address of start
            LD      A,B             ; test for
            OR      C               ; zero length.
            JR      Z,L1B7D         ; to OTHER-STR if null string

            LDIR                    ; copy string to workspace.

    ;; OTHER-STR
    L1B7D:  POP     BC              ; now second length
            POP     HL              ; and start of string
            LD      A,B             ; test this one
            OR      C               ; for zero length
            JR      Z,L1B85         ; skip forward to STK-PNTRS if so as complete.

            LDIR                    ; else copy the bytes.
                                    ; and continue into next routine which
                                    ; sets the calculator stack pointers.

    ; --------------------
    ; Check stack pointers
    ; --------------------
    ;   Register DE is set to STKEND and HL, the result pointer, is set to five
    ;   locations below this.
    ;   This routine is used when it is inconvenient to save these values at the
    ;   time the calculator stack is manipulated due to other activity on the
    ;   machine stack.
    ;   This routine is also used to terminate the VAL routine for
    ;   the same reason and to initialize the calculator stack at the start of
    ;   the CALCULATE routine.

    ;; STK-PNTRS
    L1B85:  LD      HL,($401C)      ; fetch STKEND value from system variable.
            LD      DE,$FFFB        ; the value -5
            PUSH    HL              ; push STKEND value.

            ADD     HL,DE           ; subtract 5 from HL.

            POP     DE              ; pop STKEND to DE.
            RET                     ; return.

    ; ----------------
    ; Handle CHR$ (2B)
    ; ----------------
    ;   This function returns a single character string that is a result of
    ;   converting a number in the range 0-255 to a string e.g. CHR$ 38 = "A".
    ;   Note. the ZX81 does not have an ASCII character set.

    ;; chrs
    L1B8F:  CALL    L15CD           ; routine FP-TO-A puts the number in A.

            JR      C,L1BA2         ; forward to REPORT-Bd if overflow
            JR      NZ,L1BA2        ; forward to REPORT-Bd if negative

            PUSH    AF              ; save the argument.

            LD      BC,$0001        ; one space required.
            RST     30H             ; BC-SPACES makes DE point to start

            POP     AF              ; restore the number.

            LD      (DE),A          ; and store in workspace

            CALL    L12C3           ; routine STK-STO-$ stacks descriptor.

            EX      DE,HL           ; make HL point to result and DE to STKEND.
            RET                     ; return.

    ; ---

    ;; REPORT-Bd
    L1BA2:  RST     08H             ; ERROR-1
            DEFB    $0A             ; Error Report: Integer out of range

    ; ----------------------------
    ; Handle VAL ($1A)
    ; ----------------------------
    ;   VAL treats the characters in a string as a numeric expression.
    ;       e.g. VAL "2.3" = 2.3, VAL "2+4" = 6, VAL ("2" + "4") = 24.

    ;; val
    L1BA4:  LD      HL,($4016)      ; fetch value of system variable CH_ADD
            PUSH    HL              ; and save on the machine stack.

            CALL    L13F8           ; routine STK-FETCH fetches the string operand
                                    ; from calculator stack.

            PUSH    DE              ; save the address of the start of the string.
            INC     BC              ; increment the length for a carriage return.

            RST     30H             ; BC-SPACES creates the space in workspace.
            POP     HL              ; restore start of string to HL.
            LD      ($4016),DE      ; load CH_ADD with start DE in workspace.

            PUSH    DE              ; save the start in workspace
            LDIR                    ; copy string from program or variables or
                                    ; workspace to the workspace area.
            EX      DE,HL           ; end of string + 1 to HL
            DEC     HL              ; decrement HL to point to end of new area.
            LD      (HL),$76        ; insert a carriage return at end.
                                    ; ZX81 has a non-ASCII character set
            RES     7,(IY+$01)      ; update FLAGS  - signal checking syntax.
            CALL    L0D92           ; routine CLASS-06 - SCANNING evaluates string
                                    ; expression and checks for integer result.

            CALL    L0D22           ; routine CHECK-2 checks for carriage return.

            POP     HL              ; restore start of string in workspace.

            LD      ($4016),HL      ; set CH_ADD to the start of the string again.
            SET     7,(IY+$01)      ; update FLAGS  - signal running program.
            CALL    L0F55           ; routine SCANNING evaluates the string
                                    ; in full leaving result on calculator stack.

            POP     HL              ; restore saved character address in program.
            LD      ($4016),HL      ; and reset the system variable CH_ADD.

            JR      L1B85           ; back to exit via STK-PNTRS.
                                    ; resetting the calculator stack pointers
                                    ; HL and DE from STKEND as it wasn't possible
                                    ; to preserve them during this routine.

    ; ----------------
    ; Handle STR$ (2A)
    ; ----------------
    ;   This function returns a string representation of a numeric argument.
    ;   The method used is to trick the PRINT-FP routine into thinking it
    ;   is writing to a collapsed display file when in fact it is writing to
    ;   string workspace.
    ;   If there is already a newline at the intended print position and the
    ;   column count has not been reduced to zero then the print routine
    ;   assumes that there is only 1K of RAM and the screen memory, like the rest
    ;   of dynamic memory, expands as necessary using calls to the ONE-SPACE
    ;   routine. The screen is character-mapped not bit-mapped.

    ;; str$
    L1BD5:  LD      BC,$0001        ; create an initial byte in workspace
            RST     30H             ; using BC-SPACES restart.

            LD      (HL),$76        ; place a carriage return there.

            LD      HL,($4039)      ; fetch value of S_POSN column/line
            PUSH    HL              ; and preserve on stack.

            LD      L,$FF           ; make column value high to create a
                                    ; contrived buffer of length 254.
            LD      ($4039),HL      ; and store in system variable S_POSN.

            LD      HL,($400E)      ; fetch value of DF_CC
            PUSH    HL              ; and preserve on stack also.

            LD      ($400E),DE      ; now set DF_CC which normally addresses
                                    ; somewhere in the display file to the start
                                    ; of workspace.
            PUSH    DE              ; save the start of new string.

            CALL    L15DB           ; routine PRINT-FP.

            POP     DE              ; retrieve start of string.

            LD      HL,($400E)      ; fetch end of string from DF_CC.
            AND     A               ; prepare for true subtraction.
            SBC     HL,DE           ; subtract to give length.

            LD      B,H             ; and transfer to the BC
            LD      C,L             ; register.

            POP     HL              ; restore original
            LD      ($400E),HL      ; DF_CC value

            POP     HL              ; restore original
            LD      ($4039),HL      ; S_POSN values.

            CALL    L12C3           ; routine STK-STO-$ stores the string
                                    ; descriptor on the calculator stack.

            EX      DE,HL           ; HL = last value, DE = STKEND.
            RET                     ; return.

    ; -------------------
    ; THE 'CODE' FUNCTION
    ; -------------------
    ; (offset $19: 'code')
    ;   Returns the code of a character or first character of a string
    ;   e.g. CODE "AARDVARK" = 38  (not 65 as the ZX81 does not have an ASCII
    ;   character set).

    ;; code
    L1C06:  CALL    L13F8           ; routine STK-FETCH to fetch and delete the
                                    ; string parameters.
                                    ; DE points to the start, BC holds the length.
            LD      A,B             ; test length
            OR      C               ; of the string.
            JR      Z,L1C0E         ; skip to STK-CODE with zero if the null string.

            LD      A,(DE)          ; else fetch the first character.

    ;; STK-CODE
    L1C0E:  JP      L151D           ; jump back to STACK-A (with memory check)

    ; --------------------
    ; THE 'LEN' SUBROUTINE
    ; --------------------
    ; (offset $1b: 'len')
    ;   Returns the length of a string.
    ;   In Sinclair BASIC strings can be more than twenty thousand characters long
    ;   so a sixteen-bit register is required to store the length

    ;; len
    L1C11:  CALL    L13F8           ; routine STK-FETCH to fetch and delete the
                                    ; string parameters from the calculator stack.
                                    ; register BC now holds the length of string.

            JP      L1520           ; jump back to STACK-BC to save result on the
                                    ; calculator stack (with memory check).

    ; -------------------------------------
    ; THE 'DECREASE THE COUNTER' SUBROUTINE
    ; -------------------------------------
    ; (offset $31: 'dec-jr-nz')
    ;   The calculator has an instruction that decrements a single-byte
    ;   pseudo-register and makes consequential relative jumps just like
    ;   the Z80's DJNZ instruction.

    ;; dec-jr-nz
    L1C17:  EXX                     ; switch in set that addresses code

            PUSH    HL              ; save pointer to offset byte
            LD      HL,$401E        ; address BREG in system variables
            DEC     (HL)            ; decrement it
            POP     HL              ; restore pointer

            JR      NZ,L1C24        ; to JUMP-2 if not zero

            INC     HL              ; step past the jump length.
            EXX                     ; switch in the main set.
            RET                     ; return.

    ;   Note. as a general rule the calculator avoids using the IY register
    ;   otherwise the cumbersome 4 instructions in the middle could be replaced by
    ;   dec (iy+$xx) - using three instruction bytes instead of six.

    ; ---------------------
    ; THE 'JUMP' SUBROUTINE
    ; ---------------------
    ; (Offset $2F; 'jump')
    ;   This enables the calculator to perform relative jumps just like
    ;   the Z80 chip's JR instruction.
    ;   This is one of the few routines to be polished for the ZX Spectrum.
    ;   See, without looking at the ZX Spectrum ROM, if you can get rid of the
    ;   relative jump.

    ;; jump
    ;; JUMP
    L1C23:  EXX                     ;switch in pointer set

    ;; JUMP-2
    L1C24:  LD      E,(HL)          ; the jump byte 0-127 forward, 128-255 back.
            XOR     A               ; clear accumulator.
            BIT     7,E             ; test if negative jump
            JR      Z,L1C2B         ; skip, if positive, to JUMP-3.

            CPL                     ; else change to $FF.

    ;; JUMP-3
    L1C2B:  LD      D,A             ; transfer to high byte.
            ADD     HL,DE           ; advance calculator pointer forward or back.

            EXX                     ; switch out pointer set.
            RET                     ; return.

    ; -----------------------------
    ; THE 'JUMP ON TRUE' SUBROUTINE
    ; -----------------------------
    ; (Offset $00; 'jump-true')
    ;   This enables the calculator to perform conditional relative jumps
    ;   dependent on whether the last test gave a true result
    ;   On the ZX81, the exponent will be zero for zero or else $81 for one.

    ;; jump-true
    L1C2F:  LD      A,(DE)          ; collect exponent byte

            AND     A               ; is result 0 or 1 ?
            JR      NZ,L1C23        ; back to JUMP if true (1).

            EXX                     ; else switch in the pointer set.
            INC     HL              ; step past the jump length.
            EXX                     ; switch in the main set.
            RET                     ; return.

    ; ------------------------
    ; THE 'MODULUS' SUBROUTINE
    ; ------------------------
    ; ( Offset $2E: 'n-mod-m' )
    ; ( i1, i2 -- i3, i4 )
    ;   The subroutine calculate N mod M where M is the positive integer, the
    ;   'last value' on the calculator stack and N is the integer beneath.
    ;   The subroutine returns the integer quotient as the last value and the
    ;   remainder as the value beneath.
    ;   e.g.    17 MOD 3 = 5 remainder 2
    ;   It is invoked during the calculation of a random number and also by
    ;   the PRINT-FP routine.

    ;; n-mod-m
    L1C37:  RST     28H             ;; FP-CALC          17, 3.
            DEFB    $C0             ;;st-mem-0          17, 3.
            DEFB    $02             ;;delete            17.
            DEFB    $2D             ;;duplicate         17, 17.
            DEFB    $E0             ;;get-mem-0         17, 17, 3.
            DEFB    $05             ;;division          17, 17/3.
            DEFB    $24             ;;int               17, 5.
            DEFB    $E0             ;;get-mem-0         17, 5, 3.
            DEFB    $01             ;;exchange          17, 3, 5.
            DEFB    $C0             ;;st-mem-0          17, 3, 5.
            DEFB    $04             ;;multiply          17, 15.
            DEFB    $03             ;;subtract          2.
            DEFB    $E0             ;;get-mem-0         2, 5.
            DEFB    $34             ;;end-calc          2, 5.

            RET                     ; return.

    ; ----------------------
    ; THE 'INTEGER' FUNCTION
    ; ----------------------
    ; (offset $24: 'int')
    ;   This function returns the integer of x, which is just the same as truncate
    ;   for positive numbers. The truncate literal truncates negative numbers
    ;   upwards so that -3.4 gives -3 whereas the BASIC INT function has to
    ;   truncate negative numbers down so that INT -3.4 is 4.
    ;   It is best to work through using, say, plus or minus 3.4 as examples.

    ;; int
    L1C46:  RST     28H             ;; FP-CALC              x.    (= 3.4 or -3.4).
            DEFB    $2D             ;;duplicate             x, x.
            DEFB    $32             ;;less-0                x, (1/0)
            DEFB    $00             ;;jump-true             x, (1/0)
            DEFB    $04             ;;to L1C46, X-NEG

            DEFB    $36             ;;truncate              trunc 3.4 = 3.
            DEFB    $34             ;;end-calc              3.

            RET                     ; return with + int x on stack.

    ;; X-NEG
    L1C4E:  DEFB    $2D             ;;duplicate             -3.4, -3.4.
            DEFB    $36             ;;truncate              -3.4, -3.
            DEFB    $C0             ;;st-mem-0              -3.4, -3.
            DEFB    $03             ;;subtract              -.4
            DEFB    $E0             ;;get-mem-0             -.4, -3.
            DEFB    $01             ;;exchange              -3, -.4.
            DEFB    $2C             ;;not                   -3, (0).
            DEFB    $00             ;;jump-true             -3.
            DEFB    $03             ;;to L1C59, EXIT        -3.

            DEFB    $A1             ;;stk-one               -3, 1.
            DEFB    $03             ;;subtract              -4.

    ;; EXIT
    L1C59:  DEFB    $34             ;;end-calc              -4.

            RET                     ; return.

    ; ----------------
    ; Exponential (23)
    ; ----------------
    ;
    ;

    ;; EXP
    ;; exp
    L1C5B:  RST     28H             ;; FP-CALC
            DEFB    $30             ;;stk-data
            DEFB    $F1             ;;Exponent: $81, Bytes: 4
            DEFB    $38,$AA,$3B,$29 ;;
            DEFB    $04             ;;multiply
            DEFB    $2D             ;;duplicate
            DEFB    $24             ;;int
            DEFB    $C3             ;;st-mem-3
            DEFB    $03             ;;subtract
            DEFB    $2D             ;;duplicate
            DEFB    $0F             ;;addition
            DEFB    $A1             ;;stk-one
            DEFB    $03             ;;subtract
            DEFB    $88             ;;series-08
            DEFB    $13             ;;Exponent: $63, Bytes: 1
            DEFB    $36             ;;(+00,+00,+00)
            DEFB    $58             ;;Exponent: $68, Bytes: 2
            DEFB    $65,$66         ;;(+00,+00)
            DEFB    $9D             ;;Exponent: $6D, Bytes: 3
            DEFB    $78,$65,$40     ;;(+00)
            DEFB    $A2             ;;Exponent: $72, Bytes: 3
            DEFB    $60,$32,$C9     ;;(+00)
            DEFB    $E7             ;;Exponent: $77, Bytes: 4
            DEFB    $21,$F7,$AF,$24 ;;
            DEFB    $EB             ;;Exponent: $7B, Bytes: 4
            DEFB    $2F,$B0,$B0,$14 ;;
            DEFB    $EE             ;;Exponent: $7E, Bytes: 4
            DEFB    $7E,$BB,$94,$58 ;;
            DEFB    $F1             ;;Exponent: $81, Bytes: 4
            DEFB    $3A,$7E,$F8,$CF ;;
            DEFB    $E3             ;;get-mem-3
            DEFB    $34             ;;end-calc

            CALL    L15CD           ; routine FP-TO-A
            JR      NZ,L1C9B        ; to N-NEGTV

            JR      C,L1C99         ; to REPORT-6b

            ADD     A,(HL)          ;
            JR      NC,L1CA2        ; to RESULT-OK

    ;; REPORT-6b
    L1C99:  RST     08H             ; ERROR-1
            DEFB    $05             ; Error Report: Number too big

    ;; N-NEGTV
    L1C9B:  JR      C,L1CA4         ; to RSLT-ZERO

            SUB     (HL)            ;
            JR      NC,L1CA4        ; to RSLT-ZERO

            NEG                     ; Negate

    ;; RESULT-OK
    L1CA2:  LD      (HL),A          ;
            RET                     ; return.

    ;; RSLT-ZERO
    L1CA4:  RST     28H             ;; FP-CALC
            DEFB    $02             ;;delete
            DEFB    $A0             ;;stk-zero
            DEFB    $34             ;;end-calc

            RET                     ; return.

    ; --------------------------------
    ; THE 'NATURAL LOGARITHM' FUNCTION
    ; --------------------------------
    ; (offset $22: 'ln')
    ;   Like the ZX81 itself, 'natural' logarithms came from Scotland.
    ;   They were devised in 1614 by well-traveled Scotsman John Napier who noted
    ;   "Nothing doth more molest and hinder calculators than the multiplications,
    ;    divisions, square and cubical extractions of great numbers".
    ;
    ;   Napier's logarithms enabled the above operations to be accomplished by
    ;   simple addition and subtraction simplifying the navigational and
    ;   astronomical calculations which beset his age.
    ;   Napier's logarithms were quickly overtaken by logarithms to the base 10
    ;   devised, in conjunction with Napier, by Henry Briggs a Cambridge-educated
    ;   professor of Geometry at Oxford University. These simplified the layout
    ;   of the tables enabling humans to easily scale calculations.
    ;
    ;   It is only recently with the introduction of pocket calculators and
    ;   computers like the ZX81 that natural logarithms are once more at the fore,
    ;   although some computers retain logarithms to the base ten.
    ;   'Natural' logarithms are powers to the base 'e', which like 'pi' is a
    ;   naturally occurring number in branches of mathematics.
    ;   Like 'pi' also, 'e' is an irrational number and starts 2.718281828...
    ;
    ;   The tabular use of logarithms was that to multiply two numbers one looked
    ;   up their two logarithms in the tables, added them together and then looked
    ;   for the result in a table of antilogarithms to give the desired product.
    ;
    ;   The EXP function is the BASIC equivalent of a calculator's 'antiln' function
    ;   and by picking any two numbers, 1.72 and 6.89 say,
    ;     10 PRINT EXP ( LN 1.72 + LN 6.89 )
    ;   will give just the same result as
    ;     20 PRINT 1.72 * 6.89.
    ;   Division is accomplished by subtracting the two logs.
    ;
    ;   Napier also mentioned "square and cubicle extractions".
    ;   To raise a number to the power 3, find its 'ln', multiply by 3 and find the
    ;   'antiln'.  e.g. PRINT EXP( LN 4 * 3 )  gives 64.
    ;   Similarly to find the n'th root divide the logarithm by 'n'.
    ;   The ZX81 ROM used PRINT EXP ( LN 9 / 2 ) to find the square root of the
    ;   number 9. The Napieran square root function is just a special case of
    ;   the 'to_power' function. A cube root or indeed any root/power would be just
    ;   as simple.

    ;   First test that the argument to LN is a positive, non-zero number.

    ;; ln
    L1CA9:  RST     28H             ;; FP-CALC
            DEFB    $2D             ;;duplicate
            DEFB    $33             ;;greater-0
            DEFB    $00             ;;jump-true
            DEFB    $04             ;;to L1CB1, VALID

            DEFB    $34             ;;end-calc

    ;; REPORT-Ab
    L1CAF:  RST     08H             ; ERROR-1
            DEFB    $09             ; Error Report: Invalid argument

    ;; VALID
    L1CB1:  DEFB    $A0             ;;stk-zero              Note. not
            DEFB    $02             ;;delete                necessary.
            DEFB    $34             ;;end-calc
            LD      A,(HL)          ;

            LD      (HL),$80        ;
            CALL    L151D           ; routine STACK-A

            RST     28H             ;; FP-CALC
            DEFB    $30             ;;stk-data
            DEFB    $38             ;;Exponent: $88, Bytes: 1
            DEFB    $00             ;;(+00,+00,+00)
            DEFB    $03             ;;subtract
            DEFB    $01             ;;exchange
            DEFB    $2D             ;;duplicate
            DEFB    $30             ;;stk-data
            DEFB    $F0             ;;Exponent: $80, Bytes: 4
            DEFB    $4C,$CC,$CC,$CD ;;
            DEFB    $03             ;;subtract
            DEFB    $33             ;;greater-0
            DEFB    $00             ;;jump-true
            DEFB    $08             ;;to L1CD2, GRE.8

            DEFB    $01             ;;exchange
            DEFB    $A1             ;;stk-one
            DEFB    $03             ;;subtract
            DEFB    $01             ;;exchange
            DEFB    $34             ;;end-calc

            INC     (HL)            ;

            RST     28H             ;; FP-CALC

    ;; GRE.8
    L1CD2:  DEFB    $01             ;;exchange
            DEFB    $30             ;;stk-data
            DEFB    $F0             ;;Exponent: $80, Bytes: 4
            DEFB    $31,$72,$17,$F8 ;;
            DEFB    $04             ;;multiply
            DEFB    $01             ;;exchange
            DEFB    $A2             ;;stk-half
            DEFB    $03             ;;subtract
            DEFB    $A2             ;;stk-half
            DEFB    $03             ;;subtract
            DEFB    $2D             ;;duplicate
            DEFB    $30             ;;stk-data
            DEFB    $32             ;;Exponent: $82, Bytes: 1
            DEFB    $20             ;;(+00,+00,+00)
            DEFB    $04             ;;multiply
            DEFB    $A2             ;;stk-half
            DEFB    $03             ;;subtract
            DEFB    $8C             ;;series-0C
            DEFB    $11             ;;Exponent: $61, Bytes: 1
            DEFB    $AC             ;;(+00,+00,+00)
            DEFB    $14             ;;Exponent: $64, Bytes: 1
            DEFB    $09             ;;(+00,+00,+00)
            DEFB    $56             ;;Exponent: $66, Bytes: 2
            DEFB    $DA,$A5         ;;(+00,+00)
            DEFB    $59             ;;Exponent: $69, Bytes: 2
            DEFB    $30,$C5         ;;(+00,+00)
            DEFB    $5C             ;;Exponent: $6C, Bytes: 2
            DEFB    $90,$AA         ;;(+00,+00)
            DEFB    $9E             ;;Exponent: $6E, Bytes: 3
            DEFB    $70,$6F,$61     ;;(+00)
            DEFB    $A1             ;;Exponent: $71, Bytes: 3
            DEFB    $CB,$DA,$96     ;;(+00)
            DEFB    $A4             ;;Exponent: $74, Bytes: 3
            DEFB    $31,$9F,$B4     ;;(+00)
            DEFB    $E7             ;;Exponent: $77, Bytes: 4
            DEFB    $A0,$FE,$5C,$FC ;;
            DEFB    $EA             ;;Exponent: $7A, Bytes: 4
            DEFB    $1B,$43,$CA,$36 ;;
            DEFB    $ED             ;;Exponent: $7D, Bytes: 4
            DEFB    $A7,$9C,$7E,$5E ;;
            DEFB    $F0             ;;Exponent: $80, Bytes: 4
            DEFB    $6E,$23,$80,$93 ;;
            DEFB    $04             ;;multiply
            DEFB    $0F             ;;addition
            DEFB    $34             ;;end-calc

            RET                     ; return.

    ; -----------------------------
    ; THE 'TRIGONOMETRIC' FUNCTIONS
    ; -----------------------------
    ;   Trigonometry is rocket science. It is also used by carpenters and pyramid
    ;   builders.
    ;   Some uses can be quite abstract but the principles can be seen in simple
    ;   right-angled triangles. Triangles have some special properties -
    ;
    ;   1) The sum of the three angles is always PI radians (180 degrees).
    ;      Very helpful if you know two angles and wish to find the third.
    ;   2) In any right-angled triangle the sum of the squares of the two shorter
    ;      sides is equal to the square of the longest side opposite the right-angle.
    ;      Very useful if you know the length of two sides and wish to know the
    ;      length of the third side.
    ;   3) Functions sine, cosine and tangent enable one to calculate the length
    ;      of an unknown side when the length of one other side and an angle is
    ;      known.
    ;   4) Functions arcsin, arccosine and arctan enable one to calculate an unknown
    ;      angle when the length of two of the sides is known.

    ; --------------------------------
    ; THE 'REDUCE ARGUMENT' SUBROUTINE
    ; --------------------------------
    ; (offset $35: 'get-argt')
    ;
    ;   This routine performs two functions on the angle, in radians, that forms
    ;   the argument to the sine and cosine functions.
    ;   First it ensures that the angle 'wraps round'. That if a ship turns through
    ;   an angle of, say, 3*PI radians (540 degrees) then the net effect is to turn
    ;   through an angle of PI radians (180 degrees).
    ;   Secondly it converts the angle in radians to a fraction of a right angle,
    ;   depending within which quadrant the angle lies, with the periodicity
    ;   resembling that of the desired sine value.
    ;   The result lies in the range -1 to +1.
    ;
    ;                       90 deg.
    ;
    ;                       (pi/2)
    ;                II       +1        I
    ;                         |
    ;          sin+      |\   |   /|    sin+
    ;          cos-      | \  |  / |    cos+
    ;          tan-      |  \ | /  |    tan+
    ;                    |   \|/)  |
    ;   180 deg. (pi) 0 -|----+----|-- 0  (0)   0 degrees
    ;                    |   /|\   |
    ;          sin-      |  / | \  |    sin-
    ;          cos-      | /  |  \ |    cos+
    ;          tan+      |/   |   \|    tan-
    ;                         |
    ;                III      -1       IV
    ;                       (3pi/2)
    ;
    ;                       270 deg.

    ;; get-argt
    L1D18:  RST     28H             ;; FP-CALC         X.
            DEFB    $30             ;;stk-data
            DEFB    $EE             ;;Exponent: $7E,
                                    ;;Bytes: 4
            DEFB    $22,$F9,$83,$6E ;;                 X, 1/(2*PI)
            DEFB    $04             ;;multiply         X/(2*PI) = fraction

            DEFB    $2D             ;;duplicate
            DEFB    $A2             ;;stk-half
            DEFB    $0F             ;;addition
            DEFB    $24             ;;int

            DEFB    $03             ;;subtract         now range -.5 to .5

            DEFB    $2D             ;;duplicate
            DEFB    $0F             ;;addition         now range -1 to 1.
            DEFB    $2D             ;;duplicate
            DEFB    $0F             ;;addition         now range -2 to 2.

    ;   quadrant I (0 to +1) and quadrant IV (-1 to 0) are now correct.
    ;   quadrant II ranges +1 to +2.
    ;   quadrant III ranges -2 to -1.

            DEFB    $2D             ;;duplicate        Y, Y.
            DEFB    $27             ;;abs              Y, abs(Y).    range 1 to 2
            DEFB    $A1             ;;stk-one          Y, abs(Y), 1.
            DEFB    $03             ;;subtract         Y, abs(Y)-1.  range 0 to 1
            DEFB    $2D             ;;duplicate        Y, Z, Z.
            DEFB    $33             ;;greater-0        Y, Z, (1/0).

            DEFB    $C0             ;;st-mem-0         store as possible sign
                                    ;;                 for cosine function.

            DEFB    $00             ;;jump-true
            DEFB    $04             ;;to L1D35, ZPLUS  with quadrants II and III

    ;   else the angle lies in quadrant I or IV and value Y is already correct.

            DEFB    $02             ;;delete          Y    delete test value.
            DEFB    $34             ;;end-calc        Y.

            RET                     ; return.         with Q1 and Q4 >>>

    ;   The branch was here with quadrants II (0 to 1) and III (1 to 0).
    ;   Y will hold -2 to -1 if this is quadrant III.

    ;; ZPLUS
    L1D35:  DEFB    $A1             ;;stk-one         Y, Z, 1
            DEFB    $03             ;;subtract        Y, Z-1.       Q3 = 0 to -1
            DEFB    $01             ;;exchange        Z-1, Y.
            DEFB    $32             ;;less-0          Z-1, (1/0).
            DEFB    $00             ;;jump-true       Z-1.
            DEFB    $02             ;;to L1D3C, YNEG
                                    ;;if angle in quadrant III

    ;   else angle is within quadrant II (-1 to 0)

            DEFB    $18             ;;negate          range +1 to 0

    ;; YNEG
    L1D3C:  DEFB    $34             ;;end-calc        quadrants II and III correct.

            RET                     ; return.

    ; ---------------------
    ; THE 'COSINE' FUNCTION
    ; ---------------------
    ; (offset $1D: 'cos')
    ;   Cosines are calculated as the sine of the opposite angle rectifying the
    ;   sign depending on the quadrant rules.
    ;
    ;
    ;             /|
    ;          h /y|
    ;           /  |o
    ;          /x  |
    ;         /----|
    ;           a
    ;
    ;   The cosine of angle x is the adjacent side (a) divided by the hypotenuse 1.
    ;   However if we examine angle y then a/h is the sine of that angle.
    ;   Since angle x plus angle y equals a right-angle, we can find angle y by
    ;   subtracting angle x from pi/2.
    ;   However it's just as easy to reduce the argument first and subtract the
    ;   reduced argument from the value 1 (a reduced right-angle).
    ;   It's even easier to subtract 1 from the angle and rectify the sign.
    ;   In fact, after reducing the argument, the absolute value of the argument
    ;   is used and rectified using the test result stored in mem-0 by 'get-argt'
    ;   for that purpose.

    ;; cos
    L1D3E:  RST     28H             ;; FP-CALC              angle in radians.
            DEFB    $35             ;;get-argt              X       reduce -1 to +1

            DEFB    $27             ;;abs                   ABS X   0 to 1
            DEFB    $A1             ;;stk-one               ABS X, 1.
            DEFB    $03             ;;subtract              now opposite angle
                                    ;;                      though negative sign.
            DEFB    $E0             ;;get-mem-0             fetch sign indicator.
            DEFB    $00             ;;jump-true
            DEFB    $06             ;;fwd to L1D4B, C-ENT
                                    ;;forward to common code if in QII or QIII

            DEFB    $18             ;;negate                else make positive.
            DEFB    $2F             ;;jump
            DEFB    $03             ;;fwd to L1D4B, C-ENT
                                    ;;with quadrants QI and QIV

    ; -------------------
    ; THE 'SINE' FUNCTION
    ; -------------------
    ; (offset $1C: 'sin')
    ;   This is a fundamental transcendental function from which others such as cos
    ;   and tan are directly, or indirectly, derived.
    ;   It uses the series generator to produce Chebyshev polynomials.
    ;
    ;
    ;             /|
    ;          1 / |
    ;           /  |x
    ;          /a  |
    ;         /----|
    ;           y
    ;
    ;   The 'get-argt' function is designed to modify the angle and its sign
    ;   in line with the desired sine value and afterwards it can launch straight
    ;   into common code.

    ;; sin
    L1D49:  RST     28H             ;; FP-CALC      angle in radians
            DEFB    $35             ;;get-argt      reduce - sign now correct.

    ;; C-ENT
    L1D4B:  DEFB    $2D             ;;duplicate
            DEFB    $2D             ;;duplicate
            DEFB    $04             ;;multiply
            DEFB    $2D             ;;duplicate
            DEFB    $0F             ;;addition
            DEFB    $A1             ;;stk-one
            DEFB    $03             ;;subtract

            DEFB    $86             ;;series-06
            DEFB    $14             ;;Exponent: $64, Bytes: 1
            DEFB    $E6             ;;(+00,+00,+00)
            DEFB    $5C             ;;Exponent: $6C, Bytes: 2
            DEFB    $1F,$0B         ;;(+00,+00)
            DEFB    $A3             ;;Exponent: $73, Bytes: 3
            DEFB    $8F,$38,$EE     ;;(+00)
            DEFB    $E9             ;;Exponent: $79, Bytes: 4
            DEFB    $15,$63,$BB,$23 ;;
            DEFB    $EE             ;;Exponent: $7E, Bytes: 4
            DEFB    $92,$0D,$CD,$ED ;;
            DEFB    $F1             ;;Exponent: $81, Bytes: 4
            DEFB    $23,$5D,$1B,$EA ;;

            DEFB    $04             ;;multiply
            DEFB    $34             ;;end-calc

            RET                     ; return.

    ; ----------------------
    ; THE 'TANGENT' FUNCTION
    ; ----------------------
    ; (offset $1E: 'tan')
    ;
    ;   Evaluates tangent x as    sin(x) / cos(x).
    ;
    ;
    ;             /|
    ;          h / |
    ;           /  |o
    ;          /x  |
    ;         /----|
    ;           a
    ;
    ;   The tangent of angle x is the ratio of the length of the opposite side
    ;   divided by the length of the adjacent side. As the opposite length can
    ;   be calculates using sin(x) and the adjacent length using cos(x) then
    ;   the tangent can be defined in terms of the previous two functions.

    ;   Error 6 if the argument, in radians, is too close to one like pi/2
    ;   which has an infinite tangent. e.g. PRINT TAN (PI/2)  evaluates as 1/0.
    ;   Similarly PRINT TAN (3*PI/2), TAN (5*PI/2) etc.

    ;; tan
    L1D6E:  RST     28H             ;; FP-CALC          x.
            DEFB    $2D             ;;duplicate         x, x.
            DEFB    $1C             ;;sin               x, sin x.
            DEFB    $01             ;;exchange          sin x, x.
            DEFB    $1D             ;;cos               sin x, cos x.
            DEFB    $05             ;;division          sin x/cos x (= tan x).
            DEFB    $34             ;;end-calc          tan x.

            RET                     ; return.

    ; ---------------------
    ; THE 'ARCTAN' FUNCTION
    ; ---------------------
    ; (Offset $21: 'atn')
    ;   The inverse tangent function with the result in radians.
    ;   This is a fundamental transcendental function from which others such as
    ;   asn and acs are directly, or indirectly, derived.
    ;   It uses the series generator to produce Chebyshev polynomials.

    ;; atn
    L1D76:  LD      A,(HL)          ; fetch exponent
            CP      $81             ; compare to that for 'one'
            JR      C,L1D89         ; forward, if less, to SMALL

            RST     28H             ;; FP-CALC      X.
            DEFB    $A1             ;;stk-one
            DEFB    $18             ;;negate
            DEFB    $01             ;;exchange
            DEFB    $05             ;;division
            DEFB    $2D             ;;duplicate
            DEFB    $32             ;;less-0
            DEFB    $A3             ;;stk-pi/2
            DEFB    $01             ;;exchange
            DEFB    $00             ;;jump-true
            DEFB    $06             ;;to L1D8B, CASES

            DEFB    $18             ;;negate
            DEFB    $2F             ;;jump
            DEFB    $03             ;;to L1D8B, CASES

    ; ---

    ;; SMALL
    L1D89:  RST     28H             ;; FP-CALC
            DEFB    $A0             ;;stk-zero

    ;; CASES
    L1D8B:  DEFB    $01             ;;exchange
            DEFB    $2D             ;;duplicate
            DEFB    $2D             ;;duplicate
            DEFB    $04             ;;multiply
            DEFB    $2D             ;;duplicate
            DEFB    $0F             ;;addition
            DEFB    $A1             ;;stk-one
            DEFB    $03             ;;subtract

            DEFB    $8C             ;;series-0C
            DEFB    $10             ;;Exponent: $60, Bytes: 1
            DEFB    $B2             ;;(+00,+00,+00)
            DEFB    $13             ;;Exponent: $63, Bytes: 1
            DEFB    $0E             ;;(+00,+00,+00)
            DEFB    $55             ;;Exponent: $65, Bytes: 2
            DEFB    $E4,$8D         ;;(+00,+00)
            DEFB    $58             ;;Exponent: $68, Bytes: 2
            DEFB    $39,$BC         ;;(+00,+00)
            DEFB    $5B             ;;Exponent: $6B, Bytes: 2
            DEFB    $98,$FD         ;;(+00,+00)
            DEFB    $9E             ;;Exponent: $6E, Bytes: 3
            DEFB    $00,$36,$75     ;;(+00)
            DEFB    $A0             ;;Exponent: $70, Bytes: 3
            DEFB    $DB,$E8,$B4     ;;(+00)
            DEFB    $63             ;;Exponent: $73, Bytes: 2
            DEFB    $42,$C4         ;;(+00,+00)
            DEFB    $E6             ;;Exponent: $76, Bytes: 4
            DEFB    $B5,$09,$36,$BE ;;
            DEFB    $E9             ;;Exponent: $79, Bytes: 4
            DEFB    $36,$73,$1B,$5D ;;
            DEFB    $EC             ;;Exponent: $7C, Bytes: 4
            DEFB    $D8,$DE,$63,$BE ;;
            DEFB    $F0             ;;Exponent: $80, Bytes: 4
            DEFB    $61,$A1,$B3,$0C ;;

            DEFB    $04             ;;multiply
            DEFB    $0F             ;;addition
            DEFB    $34             ;;end-calc

            RET                     ; return.

    ; ---------------------
    ; THE 'ARCSIN' FUNCTION
    ; ---------------------
    ; (Offset $1F: 'asn')
    ;   The inverse sine function with result in radians.
    ;   Derived from arctan function above.
    ;   Error A unless the argument is between -1 and +1 inclusive.
    ;   Uses an adaptation of the formula asn(x) = atn(x/sqr(1-x*x))
    ;
    ;
    ;                 /|
    ;                / |
    ;              1/  |x
    ;              /a  |
    ;             /----|
    ;               y
    ;
    ;   e.g. We know the opposite side (x) and hypotenuse (1)
    ;   and we wish to find angle a in radians.
    ;   We can derive length y by Pythagoras and then use ATN instead.
    ;   Since y*y + x*x = 1*1 (Pythagoras Theorem) then
    ;   y=sqr(1-x*x)                         - no need to multiply 1 by itself.
    ;   So, asn(a) = atn(x/y)
    ;   or more fully,
    ;   asn(a) = atn(x/sqr(1-x*x))

    ;   Close but no cigar.

    ;   While PRINT ATN (x/SQR (1-x*x)) gives the same results as PRINT ASN x,
    ;   it leads to division by zero when x is 1 or -1.
    ;   To overcome this, 1 is added to y giving half the required angle and the
    ;   result is then doubled.
    ;   That is, PRINT ATN (x/(SQR (1-x*x) +1)) *2
    ;
    ;
    ;               . /|
    ;            .  c/ |
    ;         .     /1 |x
    ;      . c   b /a  |
    ;    ---------/----|
    ;      1      y
    ;
    ;   By creating an isosceles triangle with two equal sides of 1, angles c and
    ;   c are also equal. If b+c+d = 180 degrees and b+a = 180 degrees then c=a/2.
    ;
    ;   A value higher than 1 gives the required error as attempting to find  the
    ;   square root of a negative number generates an error in Sinclair BASIC.

    ;; asn
    L1DC4:  RST     28H             ;; FP-CALC      x.
            DEFB    $2D             ;;duplicate     x, x.
            DEFB    $2D             ;;duplicate     x, x, x.
            DEFB    $04             ;;multiply      x, x*x.
            DEFB    $A1             ;;stk-one       x, x*x, 1.
            DEFB    $03             ;;subtract      x, x*x-1.
            DEFB    $18             ;;negate        x, 1-x*x.
            DEFB    $25             ;;sqr           x, sqr(1-x*x) = y.
            DEFB    $A1             ;;stk-one       x, y, 1.
            DEFB    $0F             ;;addition      x, y+1.
            DEFB    $05             ;;division      x/y+1.
            DEFB    $21             ;;atn           a/2     (half the angle)
            DEFB    $2D             ;;duplicate     a/2, a/2.
            DEFB    $0F             ;;addition      a.
            DEFB    $34             ;;end-calc      a.

            RET                     ; return.

    ; ------------------------
    ; THE 'ARCCOS' FUNCTION
    ; ------------------------
    ; (Offset $20: 'acs')
    ;   The inverse cosine function with the result in radians.
    ;   Error A unless the argument is between -1 and +1.
    ;   Result in range 0 to pi.
    ;   Derived from asn above which is in turn derived from the preceding atn. It
    ;   could have been derived directly from atn using acs(x) = atn(sqr(1-x*x)/x).
    ;   However, as sine and cosine are horizontal translations of each other,
    ;   uses acs(x) = pi/2 - asn(x)

    ;   e.g. the arccosine of a known x value will give the required angle b in
    ;   radians.
    ;   We know, from above, how to calculate the angle a using asn(x).
    ;   Since the three angles of any triangle add up to 180 degrees, or pi radians,
    ;   and the largest angle in this case is a right-angle (pi/2 radians), then
    ;   we can calculate angle b as pi/2 (both angles) minus asn(x) (angle a).
    ;
    ;
    ;            /|
    ;         1 /b|
    ;          /  |x
    ;         /a  |
    ;        /----|
    ;          y

    ;; acs
    L1DD4:  RST     28H             ;; FP-CALC      x.
            DEFB    $1F             ;;asn           asn(x).
            DEFB    $A3             ;;stk-pi/2      asn(x), pi/2.
            DEFB    $03             ;;subtract      asn(x) - pi/2.
            DEFB    $18             ;;negate        pi/2 - asn(x) = acs(x).
            DEFB    $34             ;;end-calc      acs(x)

            RET                     ; return.

    ; --------------------------
    ; THE 'SQUARE ROOT' FUNCTION
    ; --------------------------
    ; (Offset $25: 'sqr')
    ;   Error A if argument is negative.
    ;   This routine is remarkable for its brevity - 7 bytes.
    ;   The ZX81 code was originally 9K and various techniques had to be
    ;   used to shoe-horn it into an 8K Rom chip.

    ;; sqr
    L1DDB:  RST     28H             ;; FP-CALC              x.
            DEFB    $2D             ;;duplicate             x, x.
            DEFB    $2C             ;;not                   x, 1/0
            DEFB    $00             ;;jump-true             x, (1/0).
            DEFB    $1E             ;;to L1DFD, LAST        exit if argument zero
                                    ;;                      with zero result.

    ;   else continue to calculate as x ** .5

            DEFB    $A2             ;;stk-half              x, .5.
            DEFB    $34             ;;end-calc              x, .5.

    ; ------------------------------
    ; THE 'EXPONENTIATION' OPERATION
    ; ------------------------------
    ; (Offset $06: 'to-power')
    ;   This raises the first number X to the power of the second number Y.
    ;   As with the ZX80,
    ;   0 ** 0 = 1
    ;   0 ** +n = 0
    ;   0 ** -n = arithmetic overflow.

    ;; to-power
    L1DE2:  RST     28H             ;; FP-CALC              X,Y.
            DEFB    $01             ;;exchange              Y,X.
            DEFB    $2D             ;;duplicate             Y,X,X.
            DEFB    $2C             ;;not                   Y,X,(1/0).
            DEFB    $00             ;;jump-true
            DEFB    $07             ;;forward to L1DEE, XISO if X is zero.

    ;   else X is non-zero. function 'ln' will catch a negative value of X.

            DEFB    $22             ;;ln                    Y, LN X.
            DEFB    $04             ;;multiply              Y * LN X
            DEFB    $34             ;;end-calc

            JP      L1C5B           ; jump back to EXP routine.  ->

    ; ---

    ;   These routines form the three simple results when the number is zero.
    ;   begin by deleting the known zero to leave Y the power factor.

    ;; XISO
    L1DEE:  DEFB    $02             ;;delete                Y.
            DEFB    $2D             ;;duplicate             Y, Y.
            DEFB    $2C             ;;not                   Y, (1/0).
            DEFB    $00             ;;jump-true
            DEFB    $09             ;;forward to L1DFB, ONE if Y is zero.

    ;   the power factor is not zero. If negative then an error exists.

            DEFB    $A0             ;;stk-zero              Y, 0.
            DEFB    $01             ;;exchange              0, Y.
            DEFB    $33             ;;greater-0             0, (1/0).
            DEFB    $00             ;;jump-true             0
            DEFB    $06             ;;to L1DFD, LAST        if Y was any positive
                                    ;;                      number.

    ;   else force division by zero thereby raising an Arithmetic overflow error.
    ;   There are some one and two-byte alternatives but perhaps the most formal
    ;   might have been to use end-calc; rst 08; defb 05.

            DEFB    $A1             ;;stk-one               0, 1.
            DEFB    $01             ;;exchange              1, 0.
            DEFB    $05             ;;division              1/0    >> error

    ; ---

    ;; ONE
    L1DFB:  DEFB    $02             ;;delete                .
            DEFB    $A1             ;;stk-one               1.

    ;; LAST
    L1DFD:  DEFB    $34             ;;end-calc              last value 1 or 0.

            RET                     ; return.

    ; ---------------------
    ; THE 'SPARE LOCATIONS'
    ; ---------------------

    ;; SPARE
    L1DFF:  DEFB    $FF             ; That's all folks.

    ; ------------------------
    ; THE 'ZX81 CHARACTER SET'
    ; ------------------------

    ;; char-set - begins with space character.

    ; $00 - Character: ' '          CHR$(0)

    L1E00:  DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000

    ; $01 - Character: mosaic       CHR$(1)

            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000

    ; $02 - Character: mosaic       CHR$(2)

            DEFB    %00001111
            DEFB    %00001111
            DEFB    %00001111
            DEFB    %00001111
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000

    ; $03 - Character: mosaic       CHR$(3)

            DEFB    %11111111
            DEFB    %11111111
            DEFB    %11111111
            DEFB    %11111111
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000

    ; $04 - Character: mosaic       CHR$(4)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000

    ; $05 - Character: mosaic       CHR$(1)

            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000

    ; $06 - Character: mosaic       CHR$(1)

            DEFB    %00001111
            DEFB    %00001111
            DEFB    %00001111
            DEFB    %00001111
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000

    ; $07 - Character: mosaic       CHR$(1)

            DEFB    %11111111
            DEFB    %11111111
            DEFB    %11111111
            DEFB    %11111111
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000
            DEFB    %11110000

    ; $08 - Character: mosaic       CHR$(1)

            DEFB    %10101010
            DEFB    %01010101
            DEFB    %10101010
            DEFB    %01010101
            DEFB    %10101010
            DEFB    %01010101
            DEFB    %10101010
            DEFB    %01010101

    ; $09 - Character: mosaic       CHR$(1)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %10101010
            DEFB    %01010101
            DEFB    %10101010
            DEFB    %01010101

    ; $0A - Character: mosaic       CHR$(10)

            DEFB    %10101010
            DEFB    %01010101
            DEFB    %10101010
            DEFB    %01010101
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000

    ; $0B - Character: '"'          CHR$(11)

            DEFB    %00000000
            DEFB    %00100100
            DEFB    %00100100
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000

    ; $0B - Character:  £           CHR$(12)

            DEFB    %00000000
            DEFB    %00011100
            DEFB    %00100010
            DEFB    %01111000
            DEFB    %00100000
            DEFB    %00100000
            DEFB    %01111110
            DEFB    %00000000

    ; $0B - Character: '$'          CHR$(13)

            DEFB    %00000000
            DEFB    %00001000
            DEFB    %00111110
            DEFB    %00101000
            DEFB    %00111110
            DEFB    %00001010
            DEFB    %00111110
            DEFB    %00001000

    ; $0B - Character: ':'          CHR$(14)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00010000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00010000
            DEFB    %00000000

    ; $0B - Character: '?'          CHR$(15)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %00000100
            DEFB    %00001000
            DEFB    %00000000
            DEFB    %00001000
            DEFB    %00000000

    ; $10 - Character: '('          CHR$(16)

            DEFB    %00000000
            DEFB    %00000100
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00000100
            DEFB    %00000000

    ; $11 - Character: ')'          CHR$(17)

            DEFB    %00000000
            DEFB    %00100000
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00100000
            DEFB    %00000000

    ; $12 - Character: '>'          CHR$(18)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00010000
            DEFB    %00001000
            DEFB    %00000100
            DEFB    %00001000
            DEFB    %00010000
            DEFB    %00000000

    ; $13 - Character: '<'          CHR$(19)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000100
            DEFB    %00001000
            DEFB    %00010000
            DEFB    %00001000
            DEFB    %00000100
            DEFB    %00000000

    ; $14 - Character: '='          CHR$(20)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00111110
            DEFB    %00000000
            DEFB    %00111110
            DEFB    %00000000
            DEFB    %00000000

    ; $15 - Character: '+'          CHR$(21)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00111110
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00000000

    ; $16 - Character: '-'          CHR$(22)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00111110
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000

    ; $17 - Character: '*'          CHR$(23)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00010100
            DEFB    %00001000
            DEFB    %00111110
            DEFB    %00001000
            DEFB    %00010100
            DEFB    %00000000

    ; $18 - Character: '/'          CHR$(24)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000010
            DEFB    %00000100
            DEFB    %00001000
            DEFB    %00010000
            DEFB    %00100000
            DEFB    %00000000

    ; $19 - Character: ';'          CHR$(25)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00010000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00100000

    ; $1A - Character: ','          CHR$(26)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00010000

    ; $1B - Character: '"'          CHR$(27)

            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00000000
            DEFB    %00011000
            DEFB    %00011000
            DEFB    %00000000

    ; $1C - Character: '0'          CHR$(28)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000110
            DEFB    %01001010
            DEFB    %01010010
            DEFB    %01100010
            DEFB    %00111100
            DEFB    %00000000

    ; $1D - Character: '1'          CHR$(29)

            DEFB    %00000000
            DEFB    %00011000
            DEFB    %00101000
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00111110
            DEFB    %00000000

    ; $1E - Character: '2'          CHR$(30)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %00000010
            DEFB    %00111100
            DEFB    %01000000
            DEFB    %01111110
            DEFB    %00000000

    ; $1F - Character: '3'          CHR$(31)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %00001100
            DEFB    %00000010
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %00000000

    ; $20 - Character: '4'          CHR$(32)

            DEFB    %00000000
            DEFB    %00001000
            DEFB    %00011000
            DEFB    %00101000
            DEFB    %01001000
            DEFB    %01111110
            DEFB    %00001000
            DEFB    %00000000

    ; $21 - Character: '5'          CHR$(33)

            DEFB    %00000000
            DEFB    %01111110
            DEFB    %01000000
            DEFB    %01111100
            DEFB    %00000010
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %00000000

    ; $22 - Character: '6'          CHR$(34)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000000
            DEFB    %01111100
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %00000000

    ; $23 - Character: '7'          CHR$(35)

            DEFB    %00000000
            DEFB    %01111110
            DEFB    %00000010
            DEFB    %00000100
            DEFB    %00001000
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00000000

    ; $24 - Character: '8'          CHR$(36)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %00000000

    ; $25 - Character: '9'          CHR$(37)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %00111110
            DEFB    %00000010
            DEFB    %00111100
            DEFB    %00000000

    ; $26 - Character: 'A'          CHR$(38)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01111110
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %00000000

    ; $27 - Character: 'B'          CHR$(39)

            DEFB    %00000000
            DEFB    %01111100
            DEFB    %01000010
            DEFB    %01111100
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01111100
            DEFB    %00000000

    ; $28 - Character: 'C'          CHR$(40)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %01000000
            DEFB    %01000000
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %00000000

    ; $29 - Character: 'D'          CHR$(41)

            DEFB    %00000000
            DEFB    %01111000
            DEFB    %01000100
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000100
            DEFB    %01111000
            DEFB    %00000000

    ; $2A - Character: 'E'          CHR$(42)

            DEFB    %00000000
            DEFB    %01111110
            DEFB    %01000000
            DEFB    %01111100
            DEFB    %01000000
            DEFB    %01000000
            DEFB    %01111110
            DEFB    %00000000

    ; $2B - Character: 'F'          CHR$(43)

            DEFB    %00000000
            DEFB    %01111110
            DEFB    %01000000
            DEFB    %01111100
            DEFB    %01000000
            DEFB    %01000000
            DEFB    %01000000
            DEFB    %00000000

    ; $2C - Character: 'G'          CHR$(44)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %01000000
            DEFB    %01001110
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %00000000

    ; $2D - Character: 'H'          CHR$(45)

            DEFB    %00000000
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01111110
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %00000000

    ; $2E - Character: 'I'          CHR$(46)

            DEFB    %00000000
            DEFB    %00111110
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00001000
            DEFB    %00111110
            DEFB    %00000000

    ; $2F - Character: 'J'          CHR$(47)

            DEFB    %00000000
            DEFB    %00000010
            DEFB    %00000010
            DEFB    %00000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %00000000

    ; $30 - Character: 'K'          CHR$(48)

            DEFB    %00000000
            DEFB    %01000100
            DEFB    %01001000
            DEFB    %01110000
            DEFB    %01001000
            DEFB    %01000100
            DEFB    %01000010
            DEFB    %00000000

    ; $31 - Character: 'L'          CHR$(49)

            DEFB    %00000000
            DEFB    %01000000
            DEFB    %01000000
            DEFB    %01000000
            DEFB    %01000000
            DEFB    %01000000
            DEFB    %01111110
            DEFB    %00000000

    ; $32 - Character: 'M'          CHR$(50)

            DEFB    %00000000
            DEFB    %01000010
            DEFB    %01100110
            DEFB    %01011010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %00000000

    ; $33 - Character: 'N'          CHR$(51)

            DEFB    %00000000
            DEFB    %01000010
            DEFB    %01100010
            DEFB    %01010010
            DEFB    %01001010
            DEFB    %01000110
            DEFB    %01000010
            DEFB    %00000000

    ; $34 - Character: 'O'          CHR$(52)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %00000000

    ; $35 - Character: 'P'          CHR$(53)

            DEFB    %00000000
            DEFB    %01111100
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01111100
            DEFB    %01000000
            DEFB    %01000000
            DEFB    %00000000

    ; $36 - Character: 'Q'          CHR$(54)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01010010
            DEFB    %01001010
            DEFB    %00111100
            DEFB    %00000000

    ; $37 - Character: 'R'          CHR$(55)

            DEFB    %00000000
            DEFB    %01111100
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01111100
            DEFB    %01000100
            DEFB    %01000010
            DEFB    %00000000

    ; $38 - Character: 'S'          CHR$(56)

            DEFB    %00000000
            DEFB    %00111100
            DEFB    %01000000
            DEFB    %00111100
            DEFB    %00000010
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %00000000

    ; $39 - Character: 'T'          CHR$(57)

            DEFB    %00000000
            DEFB    %11111110
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00000000

    ; $3A - Character: 'U'          CHR$(58)

            DEFB    %00000000
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %00111100
            DEFB    %00000000

    ; $3B - Character: 'V'          CHR$(59)

            DEFB    %00000000
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %00100100
            DEFB    %00011000
            DEFB    %00000000

    ; $3C - Character: 'W'          CHR$(60)

            DEFB    %00000000
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01000010
            DEFB    %01011010
            DEFB    %00100100
            DEFB    %00000000

    ; $3D - Character: 'X'          CHR$(61)

            DEFB    %00000000
            DEFB    %01000010
            DEFB    %00100100
            DEFB    %00011000
            DEFB    %00011000
            DEFB    %00100100
            DEFB    %01000010
            DEFB    %00000000

    ; $3E - Character: 'Y'          CHR$(62)

            DEFB    %00000000
            DEFB    %10000010
            DEFB    %01000100
            DEFB    %00101000
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00010000
            DEFB    %00000000

    ; $3F - Character: 'Z'          CHR$(63)

            DEFB    %00000000
            DEFB    %01111110
            DEFB    %00000100
            DEFB    %00001000
            DEFB    %00010000
            DEFB    %00100000
            DEFB    %01111110
            DEFB    %00000000

    .END                                ;TASM assembler instruction.