; ===================================================
;
; An Assembly Listing of the ROM of the Sinclair ZX80
; ---------------------------------------------------
;
; -------------------------
; Last updated: 12-SEP-2002
; -------------------------
;
; Note. This is not the original text file, which was 
; written by John Grant in 1979, but a file that 
; performs a similar function in that it assembles
; a 4K ROM file that may be used in ZX80 emulators.
;
; The resultant ROM file is identical to the original
; and a comparison between the object code and the original
; is made as part of the process of uploading this file.
;
; It would be desirable that the original file be published but, until such 
; time, this file may serve as a poor substitute. 
;
; Actually I learn that the complete Assembly Listing was published, with 
; "Designer's Annotations", in 1980.   Also in that year, appeared "The ZX80
; Monitor Listing" by Ian Logan, published by LINSAC.
;
; ===================================================


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

; ===================================================
;
; To do justice to the original program it is desirable 
; that, while the instructions should not be over
; commented, what is appended should be of high quality.
;
; Send details of any improvements/corrections to
; geoff@wearmouth.demon.co.uk.spamnothanks
; All contributions will be credited.
;
; File incorporates contributions from
; Peter Liebert-Adelt
;
; and borrows from the writings of
; Wilf Rigter,
; Dr Ian Logan,
; Dr Frank O'Hara.
;
; ===================================================


.ORG     $0000

; -----------
; THE 'START'
; -----------

;; START
L0000:  LD      HL,$7FFF        ; top of possible RAM.
                                ; (highest integer is 32767).
        LD      A,$3F           ; page before RAM.
        JP      L0261           ; forward to RAM-FILL.

; -------------------
; THE 'ERROR' RESTART
; -------------------

;; ERROR-1
L0008:  POP     HL              ; drop the return address.
        LD      L,(HL)          ; fetch the error code after RST 8.
        BIT     7,(IY+$00)      ; test ERR_NR for value $FF (OK)
        JR      L0013           ; forward to continue at ERROR-2.

; -------------------------------
; THE 'PRINT A CHARACTER' RESTART
; -------------------------------


;; PRINT-A
L0010:  JP      L0560           ; jump forward immediately to PRINT-A-2

; ---

; A continuation of the previous Error restart.

;; ERROR-2
L0013:  RET     Z               ; return if $FF - OK.

        LD      (IY+$00),L      ; else set system variable ERR_NR
        RET                     ; return.

; ---------------------------------------------
; THE 'COLLECT NEXT CHARACTER OR SPACE' RESTART
; ---------------------------------------------
; This will collect any next character including space (zero).

;; NXT-CH-SP
L0018:  JR      L0052           ; forward to CH_ADD+1

; ---

; This subroutine will collect the character at the current character address
; searching for the next non-space character should the fetched character be
; a space.

;; get-char
L001A:  LD      HL,($4026)      ; get pointer from CH_ADD
        LD      A,(HL)          ; fetch addressed character.

; This subroutine tests the current character in the accumulator retrieving
; the next non-space character should the accumulator contain a space

;; TEST-CHAR
L001E:  AND     A               ; test for space (zero).
        RET     NZ              ; return if not a space.

;-------------------------------------------
; THE 'COLLECT NEXT VALID CHARACTER' RESTART
;-------------------------------------------

;; NEXT-CHAR
L0020:  CALL    L0052           ; routine CH_ADD+1
        JR      L001E           ; loop back to TEST-CHAR until valid

; ---

; This subroutine advances the character pointer and evaluates the following
; expression.
; It is called twice with CH_ADD addressing the '(' character


;; EVAL-EXPR
L0025:  CALL    L0055           ; routine CH_ADD_LP

; ---------------------------------
; THE 'SCANNING-CALCULATOR' RESTART
; ---------------------------------

;; SCAN-CALC
L0028:  CALL    L001A           ; routine get-char.
        LD      B,$00           ; set B to zero as a starting
                                ; priority marker.
        JP      L09E1           ; jump forward to SCANNING

; ----------------------------
; THE 'MAKE BC SPACES' RESTART
; ----------------------------

;; BC-SPACES
L0030:  CALL    L094F           ; routine TEST-ROOM
        RET     NC              ; return if not enough room.

        PUSH    BC              ; save number of bytes required.
        JP      L0CF3           ; jump forward to RESERVE

; --------------------------------
; THE 'MASKABLE INTERRUPT' ROUTINE
; --------------------------------
; Note. the maskable interrupt is concerned with generating the TV picture,
; one of the main tasks in the ZX80. This requires some understanding of
; how the video hardware interacts with the system and part of the process
; is to present to the Z80 chip a phantom display file in the upper
; unpopulated 32K of memory. This topsy-turvy display file
; executes characters like "HELLO WORLD" as NOP instructions but recognizes
; a newline ($76) as a true HALT instruction.

; The video hardware sniffs the databus and grabs the data as it flies by
; sending it on to the shifting circuits. The I register permanently holds
; $0E. The video circuitry uses this register and the lower six bits of the
; character to index into the character set bitmaps at the end of this ROM,
; at $0E00, and so cobble together a scan-line.

; If bit 7 of the character latch is set, then the serial video data is
; inverted so that any character in the range 127-191 appears as the inverse
; of normal characters 0 - 63.

; For a proper explanation of this system, I recommend Wilf Rigter's
; online documentation, available from several indexed sites.
; I have borrowed a few comments from that file to remind myself of what
; is happening. I have indicated where the Z80 instructions should be
; read in conjunction with Wilf's file by using a double semi-colon.

; On entry, B holds the line number and C the number of the scanline.

;; MASK-INT
L0038:  DEC     C               ;; decrement the scan line counter in register C.
        JP      NZ,L0045        ;; JUMP to SCAN-LINE : repeats 8 times for each
                                ;; row of characters in DFILE.

        POP     HL              ;; point to the start of next DFILE row
        DEC     B               ;; decrement ROW counter
        RET     Z               ;; return if zero to

        SET     3,C             ;; load scan line counter with 08 was 00.

;; WAIT-INT
L0041:  LD      R,A             ;; load refresh register with value $DD.
        EI                      ;; enable interrupts.
        JP      (HL)            ;; jump to execute the NOPs in DFILE
                                ;; terminated by a NEWLINE/HALT instruction.

; ---

;; SCAN-LINE
L0045:  POP     DE              ;; discard return address.
        RET     Z               ;; delay (Zero never set)

        JR      L0041           ;; back to WAIT-INT above

; ----------------------------------------------
; THE 'EVALUATE BRACKETED EXPRESSION' SUBROUTINE
; ----------------------------------------------
; This subroutine is used when an opening bracket is encountered to evaluate
; the expression within. It is called from LOOK-VARS when an integral function
; or array is encountered and recursively from within SCANNING when any 
; bracketed argument or sub-expression is encountered.

;; BRACKET
L0049:  CALL    L0025           ; routine EVAL-EXPR
        LD      A,(HL)          ; fetch subsequent character
        CP      $D9             ; is character a ')' ?
        JP      NZ,L08AE        ; jump to INS-ERR with other characters.

; else continue and get the character after the ')' ...

; ---------------------------------
; THE 'INCREMENT CH_ADD' SUBROUTINE
; ---------------------------------

;; CH_ADD+1
L0052:  LD      HL,($4026)      ; fetch character address from CH_ADD

;; CH_ADD_LP
L0055:  INC     HL              ; increment the pointer.
        LD      ($4026),HL      ; set system variable CH_ADD
        LD      A,(HL)          ; fetch the addressed value.
        CP      $B0             ; is character inverse 'K'
        RET     NZ              ; return if not.                >>

        LD      ($4004),HL      ; set P_PTR system variable
        BIT     7,(IY+$19)      ; test FLAGX - will be set if K-mode
        JR      Z,L0055         ; back to CH_ADD_LP if not K-mode

L0066:  SET     2,(IY+$01)      ; update FLAGS set K mode.

        JR      L0055           ; back to CH_ADD_LP

; Note there is no NMI routine at L0066.

; ---------------
; THE 'KEY' TABLE
; ---------------
; The Key Table is indexed with a key value 1-78.

; -----------------------
; THE 39 'UNSHIFTED' KEYS
; -----------------------

;; MAIN-KEYS
L006C:  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       ED-ENTER
        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 39 'SHIFTED' CODES
; ----------------------

        DEFB    $0E             ; ':'
        DEFB    $D7             ; ';'
        DEFB    $0F             ; '?'
        DEFB    $DF             ; '/'

        DEFB    $09             ; mosaic $09
        DEFB    $08             ; mosaic $08
        DEFB    $06             ; mosaic $06
        DEFB    $07             ; mosaic $07
        DEFB    $0B             ; mosaic $0B

        DEFB    $02             ; mosaic $02
        DEFB    $03             ; mosaic $03
        DEFB    $04             ; mosaic $0A
        DEFB    $05             ; mosaic $04
        DEFB    $0A             ; mosaic $05

        DEFB    $DB             ; 'NOT'
        DEFB    $E0             ; 'AND'
        DEFB    $D5             ; 'THEN'
        DEFB    $D6             ; 'TO'
        DEFB    $72             ; cursor left

        DEFB    $77             ; [ RUBOUT ]
        DEFB    $74             ; [ HOME ]
        DEFB    $73             ; cursor right
        DEFB    $70             ; cursor up
        DEFB    $71             ; cursor down

        DEFB    $DE             ; '*'
        DEFB    $D9             ; ')'
        DEFB    $DA             ; '('
        DEFB    $0D             ; '$'
        DEFB    $01             ; '"'

        DEFB    $75             ; [ EDIT ]
        DEFB    $E3             ; '='
        DEFB    $DD             ; '+'
        DEFB    $DC             ; '-'
        DEFB    $E2             ; '**'

        DEFB    $0C             ; uk currency symbol
        DEFB    $D8             ; ','
        DEFB    $E4             ; '>'
        DEFB    $E5             ; '<'
        DEFB    $E1             ; 'OR'

; -----------------
; THE 'TOKEN' TABLE
; -----------------


;; TKN-TABLE
L00BA:  DEFB    $D4                     ; chr$ 212 - the threshold character
                                        ; tokens below this are printed using
                                        ; the next character
        DEFB    $8F                     ; '?' + $80
        DEFB    $81                     ; '"' + $80

        DEFB    $39,$2D,$2A,$B3         ; THEN
        DEFB    $39,$B4                 ; TO
        DEFB    $99                     ; ;
        DEFB    $9A                     ; ,
        DEFB    $91                     ; (
        DEFB    $90                     ; )
        DEFB    $33,$34,$B9             ; NOT
        DEFB    $92                     ; -
        DEFB    $93                     ; +
        DEFB    $94                     ; *
        DEFB    $95                     ; /
        DEFB    $26,$33,$A9             ; AND
        DEFB    $34,$B7                 ; OR
        DEFB    $14,$14+$80             ; **
        DEFB    $96                     ; =
        DEFB    $97                     ; <
        DEFB    $98                     ; >
        DEFB    $31,$2E,$38,$B9         ; LIST
        DEFB    $37,$2A,$39,$3A,$37,$B3 ; RETURN
        DEFB    $28,$31,$B8             ; CLS
        DEFB    $29,$2E,$B2             ; DIM
        DEFB    $38,$26,$3B,$AA         ; SAVE
        DEFB    $2B,$34,$B7             ; FOR
        DEFB    $2C,$34,$00,$39,$B4     ; GO TO
        DEFB    $35,$34,$30,$AA         ; POKE
        DEFB    $2E,$33,$35,$3A,$B9     ; INPUT
        DEFB    $37,$26,$33,$29         ; ...
        DEFB    $34,$32,$2E,$38,$AA     ; RANDOMISE
        DEFB    $31,$2A,$B9             ; LET
        DEFB    $8F                     ; '?' + $80
        DEFB    $8F                     ; '?' + $80
        DEFB    $33,$2A,$3D,$B9         ; NEXT
        DEFB    $35,$37,$2E,$33,$B9     ; PRINT
        DEFB    $8F                     ; '?' + $80
        DEFB    $33,$2A,$BC             ; NEW
        DEFB    $37,$3A,$B3             ; RUN
        DEFB    $38,$39,$34,$B5         ; STOP
        DEFB    $28,$34,$33,$39,$2E     ; ...
        DEFB    $33,$3A,$AA             ; CONTINUE
        DEFB    $2E,$AB                 ; IF
        DEFB    $2C,$34,$00,$38,$3A,$A7 ; GO SUB
        DEFB    $31,$34,$26,$A9         ; LOAD
        DEFB    $28,$31,$2A,$26,$B7     ; CLEAR
        DEFB    $37,$2A,$B2             ; REM
        DEFB    $8F                     ; '?' + $80


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

; ->

;; DISP-1
L013C:  CALL    L01AD           ;; routine DISP-2

; The initial entry point 

;; KEYBOARD
L013F:  LD      B,$08           ; (7) set counter to 8

;; KB-1
L0141:  DJNZ    L0141           ; (13,8) and loop back 7 times. (7*13+8)

                                ;       "WASTE 99 T-STATES"

;; KB-2
L0143:  LD      HL,($401E)      ; (16) fetch two-byte FRAMES value.
        INC     HL              ; ( 6) increment
        LD      ($401E),HL      ; (16) and store in FRAMES again.

; now read the keyboard

        LD      HL,$FFFF        ; (10) prepare a buffer
        LD      B,$FE           ; ( 7) set B to $FE 
        LD      C,B             ; ( 4) now BC is $FEFE - slightly slower than
                                ; the equally time-critical LD BC,$FEFE  (10)  
                                ; that is used in the ZX81 ROM.             
        IN      A,(C)           ; (12) now read port $FEFE the half-row with 
                                ; the shift key.

                                ; "START FRAME SYNC"
;   START COUNTING

        OR      $01             ; (7) set the rightmost bit so as to ignore 
                                ; shift.


;; EACH-LINE
L0154:  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               ; [4] $FF or port FE,FD,FB....
        AND     L               ; [4] unless more than one key, L will still 
                                ;     be $FF if more than one key pressed 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)           ; [12] read another half-row.
                                ;      all five bits this time.

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

                                ; (658 T-states). 

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

        RRA                     ; (4) test the shift key - carry reset if
                                ;     pressed.

;; KB-3
L0168:  RL      H               ; (8) rotate H to the left 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 columns and L identifying the row of 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) and 24
        ADD     A,$20           ; (7) add 32

; gives either 32 (USA) or 56 (UK) blank lines above the TV picture.
; This value will be decremented for the lower border.

        LD      ($4023),A       ; (13) place margin in RESULT_hi.

; The next snippet tests that the same raw key is read twice in succession.
; The first time through, the routine uses a character address value,
; which is inappropriate to match against a key value, but the next time
; through it matches the key value it placed there on the first pass.
; Seems to be 713 T-states.
;
; "717 T-STATES SINCE START OF FRAME SYNC, 545 BEFORE END"

        LD      BC,($4026)      ; (20) fetch possible previous key value from 
                                ;      CH_ADD
        LD      ($4026),HL      ; (16) put the fresh key value in CH_ADD.

        LD      A,B             ; ( 4)  fetch high byte.
        ADD     A,$02           ; ( 7)  test for $FF, no-key which will set 
                                ;      carry.

        SBC     HL,BC           ; (15) subtract the two raw keys.
        EX      DE,HL           ; ( 4) result, possibly zero, to DE.

        LD      HL,$4022        ; (10) now address system variable RESULT.
        LD      A,(HL)          ; ( 7) load A from RESULT_lo.
        OR      D               ; ( 4) check the 
        OR      E               ; ( 4) subtraction result.
        RET     Z               ; ( 5,11) return if all three zero.       >>>

; T-states = 96 so far
; proceed to debounce. The 'no-key' value $FF must be returned five times
; before a new key is accepted above.
; Holding down a key causes the shift counter to be maintained at five.
; The initial state of RESULT is unimportant.

        LD      A,B             ; ( 4) fetch hi byte of PREVIOUS key code.
        CP      $FE             ; ( 7) sets carry if valid - 
                                ;      $FD, $FB, $F7, $EF, $DF
        SBC     A,A             ; ( 4) gives $FF if pressed or $00 if no-key.

        LD      B,$1F           ; ( 7) prepare the shift counter 
                                ;      (and also the timed delay)

        OR      (HL)            ; ( 7) OR with RESULT_lo
        AND     B               ; ( 4) limit the count to five set bits.
        RRA                     ; ( 4) 'shift' to right
        LD      (HL),A          ; ( 7) place result in RESULT_lo

        DEC     B               ; ( 4) adjust the delay counter B to thirty.

; t states = 48 ( Total 96+48=144)

;; KB-4
L0194:  DJNZ    L0194           ;; (13,8) wait a while looping to KB-4 
                                ;; equals 13*29+8 = 385

                                ; "FRAME SYNC ENDS AT NEXT M1"

        OUT     ($FF),A         ;; (11) stops the VSYNC pulse


        LD      A,$EC           ;; ( 7) the value for R register
        LD      B,$19           ;; there are 25 HALTs including the initial
                                ;; one.
        LD      HL,($400C)      ;; point HL to D-FILE the first HALT
                                ;; instruction.
        SET     7,H             ;; now point to the DFILE echo in the 
                                ;; top 32K of address space.

        CALL    L01AD           ;; routine DISP-2

        LD      A,$F3           ;; prepare to set the R refresh register to $F3.
        INC     B               ;; increment the line count
        DEC     HL              ;; decrement screen address.
        DEC     (IY+$23)        ;; decrement RESULT_hi the blank line counter.
        JR      L013C           ;; back to display and read

; ---

;; DISP-2
L01AD:  LD      C,(IY+$23)      ;; load C the col count from RESULT_hi.

        LD      R,A             ;; R increments with each opcode until A6
                                ;; goes low which generates the INT signal.

        LD      A,$DD           ;; set the left margin of all other lines.
                                ;; loaded later to R - the incremental refresh
                                ;; register.

        EI                      ;; with R set up, enable interrupts.

        JP      (HL)            ;; jump to execute the echo DFILE starting with
                                ;; HALT and waits for the first INT to
                                ;; come to the rescue.

; --------------------------
; THE 'SAVE' COMMAND ROUTINE
; --------------------------
; There isn't a program name involved.
; The routine saves the System Variables, Program Area and BASIC Variables.
; One of the five System commands that cannot be used from within a program.

;; SAVE
L01B6:  POP     DE              ; discard return address.
        LD      DE,$12CB        ; timing value of 5 seconds for leader.

;; SAVE-1
L01BA:  LD      A,$7F           ; read port $7FFE.
        IN      A,($FE)         ; all 16 bits are placed on address bus.
        RRA                     ; test for the space key.
        JR      NC,L0203        ; forward, if pressed, indirectly to MAIN-EXEC.

;; SAVE-2
L01C1:  DJNZ    L01C1           ; delay self-looping to SAVE-2

        DEC     DE              ; decrement
        LD      A,D             ; and test
        OR      E               ; for zero.
        JR      NZ,L01BA        ; back if not zero to outer delay loop SAVE-1.

        LD      HL,$4000        ; commence saving at start of RAM.

;; SAVE-3
L01CB:  LD      DE,$F808        ; register E counts the 8 bits.
                                ; $F8 is first delay.

;; EACH-BIT
L01CE:  RLC     (HL)            ; spin the actual program byte.
        SBC     A,A             ; $FF or $00.
        AND     $05             ; $05 or $00.
        ADD     A,$04           ; $09 or $04.
        LD      C,A             ; timer to C.
                                ; a set bit has a pulse longer than
                                ; an unset bit.

;; SAVE-4
L01D6:  OUT     ($FF),A         ; pulses

        LD      B,$24           ; delay counter.

;; SAVE-5
L01DA:  DJNZ    L01DA           ; self loop for delay to SAVE-5

        LD      A,$7F           ; read the space row and hold for later.
        IN      A,($FE)         ; also ...

        LD      B,$23           ; another delay counter.

;; SAVE-6
L01E2:  DJNZ    L01E2           ; self loop for delay2 to SAVE-6

        DEC     C               ; decrement pulse counter
        JR      NZ,L01D6        ; back while more to SAVE-4.

        LD      B,D             ; a terminating delay - D is zero (256).

;; SAVE-7
L01E8:  NOP                     ; 4 T-states.
        DJNZ    L01E8           ; execute the NOP 256 times.

        LD      D,$FE           ; subsequent timing value
        DEC     E               ; decrement the 8 counter.
        JR      NZ,L01CE        ; back if more to EACH-BIT.

        RRA                     ; test for space key pressed at last test.
        JR      NC,L0203        ; forward, if so, indirectly to MAIN-EXEC.

        CALL    L01F8           ; routine TEST-END does not return if at 
                                ; the end.                                >>

        JR      L01CB           ; else back to do another byte.

; ---

; This subroutine is used by both the SAVE and LOAD command routines 
; to check when the required area has been completed and to then make an exit 
; from the called loop.
; Note. that for the LOAD command the value of E_LINE is not that at the outset
; of the LOAD command but at the start of the command that saved the section.
; The first bytes to be loaded are the System Variables and E_LINE will be the
; eleventh and twelfth bytes to be loaded. The low byte is read in before the 
; high byte so after the low byte is read in, E_LINE is in an indeterminate
; state. Hence E_LINE_hi is incremented at the outset to avoid a premature
; end to loading. 

;; TEST-END
L01F8:  INC     HL              ; increase pointer.
        EX      DE,HL           ;
        LD      HL,($400A)      ; load HL with E_LINE - the location following
                                ; the variables end-marker.
        SCF                     ; force a carry when equal.
        SBC     HL,DE           ; trial subtraction.
        EX      DE,HL           ; restore pointer.
        RET     NC              ; return if more bytes to do.

        POP     HL              ; else drop the return address.

;; JUMP-EXEC
L0203:  JP      L0283           ; JUMP forward to MAIN-EXEC.

; Note. the above jump could be replaced by a relative jump saving one 
; instruction byte.  A few other direct jumps to this destination could be 
; replaced with a series of relative jumps as has been done elsewhere.

; --------------------------
; THE 'LOAD' COMMAND ROUTINE
; --------------------------
; A System Command to load a program from tape.

;; LOAD
L0206:  POP     DE              ; discard the return address.

;; LOAD-1
L0207:  LD      DE,$5712        ; set a timing constant.

;; LOAD-2
L020A:  LD      A,$7F           ; read from port $7FFE.
        IN      A,($FE)         ; the keyboard row with space.
        RRA                     ; test the outer key.
        JR      NC,L0203        ; back, if pressed, indirectly to MAIN-EXEC

        RLA                     ; cancel the above RRA.
        RLA                     ; now do an RLA to read tape signal - bit 7.

        JR      C,L0207         ; back without signal to outer loop LOAD-1.

        DEC     DE              ; decrement timer
        LD      A,D             ; and test 
        OR      E               ; for zero.
        JR      NZ,L020A        ; back if not to inner loop LOAD-2.

        INC     (IY+$0B)        ; increment E_LINE_hi to prevent premature
                                ; end after loading E_LINE-lo.
                                ; see TEST-END.

        LD      HL,$4000        ; start of RAM - system variables to be 
                                ; overwritten.

;; LOAD-3
L0220:  LD      E,$08           ; the bit counter for each byte.

;; LOAD-4
L0222:  LD      A,$7F           ; test the keyboard
        IN      A,($FE)         ; reading the 
        RRA                     ; space key.
        JR      NC,L024D        ; forward, if space pressed, to LD-ABORT.

        RLA                     ; restore to original state.
        RLA                     ; now test the tape bit.
        JR      NC,L0222        ; back if ???? to LOAD-4

; start building up a byte.

        LD      C,$94           ; set timing value. The exit value of this
                                ; register determines if a bit was set or unset.

;; LOAD-5
L022F:  LD      B,$1A           ; inner timer

;; LOAD-6
L0231:  DEC     C               ; decrement counter.
        IN      A,($FE)         ; read the tape port.
        RLA                     ; test the tape bit.

        BIT     7,C             ; test if counter above 127. A set bit.
        LD      A,C             ; save in A.

        JR      C,L022F         ; back while bit set to LOAD-5

        DJNZ    L0231           ; decrement B counter and loop while not
                                ; zero to LOAD-6.
                                ; Note. this instruction has no effect on any 
                                ; flags.

        JR      NZ,L0242        ; forward if C was > $7F (with NC) to LOAD-7

        CP      $56             ; compare copy of counter to $56
        JR      NC,L0222        ; back if $56-$7F to LOAD-4

;; LOAD-7
L0242:  CCF                     ; else clear if from above but set carry if 
                                ; branching to here.
        RL      (HL)            ; rotate the bit into position.

        DEC     E               ; decrement the eight counter
        JR      NZ,L0222        ; loop back for entire byte.

        CALL    L01F8           ; routine TEST-END quits early at end.
        JR      L0220           ; and back to load another byte.

; ---------------------------
; THE 'LOAD ABORT' EXIT ROUTE
; ---------------------------
; If the LOAD command has started to load data then a reset is performed.
; If it's still waiting for the leader then rejoin the main execution loop
; after restoring the location of the Edit Line to its correct value.

;; LD-ABORT
L024D:  DEC     D               ; ??
        JP      P,L0000         ; a reset

        DEC     (IY+$0B)        ; restore E_LINE_hi to a valid state.
        JR      L0203           ; indirect jump to MAIN-EXEC.


; --------------------------
; THE 'LIST' COMMAND ROUTINE
; --------------------------
; Another System command that can't be used from within a program.

;; LIST
L0256:  RES     7,B             ; start by making the high byte,
                                ; of an invalid, user-supplied,
        RES     6,B             ; line number within range $00-$3F.

; this invisible mending is inappropriate and it is preferable to tell the
; user of any typos. e.g. LIST 40000 is silently changed to LIST 7232
; when the user probably meant to type LIST 4000. However space is tight.

        LD      ($4006),BC      ; set E-PPC from line number.
        POP     BC              ; discard return address.
        JR      L0283           ; forward to MAIN-EXEC which produces an
                                ; 'automatic listing'.

; ----------------------------
; THE 'INITIALIZATION' ROUTINE
; ----------------------------
; A holds $3F, HL holds $7FFF.

;; RAM-FILL
L0261:  LD      (HL),$01        ; fill location with 1 (null).
        DEC     HL              ; decrement address.
        CP      H               ; compare address high byte to $3F.
        JR      NZ,L0261        ; back, while higher, to RAM-FILL.

;; RAM-READ
L0267:  INC     HL              ; address the next higher location.
        DEC     (HL)            ; decrement to zero.
        JR      Z,L0267         ; back, if successful to RAM-READ.

; else we have encountered first unpopulated RAM location.

        LD      SP,HL           ; initialize stack pointer at end.
        PUSH    AF              ; place gosub end-marker $3F??

        LD      A,$0E           ; set the I register to $0E to tell
        LD      I,A             ; the video hardware where to find
                                ; the character set ($0E00).

        IM      1               ; select Interrupt Mode 1.

        LD      IY,$4000        ; set IY to the start of the forty system
                                ; variables.

; -----------------------------------------------------------------------------
;
; ---------------------
; THE 'ZX80 MEMORY MAP'
; ---------------------
;
; There are forty ($28) system variables followed by Program area
; These are located at the start of RAM.
;
; +---------+---------+-----------+---+-----------+-----------+-------+-------+
; |         |         |           |   |           |           |       |       |
; | SYSVARS | Program | Variables |80h| WKG Space | Disp File | Spare | Stack |
; |         |         |           |   |           |           |       |       |
; +---------+---------+-----------+---+-----------+-----------+-------+-------+
;           ^         ^               ^           ^     ^     ^       ^
;         $4024      VARS            E_LINE    D_FILE       DF_END   SP
;                                                     DF_EA
;
; -----------------------------------------------------------------------------

        LD      HL,$4028        ; set to location after sysvars.
        LD      ($4008),HL      ; set the system variable VARS.
        LD      (HL),$80        ; and insert variables end-marker.

        INC     HL              ; address the next location.
        LD      ($400A),HL      ; set the system variable E_LINE.
                                ; and continue...

; -------------------------
; THE 'MAIN EXECUTION' LOOP
; -------------------------
; This is the MAIN EXECUTION LOOP that handles the creation and interpretation
; of user input. The various 'subroutines'  from this main loop including those
; launched from the Editing Keys Table are really just branches which all
; ultimately jump back to here. Although service routines make use of the
; machine stack, the stack is generally empty and only has one return address
; on it during command execution.

;; MAIN-EXEC
L0283:  LD      HL,($400A)      ; fetch E-LINE
        LD      (HL),$B0        ; insert the character inverse 'K'.

        INC     HL              ; address the next location.
        LD      (HL),$76        ; insert a newline.

        INC     HL              ; address the next location.
        LD      ($400C),HL      ; set D-FILE to start of dynamic display file.
        LD      (IY+$12),$02    ; set DF-SZ to 2 lines.

; ->

;; AUTO-LIST
L0293:  CALL    L0747           ; routine CLS sets a minimal display and
                                ; initializes screen values in registers.
                                 
        EX      DE,HL           ;
        LD      A,B             ; load line value, 23, to A.
        SUB     (IY+$12)        ; subtract DF-SZ of lower screen.
        JR      C,L02F7         ; forward if the lower screen is 24 lines 
                                ; to ED-COPY.

        INC     A               ; allow for a blank line.
        LD      B,A             ; place in B line

        EXX                     ; switch to preserve line/column values.

        LD      HL,($4006)      ; fetch E_PPC the current line number.
        LD      DE,($4013)      ; fetch the top line on screen from S_TOP.
        SBC     HL,DE           ; subtract the two BASIC line numbers
        EX      DE,HL           ; and bring S_TOP to HL.
        JR      NC,L02B0        ; forward if current line >= top line to LIST-1.

        ADD     HL,DE           ; else reform the E_PPC value 
        LD      ($4013),HL      ; and make S_TOP the same.

;; LIST-1
L02B0:  CALL    L060A           ; routine LINE-ADDR gets the address of the
                                ; BASIC line in HL.
        LD      E,$00           ; signal current line yet to be printed

;; LIST-ALL
L02B5:  CALL    L04F7           ; routine OUT-LINE

        JR      C,L02B5         ; loop until upper screen is full to LIST-ALL.

        DEC     E               ; test if current line has appeared.
        JR      NZ,L02F0        ; forward to LIST-DONE if current line
                                ; has appeared.

; else the current line has yet to appear.

        PUSH    HL              ; else save HL ( )
        LD      HL,($4006)      ; fetch E_PPC - the current line.
        CALL    L060A           ; routine LINE-ADDR in DE
        POP     HL              ; restore HL

        AND     A               ; prepare to subtract.
        SBC     HL,DE           ; subtract setting carry.

        LD      HL,$4013        ; address system variable S_TOP
        JR      NC,L02D8        ; forward if E_PPC precedes to LN-FETCH

        EX      DE,HL           ; else swap pointers.

        LD      A,(HL)          ; pick up high byte.
        INC     HL              ; address low byte.
        LDI                     ; copy low byte to S_TOP_lo.
        LD      (DE),A          ; insert the high byte.

;; AUTO-L-J
L02D3:  JR      L0293           ; back to AUTO-LIST.

; ------------------------------------
; THE 'CURSOR DOWN EDITING' SUBROUTINE
; ------------------------------------


;; ED-DOWN
L02D5:  LD      HL,$4006        ; address system variable E_PPC
                                ; and continue...

; ----------------------
; THE 'LN-FETCH' SECTION
; ----------------------

;; LN-FETCH
L02D8:  LD      E,(HL)          ;
        INC     HL              ;
        LD      D,(HL)          ;
        PUSH    HL              ;
        EX      DE,HL           ;
        INC     HL              ; increment as starting point
        CALL    L060A           ; routine LINE-ADDR
        CALL    L03C2           ; LINE-NO
        POP     HL              ; restore hi pointer.

; ----------------------
; THE 'LN-STORE' SECTION
; ----------------------
; On entry, HL holds E_PPC_hi.

;; LN-STORE
L02E5:  BIT     5,(IY+$19)      ; test FLAGX.
        JR      NZ,L02F7        ; forward if INPUT to ED-COPY.

        LD      (HL),D          ; insert high byte
        DEC     HL              ; DECrement
        LD      (HL),E          ; insert low byte

;

        JR      L0293           ; back to AUTO-LIST

; --------------------------
; THE 'LIST-DONE' SUBROUTINE
; --------------------------
; When the listing is complete then the rest of the upper display is blanked,
; to erase what may have been printed during the interim, the display file
; cursor is updated and the current line is printed in the lower screen.

;; LIST-DONE
L02F0:  CALL    L05C2           ; CL-EOD clear to end of upper display.

       LD      ($400E),DE       ; set lower screen position DF_EA
                                ; to end
                                ; and continue...

; -------------------------------------
; THE 'LOWER SCREEN COPYING' SUBROUTINE
; -------------------------------------
; This is called.
; When the line in the editing area is to be printed in the lower screen.
; It is by repeatedly printing the line when any key is pressed that the
; cursor for instance appears to move.
; It is called in a similar fashion to animate the input line.

;; ED-COPY
L02F7:  LD      (IY+$01),$01    ; set FLAGS leading space allowed
        LD      HL,($400A)      ; E_LINE

        CALL    L07BE           ; routine MAIN-G checks syntax of line.

        LD      DE,($400E)      ; fetch start of lower screen from DF_EA
        LD      B,(IY+$12)      ; fetch lines in lower screen from DF_SZ
        LD      C,$01           ; set column to 1
                                ; to print an initial newline for gap?
        EXX                     ;

        LD      HL,($400A)      ; fetch start of edit line from E_LINE

        CALL    L0512           ; routine OUT-LINE-2 prints characters starting
                                ; with the individual digits of line number.

        JR      C,L031D         ; forward with success to LINE-DONE

; else there wasn't enough room in lower screen for line.

        LD      HL,$4012        ; address DF_SZ the Display Size for
                                ; the lower screen.
        INC     (HL)            ; increment it.
        LD      A,$18           ; load A with 24 decimal.
        CP      (HL)            ; compare to DF-SZ

        JR      NC,L02D3        ; indirect jump back to AUTO-LIST
                                ; if no greater than 24 lines.

        LD      (HL),A          ; else limit to 24 lines.

;; LINE-DONE
L031D:  CALL    L05C2           ; routine CL-EOD clears to the end of lower
                                ; screen

        CALL    L013F           ; routine KEYBOARD gets key values in BC.

; now decode the value

        SRA     B               ; sets carry if unshifted (bit 7 remains set)
        SBC     A,A             ; $FF unshifted, else $00
        OR      $26             ; $FF unshifted, else $26
        LD      L,$05           ; there are five keys in each row.
        SUB     L               ; set the starting point

;; KEY-LINE
L032B:  ADD     A,L             ; add value 5 (or 1)
        SCF                     ; carry will go to bit 7
        RR      C               ; test C (which has 1 unset bit identifying row)
        JR      C,L032B         ; back if carry to KEY-LINE

; if only one key pressed C should now be $FF.

        INC     C               ; test for $FF
        JR      NZ,L02F7        ; back if multiple keys to ED-COPY

; the high byte of the key value identifies the column - again only one bit is
; now reset.

        LD      C,B             ; transfer to B
        DEC     L               ; test if this is first time through
        LD      L,$01           ; reduce increment from five to one.
        JR      NZ,L032B        ; back if L was five to KEY-LINE

; The accumulator now holds a key value 1-78 decimal.

        LD      HL,L006C - 1    ; location before the MAIN-KEYS table ($006B)
                                ; the index value is 1 - 78.

        LD      E,A             ; code to E  (D is zero from keyboard)
        ADD     HL,DE           ; index into the table.
        LD      A,(HL)          ; pick up the letter/number/.

        BIT     2,(IY+$01)      ; test FLAGS K-MODE ?
        JR      Z,L034D         ; skip forward if not

        ADD     A,$C0           ; add 192 decimal
                                ; e.g. 'A' 38d + 192 = 230 (LIST)

        CP      $E6             ; compare to 'LIST'
        JR      NC,L034D        ; skip forward if command tokens to EDC-2.

        LD      A,(HL)          ; else load A from HL again
                                ; (numbers and symbols)

;; EDC-2
L034D:  CP      $C0             ; set the overflow flag for editing key $70-$77

        JP      PE,L035E        ; forward with range $40 - $7F to ED-KEYS

        LD      HL,($4004)      ; else fetch keyboard cursor from P_PTR
        LD      BC,$0001        ; one space required.
        CALL    L05D5           ; routine MAKE-ROOM makes room at cursor.
                                ; note HL - first, DE - LAST

        LD      (DE),A          ; and insert the keyboard character.

;; EDC-JR
L035C:  JR      L02F7           ; loop back to ED-COPY

; -----------------------------
; THE 'EDITING KEYS' SUBROUTINE
; -----------------------------

;; ED-KEYS
L035E:  LD      E,A             ; transfer code to E.
                                ; (D holds zero from 'keyboard')

        LD      HL,L0372-$70-$70; theoretical base of ED-K-TAB  $0292

        ADD     HL,DE           ; index twice
        ADD     HL,DE           ; as a two-byte address is required.

        LD      C,(HL)          ; low byte of routine.
        INC     HL
        LD      B,(HL)          ; high byte of routine.
        PUSH    BC              ; push routine address to stack.
        LD      HL,($4004)      ; set HL to cursor from P_PTR
        RET                     ; jump to routine.

                                ; Note the stack is empty.

; ---------------------------------------------
; THE EDITING 'DELETE ONE CHARACTER' SUBROUTINE
; ---------------------------------------------

;; ED-DEL-1
L036C:  LD      BC,$0001        ; one character
        JP      L0666           ; routine RECLAIM-2

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

;; ED-K-TAB
L0372:  DEFW    L03A9           ; ED-UP                 $70
        DEFW    L02D5           ; ED-DOWN               $71
        DEFW    L0382           ; ED-LEFT               $72
        DEFW    L0387           ; ED-RIGHT              $73
        DEFW    L03B9           ; ED-HOME               $74
        DEFW    L03CB           ; ED-EDIT               $75
        DEFW    L0408           ; ED-ENTER              $76
        DEFW    L0395           ; ED-DELETE             $77

; ------------------------------------
; THE 'CURSOR LEFT EDITING' SUBROUTINE
; ------------------------------------

;; ED-LEFT
L0382:  CALL    L039E           ; routine ED-EDGE checks that cursor
                                ; not at start without disturbing HL.
                                ; quits early if not possible.   >>

        DEC     HL              ; move left.
        DEC     HL              ; and again for luck.
                                ; ...

; -------------------------------------
; THE 'CURSOR RIGHT EDITING' SUBROUTINE
; -------------------------------------

;; ED-RIGHT
L0387:  INC     HL              ; move right

        LD      A,(HL)          ; pick up the character.
        CP      $76             ; is it newline ?

        JR      Z,L03A7         ; triple jump back to ED-COPY if so.

        LD      (HL),$B0        ; else place inverse cursor there.
        LD      HL,($4004)      ; fetch P_PTR
        LD      (HL),A          ; and put character there
        JR      L035C           ; double jump back to ED-COPY

; -------------------------------
; THE 'DELETE EDITING' SUBROUTINE
; -------------------------------

;; ED-DELETE
L0395:  CALL    L039E           ; routine ED-EDGE will loop back to
                                ; ED-COPY if no deletion possible >>

        DEC     HL              ; decrement position
        CALL    L036C           ; routine ED-DEL-1
        JR      L035C           ; back to ED-COPY

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

;; ED-EDGE
L039E:  LD      DE,($400A)      ; fetch E_LINE - start of edit line.
        LD      A,(DE)          ; pick up first character.
        CP      $B0             ; test for inverse 'K'
        RET     NZ              ; return if cursor not at start.

        POP     DE              ; else drop the return address.

;; EDC-JR2
L03A7:  JR      L035C           ; and back to ED-COPY

; ----------------------------------
; THE 'CURSOR UP EDITING' SUBROUTINE
; ----------------------------------

;; ED-UP
L03A9:  LD      HL,($4006)      ; E_PPC
        CALL    L060A           ; routine LINE-ADDR
        EX      DE,HL
        CALL    L03C2           ; LINE-NO

;; ED-LINE
L03B3:  LD      HL,$4007        ; E_PPC_hi
        JP      L02E5           ; to LN-STORE to store new line
                                ; and produce an automatic listing.

; ------------------------
; THE 'ED-HOME' SUBROUTINE
; ------------------------
; ED-HOME (SHIFT 9) starts the listing at the first line.
; dropped in later ZX computers.

;; ED-HOME
L03B9:  LD      DE,$0000        ; start at 'line zero'
        JR      L03B3           ; back to ED-LINE above.

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

;; LINE-NO-A
L03BE:  EX      DE,HL           ; bring previous line to HL
                                ; and set DE in case we loop back a second time.
        LD      DE,L03B9 + 1    ; address of $00 $00 within the subroutine
                                ; above.

; -> The Entry Point.

;; LINE-NO
L03C2:  LD      A,(HL)          ; fetch hi byte of line number
        AND     $C0             ; test against $3F
        JR      NZ,L03BE        ; back to LINE-NO-A if at end.

        LD      D,(HL)          ; else high byte to D
        INC     HL              ; increase pointer
        LD      E,(HL)          ; low byte in E.
        RET                     ; return.
                                ; with next line number in DE

; -------------------------
; THE 'EDIT KEY' SUBROUTINE
; -------------------------
; Pressing the EDIT key causes the current line to be copied to the
; edit line. The two-byte line number is converted into 4 characters
; using leading spaces if the line is less than 1000. Next the 'K'
; cursor is inserted and the rest of the characters are copied verbatim
; into the edit buffer, keywords remaining as single character tokens.

;; ED-EDIT
L03CB:  LD      C,$00           ; set column to zero to inhibit a line feed
                                ; while 'sprinting' to the edit line.
                                ; see PRINT-A-2.
        LD      DE,($400A)      ; set DE (print destination) to E_LINE
        EXX                     ; switch.

        LD      HL,($4006)      ; E_PPC current line.
        CALL    L060A           ; routine LINE-ADDR
        CALL    L03C2           ; routine LINE-NO
        LD      A,D
        OR      E
        JP      Z,L0283         ; back if zero to MAIN-EXEC
                                ; no program.

        DEC     HL              ; point to location before
        CALL    L06BF           ; routine OUT-NUM-2 prints line number
                                ; to the edit line (unseen).

        DEC     HL              ; point to line number again
        CALL    L0624           ; routine NEXT-ONE gets length in
                                ; BC register.
        INC     HL              ; point to the
        INC     HL              ; first token.
        DEC     BC              ; decrease the length
        DEC     BC              ; by the same.

        EXX
        PUSH    DE              ; pick up the print position in the
        EXX                     ; edit line.

        POP     DE              ; and pop it to this set of registers
        LD      A,$B0           ; the inverse 'K' cursor
        LD      (DE),A          ; is inserted after line number.
        INC     DE              ; address next 'print' location.

        PUSH    HL              ; push position within program.

        LD      HL,$0022        ; an overhead of 34d bytes.
        ADD     HL,DE           ; add to edit line position
        ADD     HL,BC           ; add in length of line.
        SBC     HL,SP           ; subtract the stack pointer.
        JR      NC,L03A7        ; back to ED-COPY if not enough
                                ; room to fill edit line.

        POP     HL              ; restore program position.
        LDIR                    ; and copy it to edit line.
        LD      ($400C),DE      ; update D_FILE

        JP      L0293           ; jump back to AUTO-LIST

; ------------------------------
; THE 'ENTER EDITING' SUBROUTINE
; ------------------------------
; This causes the line to be parsed.
; The subroutine then loops back to MAIN-EXEC.

;; ED-ENTER
L0408:  LD      HL,($4015)      ; fetch X_PTR the error pointer.
        LD      A,H             ; check that it is
        OR      L               ; zero - no error.
        JR      NZ,L03A7        ; double jump back to ED-COPY
                                ; if an error has occurred during
                                ; syntax checking.

        LD      HL,($4004)      ; P_PTR

        CALL    L036C           ; ED-DEL-1 gets rid of cursor.

        LD      HL,($400A)      ; E_LINE

        LD      ($4026),HL      ; CH_ADD
        CALL    L001A           ; get-char
        BIT     5,(IY+$19)      ; FLAGX              input 1/edit 0
        JR      NZ,L043C        ; forward to MAIN-1 if in input mode.

; else the edit line is to be run.

        CALL    L0679           ; INT-TO-HL line number to HL'
        EXX                     ; switch in set with the line number.
        LD      A,H             ; and test
        OR      L               ; for zero.
        JP      NZ,L04BA        ; jump forward with a number to MAIN-ADD
                                ; to add a new BASIC line or replacement.

; else must be a direct command.

        DEC     HL              ; make the line number
        DEC     HL              ; the value minus two.

        LD      ($4002),HL      ; and set PPC

        CALL    L0747           ; routine CLS

        EXX                     ;
        LD      A,(HL)          ; fetch first character.
        CP      $76             ; is it just a newline ?
        JP      Z,L0283         ; jump back with newline to MAIN-EXEC
                                ; to produce an automatic listing.

; else check syntax and enter

;; MAIN-1
L043C:  LD      (IY+$00),$FF    ; set ERR_NR to no error
        LD      (IY+$01),$88    ; update FLAGS
                                ; set bit 7 - syntax checking off
                                ; set bit 3 - 'K' mode

;; M-2
L0444:  CALL    L07BE           ; routine MAIN-G parses and executes the line.

                                ; Note. this causes the value L0447 to be placed
                                ; on the machine stack as a return address.

;; M-3
L0447:  CALL    L0D0A           ; REC-EDIT reclaims the edit line

        LD      DE,($4002)      ; fetch current line number from PPC
        LD      HL,$4019        ; address FLAGX

        BIT     5,(HL)          ; test FLAGX - input???
        JR      Z,L0458         ; skip if editing to ->

        RES     5,(HL)          ; update FLAGX - signal editing.
        INC     DE              ; increase line number so cursor doesn't show.

;; M-4
L0458:  BIT     7,(IY+$00)      ; check ERR_NR.
        JR      Z,L0488         ; forward if an error has occurred.

        LD      HL,$4001        ; address FLAGS system variable

        BIT     3,(HL)          ; test FLAGS - K mode ?
        RES     3,(HL)          ; update FLAGS - set L mode for future anyway.

        LD      HL,($4026)      ; fetch character address CH_ADD
        INC     HL              ;
        JR      Z,L0474         ; forward if not K mode.

        EX      DE,HL           ; current line to HL, next char to DE.

        LD      A,H             ; fetch high byte of line number.
        AND     $C0             ; test for -2, -1 - direct command.
        JR      NZ,L0488        ; forward to MAIN-ERR if so

        CALL    L060A           ; routine LINE-ADDR gets address of this line.

;; M-5
L0474:  LD      A,(HL)          ; fetch
        AND     $C0             ;
        JR      NZ,L0488        ; at program end

; else pick up the next line number

        LD      D,(HL)          ;
        INC     HL              ;
        LD      E,(HL)          ;
        LD      ($4002),DE      ; place in PPC system variable
        INC     HL              ; point to first character
                                ; (space or command)

        LD      A,$7F           ; test for
        IN      A,($FE)         ; space key pressed.
        RRA                     ; the space bit.
        JR      C,L0444         ; back if BREAK
                                ; else continue...

;; MAIN-ERR
L0488:  CALL    L06E0           ; UNSTACK-Z quits if checking syntax >>>

        CALL    L05C2           ; routine CL-EOD clears to the end of upper
                                ; display area.
        LD      BC,$0120        ; set line 1, column 32 for lower screen.
        EXX                     ;

        LD      A,($4000)       ; fetch the error number from ERR_NR
        LD      BC,($4002)      ; fetch the current line from PPC
        INC     A               ; test if error still $FF
        JR      Z,L04A8         ; forward if so to MAIN-5.

        CP      $09             ; is the error the STOP statement ?
        JR      NZ,L04A1        ; forward if not STOP to SET-CONT to make the
                                ; continuing line the same as current.

        INC     BC              ; else increment line number for STOP.

;; SET-CONT
L04A1:  LD      ($4017),BC      ; store line number in OLDPPC
        JR      NZ,L04A8        ; forward if not STOP as line number is current

        DEC     BC              ; else decrement line number again.

; Now print the report line e.g. 100/0   (terminated OK at line 100)

;; MAIN-5
L04A8:  CALL    L0556           ; routine OUT-CODE prints line number

        LD      A,$15           ; prepare character '/'
        RST     10H             ; print the separator

        CALL    L06A1           ; OUT-NUM-1 to print error-code in A.

        CALL    L05C2           ; routine CL-EOD

        CALL    L013F           ; routine KEYBOARD

        JP      L0283           ; jump back to MAIN-EXEC

; ---------------------
; THE 'MAIN-ADD' BRANCH
; ---------------------
; This section allows a new BASIC line to be added to the Program.

;; MAIN-ADD
L04BA:  LD      ($4006),HL      ; make E_PPC the new line number.

        EXX                     ;
        EX      DE,HL           ;
        CALL    L0747           ; routine CLS
        SBC     HL,DE           ;
        EXX                     ;

        CALL    L060A           ; routine LINE-ADDR
        PUSH    HL              ;
        JR      NZ,L04D1        ; forward if line doesn't exist to MAIN-ADD1.

        CALL    L0624           ; routine NEXT-ONE gets length of old line
        CALL    L0666           ; routine RECLAIM-2

;; MAIN-ADD1
L04D1:  EXX                     ;
        INC     HL              ;
        LD      B,H             ;
        LD      C,L             ;
        LD      A,L             ;
        SUB     $03             ;
        OR      H               ;
        CALL    NZ,L094F        ; routine TEST-ROOM

        POP     HL              ;
        JR      NC,L04F4        ; double jump back to MAIN-EXEC
                                ; not possible.

        PUSH    BC              ;
        DEC     HL              ;
        CALL    L05D5           ; routine MAKE-ROOM
        INC     DE              ;
        LD      HL,($400C)      ; set HL from D_FILE
        DEC     HL              ; now points to end of edit line.
        POP     BC              ; restore length

        DEC     BC              ;
        LDDR                    ; copy line from edit line to prog.
        LD      HL,($4006)      ; E_PPC - line number
        EX      DE,HL           ; swap
        LD      (HL),D          ; insert high byte
        INC     HL              ;
        LD      (HL),E          ; insert low byte

;; MAIN-JR
L04F4:  JP      L0283           ; jump back to MAIN-EXEC

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

;; OUT-LINE
L04F7:  LD      BC,($4006)      ; fetch E_PPC
        CALL    L061C           ; routine CP-LINES
        LD      D,$97           ; prepare character '>'
        JR      Z,L0507         ; forward with line cursor if line is the
                                ; current edit line to OUT-LINE-1

        LD      DE,$0000        ; else replace line cursor with a
                                ; space in D, and zero to E.
        RL      E               ; pick up any carry from CP-LINES
                                ; should the line precede the
                                ; current edit line.

;; OUT-LINE-1
L0507:  LD      A,(HL)          ; fetch the high byte of line number.
        CP      $40             ; compare with end marker
        CALL    C,L06BF         ; routine OUT-NUM-2 if a valid line number.
        RET     NC              ; return if out of screen                >>>

        INC     HL              ; address the first command character.
        LD      A,D             ; fetch the space/cursor
        RST     10H             ; print it.
        RET     NC              ; return if out of screen.

;; OUT-LINE-2
L0512:  SET     0,(IY+$01)      ; update FLAGS - suppress a leading space

;; OUT-LINE-3
L0516:  LD      BC,($4015)      ; fetch error pointer - X_PTR
        AND     A               ; prepare to subtract.
        SBC     HL,BC           ; subtract the current address.
        JR      NZ,L0523        ; forward to OUT-LINE-4 if not an
                                ; exact match.
        LD      A,$B8           ; prepare inverse 'S' to show syntax error.
        RST     10H             ; print it.
        RET     Z               ; return if at end

;; OUT-LINE-4
L0523:  ADD     HL,BC           ; restore pointer.
        LD      A,(HL)          ; fetch character.
        INC     HL              ; address next character.

        CP      $B0             ; is character inverse 'K' ?
        JR      Z,L053C         ; forward if so to OUT-CURS.

; then cleverly split the characters into 4 streams.

        CP      $C0             ; compare character to 192 ?

        JP      PE,L0559        ; jump forward with 64-127 to OUT-SP-CH
                                ; thereby exiting the routine
                                ; as it must be the 118, NEWLINE character.

        JR      C,L0536         ; forward with 0-63, 128-191 to OUT-LINE-5
                                ; to print simple characters and their inverse
                                ; forms.

; that leaves tokens $C0 - $FF

        CALL    L0584           ; routine PO-TOKEN

        JR      L0539           ; forward to OUT-LINE-6

; ---

;; OUT-LINE-5
L0536:  CALL    L0559           ; routine OUT-SP-CH

;; OUT-LINE-6
L0539:  RET     NC              ; return if out of screen.            >>
        JR      L0516           ; else back to OUT-LINE-3 for more.

; ---------------------------------------------------------------------------
; Z80 PARITY/OVERFLOW FLAG:
; ------------------------
; The use of this flag is two-fold depending on the type of operation.
; It indicates the parity of the result of a LOGICAL operation such as an AND,
; OR, XOR by being set PE if there are an even number of set bits and reset
; PO if there are an odd number of set bits.
; so 10101010 is parity even, 00000001 is parity odd.
; JP PE, LABEL
; JP PO, LABEL are obvious.
; For MATHEMATICAL operations, (ADD, SUB, CP etc.) the P/V bit indicates a
; carry out of bit position 6 of the accumulator if signed values are being
; used.
; This indicates an overflow of a result greater than 127, which carries
; into bit 7, the sign bit.
; So as CP is just a SUB with the result thrown away.
; $C0 SUB $CO gives result $00   (PO - no overflow from 6 to 7)
; $8O SUB $C0 gives result $C0   (PO - no overflow from 6 to 7)
; $00 SUB $C0 gives result $40   (PO - no overflow from 6 to 7)
; $40 SUB $CO gives result $80   (PE - overflow from 6 to 7)
; The overflow flag is similarly set following 16-bit addition and subtraction
; routines.
; ---------------------------------------------------------------------------


; -----------------------------
; THE 'PRINT THE CURSOR' BRANCH
; -----------------------------

;; OUT-CURS
L053C:  BIT     2,(IY+$01)      ; test FLAGS - K-mode ?
        JR      NZ,L0543        ; skip to OUT-K if 'K' mode.

        INC     A               ; change from 'K' to 'L' cursor.

;; OUT-K
L0543:  RST     10H             ; print the cursor.
        JR      L0539           ; back to OUT-LINE-6 above.

; -----------------------------------------------------
; THE 'PRINTING CHARACTERS IN A BASIC LINE' SUBROUTINES
; -----------------------------------------------------

;; OUT-SP-2
L0546:  LD      A,E             ; transfer E to A
                                ; register E will be
                                ; $FF - no leading space.
                                ; $01 - the leading space itself.
                                ; $1C - '0' from a previous non-space print.
        RLCA                    ; test for the
        RRCA                    ; value $FF.
        RET     C               ; return if no leading space

        JR      L055C           ; forward to OUT-LD-SP

; ---

; --> The Entry Point.

;; OUT-SP-NO
L054C:  XOR     A               ; set accumulator to zero.

;; OUT-SP-1
L054D:  ADD     HL,BC           ; addition of negative number.
        INC     A               ; increment the digit.
        JR      C,L054D         ; back while overflow exists to OUT-SP-1

        SBC     HL,BC           ; else reverse the last addition.
        DEC     A               ; and decrement the digit.

        JR      Z,L0546         ; back to OUT-SP-2 if digit is zero again.

; else continue to print the final digit using OUT-CODE.

;; OUT-CODE
L0556:  LD      E,$1C           ; load E with '0'
                                ; Note. that E will remain as such for all
                                ; further calls. The leading space is no more.
        ADD     A,E             ; add the digit 1-9 to give '1' to '9'

;; OUT-SP-CH
L0559:  AND     A               ; test value for space.
        JR      Z,L0560         ; skip if zero to PRINT-A-2

;; OUT-LD-SP
L055C:  RES     0,(IY+$01)      ; signal allow leading space to FLAGS
                                ; and continue...

; ------------------------------
; THE 'MAIN PRINTING' SUBROUTINE
; ------------------------------
; This is a continuation of the PRINT restart.
; It is used primarily to print to the dynamic screen checking free memory
; before every character is printed.
; However it can also be used as an invisible process to 'sprint' the line
; number of a BASIC line to the Edit Line by ED-EDIT setting DE from E_LINE.
;
; As lines are unexpanded, then when the column count is reduced from 32 to 0 a
; newline is inserted before the character and the column count is reset.

;; PRINT-A-2
L0560:  EXX                     ; switch sets.

        LD      H,A             ; preserve character in H.
                                ; Note. this is restored by TEST-RM-2
        RLA                     ; rotate character twice to
        RLA                     ; test bit 6 - sets carry for NEWLINE.

        DEC     C               ; decrease column count - affects zero / sign.

        JR      NC,L0569        ; forward if 0-63 or inverse to NO-NL

; else the incoming character is a NEWLINE $76

        LD      C,$00           ; set column to zero without disturbing flags.
                                ; if this is a received NEWLINE.
                                ; this will be set to 32 if a subsequent
                                ; character is printed

;; NO-NL
L0569:  JP      M,L0574         ; jump to PR-SPR if column was originally 0

        JR      C,L057C         ; forward to PRI-CHAR with a received NEWLINE.

        JR      NZ,L057C        ; forward if column not yet reduced to zero
                                ; to PRI-CHAR

; else an automatic newline is required before the received character as
; we are at end of line.

        LD      A,$76           ; prepare the newline
        LD      (DE),A          ; insert at screen position
        INC     DE              ; increase the address pointer.

;; PR-SPR
L0574:  JR      C,L0578         ; skip if a received newline to PRI-SKIP

        LD      C,$20           ; reset column to 32 decimal.

;; PRI-SKIP
L0578:  AND     A               ; clear carry now to signal failure should the
                                ; next test fail.
        DEC     B               ; decrease line.
        JR      Z,L0582         ; forward with out of screen to PR-END.

;; PRI-CH
L057C:  LD      L,B             ; transfer line number, B to L for next routine.

        CALL    L0958           ; routine TEST-RM-2 tests room.
                                ; (character is in H returned in A)
                                ; carry set if there is room.

        LD      (DE),A          ; insert chr at screen (or edit line).
        INC     DE              ; increase destination address.

;; PR-END
L0582:  EXX                     ; switch to protect registers.
        RET                     ; return

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

;; PO-TOKEN
L0584:  CALL    L05A8           ; routine PO-SEARCH locates token
        JR      NC,L0592        ; forward to PO-LOOP if first character is
                                ; not alphanumeric. e.g. '**'

; else consider a leading space.

        BIT     0,(IY+$01)      ; test FLAGS - leading space allowed ?
        JR      NZ,L0592        ; forward to PO-LOOP if not.

; else print a leading space.

        XOR     A               ; prepare a space
        RST     10H             ; print it
        RET     NC              ; return if out of screen.

; now enter a loop to print each character and then consider a trailing space.

;; PO-LOOP
L0592:  LD      A,(BC)          ; fetch character from token table.
        AND     $3F             ; mask to give range ' ' to 'Z'

        CALL    L0559           ; routine OUT-SP-CH

        RET     NC              ; return if out of screen.

        LD      A,(BC)          ; reload the character
        INC     BC              ; point to next.
        ADD     A,A             ; test for the inverted bit.
        JR      NC,L0592        ; loop back if not inverted to PO-LOOP

;

        CP      $38             ; compare with what was '0' before doubling.
        RET     C               ; return if less. i.e. not a command.     >>

        XOR     A               ; else prepare a space
        SET     0,(IY+$01)      ; update FLAGS - use no leading space
        JR      L0560           ; back to PRINT-A-2 for trailing space.   >>

; -----------------------------
; THE 'TABLE SEARCH' SUBROUTINE
; -----------------------------

;; PO-SEARCH
L05A8:  PUSH    HL              ; * preserve character pointer

        LD      HL,$00BA        ; point to start of the table
        SUB     (HL)            ; test against the threshold character 212
        INC     HL              ; address next in table.   ('?' + $80 )
        JR      C,L05B9         ; forward to PO-FOUND if less than 212
                                ; to print a question mark.

        INC     A               ; make range start at 1 for chr 212.
                                ; note - should the required token be 212
                                ; the printable quote character then the
                                ; pointer currently addresses '"' + $80.
        LD      B,A             ; save reduced token in B as a counter.

;; PO-STEP
L05B2:  BIT     7,(HL)          ; test for inverted bit
        INC     HL              ; increase address
        JR      Z,L05B2         ; back to PO-STEP for inverted bit

        DJNZ    L05B2           ; decrement counter and loop back to PO-STEP
                                ; until at required token.

;; PO-FOUND
L05B9:  LD      B,H             ; transfer the address
        LD      C,L             ; to BC.

        POP     HL              ; * restore string address
        LD      A,(BC)          ; fetch first character from token.
        AND     $3F             ; mask off range 0-63d, SPACE to Z
        ADD     A,$E4           ; add value 228
        RET                     ; return with carry set if alphanumeric and a
                                ; leading space is required.

; -------------------------------------
; THE 'CLEAR TO END OF DISPLAY' ROUTINE
; -------------------------------------

;; CL-EOD
L05C2:  EXX                     ; switch in the set with screen values.

        XOR     A               ; clear accumulator.
        CP      B               ; compare with line counter - 0 to 23.
        JR      Z,L05D0         ; forward if clear to SET-EOD.

        CP      C               ; compare to column count - 0 to 32.
        LD      A,$76           ; prepare a NEWLINE.
        JR      Z,L05CE         ; forward, if zero, to CL-EOL.

;; INS-CR
L05CC:  LD      (DE),A          ; insert a newline/carriage return.
        INC     DE              ; address next position.

;; CL-EOL
L05CE:  DJNZ    L05CC           ; reduce line counter and loop back to INS-CR.

;; SET-EOD
L05D0:  LD      ($4010),DE      ; update DF_END - display file end.
        RET                     ; return.

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

;; MAKE-ROOM
L05D5:  CALL    L05DF           ; routine POINTERS also sets BC
        LD      HL,($4010)      ; fetch new display file end DF_END
        EX      DE,HL           ; switch source/destination.
        LDDR                    ; now make the room.
        RET                     ; return.
                                ; with HL pointing at first new location.

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

;; POINTERS
L05DF:  PUSH    AF              ;
        PUSH    HL              ;
        LD      HL,$4008        ; VARS
        LD      A,$05           ;

;; PTR-NEXT
L05E6:  LD      E,(HL)          ;
        INC     HL              ;
        LD      D,(HL)          ;
        EX      (SP),HL         ;
        AND     A               ;
        SBC     HL,DE           ;
        ADD     HL,DE           ;
        EX      (SP),HL         ;
        JR      NC,L05FA        ; forward 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
L05FA:  INC     HL              ;
        DEC     A               ;
        JR      NZ,L05E6        ; back to PTR-NEXT for all five
                                ; dynamic variables.

; now find the size of the block to be moved.

        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                     ; return  ->

; --------------------------
; THE 'LINE-ADDR' SUBROUTINE
; --------------------------

;; LINE-ADDR
L060A:  PUSH    HL              ; save the given line number.
        LD      HL,$4028        ; start of PROG
        LD      D,H             ; transfer the address
        LD      E,L             ; to the DE register pair.

;; LINE-AD-1
L0610:  POP     BC              ; the given line number.
        EX      DE,HL           ;

        CALL    L061C           ; routine CP-LINES

        RET     NC              ; return if carry set                   >>

        PUSH    BC              ; otherwise save given line number

        CALL    L0624           ; routine NEXT-ONE

        JR      L0610           ; back to LINE-AD-1 to consider the next
                                ; line of the program.

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

;; CP-LINES
L061C:  LD      A,(HL)          ; fetch the high byte of the addressed line
        CP      B               ; number and compare it.
        RET     NZ              ; return if they do not match.

        INC     HL              ; next compare the low bytes.
        LD      A,(HL)          ;
        DEC     HL              ;
        CP      C               ;
        RET                     ; return with carry flag set if the addressed
                                ; line number has yet to reach the
                                ; given line number.

;------------------------------------------------------------------------
; Storage of variables. For full details - see Page 107
; ZX80 BASIC Programming by Hugo Davenport 1980.
; It is bits 7-5 of the first character of a variable that allow
; the five types to be distinguished. Bits 4-0 are the reduced letter.
; So any variable name is higher that $3F and can be distinguished
; also from the variables area end-marker $80.
;
; 76543210 meaning                       brief outline of format after letter.
; -------- ------------------------      -----------------------
; 011      simple integer variable.      2 bytes. (after letter)
; 010      long-named integer variable   2 bytes. (after inverted name)
; 100      string                        letter + contents + $01.
; 101      array of integers             letter + max subs byte + subs * 2.
; 111      for-next loop variable.       7 bytes - letter, value, limit, line.
; 10000000 the variables end-marker.
;
; Note. any of the above six will serve as a program end-marker.
;
; -----------------------------------------------------------------------

; -------------------------
; THE 'NEXT-ONE' SUBROUTINE
; -------------------------

;; NEXT-ONE
L0624:  PUSH    HL              ; save address of current line or variable.

        LD      A,(HL)          ; fetch the first byte.
        ADD     A,A             ; test bits 7 and 6
        JP      M,L0635         ; jump forward if simple, long-named or for-next
                                ; control variable to NO-SLNFM

        JR      C,L0643         ; forward if string or arrays to NO-STR-AR

; that leaves program line numbers.

        INC     HL              ; step past high byte
        LD      A,$76           ; the search is for newline

;; NO-SEARCH
L062F:  INC     HL              ; skip to next address past low byte.
        LD      B,A             ; save search byte in B to create
                                ; a large value in BC so that search is
                                ; not curtailed.
        CPIR                    ; and locate the known character.
        JR      L0652           ; forward to ??? with HL addressing
                                ; the following character.

; ---

; the branch was here with simple, long-named and for-next variables

;; NO-SLNFN
L0635:  LD      BC,$0002        ; presume a for-next variable (1+2 cells)
        JR      C,L063B         ; skip forward if for-next variable.

        LD      C,B             ; set C to zero - just one cell for simple
                                ; and long-named.

;; NO-FNXT
L063B:  RLA                     ; original bit 5 is now bit 7.

;; NO-LNLP
L063C:  RLA                     ; test original bit 5 of letter.

        INC     HL              ; advance address.
        LD      A,(HL)          ; pick up next byte - possibly a letter
        JR      NC,L063C        ; back if originally long-named or if
                                ; on subsequent loops character is not inverted

; whatever the route we are now pointing at the first cell with the number
; of cells less one in register C.

        JR      L064F           ; forward to NO-CELLS to calculate space to the
                                ; end of variable.

; ---

; the branch was here with either single strings or numeric array variables

;; NO-STR_AR
L0643:  AND     $40             ; test shifted bit 6 - will be set for arrays
        LD      A,$01           ; set search for null terminator
        JR      Z,L062F         ; back if not an array to NO-SEARCH to
                                ; search for the end of string.

; the object is a NUMERIC ARRAY

        INC     HL              ; point to maximum subscription
        LD      A,(HL)          ; and fetch
        INC     HL              ; point to first cell.
        LD      B,$00           ; prepare to index
        LD      C,A             ; max subscription to C
                                ; and continue to find following byte.

;; NXT-O-6
L064F:  INC     BC              ; bump the range
        ADD     HL,BC           ; add to start
        ADD     HL,BC           ; add again as each cell is two bytes.

;; NXT-O-7
L0652:  POP     DE              ; restore previous address to DE and
                                ; continue into the difference routine...

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

;; DIFFER
L0653:  AND     A               ; prepare to subtract.
        SBC     HL,DE           ; calculate the length of the line/var

        LD      B,H             ; transfer the length
        LD      C,L             ; to the BC register pair.

        ADD     HL,DE           ; reform the address of next one in HL.
        EX      DE,HL           ; swap pointers
        RET                     ; return.

; ------------------------------
; THE 'CLEAR' COMMAND SUBROUTINE
; ------------------------------
; The CLEAR command removes all BASIC variables.

;; CLEAR
L065B:  LD      HL,($400A)      ; set HL to E_LINE.
        DEC     HL              ; decrement to point to the $80 end-marker.
        LD      DE,($4008)      ; set start from VARS system variable.

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

;; RECLAIM-1
L0663:  CALL    L0653           ; routine DIFFER

;; RECLAIM-2
L0666:  PUSH    BC              ;

        LD      A,B             ;
        CPL                     ;
        LD      B,A             ;

        LD      A,C             ;
        CPL                     ;
        LD      C,A             ;

        INC     BC              ;

        CALL    L05DF           ; routine POINTERS

        EX      DE,HL           ;
        POP     HL              ;
        ADD     HL,DE           ;
        PUSH    DE              ;
        LDIR                    ;
        POP     HL              ;
        RET                     ; return.

; ----------------------------------------
; THE 'INTEGER TO ALTERNATE HL' SUBROUTINE
; ----------------------------------------

;; INT-TO-HL
L0679:  LD      A,(HL)          ; fetch first digit
        EXX                     ; switch
        LD      HL,$0000        ; initialize result register to zero.
        LD      B,H             ; make B zero also.

;; DEC-LP
L067F:  SUB     $1C             ; subtract chr '0'
        JR      C,L069A         ; forward to STOR-RSLT if less.            >>

        CP      $0A             ; compare with 'ten'
        JR      NC,L069A        ; forward to STOR-RSLT if higher than '9'. >>

        LD      C,A             ; save unit in C.

; now test that the result is not about to enter the 32768 - 65535 region.

        LD      A,$0D           ; value 13 to A
        CP      H               ; compare to result_hi
        JR      NC,L068E        ; forward if less to NO-OVERFLW

        LD      H,A             ; else maintain the overflow condition.

;; NO-OVRFLW
L068E:  LD      D,H             ; copy HL.
        LD      E,L             ; to DE.
        ADD     HL,HL           ; double result
        ADD     HL,HL           ; and again.
        ADD     HL,DE           ; now * 5
        ADD     HL,HL           ; now *10
        ADD     HL,BC           ; add in new digit.

        EXX                     ; switch
        RST     18H             ; NXT-CH-SP
        EXX                     ; switch

        JR      L067F           ; loop back to DEC-LP for more digits.

; -------------------------------------
; THE 'STORE INTEGER RESULT' SUBROUTINE
; -------------------------------------

;; STOR-RSLT
L069A:  LD      A,H             ; transfer high byte to A.
        LD      ($4022),HL      ; set value of expression RESULT
        EXX                     ; switch
        RLA                     ; sets carry if higher than 32767
        RET                     ; return.

; ------------------------------------------------
; THE 'REPORT AND LINE NUMBER PRINTING' SUBROUTINE
; ------------------------------------------------
; Actually the first entry point prints any number in the
; range -32768 to 32767.

; --> This entry point prints a number in BC.

;; OUT-NUM-1
L06A1:  PUSH    DE              ; preserve registers
        PUSH    HL              ; throughout

        LD      H,B             ; transfer number
        LD      L,C             ; to be printed to HL.

        BIT     7,B             ; test the sign bit
        JR      Z,L06B5         ; forward if positive to OUT-NUM-P

        LD      A,$12           ; prepare character '-'
        CALL    L0559           ; routine OUT-SP-CH

        JR      NC,L06DD        ; forward if out of screen to OUT-NUM-4

        LD      HL,$0001        ; else make the negative number
        SBC     HL,BC           ; positive.

; at this stage the number is positive

;; OUT-NUM-P
L06B5:  LD      E,$FF           ; signal no leading space.

        LD      BC,$D8F0        ; prepare the value -10000

        CALL    L054C           ; routine OUT-SP-NO will print the first digit
                                ; of a 5-digit number but nothing if smaller.

        JR      L06C8           ; forward to OUT-NUM-3
                                ; to consider other four digits in turn.
                                ; (with carry set from a successful print)

; ---

; --> This entry point prints a BASIC line number addressed by HL.

;; OUT-NUM-2
L06BF:  PUSH    DE              ; save DE throughout
        LD      D,(HL)          ; fetch high byte of number to D
        INC     HL
        LD      E,(HL)          ; fetch low byte of number to E

        PUSH    HL              ; save HL now till the end.
        EX      DE,HL           ; number to HL.

        LD      E,$00           ; prepare a leading space
        SCF                     ; set carry flag for subtractions.

; both paths converge here.

;; OUT-NUM-3
L06C8:  LD      BC,$FC18        ; the value -1000
        CALL    C,L054C         ; routine OUT-SP-NO

        LD      BC,$FF9C        ; the value -100
        CALL    C,L054C         ; routine OUT-SP-NO

        LD      C,$F6           ; the value -10
        CALL    C,L054C         ; routine OUT-SP-NO

        LD      A,L             ; the remainder.
        CALL    C,L0556         ; routine OUT-CODE

;; OUT-NUM-4
L06DD:  POP     HL              ; restore original
        POP     DE              ; registers.
        RET                     ; return.

; --------------------------
; THE 'UNSTACK-Z' SUBROUTINE
; --------------------------

;; UNSTACK-Z
L06E0:  BIT     7,(IY+$01)      ; test FLAGS - Checking Syntax ?
        POP     HL              ; drop the return address
        RET     Z               ; return if so.

; else fetch screen coordinates alternate registers for the run-time situation.

        EXX
        LD      DE,($400E)      ; fetch display print position DF_EA
        LD      BC,($4024)      ; fetch line and column from SPOSN
        EXX                     ; exchange and continue...

; and jump back to the calling routine...

; ------------------
; THE 'USR' FUNCTION
; ------------------

;; USR
L06F0:  JP      (HL)            ; that appears to be it.

; ---------------------------
; THE 'PRINT ITEM' SUBROUTINE
; ---------------------------

;; PR-ITEM
L06F1:  BIT     7,(IY+$00)      ; ERR_NR
        RET     Z               ; return if an error has already been
                                ; encountered.

        CALL    L06E0           ; UNSTACK-Z quits if checking syntax

        LD      HL,($4022)      ; fetch result of SCANNING from RESULT
        BIT     6,(IY+$01)      ; test FLAGS for result type.
        JR      Z,L070C         ; forward to PR-STRING if type string.

        LD      B,H             ; transfer result
        LD      C,L             ; to BC register pair.

        CALL    L06A1           ; routine OUT-NUM-1
        JR      L0723           ; forward to PO-CHECK to check for
                                ; success and store position

; -----------------------------
; THE 'PRINT STRING' SUBROUTINE
; -----------------------------

;; PO-CHAR
L0709:  RST     10H             ; PRINT-A

;; PO-LOOP
L070A:  JR      NC,L0725        ; forward to ERROR-05 with carry
                                ; Out of screen.
; --> Entry Point.

;; PR-STRING
L070C:  LD      A,(HL)          ; fetch a character.
        INC     HL              ; increment pointer.
        CP      $01             ; is it null-terminator.
        JR      Z,L073A         ; forward to PO-STORE if so.

        BIT     6,A             ; test if simple character or inverse
        JR      Z,L0709         ; back to PO-CHAR if so

        CALL    L0584           ; routine PO-TOKEN to print
                                ; ranges $40 - $7f, $0C - $FF
        JR      L070A           ; loop back to PO-LOOP

; --------------------------------
; THE 'CARRIAGE RETURN' SUBROUTINE
; --------------------------------

;; PRINT-CR
L071B:  CALL    L06E0           ; UNSTACK-Z quits if checking syntax

        LD      A,$76           ; prepare a NEWLINE character
        CALL    L0559           ; routine OUT-SP-CH prints it
                                ; returning with carry reset if there
                                ; was no room on the screen.

;; PO-CHECK
L0723:  JR      C,L073A         ; forward to PO-STORE if OK

;; ERROR-05
L0725:  RST     08H             ; ERROR restart
        DEFB    $04             ; No more room on screen.

; ------------------------
; THE 'PO-FILL' SUBROUTINE
; ------------------------

;; PO-FILL
L0727:  CALL    L06E0           ; UNSTACK-Z return if checking syntax.

        SET     0,(IY+$01)      ; signal no leading space.

;; PO-SPACE
L072E:  XOR     A               ; prepare a space
        RST     10H             ; PRINT-A outputs the character.
        JR      NC,L0725        ; back to ERROR-05 if out of screen

        EXX                     ;
        LD      A,C             ; get updated column
        EXX                     ;

        DEC     A               ; decrement it.
        AND     $07             ; isolate values 0 - 7
        JR      NZ,L072E        ; back to PO-SPACE for more.

; -------------------------------
; THE 'POSITION STORE' SUBROUTINE
; -------------------------------

;; PO-STORE
L073A:  EXX                     ; switch in the set that maintains the print
                                ; positions in the registers.
        EX      DE,HL           ; switch print position to HL for easier coding.

;; PO-STOR-2
L073C:  LD      ($4024),BC      ; set SPOSN to line/column
        LD      ($400E),HL      ; set DF_EA to output address
        LD      ($4010),HL      ; set DF_END output address
        RET                     ; return.

; ----------------------------
; THE 'CLS' COMMAND SUBROUTINE
; ----------------------------

;; CLS
L0747:  LD      HL,($400C)      ; fetch start of display from D_FILE

        LD      (HL),$76        ; insert a single newline.
        INC     HL              ; advance address.

        LD      BC,$1721        ; set line to 23 and column to 33.
        JR      L073C           ; back to PO-STOR-2 above

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

;; i. The offset table


L0752:  DEFB    L07A1 - $       ; $4F offset to $07A1 P-LIST
        DEFB    L077F - $       ; $2C offset to $077F P-RETURN
        DEFB    L07B8 - $       ; $64 offset to $07B8 P-CLS
        DEFB    L0794 - $       ; $3F offset to $0794 P-DIM
        DEFB    L07AF - $       ; $59 offset to $07AF P-SAVE
        DEFB    L0782 - $       ; $2B offset to $0782 P-FOR
        DEFB    L076F - $       ; $17 offset to $076F P-GO-TO
        DEFB    L07A4 - $       ; $4B offset to $07A4 P-POKE
        DEFB    L0790 - $       ; $36 offset to $0790 P-INPUT
        DEFB    L07A9 - $       ; $4E offset to $07A9 P-RANDOMISE
        DEFB    L076C - $       ; $10 offset to $076C P-LET
        DEFB    L07BB - $       ; $5E offset to $07BB P-CH-END
        DEFB    L07BB - $       ; $5D offset to $07BB P-CH-END
        DEFB    L0789 - $       ; $2A offset to $0789 P-NEXT
        DEFB    L078D - $       ; $2D offset to $078D P-PRINT
        DEFB    L07BB - $       ; $5A offset to $07BB P-CH-END
        DEFB    L07C2 + 1 - $   ; $61 offset to $07C3 P-NEW
        DEFB    L079E - $       ; $3B offset to $079E P-RUN
        DEFB    L077C - $       ; $18 offset to $077C P-STOP
        DEFB    L07B2 - $       ; $4D offset to $07B2 P-CONTINUE
        DEFB    L0773 - $       ; $0D offset to $0773 P-IF
        DEFB    L0778 - $       ; $11 offset to $0778 P-GOSUB
        DEFB    L07AC - $       ; $44 offset to $07AC P-LOAD
        DEFB    L07B5 - $       ; $4C offset to $07B5 P-CLEAR
        DEFB    L079B - $       ; $31 offset to $079B P-REM
        DEFB    L07BB - $       ; $50 offset to $07BB P-CH-END


;; ii. The parameter table.

;; P-LET
L076C:  DEFB    $01             ; Class-01 - a variable is required.
        DEFB    $E3             ; separator '='
        DEFB    $02             ; Class-02 - an expression, of type integer or
                                ; string must follow.

;; P-GO-TO
L076F:  DEFB    $06             ; Class-06 - a numeric expression must follow.
        DEFB    $00             ; Class-00 - no further operands.
        DEFW    L0934           ; address: $0934

;; P-IF
L0773:  DEFB    $06             ; Class-06 - a numeric expression must follow.
        DEFB    $D5             ; separator 'THEN'
        DEFB    $05             ; Class-05 - variable syntax checked entirely
                                ; by routine.
        DEFW    L08B9           ; address: $08B9

;; P-GOSUB
L0778:  DEFB    $06             ; Class-06 - a numeric expression must follow.
        DEFB    $00             ; Class-00 - no further operands.
        DEFW    L0943           ; address: $0943

;; P-STOP
L077C:  DEFB    $00             ; Class-00 - no further operands.
        DEFW    L092E           ; address: $092E

;; P-RETURN
L077F:  DEFB    $00             ; Class-00 - no further operands.
        DEFW    L0965           ; address: $0965

;; P-FOR
L0782:  DEFB    $04             ; Class-04 - a single-character variable must
                                ; follow.
        DEFB    $E3             ; separator '='
        DEFB    $06             ; Class-06 - a numeric expression must follow.
        DEFB    $D6             ; separator 'TO'
        DEFB    $05             ; Class-05 - variable syntax checked entirely
                                ; by routine.
        DEFW    L08C4           ; address: $08C4

;; P-NEXT
L0789:  DEFB    $04             ; Class-04 - a single-character variable must
                                ; follow.
        DEFB    $00             ; Class-00 - no further operands.
        DEFW    L08F9           ; address: $08F9

;; P-PRINT
L078D:  DEFB    $05             ; Class-05 - variable syntax checked entirely
                                ; by routine.
        DEFW    L0972           ; address: $0972

;; P-INPUT
L0790:  DEFB    $01             ; Class-01 - a variable is required.
        DEFB    $00             ; Class-00 - no further operands.
        DEFW    L099A           ; address: $099A

;; P-DIM
L0794:  DEFB    $04             ; Class-04 - a single-character variable must
                                ; follow.
        DEFB    $DA             ; separator '('
        DEFB    $06             ; Class-06 - a numeric expression must follow.
        DEFB    $D9             ; separator ')'
        DEFB    $00             ; Class-00 - no further operands.
        DEFW    L0CD3           ; address: $0CD3

;; P-REM
L079B:  DEFB    $05             ; Class-05 - variable syntax checked entirely
                                ; by routine.
        DEFW    L084A           ; address: $084A

;; P-RUN
L079E:  DEFB    $03             ; Class-03 - a numeric expression may follow
                                ; otherwise zero will be used.
        DEFW    L093D           ; address: $093D


;; P-LIST
L07A1:  DEFB    $03             ; Class-03 - a numeric expression may follow
                                ; else default to zero.
        DEFW    L0256           ; Address: $0256

;; P-POKE
L07A4:  DEFB    $06             ; Class-06 - a numeric expression must follow.
        DEFB    $D8             ; separator ','
        DEFB    $05             ; Class-05 - variable syntax checked entirely
                                ; by routine.
        DEFW    L09D1           ; address: $09D1

;; P-RANDOMISE
L07A9:  DEFB    $03             ; Class-03 - a numeric expression may follow
                                ; otherwise zero will be used.
        DEFW    L0923           ; address: $0923

;; P-LOAD
L07AC:  DEFB    $00             ; Class-00 - no further operands.
        DEFW    L0206           ; address: $0206

;; P-SAVE
L07AF:  DEFB    $00             ; Class-00 - no further operands.
        DEFW    L01B6           ; address: $01B6

;; P-CONTINUE
L07B2:  DEFB    $00             ; Class-00 - no further operands.
        DEFW    L0930           ; address: $0930

;; P-CLEAR
L07B5:  DEFB    $00             ; Class-00 - no further operands.
        DEFW    L065B           ; address: $065B


;; P-CLS
L07B8:  DEFB    $00             ; Class-00 - no further operands.
        DEFW    L0747           ; Address: $0747

;; P-CH-END
L07BB:  DEFB    $05             ; Class-05 - variable syntax checked entirely
                                ; by routine.
        DEFW    L0844           ; address: $0844

; Note. one would expect the entry for the P-NEW parameters to be here.
; It should consist of a class 0, followed by the address word zero as,
; without any protected RAM, the NEW command is no more sophisticated than 
; a reset.
; However, there just isn't room. All 4096 bytes of the ROM have been
; put to good use so the required entry, three zero bytes, is embedded
; in the next routine, adding a harmless NOP to make up the three zero bytes.

; Aye, and you try telling young people of today that. And they won't
; believe you.

; ------------------------------

;; MAIN-G
L07BE:  DEC     HL
        LD      ($4026),HL      ; CH_ADD

;; P-NEW-1
L07C2:  LD      HL,$0000        ; prepare to clear error pointer.

        NOP                     ; Note. See comment above.

        LD      ($4015),HL      ; clear X_PTR

        LD      HL,$4019        ; address FLAGX
        BIT     5,(HL)          ; is INPUT mode set ?

        JR      Z,L07D7         ; forward if not to E-LINE-NO

; else runtime input.

        RES     7,(HL)          ; signal L mode.

        LD      B,(HL)          ; FLAGX to B for class routine.
        RST     18H             ; NXT-CH-SP advances.

        JP      L0889           ; jump forward to VAL-FETCH.

; -----------------------
; THE 'E-LINE-NO' SECTION
; -----------------------

;; E-LINE-NO
L07D7:  SET     7,(HL)          ; update FLAGX - signal K mode

        RST     20H             ; NEXT-CHAR
        CALL    L0679           ; routine INT-TO-HL puts the BASIC Line Number
                                ; into HL'

        JR      C,L07E5         ; forward if a negative to insert error.

; else test against upper limit.

        EXX                     ;
        LD      DE,$D8F0        ; value -9999
        ADD     HL,DE           ;
        EXX                     ;

;; E-L-ERR
L07E5:  CALL    C,L08AE         ; routine INS-ERR if greater than 9999

; -----------------------
; THE 'LINE-SCAN' SECTION
; -----------------------

;; LINE-SCAN
L07E8:  CALL    L001A           ; get the COMMAND CHARACTER.

        RES     7,(IY+$19)      ; update FLAGX signal not K mode anymore.

        LD      BC,$0000        ; this also sets B to zero for later.

        LD      ($4022),BC      ; default RESULT to ZERO
                                ; for, say, RUN without an operand.

        CP      $76             ; compare to just newline
        RET     Z               ; return if so.
                                ; for example with a space for formatting.

        LD      C,A             ; transfer the character to C
        RST     20H             ; NEXT_CHAR advances pointer
        LD      A,C             ; fetch back character to A.

        SUB     $E6             ; subtract lowest command 'LIST'

        JR      C,L07E5         ; back if not a command to E-L-ERR
                                ; the loop will eventually find the newline
                                ; and the original error point will not be
                                ; altered.

        LD      C,A             ; place reduced character in C.

        LD      HL,L0752        ; set HL to offset table
        ADD     HL,BC           ; add the one-byte offset

        LD      C,(HL)          ; fetch the offset from table
        ADD     HL,BC           ; add to form address of parameters.
        JR      L080C           ; forward to GET-PARAM

; ------------------------
; THE 'MAIN SCANNING LOOP'
; ------------------------
; entered at GET-PARAM after first instruction.

;; SCAN-LOOP
L0809:  LD      HL,($401A)      ; T_ADDR

; -->  Entry Point.

;; GET-PARAM
L080C:  LD      A,(HL)          ; get parameter from syntax table.
        INC     HL              ; point to next one.
        LD      ($401A),HL      ; initialize or update T_ADDR

        LD      BC,$0809        ; pre-load the machine stack with the
        PUSH    BC              ; return address SCAN-LOOP above.

        LD      C,A             ; copy parameter entry to C for later.
        RLA                     ; test bit 7
        JR      C,L0826         ; forward to SEPARATOR if inverted.

        LD      HL,L0836        ; base address of command class table.
        LD      B,$00           ; prepare to index.

        ADD     HL,BC           ; add the command class 0 - 6
        LD      C,(HL)          ; fetch the addressed byte to C

        ADD     HL,BC           ; compute starting address of routine.

        PUSH    HL              ; push the address on the machine stack.

        CALL    L001A           ; routine GET-CHAR advances character position
                                ; and resets the zero flag - see later.

        RET                     ; >> an indirect jump to the COMMAND CLASS
                                ; routine.

                                ; Note. HL addresses the next non-space
                                ; character e.g. the variable in LET I = 1
                                ; the non-space character is in A

; ----------------------
; THE 'SEPARATOR' BRANCH
; ----------------------
; branch to here if the parameter has bit seven set.

;; SEPARATOR
L0826:  CALL    L001A           ; get character in A
        CP      $D5             ; compare to the token 'THEN'
        JR      NZ,L0831        ; forward if another character to SEP-1.

        SET     7,(IY+$19)      ; else update FLAGX back to K mode

;; SEP-1
L0831:  CP      C               ; compare with expected token/character
        JR      NZ,L08AE        ; forward if no match to set X-PTR
                                ; using INS-ERR

        RST     20H             ; else step past a correct character.
        RET                     ; return                >>
                                ; (to SCAN-LOOP)

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

;; TAB-CLASS
L0836:  DEFB    L0855 - $       ; $1F offset to class-0 $0855
        DEFB    L086A - $       ; $33 offset to class-1 $086A
        DEFB    L0885 - $       ; $4D offset to class-2 $0885
        DEFB    L0850 - $       ; $17 offset to class-3 $0850
        DEFB    L089E - $       ; $64 offset to class-4 $089E
        DEFB    L0856 - $       ; $1B offset to class-5 $0856
        DEFB    L08A8 - $       ; $6C offset to class-6 $08A8

; --------------------------
; THE 'CHECK END' SUBROUTINE
; --------------------------

;; CHECK-END
L083D:  BIT     7,(IY+$01)      ; check FLAGS - checking syntax ?
        RET     NZ              ; return if running program.

        POP     BC              ; else drop the return address.

;; CH-END-2
L0843:  LD      A,(HL)          ; fetch character from CH_ADD address

;; CH-END-3
L0844:  CP      $76             ; compare to carriage return.

        CALL    NZ,L08AE        ; routine INS-ERR if not disturbing the 
                                ; accumulator.

;; SEE-BELOW
L0849:  LD      A,(HL)          ; reload character again.
                                ; and continue...

; -------------------------
; THE 'REM' COMMAND ROUTINE
; -------------------------
; The REM command compares each character until a newline is encountered.
; However this is a class 5 routine so the initial accumulator value will
; be zero (from the BC test) and not the character following REM.
; A line consisting of a single REM will have the newline skipped and if no
; $76 is encountered in the binary line number then the following line will
; be skipped also as in
; 10 REM
; 20 PRINT "THIS IS NOT HERE"
; The command address should be that of the previous instruction L0849 as the 
; accumulator has been disturbed.

;; REM
L084A:  CP      $76             ; compare with newline.
        RET     Z               ; return with newline.

        RST     20H             ; NEXT-CHAR
        JR      L084A           ; loop back to REM until newline found.

; -----------------------------------
; THE 'COMMAND CLASSES - 00, 03 & 05'
; -----------------------------------
; these three commands always terminate a sequence of parameters and
; are followed by the address of a routine.

;; CLASS-03
L0850:  CP      $76             ; check for carriage return
        CALL    NZ,L08A8        ; else look for optional number using CLASS-06
                                ; e.g. RUN & RUN 100
                                ; return and continue through other two classes.

;; CLASS-00
L0855:  CP      A               ; set the zero flag to invoke CHECK-END later.
                                ; this class has no operands e.g. CONTINUE.

;; CLASS-05
L0856:  POP     BC              ; drop the looping address - last in sequence.

        CALL    Z,L083D         ; routine CHECK-END if zero flag set.
                                ; (classes 03 and 00)

        EX      DE,HL           ; save HL in DE (original CH_ADD)

        LD      HL,($401A)      ; fetch table address from T_ADDR

        LD      C,(HL)          ; low byte to C
        INC     HL              ;
        LD      B,(HL)          ; high byte to B

        EX      DE,HL           ; bring back the original character address

;; JUMP-BC
L0862:  PUSH    BC              ; push routine address on machine stack
        LD      BC,($4022)      ; load value of last expression from RESULT
        LD      A,B             ; test the value
        OR      C               ; for zero.
        RET                     ; jump to the command routine.
                                ; with HL pointing at original CH_ADD
                                ; DE pointing to T_ADDR
                                ; BC holding parameter

; ---------------------------------------
; THE 'COMMAND CLASSES - 01, 02, 04 & 06'
; ---------------------------------------

; the first routine is for LET or INPUT.

;; CLASS-01
L086A:  CALL    L0D14           ; routine ALPHA tests the character.
        JR      NC,L08AE        ; forward to INS-ERR if character not A-Z.

        BIT     7,(IY+$01)      ; test FLAGS - the syntax bit.
        JP      Z,L0AAD         ; jump forward to LOOK-VARS if checking syntax.

; continue in runtime

        LD      ($4020),HL      ; save address of destination variable
                                ; in BASIC line in DEST system variable.

        RES     7,(IY+$01)      ; signal to FLAGS that syntax is being checked.

        CALL    L0AAD           ; routine LOOK-VARS.

        SET     7,(IY+$01)      ; set FLAGS back to 'running program' status.
        RET                     ; return     (to SCAN-LOOP).

; ------------------------------

; used only for LET - an expression of the correct type must be present.

;; CLASS-02
L0885:  POP     BC              ; drop the looping address as CLASS-02 is the
                                ; last in a sequence of parameters. It is
                                ; relevant only to the LET command.

        LD      B,(IY+$01)      ; load B with value of FLAGS.

; (runtime input joins here with FLAGX in B instead of FLAGS)

; ---------------------------
; THE 'FETCH A VALUE' SECTION
; ---------------------------

;; VAL-FETCH
L0889:  PUSH    BC              ; preserve value of FLAGS (or FLAGX if input)
        RST     28H             ; SCAN-CALC evaluates the expression
                                ; to be assigned setting the result type flag.
        POP     DE              ; restore the pre-evaluation copy of the
                                ; flag register to D.

        LD      BC,L0C3D        ; the address of the LET routine is pushed on
                                ; the machine stack.

        LD      A,($4001)       ; fetch the post-evaluation FLAGS to A
        BIT     7,A             ; test the syntax bit.
        JR      NZ,L0862        ; back in runtime to JUMP-BC and then LET

; if checking syntax.

        XOR     D               ; exclusive or the two flags
        AND     $40             ; AND 01000000 to isolate the type bit.

        CALL    NZ,L08AE        ; routine INS-ERR inserts the error position
                                ; when they are not the same type.

        JR      L0843           ; back to CH-END-2 to consider lesser errors
                                ; and advance to end of line.

; ------------------------------

; FOR, NEXT, DIM - HL points to variable in BASIC line, A holds the character

;; CLASS-04
L089E:  LD      ($4020),HL      ; set system variable DEST from HL.

        CALL    L0D14           ; routine ALPHA checks the character.

        JR      NC,L08AE        ; forward to INS-ERR if not A-Z.

        RST     18H             ; NXT-CH-SP advances character address.

        RET                     ; return to SCAN-LOOP >>

; ------------------------------

; a mandatory INTEGER expression must follow. e.g. GO TO 100

;; CLASS-06
L08A8:  RST     28H             ; SCAN-CALC evaluates expression.
        BIT     6,(IY+$01)      ; test FLAGS - numeric result ?
        RET     NZ              ; return if numeric.

; -----------------------------
; THE 'INSERT ERROR' SUBROUTINE
; -----------------------------

;; INS-ERR
L08AE:  LD      A,($4015)       ; check that error pointer X_PTR
        OR      (IY+$16)        ; contains zero.
        RET     NZ              ; return if there is already an error

        LD      ($4015),HL      ; else place error address at X-PTR
        RET                     ; return.

; ------------------------
; THE 'IF' COMMAND ROUTINE
; ------------------------

;; IF
L08B9:  JR      NZ,L08C1        ; if expression is TRUE forward to IF-1

        BIT     7,(IY+$01)      ; test FLAGS - checking syntax ?
        JR      NZ,L084A        ; back to REM to ignore rest of the line
                                ; in runtime.

; - else continue and check the syntax of the rest of the line.

;; IF-1
L08C1:  JP      L07E8           ; jump back to LINE-SCAN to execute what
                                ; follows the 'THEN'

; -------------------------
; THE 'FOR' COMMAND ROUTINE
; -------------------------
; for example, FOR X = 1 TO 10
; There is no step or direction.
; The body of the loop is always entered at least once - even if the initial
; value exceeds the limit.
; The ZX81 and ZX Spectrum adhered more closely to the ANS X3.60 1978 BASIC 
; standard.

;; FOR
L08C4:  PUSH    BC              ; save the start value.

        CALL    L08A8           ; routine CLASS-06 evaluates LIMIT
                                ; expression.

        POP     BC              ; start value back to BC

        CALL    L083D           ; routine CHECK-END quits if checking
                                ; syntax                        >>
        LD      HL,($4022)      ; fetch limit from RESULT
        PUSH    HL              ; save limit

        CALL    L0C3D           ; routine LET

        POP     BC              ; restore limit to BC
        BIT     7,(IY+$00)      ; examine ERR_NR
        RET     Z               ; return if not $FF             >>

        PUSH    BC              ; push the limit value.
        DEC     HL              ; point to letter.
        BIT     7,(HL)          ; test bit 7 - is it a FOR-NEXT variable.
        SET     7,(HL)          ; set bit 7 as it is going to be.

        INC     HL              ; point to end of value
        INC     HL
        JR      NZ,L08EA        ; skip forward if it is a proper
                                ; for/next variable to FOR-2

        LD      BC,$0004        ; else an extra 4 bytes are needed.
        INC     HL              ; point to start of new space.

        CALL    L05D5           ; routine MAKE-ROOM creates it.
                                ; HL - first, DE- last

;; FOR-2
L08EA:  INC     HL              ; address limit location
        POP     DE              ; retrieve limit value to DE.
        LD      (HL),E          ; insert low byte of limit.
        INC     HL
        LD      (HL),D          ; and then the high byte

        INC     HL              ; point to the looping line cell.
        LD      DE,($4002)      ; load DE with the current line from PPC
        INC     DE              ; increment as iteration will start from the
                                ; next line at least.

        LD      (HL),E          ; insert low byte of line number.
        INC     HL
        LD      (HL),D          ; insert high byte of line number.
        RET                     ; return.

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

;; NEXT
L08F9:  LD      HL,($4020)      ; fetch address of variable in BASIC from DEST.

        CALL    L0B3B           ; routine LV-FIND finds the equivalent in the
                                ; variables area and returns the value in HL.
        BIT     7,(IY+$00)      ; test ERR_NR
        RET     Z               ; return with error.
                                ; will be 02 - variable not found.

; continue if LV-FIND found the variable - HL contains the value, DE points
; to the high byte of value location.

        EX      DE,HL           ; value to DE, address to HL
        DEC     HL              ; point to low byte
        DEC     HL              ; point to the variable letter.
        BIT     7,(HL)          ; - should have letter mask 111xxxxx

        JR      Z,L0921         ; forward to ERROR-01 if not initialized by FOR.
                                ; - NEXT without FOR.

        INC     DE              ; increment the integer value
                                ; no step or direction possible.
        INC     HL              ; address first location
        LD      (HL),E          ; store low byte of value.
        INC     HL              ; next
        LD      (HL),D          ; store high byte of value.
        INC     HL              ;
        LD      C,(HL)          ; pick up limit low
        INC     HL              ;
        LD      B,(HL)          ; and limit high.
        PUSH    BC              ; save limit.
        EX      (SP),HL         ; limit to HL, pointer to stack.

        CALL    L0DCD           ; routine no-less compares HL DE
                                ; setting carry if HL is less.

        POP     HL              ; retrieve the pointer from the stack.
        RET     C               ; return if no more iterations possible  >>

        INC     HL              ; else address next location.
        LD      C,(HL)          ; pick up low byte of line number
        INC     HL              ; address next
        LD      B,(HL)          ; pick up high byte of looping line.

        JR      L0934           ; jump to GOTO to perform another
                                ; iteration

; ---

;; ERROR-01
L0921:  RST     08H             ; ERROR restart
        DEFB    $00             ; NEXT without FOR

; -------------------------------
; THE 'RANDOMISE' COMMAND ROUTINE
; -------------------------------
; This command sets the seed to the supplied integer -32767 to 32767.
; In the absence of a parameter the FRAMES counter, related to the time
; the computer has been switched on, is used.

;; RANDOMISE
L0923:  JR      NZ,L0929        ; forward to RAND-1 if parameter is
                                ; not zero.

        LD      BC,($401E)      ; else use value of system variable FRAMES.

;; RAND-1
L0929:  LD      ($401C),BC      ; insert value in system variable SEED.
        RET                     ; return.

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

;; STOP
;; ERROR-9
L092E:  RST     08H             ; ERROR restart
        DEFB    $08             ; - STOP statement executed.

; ------------------------------
; THE 'CONTINUE' COMMAND ROUTINE
; ------------------------------

;; CONTINUE
L0930:  LD      BC,($4017)      ; fetch continuing line number from OLDPPC
                                ; and continue into GOTO routine.

; ---------------------------
; THE 'GO TO' COMMAND ROUTINE
; ---------------------------

;; GOTO
L0934:  LD      ($4002),BC      ; set PPC to supplied line number.
        SET     3,(IY+$01)      ; update FLAGS - use K cursor.
        RET                     ; return.

; -------------------------
; THE 'RUN' COMMAND ROUTINE
; -------------------------
; The RUN command may have an optional line number that will be passed to
; the GOTO routine before erasing any variables and executing the line
; (or first line after zero).

;; RUN
L093D:  CALL    L0934           ; routine GOTO sets up any supplied line number.
        JP      L065B           ; exit via CLEAR to erase variables.

; ----------------------------
; THE 'GO SUB' COMMAND ROUTINE
; ----------------------------

;; GOSUB
L0943:  LD      HL,($4002)      ; fetch current line from PPC
        INC     HL              ; increment the line number
        EX      (SP),HL         ; place on machine stack
                                ;
        PUSH    HL              ; push what was on the stack back up there.
        CALL    L0934           ; routine GOTO sets up a branch to the line
                                ; number.
        LD      BC,$0006        ; and exit by a six-byte memory check.

; --------------------------
; THE 'TEST ROOM' SUBROUTINE
; --------------------------
; The ZX80 dates from the days when RAM chips cost a fortune and it came with
; only 1K of RAM, 1024 bytes.
; The screen could show 768 characters and to economize it is dynamic and
; initialized to a single newline ($76) by CLS. The TEST-ROOM routine has to
; allow for enough newlines to expand down to the bottom line and a few extra
; for the report codes "0/9999".
; The second entry point is from PRINT-A and the character is similarly
; in H and the line number in L.

;; TEST-ROOM
L094F:  LD      HL,($4010)      ; fetch DF_END last location before
                                ; spare memory.
        ADD     HL,BC           ; add the supplied overhead.
        EX      DE,HL           ; save the result in DE.

        LD      HL,($4025)      ; SPOSN-Y to L gives 24 - number
                                ; of screen lines used so far.
        LD      H,A             ; preserve the accumulator in H

;; TEST-RM-2
L0958:  LD      A,$13           ; load A with 19
        ADD     A,L             ; add to L to give the number of bytes
                                ; required to fill rest of screen with
                                ; newlines - plus a bit extra.
        LD      L,A             ; put result in L.
        LD      A,H             ; restore the accumulator.
        LD      H,$00           ; set H to zero.
        ADD     HL,DE           ; add this extra screen allowance
                                ; to the previous result.
        SBC     HL,SP           ; subtract the stack pointer.
        RET     C               ; return if the stack pointer is
                                ; above the estimate. All is well.

;

;; ERROR-4
L0963:  RST     08H             ; ERROR restart
        DEFB    $03             ; No room

; ----------------------------
; THE 'RETURN' COMMAND ROUTINE
; ----------------------------
; As with all commands, there is only one value on the machine stack during
; command execution. This is the return address.
; Above the machine stack is the gosub stack that contains a line number
; (only one statement per line).

;; RETURN
L0965:  POP     HL              ; drop the return address clearing the stack.
        POP     BC              ; drop a line number off the gosub stack.
        PUSH    HL              ; restore the machine stack.

        LD      A,B             ; test high byte of line number.
        CP      $3F             ; against the gosub stack end-marker.
        JR      NZ,L0934        ; back to GOTO if a valid line number.

        POP     HL              ; else collapse the machine stack.
        PUSH    BC              ; push the end-marker.
        PUSH    HL              ; restore the machine stack.

;; ERROR-07
        RST     08H             ; ERROR restart
        DEFB    $06             ; RETURN with no corresponding GO SUB.

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

;; PRINT
L0972:  LD      A,(HL)          ; fetch the character
        CP      $76             ; compare to NEWLINE
        JP      Z,L071B         ; back to PRINT-CR if so.

;; PR-POSN-1
L0978:  SUB     $D8             ; subtract ','
                                ; (';' gives -1 and carry set)

        ADC     A,$00           ; convert the two separators to zero.
        JR      Z,L0991         ; forward to PR-POSN-2 with ';' and ','

        RST     28H             ; else SCAN-CALC evaluates expression.
        CALL    L06F1           ; routine PRINT-ITEM prints it.
        CALL    L001A           ; routine GET-CHAR gets following character.

        SUB     $D8             ; compare with ',' and test for
        ADC     A,$00           ; terminating separators.
        JR      Z,L0991         ; forward to PR-POSN-2 with ';' and ','

        CALL    L083D           ; routine CHECK-END errors with anything else.
        JP      L071B           ; jump to PRINT-CR for carriage return.

; ---


;; PR-POSN-2
L0991:  CALL    NC,L0727        ; routine PO-FILL if comma control.

        RST     20H             ; NEXT-CHAR
        CP      $76             ; compare to NEWLINE
        RET     Z               ; return if so leaving print position
                                ; unchanged.

        JR      L0978           ; else loop back to PR-POSN-1 to consider
                                ; more sequences of positional
                                ; controls and print items.

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

; INPUT must be used from a running program. It is not available as a
; direct command.

;; INPUT
L099A:  BIT     7,(IY+$03)      ; test PPC_hi - will be -2 if a direct command
        JR      NZ,L09CF        ; forward if so, to ERROR-08

        POP     HL              ; discard return address - L0447

        LD      HL,$4019        ; point to FLAGX

        SET     5,(HL)          ; signal input
        RES     6,(HL)          ;           reset so as not to affect combine

        LD      A,($4001)       ; fetch FLAGS to A

        AND     $40             ; isolate bit 6 - the result type

        LD      BC,$0002        ; allow two locations for numeric.

        JR      NZ,L09B4        ; skip forward to IN-PR-1 if numeric.

        LD      C,$04           ; allow two extra spaces for quotes.

;; IN-PR-1
L09B4:  OR      (HL)            ; combine FLAG bit with FLAGX.
        LD      (HL),A          ; and place result in FLAGS.

        RST     30H             ; BC-SPACES creates 2/4 locations.
        RET     NC              ; return with problems.

        LD      (HL),$76        ; insert a newline at end.

        LD      A,C             ; now test C - 2 (num) 4 (str).
        RRCA                    ;              1       2
        RRCA                    ;              carry   1
        JR      C,L09C2         ; skip forward with numeric to IN-PR-3

        LD      (DE),A          ; insert initial quote (chr$ 1) at DE
        DEC     HL              ; decrease HL pointer
        LD      (HL),A          ; insert closing quote.

;; IN-PR-3
L09C2:  DEC     HL              ; decrease pointer
        LD      (HL),$B0        ; insert cursor inverse 'K'

        LD      A,($4025)       ; SPOSN-Y
        INC     A               ; allow a blank line
        LD      ($4012),A       ; set DF-SZ

        JP      L02F7           ; jump back to ED-COPY

; ---

;; ERROR-08
L09CF:  RST     08H             ; ERROR restart
        DEFB    $07             ; INPUT can only be used in a program.

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

;; POKE
L09D1:  PUSH    BC              ; save result of first expression.
        RST     28H             ; use SCAN-CALC to evaluate expression
                                ; after the comma.

        POP     DE              ; restore destination address.
        CALL    L083D           ; routine CHECK-END
        LD      A,($4022)       ; RESULT
        BIT     7,(IY+$00)      ; ERR_NR
        RET     Z               ; return if error

        LD      (DE),A          ; load memory location with A
        RET                     ; return

; ----------------------
; THE 'SCANNING' ROUTINE
; ----------------------
; The scanning routine is a continuation of RST 28.
; The B register has been set to zero as a starting priority.
; The HL register contains the character address CH_ADD.
; The addressed character is in A.

;; SCANNING
L09E1:  LD      C,B             ; make BC zero - the starting priority
                                ; marker.
        PUSH    BC              ; save on machine stack.

;; S-LOOP-1
L09E3:  CALL    L0D18           ; routine ALPHANUM
        JR      C,L0A24         ; forward if a variable or digit. to S-VAR-NUM

; now consider negate (-) and perform '$0000 - value' if so.

        LD      BC,$0900        ; prepare priority $09, operation 'subtract'
        LD      D,C             ; set DE to $0000 for value to be stacked.
        LD      E,C             ;
        SUB     $DC             ; subtract the character '-'
        JR      Z,L0A17         ; forward with unary minus to S-PUSH-PO

; now consider 'not' and perform $FFFF - value if so.

        DEC     DE              ; set DE to $FFFF for value to be stacked.
        LD      B,$04           ; prepare priority 4, operation still 'subtract'
        INC     A               ; test for 'NOT' ?
        JR      Z,L0A17         ; forward with NOT to S-PUSH-PO

; now consider an opening bracket.

        INC     A               ; test the character.
        JR      Z,L0A1C         ; forward with '(' to S-BRACKET
                                ; to evaluate the sub-expression recursively
                                ; using SCANNING.

        CP      $27             ; commencing quote ?
        JR      NZ,L0A0E        ; forward to S-ABORT if not, as all valid
                                ; possibilities have been exhausted.

; continue to evaluate a string.

        RES     6,(IY+$01)      ; signal string result to FLAGS.
        INC     HL              ; step past the opening quote.
        LD      ($4022),HL      ; store the string pointer in
                                ; system variable RESULT.

;; S-Q-CHAR
L0A06:  RST     18H             ; NXT-CH-SP
        DEC     A               ; test for the string terminator.
        JR      Z,L0A21         ; forward to S-CONT if found.           >>

        CP      $75             ; [ EDIT ]      SHIFT-ENTER
        JR      NZ,L0A06        ; loop back to S-Q-CHAR till terminator found.

; ---

; the branch was here when something unexpected appeared in the expression
; or, if from above, in the string.

;; S-ABORT
L0A0E:  CALL    L08AE           ; routine INS-ERR marks the spot.
        EXX                     ;
        LD      BC,$0000        ; this forces the zero priority marker down
                                ; from the stack.
                                ; Note. just setting B to zero should do.
        JR      L0A4C           ; forward to S-LOOP to balance and exit

; ---

; the ZX80 juggles with expression components using just the machine stack
; pushing first the value and then the priority/operator beneath.
; As with all ZX computers, provided there is enough memory, an expression of
; unlimited complexity can be evaluated.

;; S-PUSH-PO
L0A17:  PUSH    DE              ; push the value ($0000 if '-', $FFFF if 'NOT')
        PUSH    BC              ; then push the priority and operator.

;; SCAN-LOOP
L0A19:  RST     20H             ; NEXT-CHAR advances the character address.
        JR      L09E3           ; back to S-LOOP-1

; ---

;; S-BRACKET
L0A1C:  CALL    L0049           ; routine BRACKET evaluates expression
                                ; inside the brackets checking for
                                ; terminator using SCANNING
                                ; recursively.
        JR      L0A37           ; forward to S-OPERTR

; ---

; the branch was here when the end of a string had been found.

;; S-CONT
L0A21:  RST     18H             ; NXT-CH-SP
        JR      L0A37           ; forward to S-OPERTR to consider comparisons

; ---

;; S-VAR-NUM
L0A24:  CP      $26             ; compare to 'A'
        JR      C,L0A2D         ; forward if numeric to S-DIGIT

; present character is alpha

        CALL    L0AAD           ; routine LOOK-VARS
        JR      L0A37           ; forward to S-OPERTR

; ---

;; S-DIGIT
L0A2D:  CALL    L0679           ; routine INT-TO-HL
        CALL    C,L08AE         ; routine INS-ERR with overflow.
        SET     6,(IY+$01)      ; signal numeric result in FLAGS

;; S-OPERTR
L0A37:  CALL    L001A           ; routine get-char

        EXX
        LD      BC,$0000        ; prepare zero priority in case not an operator
                                ; in which case at end of expression

        SUB     $DC             ; reduce by '-'
        JR      C,L0A4C         ; forward if less than an operator to S-LOOP

        CP      $0A             ; compare to ten.
        JR      NC,L0A4C        ; forward if higher than nine to S-LOOP

; leaves ten operators -, +, *, /, AND, OR, **, =, >, <.

        LD      C,A             ; transfer operation to C, register B is zero.
        LD      HL,L0AA3        ; address table of priorities.
        ADD     HL,BC           ; index into table.
        LD      B,(HL)          ; pick up the priority.

;; S-LOOP
L0A4C:  POP     DE              ; pop the previous priority/operation
        LD      A,D             ; priority to A
        CP      B               ; compare with current priority B
        JR      C,L0A88         ; forward to S-TIGHTER if current priority is
                                ; higher

; else this is the correct place in the expression to perform this operation.

        AND     A               ; first test for zero priority marker

        EXX                     ;
        RET     Z               ; return if so, HL is result.  >>>>>
        EXX                     ;

        BIT     7,(IY+$01)      ; FLAGS
        JR      Z,L0A6F         ; forward if checking syntax to S-SYNTEST

; but in runtime the operation is performed.

        LD      D,$00           ; prepare to index.
        LD      HL,L0D1F        ; address the table of operators and addresses.

        ADD     HL,DE           ; index twice using the operation code.
        ADD     HL,DE           ; as there are two bytes per entry.
        LD      E,(HL)          ; pick up low byte of address.
        INC     HL              ; next location.
        LD      D,(HL)          ; get high byte of address.

        LD      HL,L0A7F        ; the return address S-INS-VAL
        EX      (SP),HL         ; goes to the stack and argument to HL

        PUSH    DE              ; now push the address of the routine.
        LD      DE,($4022)      ; pick up last value from RESULT
        RET                     ; and make an indirect jump to
                                ; the routine.                  >>>>>>>>

; ------------------------------

;; S-SYNTEST
L0A6F:  LD      A,E             ; get the last operation code
        CP      $0A             ; compare to ten - sets carry if numeric
        RRA                     ; carry to bit 7
        RRA                     ; carry to bit 6
        XOR     (IY+$01)        ; exclusive or with FLAGS
        AND     $40             ; isolate bit 6 - the result type.

        EXX                     ;
        CALL    NZ,L08AE        ; routine INS-ERR if not of same type.
        EXX                     ;

        POP     HL              ; fetch the last value from machine stack

;  >>>>>>>>
; Note. this is also the return address from mathematical and string
; comparisons, see above, in which case HL will contain the result and BC
; the priority/operation.

;; S-INS-VAL
L0A7F:  LD      ($4022),HL      ; place value in system variable RESULT
        SET     6,(IY+$01)      ; signal numeric result to FLAGS
        JR      L0A4C           ; back to S-LOOP

; ---

;; S-TIGHTER
L0A88:  PUSH    DE              ; push lower priority

        LD      A,C             ; fetch operator
        BIT     6,(IY+$01)      ; test FLAGS
        JR      NZ,L0A9A        ; forward if numeric to S-NEXT.

        ADD     A,$03           ; augment nos-eql to strs-eql etc.
        LD      C,A             ; and put back in C

        CP      $0A             ; compare to ten - start of string comparisons

        EXX                     ;
        CALL    C,L08AE         ; routine INS-ERR if lower
                                ; a$ * b$ is invalid but so too
                                ; is a$ + b$ (no string concatenation)
        EXX                     ;

;; S-NEXT
L0A9A:  LD      HL,($4022)      ; fetch RESULT to HL
        PUSH    HL              ; push intermediate result
        PUSH    BC              ; and then priority/operator
        EXX                     ;
        JP      L0A19           ; jump back to SCAN-LOOP


; -------------------------
; THE 'TABLE OF PRIORITIES'
; -------------------------
; Table of mathematical priorities that dictate, in the absence of brackets,
; the order in which operations are performed.
; unary minus (priority $09) and NOT (priority $04) are handled directly.

;; TAB-PRIO
L0AA3:  DEFB    $06             ; $00  subtract
        DEFB    $06             ; $01  addition
        DEFB    $08             ; $02  multiply
        DEFB    $07             ; $03  division
        DEFB    $03             ; $04  and
        DEFB    $02             ; $05  or
        DEFB    $0A             ; $06  to-power
        DEFB    $05             ; $07  nos-eql
        DEFB    $05             ; $08  no-grtr
        DEFB    $05             ; $09  no-less

; --------------------------
; THE 'LOOK-VARS' SUBROUTINE
; --------------------------

;; LOOK-VARS
L0AAD:  PUSH    HL              ; * push pointer to first letter

        LD      HL,$4001        ; address FLAGS
        RES     5,(HL)          ; update FLAGS - signal not a function yet.
                                ; but no use is made of this flag bit.
        SET     6,(HL)          ; update FLAGS - presume a numeric result.
        RST     18H             ; NXT-CH-SP
        CP      $0D             ; compare  to '$' ?
        JP      Z,L0B30         ;; JUMP forward with match to STRING

        CP      $DA             ; compare  to '(' ?
        JP      Z,L0B2B         ;; JUMP forward with match to ARRAY

; that leaves three types of integer plus functions.

;; V-CHAR
L0AC0:  CALL    L0D18           ; routine ALPHANUM
        JR      NC,L0AC8        ; forward when not alphanumeric to FUNC-LOOP.

        RST     18H             ; fetch NXT-CH-SP.
        JR      L0AC0           ; loop back to V-CHAR for more.

; ---

;; FUNC-LOOP
L0AC8:  CP      $DA             ; compare  to '(' ?
        JR      Z,L0AD6         ; forward with a match to FUNC-SRCH

        CP      $0D             ; compare  to '$' ?
        JP      NZ,L0B35        ;; JUMP forward if not to V-SYN

; but if this is a string function such as CHR$ then the bracket must follow.

        RST     18H             ; NXT-CH-SP
        CP      $DA             ; compare  to '(' ?
        JR      NZ,L0B27        ; forward if not to FUNC-ERR.

; This has the correct format for a function and an exact match must now be
; made to one of the entries in the functions table.

;; FUNC-SRCH
L0AD6:  LD      DE,L0BC0 - 1    ; point to location before TAB-FUNC

;; FUNC-LOOP
L0AD9:  POP     HL              ; pop pointer to first character in command
        PUSH    HL              ; and push again.

;; FUNC-CHAR
L0ADB:  LD      C,(HL)          ; fetch command character to C.
        CALL    L0055           ; routine CH-ADD-LP advances CH-ADD
                                ; to next non-space position.
        INC     DE              ; increment position in table
        LD      A,(DE)          ; fetch table character to A.
        CP      C               ; compare with one in command.
        JR      Z,L0ADB         ; loop back with match to FUNC-CHAR
                                ; e.g. PEEK

        AND     $3F             ; cancel any inversion.
        CP      C               ; and compare again
        JR      NZ,L0AEE        ; skip if no match to FUNC-NEXT.

        LD      A,$DA           ; load with '('
        CP      (HL)            ; compare to next valid character
        JR      Z,L0AF9         ; forward with success to FUNC-MTCH.


;; FUNC-NEXT
L0AEE:  LD      A,(DE)          ; fetch next character from table.
        AND     A               ; test for zero end-marker.
        JR      Z,L0B27         ; forward if at end of table to FUNC-ERR.

        INC     DE              ; else increment pointer.
        RLA                     ; test for inverted bit.
        JR      NC,L0AEE        ; loop back to FUNC-NEXT
                                ; until new token found.

        INC     DE              ; increment pointer.
                                ; to skip address in table.

        JR      L0AD9           ; loop back to FUNC-LOOP
                                ; which begins by skipping the
                                ; remaining address byte.

; ---

; A function such as PEEK has been found with the necessary opening bracket.

;; FUNC-MTCH
L0AF9:  PUSH    DE              ; save pointer to address within
                                ; table.

        CALL    L0049           ; routine BRACKET evaluates an
                                ; expression within brackets in command.
                                ; result in HL

        POP     DE              ; retrieve table address pointer.

        EX      (SP),HL         ; result to stack, discarding command
                                ; character pointer.
        LD      HL,$4001        ; load with address FLAGS

        LD      A,(DE)          ; fetch the last inverted character.
        XOR     (HL)            ; XOR with FLAGS
        AND     $40             ; isolate bit 6 - result type.
        JR      NZ,L0B27        ; to FUNC-ERR to insert an error with
                                ; an argument type mismatch.

        SET     5,(HL)          ; update FLAGS signal a function has been found
                                ; but no use is made of this ?????
        SET     6,(HL)          ; default the result type to be numeric.

        LD      A,(DE)          ; fetch last character
        AND     $3F             ; lose the indicator bits.

        CP      $0D             ; is character '$' ?
                                ; i.e. CHR$, STR$ or TL$.
        JR      NZ,L0B15        ; forward with numeric function results
                                ; to FUNC-SYN.

        RES     6,(HL)          ; else set FLAGS to indicate a string
                                ; result is expected.

;; FUNC-SYN
L0B15:  BIT     7,(HL)          ; test FLAGS checking syntax?

        POP     HL              ; restore RESULT of expression in brackets.
        RET     Z               ; return if checking syntax.           >>

        LD      HL,L0BBA        ; else the routine INS-RSLT
        PUSH    HL              ; is pushed on the machine stack

        EX      DE,HL           ; HL now points to table entry.
        INC     HL              ; point to address low byte.
        LD      E,(HL)          ; pick up the low byte.
        INC     HL
        LD      D,(HL)          ; pick up the high byte.
        PUSH    DE              ; push routine address on stack.

        LD      HL,($4022)      ; load HL with argument from RESULT
                                ; either integer or string pointer.
        RET                     ; indirect jump to routine and then
                                ; to INS-RSLT .

; ---

;; FUNC-ERR
L0B27:  POP     HL              ; balance stack.
        JP      L08AE           ; jump back to INS-ERR

; ------------------------------

;; ARRAY
L0B2B:  CALL    L0049           ; routine BRACKET evaluates expression
        JR      L0B35           ; skip to V-SYN

; ---

;; STRING
L0B30:  RES     6,(IY+$01)      ; FLAGS signal string result.
        RST     18H             ; NXT-CH-SP

;; V-SYN
L0B35:  POP     HL              ; * restore pointer to first letter
        BIT     7,(IY+$01)      ; check FLAGS
        RET     Z               ; return if checking syntax
                                ; but continue in run-time

; also called from NEXT and LET 
; HL points to first letter of variable in the command.

;; LV-FIND
L0B3B:  LD      C,(HL)          ; C first character
        INC     HL
        LD      A,(HL)          ; A second character

        PUSH    HL              ; save pointer to character 2

        CP      $DA             ; is second character '(' ?
        JR      NZ,L0B5C        ; forward if not to LV-ENCODE with strings and 
                                ; simple numeric variables.

; an array

        PUSH    BC              ; save BC on stack
        LD      BC,($4026)      ; fetch character address CH_ADD
        PUSH    BC              ; and save that on stack as well.

        CALL    L0025           ; routine EVAL-EXPR evaluates the
                                ; expression after the current '('
                                ; disturbing CH_ADD

        POP     HL              ; restore original value of CH_ADD
        LD      ($4026),HL      ; and backdate CH_ADD system variable.
        POP     BC              ; restore the letter in BC.

        LD      HL,$4000        ; address system variable ERR_NR
        BIT     7,(HL)          ; test if $FF has been disturbed by eval_expr.
        JR      NZ,L0B6B        ; forward if not to V-RUN.

        LD      (HL),$02        ; else insert the code for subscript error
        POP     HL              ; balance the stack
        RET                     ; return with error set.        >>

; ---

; encode the variable type into bits 5-7 of the letter.

;; LV-ENCODE
L0B5C:  RES     5,C             ; presume type string
        CP      $0D             ; is second character '$' ?
        JR      Z,L0B6B         ; forward if so to V-RUN

        SET     6,C             ; presume long-named numeric.

        CALL    L0D18           ; routine ALPHANUM test second character.

        JR      C,L0B6B         ; forward if so to V-RUN

        SET     5,C             ; else mark as simple numeric or for/next

;; V-RUN
L0B6B:  LD      HL,($4008)      ; point HL to the first variable from VARS.

;; V-EACH
L0B6E:  LD      A,(HL)          ; fetch letter/marker
        AND     $7F             ; reset bit 7 to allow simple numeric variables
                                ; to match against FOR-NEXT variables.
        JP      Z,L0CD0         ; if character was $80 then forward to ERROR-02
                                ; Variable not found.

        CP      C               ; else compare to first letter in command
        JR      NZ,L0B93        ; forward if no match to V-NEXT

        RLA                     ; rotate A to left and then
        ADD     A,A             ; double to test bits 5 and 6.

        JP      M,L0BA4         ; forward to STK-VAR with
                                ; all single letter numeric variables
                                ; including for/next and arrays.

        JR      NC,L0BB8        ; forward to STR-RSLT with string.

; that leaves long-named variables (mask 010xxxxx)
; that have to be matched in full.

        POP     DE              ; take a copy of pointer.
        PUSH    DE              ; to 2nd character in BASIC area.
        PUSH    HL              ; save 1st letter pointer in vars area.


;; V-MATCHES
L0B81:  INC     HL              ; point to next vars character.
        LD      A,(DE)          ; fetch each BASIC char in turn.
        INC     DE              ; advance BASIC pointer
        CP      (HL)            ; compare to character in variable
        JR      Z,L0B81         ; back if the same to V-MATCHES

        OR      $80             ; try a match on inverted character.
        CP      (HL)            ; compare to variable
        JR      NZ,L0B92        ; forward to V-GET-PTR without full
                                ; match.

        LD      A,(DE)          ; check that the end of name in BASIC
                                ; has been reached.

        CALL    L0D18           ; routine ALPHANUM checks that no
                                ; more letters follow.

        JR      NC,L0B9B        ; forward to V-FOUND-1 with a full
                                ; match on an inverted long name.

; else continue the search

;; V-GET-PTR
L0B92:  POP     HL              ; fetch the pointer.

;; V-NEXT
L0B93:  PUSH    BC              ; save B and C

        CALL    L0624           ; routine NEXT-ONE points DE at next
                                ; variable

        EX      DE,HL           ; switch pointers.
        POP     BC              ; retrieve B and C.
        JR      L0B6E           ; back for another search to V-EACH.

; ---

;; V-FOUND-1
L0B9B:  POP     DE              ; drop saved var pointer

;; V-FOUND-2
L0B9C:  POP     DE              ; drop pointer to second character

;; V-FOUND-3
L0B9D:  INC     HL              ; advance to value.
        LD      E,(HL)          ; fetch low byte to E
        INC     HL              ;
        LD      D,(HL)          ; fetch high byte to D.
        EX      DE,HL           ; value to HL
        JR      L0BBA           ; forward to INS-RSLT

; ---

; simple 011xxxxx, array 101xxxxx, for/next 111xxxxx

;; STK-VAR
L0BA4:  JR      C,L0B9C         ; back to V-FOUND-2 above with simple
                                ; and FOR/NEXT variables.

;; SV-ARRAYS
        EX      (SP),HL         ; save pointer to letter on stack discarding
                                ; the second letter pointer
        LD      HL,($4022)      ; fetch argument within brackets from RESULT

        RLC     H               ; test the high byte.

        POP     DE              ; retrieve pointer to letter
        JR      NZ,L0BBE        ; forward to ERROR-03 subscript error
                                ; if subscript > 255

        INC     DE              ; point to dimensions value - 1 byte
        LD      A,(DE)          ; fetch the max subscription

        CP      L               ; compare to low byte of argument.
        JR      C,L0BBE         ; forward if higher than max subscription
                                ; to ERROR-03.

        ADD     HL,HL           ; double the subscript 0 - 510
        ADD     HL,DE           ; add to variable pointer
                                ; now point to location before required cell.
                                ; if the first element is 0 then still pointing
                                ; at the max subscription byte.
        JR      L0B9D           ; back to V-FOUND-3 above.

; ---

; string type mask 100xxxxx

;; STR-RSLT
L0BB8:  POP     DE              ; drop pointer to var.
        INC     HL              ; advance to first character of string.

;; INS-RSLT
L0BBA:  LD      ($4022),HL      ; insert value/pointer into RESULT
        RET                     ; return.

; ---

;; ERROR-03
L0BBE:  RST     08H             ; ERROR restart
        DEFB    $02             ; subscript error

; ------------------------------
; THE 'INTEGRAL FUNCTIONS TABLE'
; ------------------------------
; Table of functions to be parsed and addresses.
; Parsed by LOOK-VARS.
; Inversion is with $80 (string argument)
; and with $CO (numeric argument).
; The TL$, "Truncate Left string", of "CABBAGE" is "ABBAGE".

;; TAB-FUNC
L0BC0:  DEFB    $35,$2A,$2A,$F0 ; PEEK  (+$C0)
        DEFW    L0C24           ; $0C24

        DEFB    $28,$2D,$37,$CD ; CHR$  (+$C0)
        DEFW    L0C28           ; $0C28

        DEFB    $28,$34,$29,$AA ; CODE  (+$80)
        DEFW    L0C24           ; $0C24

        DEFB    $37,$33,$E9     ; RND   (+$C0)
        DEFW    L0BED           ; $OBED

        DEFB    $39,$31,$8D     ; TL$   (+$80)
        DEFW    L0C38           ; $0C38

        DEFB    $3A,$38,$F7     ; USR   (+$C0)
        DEFW    L06F0           ; $06F0

        DEFB    $38,$39,$37,$CD ; STR$  (+$C0)
        DEFW    L0C10           ; $0C10

        DEFB    $26,$27,$F8     ; ABS   (+$C0)
        DEFW    L0DF2           ; $0DF2

        DEFB    $00             ; zero end-marker

; ------------------
; THE 'RND' FUNCTION
; ------------------
; e.g. LET LOTTERYNUMBER = RND (49) produces a random number in the range
; 1 to 49.
; the routine has two stages -
; First the seed is fetched and manipulated in such a way that it cycles through
; every value between 0 and 65535 in a pseudo-random way before repeating the
; sequence. If the seed fetched is zero it is set to 65536-77.
; The multiplicand used is 77 and any overflow is subtracted from the
; register result.

;; RND
L0BED:  PUSH    HL              ; * save the integer parameter e.g. 49.
        LD      HL,($401C)      ; fetch the 'seed' from SEED.
        LD      DE,$004D        ; place 77 in DE
        LD      A,H             ; test the seed
        OR      L               ; for value zero
        JR      Z,L0C03         ; forward if zero.

        CALL    L0D55           ; routine MULT16 multiplies seed by 77
                                ; BC contains zero or overflow

        AND     A               ; clear carry flag.
        SBC     HL,BC           ; subtract any overflow from lower 16 bits
        JR      NC,L0C05        ; forward if no carry to RND-3

        INC     HL              ; increase seed value.
        JR      L0C05           ; forward to RND-3

; ---

;; RND-2
L0C03:  SBC     HL,DE           ; form number $FFB3 if seed is zero.


;; RND-3
L0C05:  LD      ($401C),HL      ; store new value of SEED

; now multiply the new seed by the argument to give result-1 in BC.

        POP     DE              ; * restore argument

        CALL    L0D55           ; routine MULT16 multiplies HL by DE
                                ; returning in BC, for the example, 0-48

        LD      H,B             ; transfer BC
        LD      L,C             ; to HL - the result register.
        INC     HL              ; increment - make range start with 1.
        RET                     ; return

; -------------------
; THE 'STR$' FUNCTION
; -------------------
; the function produces a string comprising the characters that would appear
; if the numeric argument were printed.
; So seven characters e.g. "-10000" terminated by the null character ($01)
; is the maximum amount of characters required.
; Note. that for this reason the ZX80, unlike the ZX81 and ZX Spectrum, is able
; to have four tabstops across the 32 character screen.

;; str$
L0C10:  EXX
        LD      BC,$0007        ; 7 characters required at most.
        RST     30H             ; routine BC-SPACES
        JR      NC,L0C34        ; forward to NULL-STR if not enough
                                ; memory.

        PUSH    DE              ; * save start of new space

        EXX                     ; switch in other set
        LD      B,H             ; transfer argument to BC
        LD      C,L             ; register.

        CALL    L06A1           ; OUT-NUM-1 prints at this DE in WKG Space.

        EXX                     ; switch back

        LD      A,$01           ; prepare the terminating '"'
        LD      (DE),A          ; and place at end of string.

;; POP-RET
L0C22:  POP     HL              ; * restore result pointer.
        RET                     ; return.

; -------------------------------
; THE 'CODE' AND 'PEEK' FUNCTIONS
; -------------------------------
; Two functions in one subroutine.
; CODE with HL pointing to start of string.
; and also,
; PEEK with HL pointing to a memory address.
; The return value is in HL.

;; CODE
;; PEEK
L0C24:  LD      L,(HL)          ; parameter is in HL.
        LD      H,$00           ;
        RET                     ; return with result in HL.

; -------------------
; THE 'CHR$' FUNCTION
; -------------------
; this function returns the null-terminated single-character string that
; corresponds to the integer argument e.g. CHR$(38) returns "A".

;; chr$
L0C28:  LD      BC,$0002        ; two locations required.
        LD      A,L             ; character to A.
        RST     30H             ; BC-SPACES creates two locations
                                ; in WORKSPACE
        JR      NC,L0C34        ; forward to NULL-STR if no room.

;; NULL-PTR
L0C2F:  LD      (HL),$01        ; insert the '"' terminator at last new location
        DEC     HL              ; decrease the pointer.
        LD      (HL),A          ; insert the character.
        RET                     ; return with HL pointing to string.

; ---

;; NULL-STR
L0C34:  LD      HL,L0C2F + 1    ; point to the null string at NULL-PTR + 1
                                ; in the above code.
        RET                     ; return.

; ------------------
; THE 'TL$' FUNCTION
; ------------------
; This limited string slicing function returns the tail of a string starting
; at the second character and the null string otherwise.
; It requires no string workspace.

;; tl$
L0C38:  LD      A,(HL)          ; fetch first character of string
        DEC     A               ; decrement it.
        RET     Z               ; return if was CHR$ 1 - the null string.

        INC     HL              ; else increase the string pointer
        RET                     ; return with HL pointing at result.


; -----------------
; THE 'LET' ROUTINE
; -----------------
; This subroutine is called from the FOR command and the CLASS-02 routine
; to create the variable.

;; LET
L0C3D:  BIT     7,(IY+$00)      ; test ERR_NR
        RET     Z               ; return if not $FF

; proceed if no errors so far.

        PUSH    BC              ; save start val

        LD      HL,($4020)      ; fetch location of letter in BASIC from DEST

        CALL    L0B3B           ; routine LV-FIND will set error

        LD      HL,$4000        ; ERR_NR
        LD      A,(HL)
        CP      $02             ; compare to 2 - subscript out of range

        JR      Z,L0C22         ; back to POP-RET if so         >>>

; continue with variable not found or OK.

        RLA                     ; test for $FF??
        BIT     6,(IY+$01)      ; test bit 6 FLAGS - affects zero flag only.
                                ; zero if string NZ if numeric
        JR      C,L0C93         ; forward if error was $FF to L-EXISTS

; continue if variable does not exist.

        LD      (HL),$FF        ; cancel the error as variable will be created.

        JR      Z,L0CA3         ; forward to L-STRING with string var.

; continue with numeric INTEGER variable

        LD      HL,($4020)      ; pick up  destination from DEST
        LD      BC,$0002        ; set default space for integer contents
                                ; will be 3 including letter

;; L-EACH-CH
L0C62:  INC     BC              ; pre-increment character count.
        INC     HL              ; increment character pointer in BASIC or
                                ; workspace.
        LD      A,(HL)          ; fetch the character.

        CALL    L0D18           ; routine ALPHANUM check if "[0-Z]"
        JR      C,L0C62         ; loop back if so to L-EACH-CH

        CP      $DA             ; is character '(' ?
        JR      Z,L0CD0         ; forward if so to ERROR-02 - var not found.
                                ; e.g. perhaps a function has been misspelled.

        RST     30H             ; BC-SPACES creates room for new INTEGER
                                ; variable at D-FILE - 1, the variables
                                ; end-marker.
        JR      NC,L0C22        ; back to POP-RET if not enough room

        PUSH    DE              ; save first new location        ***
        LD      HL,($4020)      ; fetch DEST the pointer to letter in command

        DEC     BC              ; reduce count by
        DEC     BC              ; the three bytes
        DEC     BC              ; for simple integer.

        DEC     DE              ; point to destination

        LD      A,B             ; check if this is a one-character
        OR      C               ; variable name from reduced count.

        LD      A,$40           ; prepare mask 010xxxxx
        JR      Z,L0C87         ; forward to L-SINGLE if is simple numeric.

        LDIR                    ; else copy all but one characters of name.
        LD      A,(HL)          ; fetch last character
        OR      $80             ; invert it
        LD      (DE),A          ; place at last destination

        LD      A,$60           ; prepare mask 011xxxxx

;; L-SINGLE
L0C87:  POP     HL              ; restore first new location            ***

        CALL    L0CB9           ; routine L-MASK inserts masked letter.

        EX      DE,HL           ;
        DEC     DE              ;
                                ; and continue to initialize variable contents.

; this branch is taken from below to overwrite contents.

;; L-NUMERIC
L0C8D:  POP     HL              ; restore variable value
        EX      DE,HL           ; HL points last location

        LD      (HL),D          ; insert high byte.
        DEC     HL              ; decrement the pointer.
        LD      (HL),E          ; and insert low-byte value
        RET                     ; return. with HL addressing the value. >>>>

; ---

;; L-EXISTS
L0C93:  JR      NZ,L0C8D        ; back to L-NUMERIC to overwrite variable
                                ; if numeric type.

        POP     HL              ; restore string

        CALL    L0CA4           ; routine L-LENGTH evaluates length of OLD
                                ; string

        LD      HL,($4022)      ; fetch string pointer from RESULT
        DEC     HL              ; decrement to point to letter.
        CALL    L0624           ; routine NEXT-ONE calculate space to delete
        JP      L0666           ; routine RECLAIM-2

; now continue into L-STRING to evaluate length of new string.

; ---

;; L-STRING
L0CA3:  POP     HL              ; restore pointer to contents.

;; L-LENGTH
L0CA4:  LD      A,$01           ; the search will be for the quote character.
        LD      BC,$0001        ; initialize length to one.

;; L-COUNT
L0CA9:  CP      (HL)            ; is addressed character null ?
        INC     HL              ; increase pointer.
        INC     BC              ; increase length.

        JR      NZ,L0CA9        ; loop back to L-COUNT till terminating
                                ; quote found.

        PUSH    HL              ; save pointer to end - null terminator.

        RST     30H             ; routine BC-SPACES creates room at end.
        EX      DE,HL           ; transfer end to DE.

        POP     HL              ; retrieve pointer to null terminator in E-LINE.

        RET     NC              ; return if no room was available.

        LDDR                    ; else copy string to the variables area.
        EX      DE,HL           ; HL now points to letter -1
        INC     HL              ; adjust
        LD      A,$A0           ; prepare mask %10100000

;; L-MASK
L0CB9:  EX      DE,HL           ; save variable pointer in DE.
        LD      HL,($4020)      ; fetch destination in prog/e-line area
                                ; from system variable DEST
        XOR     (HL)            ; XOR mask with the letter.
                                ; Note. All letters have bit 5 set. The 
                                ; preparation of masks must accommodate this.
        EX      DE,HL           ; variable pointer to HL,
        PUSH    AF              ; save masked letter

        CALL    L0D0D           ; routine REC-V80 reclaims
                                ; the previous $80 variables end-marker.

        POP     AF              ; pop the letter.
        DEC     HL              ; point to the letter in the variables area.
                                ; which is now one location lower than it was
                                ; a moment ago.
        LD      (HL),A          ; insert masked letter.

        LD      HL,($400C)      ; use D_FILE value
        LD      ($400A),HL      ; to update new E_LINE
        DEC     HL              ; step back.
        LD      (HL),$80        ; and insert the new variable $80 end-marker.
        RET                     ; return.

; ---

;; ERROR-02
L0CD0:  POP     HL              ;

        RST     08H             ; ERROR restart
        DEFB    $01             ; variable name not found.

; -------------------------
; THE 'DIM' COMMAND ROUTINE
; -------------------------
; This routine creates a one-dimensional numeric array with up to
; 256 subscripts. Each is initialized to the integer zero.
; Note. array subscripts begin at zero. On later ZX computers subscripts began
; at 1 and there were no limits to the dimensions and subscripts other than
; memory.

;; DIM
L0CD3:  AND     B               ; check high byte of parameter.
                                ; a maximum of 255 subscripts possible.
        JP      NZ,L0BBE        ; back to ERROR-03 - subscript error.

        PUSH    BC              ; save max subscript
        LD      H,B             ; transfer
        LD      L,C             ; to HL.

        INC     HL              ; increment to make range 1-256 from 0-255
        INC     HL              ; increment for letter and subscript byte
        ADD     HL,HL           ; double - allocates two bytes per integer
                                ; and two for the letter and subscript.

        LD      B,H             ; transfer count
        LD      C,L             ; to BC

        RST     30H             ; BC-SPACES
        JP      NC,L0C22        ; back to POP-RET if out of memory

        DEC     HL              ; point to last new location
        LD      D,H             ; transfer to DE
        LD      E,L             ; - the destination.
        DEC     DE              ; make DE one less than source.
        DEC     BC              ; reduce count
        DEC     BC              ; by two.
        LD      (HL),$00        ; insert a zero at source.

        LDDR                    ; block fill locations with zero.

        POP     BC              ; restore number of subscripts
        LD      (HL),C          ; and place in location before data.
        LD      A,$80           ; prepare mask %100
        JR      L0CB9           ; back to L-MASK

; ---------------------
; THE 'RESERVE' ROUTINE
; ---------------------
; A continuation of the BC-SPACES RESTART.
; the number of bytes required is on the machine stack.

;; RESERVE
L0CF3:  LD      HL,($400A)      ; fetch start of WKG Space from E_LINE
        PUSH    HL              ; preserve location.

        LD      HL,($400C)      ; fetch location after WKG Space from D_FILE
        DEC     HL              ; point to last byte of WKG space.

        CALL    L05D5           ; routine MAKE-ROOM creates the space after
                                ; last byte sliding D-FILE up and updating
                                ; D_FILE, DF_EA and DF_END

        INC     HL              ; increase address
        INC     HL              ; by two bytes

        POP     BC              ; retrieve E_LINE which may have been updated
                                ; by pointers
        LD      ($400A),BC      ; restore E_LINE
        POP     BC              ; restore the number of bytes required.

        EX      DE,HL           ; switch - DE points to first
        INC     HL              ; make HL point to last new byte
        SCF                     ; signal success
        RET                     ; return

; --------------------------------------
; THE 'RECLAIM THE EDIT LINE' SUBROUTINE
; --------------------------------------
; Interestingly, Hugo Davenport refers to this subroutine in the manual
; by its Nine Tiles source code label X_TEMP.
; The second entry point deletes the old variables end-marker when creating
; a new variable immediately after this position.

;; REC-EDIT
L0D0A:  LD      HL,($400C)      ; D_FILE

;; REC-V80
L0D0D:  LD      DE,($400A)      ; E_LINE
        JP      L0663           ; RECLAIM-1

; ----------------------
; THE 'ALPHA' SUBROUTINE
; ----------------------

;; ALPHA
L0D14:  CP      $26             ; compare to 'A'
        JR      L0D1A           ; forward to ALPHA-2 to compare
                                ; against 'Z'

; -------------------------
; THE 'ALPHANUM' SUBROUTINE
; -------------------------
; The zx80 character set makes this routine as straightforward as the one above
; as there is no gap between numerals and alphabetic characters.

;; ALPHANUM
L0D18:  CP      $1C             ; compare to '0' - carry set if less

;; ALPHA-2
L0D1A:  CCF                     ; change to carry reset if less.
        RET     NC              ; return if less than '0'

        CP      $40             ; compare to character after 'Z'
        RET                     ; return with carry set if in the
                                ; range '0' - 'Z'

; ------------------------------------------------
; THE 'ARITHMETIC OPERATORS AND COMPARISONS' TABLE
; ------------------------------------------------
; This table is indexed with the operator * 2 to access the address of the
; associated routine.

;; TAB-OPS
L0D1F:  DEFW    L0D39           ; $00  subtract
        DEFW    L0D3E           ; $01  addition
        DEFW    L0D44           ; $02  multiply
        DEFW    L0D90           ; $03  division
        DEFW    L0DB5           ; $04  and
        DEFW    L0DBC           ; $05  or
        DEFW    L0D70           ; $06  to-power
        DEFW    L0DC3           ; $07  nos-eql
        DEFW    L0DCC           ; $08  no-grtr
        DEFW    L0DCD           ; $09  no-less
        DEFW    L0DD9           ; $0A  strs-eql
        DEFW    L0DDF           ; $0B  str-grtr
        DEFW    L0DDE           ; $0C  str-less

; ---------------------------
; THE 'SUBTRACTION' OPERATION
; ---------------------------
; offset $00 : subtract
; This operation simply uses the Z80's 16-bit register subtract instruction
; which sets the overflow flag if the lower 15 bits overflow.

;; subtract
L0D39:  AND     A               ; clear carry flag.
        SBC     HL,DE           ; 16 bit subtraction.
        JR      L0D41           ; forward to RSLT-TEST

; ------------------------
; THE 'ADDITION' OPERATION
; ------------------------
; offset $01 : add
; This operation simply uses the Z80's 16-bit register add instruction
; which sets the overflow flag in the manner above.

;; addition
L0D3E:  AND     A               ; clear carry flag.
        ADC     HL,DE           ; 16 bit addition.

;; RSLT-TEST
L0D41:  RET     PO              ; return if no twos-complement arithmetic
                                ; overflow.

;; ERROR-06
L0D42:  RST     08H             ; ERROR restart
        DEFB    $05             ; arithmetic overflow.

; ------------------------------
; THE 'MULTIPLICATION' OPERATION
; ------------------------------
; offset $02 : multiply
; the multiplication operation converts the two numbers HL and DE to positive
; integers, saving the result sign in the accumulator. If the positive result
; is above 32767 then an error code is produced else result is converted
; to the required sign, if necessary, as dictated by the accumulator.

;; multiply
L0D44:  CALL    L0DED           ; routine PREP-MD

        PUSH    BC              ; save priority/operation
        EX      AF,AF'          ; save result sign

        CALL    L0D55           ; routine MULT16

        JR      NZ,L0D8D        ; forward with overflow to POP6
                                ; clear the stack and produce ERROR-06

;; MULT-2
L0D4E:  POP     BC              ; restore priority/operation
        EX      AF,AF'          ; restore result sign.
        RRA                     ; test sign bit.
        RET     NC              ; return if result positive.

        JP      L0DF6           ; exit via routine TWOS-COMP

; ----------------------------------------
; THE 'SIXTEEN BIT MULTIPLICATION' ROUTINE
; ----------------------------------------
; Binary long multiplication by shifting and addition at the appropriate place
; if the multiplier bit is set.
; This important subroutine is called from the multiply routine, the to-power
; routine and twice from the RND function routine.
; It multiplies the 16 bit multiplier, HL, by the 16-bit multiplicand DE.
; Since the highest number the ZX80 can hold is 32767, the routine detects
; any overflow above this, resetting the zero flag - NZ with overflow.
; However if overflow occurs the routine does not abort, as does say the
; Spectrum, but continues to calculate the 32-bit result in B, C, H, L.
; Use is made of this by the RND routine.

;; MULT16
L0D55:  LD      B,H             ; transfer HL to BC
        LD      C,L             ; register.

        LD      A,$10           ; count 16 bits.
        LD      HL,$0000        ; initialize result register.

;; MULT-LP
L0D5C:  ADD     HL,HL           ; shift result left.
        RL      C               ; shift multiplier
        RL      B               ; to the left.
                                ; and capture any overflow.
        JR      NC,L0D67        ; skip addition if no carry to MULT-SKIP.

        ADD     HL,DE           ; else add in multiplicand for this bit
        JR      NC,L0D67        ; forward if no overflow.

        INC     BC              ; capture overflow in BC

;; MULT-SKIP
L0D67:  DEC     A               ; decrement bit count.
        JR      NZ,L0D5C        ; loop back for all 16 bits to MULT-LP.

        LD      A,H             ; test for a
        AND     $80             ; negative result.

        OR      B               ; test for any
        OR      C               ; intermediate overflow

        RET                     ; return with zero flag set
                                ; for success.

; ------------------------
; THE 'TO-POWER' OPERATION
; ------------------------
; offset $06 : to-power
; This routine raises HL to the power DE, by performing a multiplication
; for each unit of the power. For the integer range supported this is quite
; adequate with 2**14 returning the result without any noticeable delay
; and 1**32767 blacking the screen out for no more than a second.
; Note also that
; 0 ** 0 = 1.
; 0 ** +n = 0.
; 0 ** -n = arithmetic overflow.

;; to-power
L0D70:  BIT     7,D             ; test if second number negative.
        JR      NZ,L0D42        ; back to ERROR-06 if so.

        XOR     A               ; initialize sign flag
        CALL    L0DF2           ; routine ABS - makes HL positive.
                                ; A holds 1 if HL was negative else 0.

        AND     E               ;
        EX      AF,AF'          ; save result

        PUSH    BC              ; save priority/operation

        LD      B,D             ; transfer power
        LD      C,E             ; to BC

        EX      DE,HL           ; transfer number to DE
        LD      HL,$0001        ; initialize result.

;; POWER-LP
L0D81:  DEC     BC              ; decrement power counter.
        BIT     7,B             ; check when zero passed.

        JR      NZ,L0D4E        ; back when finished to MULT-2
                                ; to test result.                   >>

        PUSH    BC              ; save counter.

        CALL    L0D55           ; routine MULT16

        POP     BC              ; restore counter.
        JR      Z,L0D81         ; loop while no overflow exists from
                                ; the multiplication to POWER-LP.

;; POP6
L0D8D:  POP     BC              ; restore priority/operation
        JR      L0D42           ; back to ERROR-06 - arithmetic overflow.

; ------------------------
; THE 'DIVISION' OPERATION
; ------------------------
; offset $03 : division
; Binary long division by shifting and subtraction at the appropriate place,
; setting correct quotient bit if the subtraction goes.
; dividend (HL) / divisor (DE) = quotient (HL)

;; division
L0D90:  LD      A,D             ; test divisor for zero
        OR      E               ; avoiding division by zero.

        JR      Z,L0D42         ; to ERROR-06 - arithmetic overflow
                                ; if so.

        CALL    L0DED           ; routine PREP-MD converts HL and DE to 15-bit 
                                ; integers and records the result sign in A.

        PUSH    BC              ; save the priority/operation.

        RRA                     ; sets carry if a negative result.

        ADC     HL,HL           ; pick up the carry in HL, (bit 15 was reset)
        LD      A,H             ; transfer modified dividend to 
        LD      C,L             ; registers A and C.

        LD      HL,L0000        ; initialize 'accumulator' to zero.
        LD      B,$10           ; sixteen bits including sign bit.

;; DIV-1
L0DA2:  ADC     HL,HL           ; 
        SBC     HL,DE           ; subtract divisor.
        JR      NC,L0DA9        ; skip forward if subtraction goes to DIV-2.

        ADD     HL,DE           ; add back divisor.

;; DIV-2
L0DA9:  RL      C               ; as dividend bits are shifted out, the 
        RLA                     ; result bits are shifted in.
        DJNZ    L0DA2           ; back for all 16 bits.

; note after 16 bits the final RLA retrieves the sign

        LD      H,A             ; transfer result in A and C
        LD      L,C             ; to HL
        INC     HL              ; increment

        POP     BC              ; restore priority/operation.
        RET     C               ; return if .

        JR      L0DF6           ; else forward to TWOS-COMP.

; ---------------------------
; THE 'BITWISE AND' OPERATION
; ---------------------------
; offset $04 : and

;; and
L0DB5:  LD      A,H             ;
        AND     D               ;
        LD      H,A             ;

        LD      A,L             ;
        AND     E               ;
        LD      L,A             ;

        RET                     ;

; --------------------------
; THE 'BITWISE OR' OPERATION
; --------------------------
; offset $05 : or

;; or
L0DBC:  LD      A,H             ;
        OR      D               ;
        LD      H,A             ;

        LD      A,L             ;
        OR      E               ;
        LD      L,A             ;

        RET                     ;

; -----------------------------------------
; THE 'THREE NUMERIC COMPARISON' OPERATIONS
; -----------------------------------------
; offsets $07 - nos-eql, $08 - no-grtr, $09 - no-less.
;
; for example, PRINT 2=2 gives result -1 (true)

;; nos-eql
L0DC3:  AND     A               ; prepare to subtract.
        SBC     HL,DE           ; subtract the two numbers.

;; SET-RSLT
L0DC6:  LD      HL,$FFFF        ; prepare true result.
        RET     Z               ; return true result, $FFFF, in HL
                                ; if remainder was zero.

        INC     HL              ; else increment to $0000
        RET                     ; return false result, zero in HL.

; ---

;; no-grtr
L0DCC:  EX      DE,HL           ; swap values and continue into ...

;; no-less
L0DCD:  AND     A               ; prepare for true subtraction
        SBC     HL,DE           ; subtract using registers
        LD      A,H             ; fetch MSB
        RLA                     ; test the sign bit without affecting P/V flag
        JP      PO,L0DD6        ; skip to TEST-HL with no overflow

        CCF                     ; complement the carry flag

;; TEST-HL
L0DD6:  SBC     HL,HL           ; result HL will be $0000 false or $FFFF true
                                ; with carry.
        RET                     ; return

; ----------------------------------------
; THE 'THREE STRING COMPARISON' OPERATIONS
; ----------------------------------------
; offsets $0A - strs-eql, $0B - str-grtr, $0C - str-less.

;; strs-eql
L0DD9:  CALL    L0DE4           ; routine STR-CMP
        JR      L0DC6           ; to SET-RSLT

; ---

;; str-grtr
L0DDE:  EX      DE,HL           ; swap the two string pointers

;; str-less
L0DDF:  CALL    L0DE4           ; routine STR-CMP
        JR      L0DD6           ; back to TEST-HL

; ----------------------------------
; THE 'STRING COMPARISON' SUBROUTINE
; ----------------------------------

;; STR-CMP
L0DE4:  LD      A,(DE)          ; fetch character of 2nd string.
        CP      (HL)            ; compare to first.
        RET     NZ              ; return with mismatch, carry flag
                                ; shows the comparison.

        DEC     A               ; test for the null string chr$ 1.
        RET     Z               ; return as both strings have
                                ; terminated - an exact match.

        INC     DE              ; else increase
        INC     HL              ; both the string pointers.

        JR      L0DE4           ; and loop back to STR-CMP till one
                                ; of the two conditions is met.

; ----------------------------------------------
; THE 'PREPARE TO MULTIPLY OR DIVIDE' SUBROUTINE
; ----------------------------------------------

;; PREP-MD
L0DED:  XOR     A               ; initialize a sign flag.
        CALL    L0DF1           ; call PREP-1 to prepare one number
                                ; and continue into routine to prepare
                                ; the other number.
;; PREP-1
L0DF1:  EX      DE,HL           ; switch numbers at each pass

; ------------------
; THE 'ABS' FUNCTION
; ------------------
; finds the absolute value of an signed integer.
; Negative numbers are twos complemented.
; e.g. minus 1 ($FFFF) is first 'ones complemented' to $0000 then incremented.

;; abs
L0DF2:  BIT     7,H             ; test sign of HL.
        RET     Z               ; return if positive.

        INC     A               ; sets bit 0 if result is negative.
                                ; two negatives will reset bit 0 when this
                                ; routine is used to prepare for multiplication.
                                ; 'a minus times a minus gives a plus'.

;; TWOS-COMP
L0DF6:  EX      AF,AF'          ; save running flag.

        LD      A,H             ; fetch high byte
        CPL                     ; complement it
        LD      H,A             ; put back

        LD      A,L             ; fetch low byte
        CPL                     ; complement
        LD      L,A             ; put back

        INC     HL              ; twos complement

        EX      AF,AF'          ; restore running flag.
        RET                     ; return.

; -------------------
; THE 'SPARE' SECTION
; -------------------

; Start of Spare bytes

; End of Spare bytes.

;--------------------
; THE 'CHARACTER SET'
;--------------------

;; char-set

; $00 - space character           CHR$(0)

L0E00:  DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000

; $01 - Character: '"'            CHR$(1)

        DEFB    %00000000
        DEFB    %00010100
        DEFB    %00010100
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000

; $02 - Character: mosaic         CHR$(2)

        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000

; $03 - Character: mosaic         CHR$(3)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %11111111
        DEFB    %11111111
        DEFB    %11111111
        DEFB    %11111111

; $04 - Character: mosaic         CHR$(4)

        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000

; $05 - Character: mosaic         CHR$(5)

        DEFB    %00001111
        DEFB    %00001111
        DEFB    %00001111
        DEFB    %00001111
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000

; $06 - Character: mosaic         CHR$(6)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000

; $07 - Character: mosaic         CHR$(7)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00001111
        DEFB    %00001111
        DEFB    %00001111
        DEFB    %00001111

; $08 - Character: mosaic         CHR$(8)

        DEFB    %00001111
        DEFB    %00001111
        DEFB    %00001111
        DEFB    %00001111
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000
        DEFB    %11110000

; $09 - Character: mosaic         CHR$(9)

        DEFB    %10101010
        DEFB    %01010101
        DEFB    %10101010
        DEFB    %01010101
        DEFB    %10101010
        DEFB    %01010101
        DEFB    %10101010
        DEFB    %01010101

; $0A - Character: mosaic         CHR$(10)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %10101010
        DEFB    %01010101
        DEFB    %10101010
        DEFB    %01010101

; $0B - Character: mosaic         CHR$(11)

        DEFB    %10101010
        DEFB    %01010101
        DEFB    %10101010
        DEFB    %01010101
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000

; $0C - Character: uk pound       CHR$(12)

        DEFB    %00000000
        DEFB    %00011110
        DEFB    %00100001
        DEFB    %01111000
        DEFB    %00100000
        DEFB    %00100000
        DEFB    %01111111
        DEFB    %00000000

; $0D - Character: '$'            CHR$(13)

        DEFB    %00000000
        DEFB    %00001000
        DEFB    %00111110
        DEFB    %01001000
        DEFB    %00111110
        DEFB    %00001001
        DEFB    %00111110
        DEFB    %00001000

; $0E - Character: ':'            CHR$(14)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00001000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00001000
        DEFB    %00000000

; $0F - Character: '?'            CHR$(15)

        DEFB    %00000000
        DEFB    %00111110
        DEFB    %01000001
        DEFB    %00000110
        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    %00010000
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00010000
        DEFB    %00000000

; $12 - Character: '-'            CHR$(18)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00111110
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000

; $13 - Character: '+'            CHR$(19)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00111110
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00000000

; $14 - Character: '*'            CHR$(20)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00101010
        DEFB    %00011100
        DEFB    %00001000
        DEFB    %00011100
        DEFB    %00101010
        DEFB    %00000000

; $15 - Character: '/'            CHR$(21)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000010
        DEFB    %00000100
        DEFB    %00001000
        DEFB    %00010000
        DEFB    %00100000
        DEFB    %00000000

; $16 - Character: '='            CHR$(22)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00111110
        DEFB    %00000000
        DEFB    %00111110
        DEFB    %00000000
        DEFB    %00000000

; $17 - Character: '>'            CHR$(23)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00010000
        DEFB    %00001000
        DEFB    %00000100
        DEFB    %00001000
        DEFB    %00010000
        DEFB    %00000000

; $18 - Character: '<'            CHR$(24)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00000100
        DEFB    %00001000
        DEFB    %00010000
        DEFB    %00001000
        DEFB    %00000100
        DEFB    %00000000

; $19 - Character: ';'            CHR$(25)

        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00001000
        DEFB    %00000000
        DEFB    %00000000
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00010000

; $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    %00001100
        DEFB    %00001100
        DEFB    %00000000

; $1C - Character: '0'            CHR$(28)

        DEFB    %00000000
        DEFB    %00011100
        DEFB    %00100010
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %00100010
        DEFB    %00011100
        DEFB    %00000000

; $1D - Character: '1'            CHR$(29)

        DEFB    %00000000
        DEFB    %00001100
        DEFB    %00010100
        DEFB    %00000100
        DEFB    %00000100
        DEFB    %00000100
        DEFB    %00011110
        DEFB    %00000000

; $1E - Character: '2'            CHR$(30)

        DEFB    %00000000
        DEFB    %00111110
        DEFB    %01000001
        DEFB    %00000001
        DEFB    %00111110
        DEFB    %01000000
        DEFB    %01111111
        DEFB    %00000000

; $1F - Character: '3'            CHR$(31)

        DEFB    %00000000
        DEFB    %00111110
        DEFB    %01000001
        DEFB    %00000110
        DEFB    %00000001
        DEFB    %01000001
        DEFB    %00111110
        DEFB    %00000000

; $20 - Character: '4'            CHR$(32)

        DEFB    %00000000
        DEFB    %00001100
        DEFB    %00010100
        DEFB    %00100100
        DEFB    %01000100
        DEFB    %01111111
        DEFB    %00000100
        DEFB    %00000000

; $21 - Character: '5'            CHR$(33)

        DEFB    %00000000
        DEFB    %01111111
        DEFB    %01000000
        DEFB    %01111110
        DEFB    %00000001
        DEFB    %01000001
        DEFB    %00111110
        DEFB    %00000000

; $22 - Character: '6'            CHR$(34)

        DEFB    %00000000
        DEFB    %00111110
        DEFB    %01000000
        DEFB    %01111110
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %00111110
        DEFB    %00000000

; $23 - Character: '7'            CHR$(35)

        DEFB    %00000000
        DEFB    %01111111
        DEFB    %00000001
        DEFB    %00000010
        DEFB    %00000100
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00000000

; $24 - Character: '8'            CHR$(36)

        DEFB    %00000000
        DEFB    %00111110
        DEFB    %01000001
        DEFB    %00111110
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %00111110
        DEFB    %00000000

; $25 - Character: '9'            CHR$(37)

        DEFB    %00000000
        DEFB    %00111110
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %00111111
        DEFB    %00000001
        DEFB    %00111110
        DEFB    %00000000

; $26 - Character: 'A'            CHR$(38)

        DEFB    %00000000
        DEFB    %00111110
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01111111
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %00000000

; $27 - Character: 'B'            CHR$(39)

        DEFB    %00000000
        DEFB    %01111110
        DEFB    %01000001
        DEFB    %01111110
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01111110
        DEFB    %00000000

; $28 - Character: 'C'            CHR$(40)

        DEFB    %00000000
        DEFB    %00011110
        DEFB    %00100001
        DEFB    %01000000
        DEFB    %01000000
        DEFB    %00100001
        DEFB    %00011110
        DEFB    %00000000

; $29 - Character: 'D'            CHR$(41)

        DEFB    %00000000
        DEFB    %01111100
        DEFB    %01000010
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01000010
        DEFB    %01111100
        DEFB    %00000000

; $2A - Character: 'E'            CHR$(42)

        DEFB    %00000000
        DEFB    %01111111
        DEFB    %01000000
        DEFB    %01111100
        DEFB    %01000000
        DEFB    %01000000
        DEFB    %01111111
        DEFB    %00000000

; $2B - Character: 'F'            CHR$(43)

        DEFB    %00000000
        DEFB    %01111111
        DEFB    %01000000
        DEFB    %01111100
        DEFB    %01000000
        DEFB    %01000000
        DEFB    %01000000
        DEFB    %00000000

; $2C - Character: 'G'            CHR$(44)

        DEFB    %00000000
        DEFB    %00011110
        DEFB    %00100001
        DEFB    %01000000
        DEFB    %01000111
        DEFB    %00100001
        DEFB    %00011110
        DEFB    %00000000

; $2D - Character: 'H'            CHR$(45)

        DEFB    %00000000
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01111111
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01000001
        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    %00100010
        DEFB    %00011100
        DEFB    %00000000

; $30 - Character: 'K'            CHR$(48)

        DEFB    %00000000
        DEFB    %01000010
        DEFB    %01000100
        DEFB    %01111000
        DEFB    %01000100
        DEFB    %01000010
        DEFB    %01000001
        DEFB    %00000000

; $31 - Character: 'L'            CHR$(49)

        DEFB    %00000000
        DEFB    %01000000
        DEFB    %01000000
        DEFB    %01000000
        DEFB    %01000000
        DEFB    %01000000
        DEFB    %01111111
        DEFB    %00000000

; $32 - Character: 'M'            CHR$(50)

        DEFB    %00000000
        DEFB    %01000001
        DEFB    %01100011
        DEFB    %01010101
        DEFB    %01001001
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %00000000

; $33 - Character: 'N'            CHR$(51)

        DEFB    %00000000
        DEFB    %01100001
        DEFB    %01010001
        DEFB    %01001001
        DEFB    %01000101
        DEFB    %01000011
        DEFB    %01000001
        DEFB    %00000000

; $34 - Character: 'O'            CHR$(52)

        DEFB    %00000000
        DEFB    %00111110
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %00111110
        DEFB    %00000000

; $35 - Character: 'P'            CHR$(53)

        DEFB    %00000000
        DEFB    %01111110
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01111110
        DEFB    %01000000
        DEFB    %01000000
        DEFB    %00000000

; $36 - Character: 'Q'            CHR$(54)

        DEFB    %00000000
        DEFB    %00111110
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01001001
        DEFB    %01000101
        DEFB    %00111110
        DEFB    %00000000

; $37 - Character: 'R'            CHR$(55)

        DEFB    %00000000
        DEFB    %01111110
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01111110
        DEFB    %01000100
        DEFB    %01000010
        DEFB    %00000000

; $38 - Character: 'S'            CHR$(56)

        DEFB    %00000000
        DEFB    %00111110
        DEFB    %01000000
        DEFB    %00111110
        DEFB    %00000001
        DEFB    %01000001
        DEFB    %00111110
        DEFB    %00000000

; $39 - Character: 'T'            CHR$(57)

        DEFB    %00000000
        DEFB    %01111111
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00000000

; $3A - Character: 'U'            CHR$(58)

        DEFB    %00000000
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %00111110
        DEFB    %00000000

; $3B - Character: 'V'            CHR$(59)

        DEFB    %00000000
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %00100010
        DEFB    %00010100
        DEFB    %00001000
        DEFB    %00000000

; $3C - Character: 'W'            CHR$(60)

        DEFB    %00000000
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01000001
        DEFB    %01001001
        DEFB    %01010101
        DEFB    %00100010
        DEFB    %00000000

; $3D - Character: 'X'            CHR$(61)

        DEFB    %00000000
        DEFB    %00100001
        DEFB    %00010010
        DEFB    %00001100
        DEFB    %00001100
        DEFB    %00010010
        DEFB    %00100001
        DEFB    %00000000

; $3E - Character: 'Y'            CHR$(62)

        DEFB    %00000000
        DEFB    %01000001
        DEFB    %00100010
        DEFB    %00011100
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00001000
        DEFB    %00000000

; $3F - Character: 'Z'            CHR$(63)

        DEFB    %00000000
        DEFB    %01111111
        DEFB    %00000010
        DEFB    %00000100
        DEFB    %00001000
        DEFB    %00010000
        DEFB    %01111111
L0FFF:  DEFB    %00000000

.END                                ;TASM assembler directive.

; -----------------------------------------------------------------------------
;
; -------------------
; The 'Character set'
; -------------------
;
; $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F
;     nul gra gra gra gra gra gra gra gra gra gra  £   $   :   ?
;
; $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $1A $1B $1C $1D $1E $1F
;  (   )   -   +   *   /   =   >   <   ;   ,   .   0   1   2   3
;
; $20 $21 $22 $23 $24 $25 $26 $27 $28 $29 $2A $2B $2C $2D $2E $2F
;  4   5   6   7   8   9   A   B   C   D   E   F   G   H   I   J
;
; $30 $31 $32 $33 $34 $35 $36 $37 $38 $39 $3A $3B $3C $3D $3E $3F
;  K   L   M   N   O   P   Q   R   S   T   U   V   W   X   Y   Z
;
; -----------------------------------------------------------------------------
;
; -------------------
; THE 'ZX80 KEYBOARD'     
; -------------------
;                     [] mosaic graphic          £  currency symbol
;
;  NOT     AND    THEN     TO      <=      V       ^       =>     HOME    RUBOUT
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;|     | |     | |     | |     | |     | |     | |     | |     | |     | |     |
;| 1   | | 2   | | 3   | | 4   | | 5   | | 6   | | 7   | | 8   | | 9   | | 0   |
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;
;  NEW    LOAD    SAVE     RUN     CONT    REM     IF     INPUT   PRINT
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;|  [] | |  [] | |  [] | |  [] | |  [] | |   " | |   $ | |   ( | |   ) | |   * |
;| Q   | | W   | | E   | | R   | | T   | | Y   | | U   | | I   | | O   | | P   |
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;
;  LIST   STOP     DIM     FOR     GOTO    POKE    RAND    LET             EDIT
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;|  [] | |  [] | |  [] | |  [] | |  [] | |  ** | |   - | |   + | |   = | | NEW |
;| A   | | S   | | D   | | F   | | G   | | H   | | J   | | K   | | L   | | LINE|
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;
;                 CLEAR    CLS    GOSUB    RET     NEXT                   BREAK
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;|     | |   : | |   ; | |   ? | |   / | |  OR | |   < | |   > | |   , | |  £  |
;|SHIFT| | Z   | | X   | | C   | | V   | | B   | | N   | | M   | | .   | |SPACE|
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;
;
;
; -----------------------------------------------------------------------------
;
; ----------------------
; THE 'SYSTEM VARIABLES'
; ----------------------
; Note. the names of the System Variables are taken from the original 
; Nine Tiles Assembly Listing. 
;
;  1  16384 $4000 IY+$00  ERR_NR        One less than report code.
; X1  16385 $4001 IY+$01  FLAGS         Various Flags to control BASIC System.
;                                        7  1-Syntax off        0-Syntax on
;                                        6  1-Numeric result    0-String result
;                                        5  1-Evaluating function (not used)
;                                        3  1-K cursor          0-L cursor
;                                        2  1-K mode            0-L mode.
;                                        0  1-No leading space  0-Leading space.
;  2  16386 $4002 IY+$02  PPC           Line number of current line.
; N2  16388 $4004 IY+$04  P_PTR.        Position in RAM of [K] or [L] cursor.
;  2  16390 $4006 IY+$06  E_PPC         Number of current line with [>] cursor.
; X2  16392 $4008 IY+$08  VARS          Address of start of variables area.
; X2  16394 $400A IY+$0A  E_LINE        Address of start of Edit Line.
; X2  16396 $400C IY+$0C  D_FILE        Start of Display File.
; X2  16398 $400E IY+$0E  DF_EA         Address of the start of lower screen.
; X2  16400 $4010 IY+$10  DF_END        Display File End.

; X1  16402 $4012 IY+$12  DF_SZ         Number of lines in lower screen.
;  2  16403 $4013 IY+$13  S_TOP.        The number of first line on screen.
;  2  16405 $4015 IY+$15  X_PTR         Address of the character preceding
;                                       the [S] marker.
;  2  16407 $4017 IY+$17  OLDPPC        Line number to which continue jumps.
; N1  16409 $4019 IY+$19  FLAGX.        More flags.
;                                        7  1-K mode            0-L mode.
;                                        6  1-Numeric result    0-String result
;                                        5  1-Inputting         0-Editing
; N2  16410 $401A IY+$1A  T_ADDR        Address of next item in syntax table.
; U2  16412 $401C IY+$1C  SEED          The seed for the random number.
; U2  16414 $401E IY+$1E  FRAMES        Count of frames shown since start-up.
; N2  16416 $4020 IY+$20  DEST          Address of variable in statement.
; N2  16418 $4022 IY+$22  RESULT.       Value of the last expression.
; X1  16420 $4024 IY+$24  S_POSN_X      Column number for print position.
; X1  16421 $4025 IY+$25  S_POSN_Y      Line number for print position.
; X2  16422 $4026 IY+$26  CH_ADD.       Address of next character to be
;                                       interpreted.
;
; -----------------------------------------------------------------------------