?login_element?

Subversion Repositories NedoOS

Rev

Rev 129 | Blame | Compare with Previous | Last modification | View Log | Download

  1. ;************************************************************************
  2. ;** An assembly file listing to generate a 16K Rom for the ZX Spectrum **
  3. ;************************************************************************
  4. ;
  5. ; Copyright (c) Amstrad plc. All rights reserved.
  6. ;
  7. ; Acknowledgements
  8. ; -----------------
  9. ; Sean Irvine           for default list of section headings
  10. ;                       (author unknown).
  11. ; Dr. Ian Logan         for labels and functional disassembly.
  12. ; Dr. Frank O'Hara      for labels and functional disassembly.
  13. ;
  14. ; Credits
  15. ; -------
  16. ; Alex Pallero Gonzales for corrections.
  17. ; Mike Dailly           for comments.
  18. ; Alvin Albrecht        for comments.
  19. ; Hob of c.s.s          for full relocatability implementation and testing.
  20. ;                      
  21. ; z00m^SinDiKAT         sjasmplus adaptation and dirty reformat.
  22. ;
  23. ; obsolete labels
  24. ; L1C16 JUMP-C-R
  25.  
  26.                 OUTPUT  "zx-spectrum-rom.bin"
  27.  
  28. ; System variables definitions
  29.  
  30.                 include "zx-spectrum-rom-sysvars.i.asm"
  31.  
  32. ;*****************************************
  33. ;** Part 1. RESTART ROUTINES AND TABLES **
  34. ;*****************************************
  35.  
  36. ;------
  37. ; Start
  38. ;------
  39. ; At switch on, the Z80 chip is in interrupt mode 0.
  40. ; This location can also be 'called' to reset the machine.
  41. ; Typically with PRINT USR 0.
  42.  
  43.                 ORG     $0000
  44.                                         ;;;$0000
  45. START:          DI                      ; disable interrupts.
  46.                 XOR     A               ; signal coming from START.
  47.                 LD      DE,$FFFF        ; top of possible physical RAM.
  48.                 JP      START_NEW       ; jump forward to common code at START_NEW.
  49.  
  50. ;--------------
  51. ; Error restart
  52. ;--------------
  53. ; The error pointer is made to point to the position of the error to enable
  54. ; the editor to show the error if it occurred during syntax checking.
  55. ; It is used at 37 places in the program.
  56. ; An instruction fetch on address $0008 may page in a peripheral ROM
  57. ; although this was not an original design concept.
  58.  
  59.                                         ;;;$0008
  60. ERROR_1:        LD      HL,(CH_ADD)     ; fetch the character address from CH_ADD.
  61.                 LD      (X_PTR),HL      ; copy it to the error pointer X_PTR.
  62.                 JR      ERROR_2         ; forward to continue at ERROR_2.
  63.  
  64. ;------------------
  65. ; Print a character
  66. ;------------------
  67. ; The A register holds the code of the character that is to be sent to
  68. ; the output stream of the current channel.
  69. ; The alternate register set is used to output a character in the A register
  70. ; so there is no need to preserve any of the current registers.
  71. ; This restart occurs 21 times.
  72.  
  73.                                         ;;;$0010
  74. PRINT_A:        JP      PRINT_A_2       ; jump forward to continue at PRINT_A_2.
  75.  
  76.                 DEFB    $FF, $FF, $FF   ; five unused locations.
  77.                 DEFB    $FF, $FF
  78.  
  79. ;--------------------
  80. ; Collect a character
  81. ;--------------------
  82. ; The contents of the location currently addressed by CH_ADD are fetched.
  83. ; A return is made if the value represents a character that has
  84. ; relevance to the BASIC parser. Otherwise CH_ADD is incremented and the
  85. ; tests repeated. CH_ADD will be addressing somewhere -
  86. ; 1) in the basic program area during line execution.
  87. ; 2) in workspace if evaluating, for example, a string expression.
  88. ; 3) in the edit buffer if parsing a direct command or a new basic line.
  89. ; 4) in workspace if accepting input but not that from INPUT LINE.
  90.  
  91.                                         ;;;$0018
  92. GET_CHAR:       LD      HL,(CH_ADD)     ; fetch the address from CH_ADD.
  93.                 LD      A,(HL)          ; use it to pick up current character.
  94.  
  95.                                         ;;;$001C
  96. TEST_CHAR:      CALL    SKIP_OVER       ; routine SKIP_OVER tests if the character
  97.                 RET     NC              ; is relevant. Return if it is so.
  98.  
  99. ;-----------------------
  100. ; Collect next character
  101. ;-----------------------
  102. ; As the BASIC commands and expressions are interpreted, this routine is
  103. ; called repeatedly to step along the line. It is used 83 times.
  104.  
  105.                                         ;;;$0020
  106. NEXT_CHAR:      CALL    CH_ADD_1        ; routine CH_ADD_1 fetches the next immediate character.
  107.                 JR      TEST_CHAR       ; jump back to TEST_CHAR until a valid
  108.                                         ; character is found.
  109.                 DEFB    $FF, $FF, $FF   ; unused
  110.  
  111. ;-------------------
  112. ; Calculator restart
  113. ;-------------------
  114. ; This restart enters the Spectrum's internal, floating-point,
  115. ; stack-based, FORTH-like language.
  116. ; It is further used recursively from within the calculator.
  117. ; It is used on 77 occasions.
  118.  
  119.                                         ;;;$0028
  120. FP_CALC:        JP      CALCULATE       ; jump forward to the CALCULATE routine.
  121.  
  122.                 DEFB    $FF, $FF, $FF   ; spare - note that on the ZX81, space being a
  123.                 DEFB    $FF, $FF        ; little cramped, these same locations were
  124.                                         ; used for the five-byte END_CALC literal.
  125.  
  126. ;------------------------------------
  127. ; Create free locations in work space
  128. ;------------------------------------
  129. ; This restart is used on only 12 occasions to create BC spaces
  130. ; between workspace and the calculator stack.
  131.  
  132.                                         ;;;$0030
  133. BC_SPACES:      PUSH    BC              ; save number of spaces.
  134.                 LD      HL,(WORKSP)     ; fetch WORKSP.
  135.                 PUSH    HL              ; save address of workspace.
  136.                 JP      RESERVE         ; jump forward to continuation code RESERVE.
  137.  
  138. ;---------------------------
  139. ; Maskable interrupt routine
  140. ;---------------------------
  141. ; This routine increments the Spectrum's three-byte FRAMES counter
  142. ; fifty times a second (sixty times a second in the USA ).
  143. ; Both this routine and the called KEYBOARD subroutine use
  144. ; the IY register to access system variables and flags so a user-written
  145. ; program must disable interrupts to make use of the IY register.
  146.  
  147.                                         ;;;$0038
  148. MASK_INT:       PUSH    AF              ; save the registers.
  149.                 PUSH    HL              ; but not IY unfortunately.
  150.                 LD      HL,(FRAMES1)    ; fetch two bytes at FRAMES1.
  151.                 INC     HL              ; increment lowest two bytes of counter.
  152.                 LD      (FRAMES1),HL    ; place back in FRAMES1.
  153.                 LD      A,H             ; test if the result
  154.                 OR      L               ; was zero.
  155.                 JR      NZ,KEY_INT      ; forward to KEY_INT if not.
  156.  
  157.                 INC     (IY+$40)        ; otherwise increment FRAMES3 the third byte.
  158.  
  159.                                         ; now save the rest of the main registers and read and decode the keyboard.
  160.  
  161.                                         ;;;$0048
  162. KEY_INT:        PUSH    BC              ; save the other
  163.                 PUSH    DE              ; main registers.
  164.                 CALL    KEYBOARD        ; routine KEYBOARD executes a stage in the process of reading a key-press.
  165.                 POP     DE
  166.                 POP     BC              ; restore registers.
  167.                 POP     HL
  168.                 POP     AF
  169.                 EI                      ; enable interrupts.
  170.                 RET                     ; return.
  171.  
  172. ;----------------
  173. ; ERROR_2 routine
  174. ;----------------
  175. ; A continuation of the code at 0008.
  176. ; The error code is stored and after clearing down stacks,
  177. ; an indirect jump is made to MAIN_4, etc. to handle the error.
  178.  
  179.                                         ;;;$0053
  180. ERROR_2:        POP     HL              ; drop the return address - the location
  181.                                         ; after the RST 08H instruction.
  182.                 LD      L,(HL)          ; fetch the error code that follows.
  183.                                         ; (nice to see this instruction used.)
  184.  
  185.                                         ; Note. this entry point is used when out of memory at REPORT_4.
  186.                                         ; The L register has been loaded with the report code but X_PTR
  187.                                         ; is not updated.
  188.  
  189.                                         ;;;$0055
  190. ERROR_3:        LD      (IY+$00),L      ; store it in the system variable ERR_NR.
  191.                 LD      SP,(ERR_SP)     ; ERR_SP points to an error handler on the
  192.                                         ; machine stack. There may be a hierarchy
  193.                                         ; of routines.
  194.                                         ; to MAIN_4 initially at base.
  195.                                         ; or REPORT_G on line entry.
  196.                                         ; or ED_ERROR when editing.
  197.                                         ; or ED_FULL during ED_ENTER.
  198.                                         ; or IN_VAR_1 during runtime input etc.
  199.  
  200.                 JP      SET_STK         ; jump to SET_STK to clear the calculator
  201.                                         ; stack and reset MEM to usual place in the
  202.                                         ; systems variables area.
  203.                                         ; and then indirectly to MAIN_4, etc.
  204.  
  205.                 DEFB    $FF, $FF, $FF   ; unused locations
  206.                 DEFB    $FF, $FF, $FF   ; before the fixed-position
  207.                 DEFB    $FF             ; NMI routine.
  208.  
  209. ;-------------------------------
  210. ; Non-maskable interrupt routine
  211. ;-------------------------------
  212. ; There is no NMI switch on the standard Spectrum.
  213. ; When activated, a location in the system variables is tested
  214. ; and if the contents are zero a jump made to that location else
  215. ; a return is made. Perhaps a disabled development feature but
  216. ; if the logic was reversed, no program would be safe from
  217. ; copy-protection and the Spectrum would have had no software base.
  218. ; The location NMIADD was later used by Interface 1 for other purposes
  219. ; ironically to make use of the Spectrum's RS232 TAB character
  220. ; which was not understood when the Interface was designed.
  221. ; On later Spectrums, and the Brazilian Spectrum, the logic of this
  222. ; routine was reversed.
  223.  
  224.                                         ;;;$0066
  225. RESET:          PUSH    AF              ; save the
  226.                 PUSH    HL              ; registers.
  227.                 LD      HL,(NMIADD)     ; fetch the system variable NMIADD.
  228.                 LD      A,H             ; test address
  229.                 OR      L               ; for zero.
  230.                 JR      NZ,NO_RESET     ; skip to NO_RESET if NOT ZERO
  231.  
  232.                 JP      (HL)            ; jump to routine ( i.e. START )
  233.  
  234.                                         ;;;$0070
  235. NO_RESET:       POP     HL              ; restore the
  236.                 POP     AF              ; registers.
  237.                 RETN                    ; return to previous interrupt state.
  238.  
  239. ;----------------------
  240. ; CH ADD + 1 subroutine
  241. ;----------------------
  242. ; This subroutine is called from RST 20, and three times from elsewhere
  243. ; to fetch the next immediate character following the current valid character
  244. ; address and update the associated system variable.
  245. ; The entry point TEMP_PTR1 is used from the SCANNING routine.
  246. ; Both TEMP_PTR1 and TEMP_PTR2 are used by the READ command routine.
  247.  
  248.                                         ;;;$0074
  249. CH_ADD_1:       LD      HL,(CH_ADD)     ; fetch address from CH_ADD.
  250.  
  251.                                         ;;;$0077
  252. TEMP_PTR1:      INC     HL              ; increase the character address by one.
  253.  
  254.                                         ;;;$0078
  255. TEMP_PTR2:      LD      (CH_ADD),HL     ; update CH_ADD with character address.
  256.                 LD      A,(HL)          ; load character to A from HL.
  257.                 RET                     ; and return.
  258.  
  259. ;----------
  260. ; Skip over
  261. ;----------
  262. ; This subroutine is called once from RST 18 to skip over white-space and
  263. ; other characters irrelevant to the parsing of a basic line etc. .
  264. ; Initially the A register holds the character to be considered
  265. ; and HL holds it's address which will not be within quoted text
  266. ; when a basic line is parsed.
  267. ; Although the 'tab' and 'at' characters will not appear in a basic line,
  268. ; they could be present in a string expression, and in other situations.
  269. ; Note. although white-space is usually placed in a program to indent loops
  270. ; and make it more readable, it can also be used for the opposite effect and
  271. ; spaces may appear in variable names although the parser never sees them.
  272. ; It is this routine that helps make the variables 'Anum bEr5 3BUS' and
  273. ; 'a number 53 bus' appear the same to the parser.
  274.  
  275.                                         ;;;$007D
  276. SKIP_OVER:      CP      $21             ; test if higher than space.
  277.                 RET     NC              ; return with carry clear if so.
  278.  
  279.                 CP      $0D             ; carriage return ?
  280.                 RET     Z               ; return also with carry clear if so.
  281.  
  282.                                         ; all other characters have no relevance
  283.                                         ; to the parser and must be returned with
  284.                                         ; carry set.
  285.  
  286.                 CP      $10             ; test if 0-15d
  287.                 RET     C               ; return, if so, with carry set.
  288.  
  289.                 CP      $18             ; test if 24-32d
  290.                 CCF                     ; complement carry flag.
  291.                 RET     C               ; return with carry set if so.
  292.  
  293.                                         ; now leaves 16d-23d
  294.  
  295.                 INC     HL              ; all above have at least one extra character
  296.                                         ; to be stepped over.
  297.                 CP      $16             ; controls 22d ('at') and 23d ('tab') have two.
  298.                 JR      C,SKIPS         ; forward to SKIPS with ink, paper, flash,
  299.                                         ; bright, inverse or over controls.
  300.                                         ; Note. the high byte of tab is for RS232 only.
  301.                                         ; it has no relevance on this machine.
  302.                 INC     HL              ; step over the second character of 'at'/'tab'.
  303.  
  304.                                         ;;;$0090
  305. SKIPS:          SCF                     ; set the carry flag
  306.                 LD      (CH_ADD),HL     ; update the CH_ADD system variable.
  307.                 RET                     ; return with carry set.
  308.  
  309.  
  310. ;-------------
  311. ; Token tables
  312. ;-------------
  313. ; The tokenized characters 134d (RND) to 255d (COPY) are expanded using
  314. ; this table. The last byte of a token is inverted to denote the end of
  315. ; the word. The first is an inverted step-over byte.
  316.  
  317.                                         ;;;$0095
  318. TKN_TABLE:      DEFB    '?'+$80
  319.                 DEFB    "RN",'D'+$80
  320.                 DEFB    "INKEY",'$'+$80
  321.                 DEFB    "P",'I'+$80
  322.                 DEFB    "F",'N'+$80
  323.                 DEFB    "POIN",'T'+$80
  324.                 DEFB    "SCREEN",'$'+$80
  325.                 DEFB    "ATT",'R'+$80
  326.                 DEFB    "A",'T'+$80
  327.                 DEFB    "TA",'B'+$80
  328.                 DEFB    "VAL",'$'+$80
  329.                 DEFB    "COD",'E'+$80
  330.                 DEFB    "VA",'L'+$80
  331.                 DEFB    "LE",'N'+$80
  332.                 DEFB    "SI",'N'+$80
  333.                 DEFB    "CO",'S'+$80
  334.                 DEFB    "TA",'N'+$80
  335.                 DEFB    "AS",'N'+$80
  336.                 DEFB    "AC",'S'+$80
  337.                 DEFB    "AT",'N'+$80
  338.                 DEFB    "L",'N'+$80
  339.                 DEFB    "EX",'P'+$80
  340.                 DEFB    "IN",'T'+$80
  341.                 DEFB    "SQ",'R'+$80
  342.                 DEFB    "SG",'N'+$80
  343.                 DEFB    "AB",'S'+$80
  344.                 DEFB    "PEE",'K'+$80
  345.                 DEFB    "I",'N'+$80
  346.                 DEFB    "US",'R'+$80
  347.                 DEFB    "STR",'$'+$80
  348.                 DEFB    "CHR",'$'+$80
  349.                 DEFB    "NO",'T'+$80
  350.                 DEFB    "BI",'N'+$80
  351.  
  352.                                         ; The previous 32 function-type words are printed without a leading space
  353.                                         ; The following have a leading space if they begin with a letter
  354.  
  355.                 DEFB    "O",'R'+$80
  356.                 DEFB    "AN",'D'+$80
  357.                 DEFB    $3C,'='+$80     ; <=
  358.                 DEFB    $3E,'='+$80     ; >=
  359.                 DEFB    $3C,$3E+$80     ; <>
  360.                 DEFB    "LIN",'E'+$80
  361.                 DEFB    "THE",'N'+$80
  362.                 DEFB    "T",'O'+$80
  363.                 DEFB    "STE",'P'+$80
  364.                 DEFB    "DEF F",'N'+$80
  365.                 DEFB    "CA",'T'+$80
  366.                 DEFB    "FORMA",'T'+$80
  367.                 DEFB    "MOV",'E'+$80
  368.                 DEFB    "ERAS",'E'+$80
  369.                 DEFB    "OPEN ",'#'+$80
  370.                 DEFB    "CLOSE ",'#'+$80
  371.                 DEFB    "MERG",'E'+$80
  372.                 DEFB    "VERIF",'Y'+$80
  373.                 DEFB    "BEE",'P'+$80
  374.                 DEFB    "CIRCL",'E'+$80
  375.                 DEFB    "IN",'K'+$80
  376.                 DEFB    "PAPE",'R'+$80
  377.                 DEFB    "FLAS",'H'+$80
  378.                 DEFB    "BRIGH",'T'+$80
  379.                 DEFB    "INVERS",'E'+$80
  380.                 DEFB    "OVE",'R'+$80
  381.                 DEFB    "OU",'T'+$80
  382.                 DEFB    "LPRIN",'T'+$80
  383.                 DEFB    "LLIS",'T'+$80
  384.                 DEFB    "STO",'P'+$80
  385.                 DEFB    "REA",'D'+$80
  386.                 DEFB    "DAT",'A'+$80
  387.                 DEFB    "RESTOR",'E'+$80
  388.                 DEFB    "NE",'W'+$80
  389.                 DEFB    "BORDE",'R'+$80
  390.                 DEFB    "CONTINU",'E'+$80
  391.                 DEFB    "DI",'M'+$80
  392.                 DEFB    "RE",'M'+$80
  393.                 DEFB    "FO",'R'+$80
  394.                 DEFB    "GO T",'O'+$80
  395.                 DEFB    "GO SU",'B'+$80
  396.                 DEFB    "INPU",'T'+$80
  397.                 DEFB    "LOA",'D'+$80
  398.                 DEFB    "LIS",'T'+$80
  399.                 DEFB    "LE",'T'+$80
  400.                 DEFB    "PAUS",'E'+$80
  401.                 DEFB    "NEX",'T'+$80
  402.                 DEFB    "POK",'E'+$80
  403.                 DEFB    "PRIN",'T'+$80
  404.                 DEFB    "PLO",'T'+$80
  405.                 DEFB    "RU",'N'+$80
  406.                 DEFB    "SAV",'E'+$80
  407.                 DEFB    "RANDOMIZ",'E'+$80
  408.                 DEFB    "I",'F'+$80
  409.                 DEFB    "CL",'S'+$80
  410.                 DEFB    "DRA",'W'+$80
  411.                 DEFB    "CLEA",'R'+$80
  412.                 DEFB    "RETUR",'N'+$80
  413.                 DEFB    "COP",'Y'+$80
  414.                
  415. ;-----------
  416. ; Key tables
  417. ;-----------
  418. ; These six look-up tables are used by the keyboard reading routine
  419. ; to decode the key values.
  420.  
  421. ; The first table contains the maps for the 39 keys of the standard
  422. ; 40-key Spectrum keyboard. The remaining key [SHIFT $27] is read directly.
  423. ; The keys consist of the 26 upper-case alphabetic characters, the 10 digit
  424. ; keys and the space, ENTER and symbol shift key.
  425. ; Unshifted alphabetic keys have $20 added to the value.
  426. ; The keywords for the main alphabetic keys are obtained by adding $A5 to
  427. ; the values obtained from this table.
  428.  
  429.                                         ;;;$0205
  430. MAIN_KEYS:      DEFB    $42             ; B
  431.                 DEFB    $48             ; H
  432.                 DEFB    $59             ; Y
  433.                 DEFB    $36             ; 6
  434.                 DEFB    $35             ; 5
  435.                 DEFB    $54             ; T
  436.                 DEFB    $47             ; G
  437.                 DEFB    $56             ; V
  438.                 DEFB    $4E             ; N
  439.                 DEFB    $4A             ; J
  440.                 DEFB    $55             ; U
  441.                 DEFB    $37             ; 7
  442.                 DEFB    $34             ; 4
  443.                 DEFB    $52             ; R
  444.                 DEFB    $46             ; F
  445.                 DEFB    $43             ; C
  446.                 DEFB    $4D             ; M
  447.                 DEFB    $4B             ; K
  448.                 DEFB    $49             ; I
  449.                 DEFB    $38             ; 8
  450.                 DEFB    $33             ; 3
  451.                 DEFB    $45             ; E
  452.                 DEFB    $44             ; D
  453.                 DEFB    $58             ; X
  454.                 DEFB    $0E             ; SYMBOL SHIFT
  455.                 DEFB    $4C             ; L
  456.                 DEFB    $4F             ; O
  457.                 DEFB    $39             ; 9
  458.                 DEFB    $32             ; 2
  459.                 DEFB    $57             ; W
  460.                 DEFB    $53             ; S
  461.                 DEFB    $5A             ; Z
  462.                 DEFB    $20             ; SPACE
  463.                 DEFB    $0D             ; ENTER
  464.                 DEFB    $50             ; P
  465.                 DEFB    $30             ; 0
  466.                 DEFB    $31             ; 1
  467.                 DEFB    $51             ; Q
  468.                 DEFB    $41             ; A
  469.  
  470.                                         ;;;$022C
  471.                                         ;  The 26 unshifted extended mode keys for the alphabetic characters.
  472.                                         ;  The green keywords on the original keyboard.
  473. E_UNSHIFT:      DEFB    $E3             ; READ
  474.                 DEFB    $C4             ; BIN
  475.                 DEFB    $E0             ; LPRINT
  476.                 DEFB    $E4             ; DATA
  477.                 DEFB    $B4             ; TAN
  478.                 DEFB    $BC             ; SGN
  479.                 DEFB    $BD             ; ABS
  480.                 DEFB    $BB             ; SQR
  481.                 DEFB    $AF             ; CODE
  482.                 DEFB    $B0             ; VAL
  483.                 DEFB    $B1             ; LEN
  484.                 DEFB    $C0             ; USR
  485.                 DEFB    $A7             ; PI
  486.                 DEFB    $A6             ; INKEY$
  487.                 DEFB    $BE             ; PEEK
  488.                 DEFB    $AD             ; TAB
  489.                 DEFB    $B2             ; SIN
  490.                 DEFB    $BA             ; INT
  491.                 DEFB    $E5             ; RESTORE
  492.                 DEFB    $A5             ; RND
  493.                 DEFB    $C2             ; CHR$
  494.                 DEFB    $E1             ; LLIST
  495.                 DEFB    $B3             ; COS
  496.                 DEFB    $B9             ; EXP
  497.                 DEFB    $C1             ; STR$
  498.                 DEFB    $B8             ; LN
  499.  
  500.                                         ;;;$0246
  501.                                         ;  The 26 shifted extended mode keys for the alphabetic characters.
  502.                                         ;  The red keywords below keys on the original keyboard.
  503. EXT_SHIFT:      DEFB    $7E             ; ~
  504.                 DEFB    $DC             ; BRIGHT
  505.                 DEFB    $DA             ; PAPER
  506.                 DEFB    $5C             ; \ ;
  507.                 DEFB    $B7             ; ATN
  508.                 DEFB    $7B             ; {
  509.                 DEFB    $7D             ; }
  510.                 DEFB    $D8             ; CIRCLE
  511.                 DEFB    $BF             ; IN
  512.                 DEFB    $AE             ; VAL$
  513.                 DEFB    $AA             ; SCREEN$
  514.                 DEFB    $AB             ; ATTR
  515.                 DEFB    $DD             ; INVERSE
  516.                 DEFB    $DE             ; OVER
  517.                 DEFB    $DF             ; OUT
  518.                 DEFB    $7F             ; (Copyright character)
  519.                 DEFB    $B5             ; ASN
  520.                 DEFB    $D6             ; VERIFY
  521.                 DEFB    $7C             ; |
  522.                 DEFB    $D5             ; MERGE
  523.                 DEFB    $5D             ; ]
  524.                 DEFB    $DB             ; FLASH
  525.                 DEFB    $B6             ; ACS
  526.                 DEFB    $D9             ; INK
  527.                 DEFB    $5B             ; [
  528.                 DEFB    $D7             ; BEEP
  529.  
  530.                                         ;;;$0260
  531.                                         ;  The ten control codes assigned to the top line of digits when the shift
  532.                                         ;  key is pressed.
  533. CTL_CODES:      DEFB    $0C             ; DELETE
  534.                 DEFB    $07             ; EDIT
  535.                 DEFB    $06             ; CAPS LOCK
  536.                 DEFB    $04             ; TRUE VIDEO
  537.                 DEFB    $05             ; INVERSE VIDEO
  538.                 DEFB    $08             ; CURSOR LEFT
  539.                 DEFB    $0A             ; CURSOR DOWN
  540.                 DEFB    $0B             ; CURSOR UP
  541.                 DEFB    $09             ; CURSOR RIGHT
  542.                 DEFB    $0F             ; GRAPHICS
  543.  
  544.                                         ;;;$026A
  545.                                         ;  The 26 red symbols assigned to the alphabetic characters of the keyboard.
  546.                                         ;  The ten single-character digit symbols are converted without the aid of
  547.                                         ;  a table using subtraction and minor manipulation.
  548. SYM_CODES:      DEFB    $E2             ; STOP
  549.                 DEFB    $2A             ; *
  550.                 DEFB    $3F             ; ?
  551.                 DEFB    $CD             ; STEP
  552.                 DEFB    $C8             ; >=
  553.                 DEFB    $CC             ; TO
  554.                 DEFB    $CB             ; THEN
  555.                 DEFB    $5E             ; ^
  556.                 DEFB    $AC             ; AT
  557.                 DEFB    $2D             ; -
  558.                 DEFB    $2B             ; +
  559.                 DEFB    $3D             ; =
  560.                 DEFB    $2E             ; .
  561.                 DEFB    $2C             ; ,
  562.                 DEFB    $3B             ; ;
  563.                 DEFB    $22             ; "
  564.                 DEFB    $C7             ; <=
  565.                 DEFB    $3C             ; <
  566.                 DEFB    $C3             ; NOT
  567.                 DEFB    $3E             ; >
  568.                 DEFB    $C5             ; OR
  569.                 DEFB    $2F             ; /
  570.                 DEFB    $C9             ; <>
  571.                 DEFB    $60             ; pound
  572.                 DEFB    $C6             ; AND
  573.                 DEFB    $3A             ; :
  574.  
  575.                                         ;;;$0284
  576.                                         ;  The ten keywords assigned to the digits in extended mode.
  577.                                         ;  The remaining red keywords below the keys.
  578. E_DIGITS:       DEFB    $D0             ; FORMAT
  579.                 DEFB    $CE             ; DEF FN
  580.                 DEFB    $A8             ; FN
  581.                 DEFB    $CA             ; LINE
  582.                 DEFB    $D3             ; OPEN#
  583.                 DEFB    $D4             ; CLOSE#
  584.                 DEFB    $D1             ; MOVE
  585.                 DEFB    $D2             ; ERASE
  586.                 DEFB    $A9             ; POINT
  587.                 DEFB    $CF             ; CAT
  588.  
  589.  
  590. ;*******************************
  591. ;** Part 2. KEYBOARD ROUTINES **
  592. ;*******************************
  593.  
  594. ; Using shift keys and a combination of modes the Spectrum 40-key keyboard
  595. ; can be mapped to 256 input characters
  596.  
  597. ;----------------------------------------------------------------------------
  598. ;
  599. ;         0     1     2     3     4 -Bits-  4     3     2     1     0
  600. ; PORT                                                                    PORT
  601. ;
  602. ; F7FE  [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ]  |  [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 0 ]   EFFE
  603. ;  ^                                   |                                   v
  604. ; FBFE  [ Q ] [ W ] [ E ] [ R ] [ T ]  |  [ Y ] [ U ] [ I ] [ O ] [ P ]   DFFE
  605. ;  ^                                   |                                   v
  606. ; FDFE  [ A ] [ S ] [ D ] [ F ] [ G ]  |  [ H ] [ J ] [ K ] [ L ] [ ENT ] BFFE
  607. ;  ^                                   |                                   v
  608. ; FEFE  [SHI] [ Z ] [ X ] [ C ] [ V ]  |  [ B ] [ N ] [ M ] [sym] [ SPC ] 7FFE
  609. ;  ^     $27                                                 $18           v
  610. ; Start                                                                   End
  611. ;        00100111                                            00011000
  612. ;
  613. ;----------------------------------------------------------------------------
  614. ; The above map may help in reading.
  615. ; The neat arrangement of ports means that the B register need only be
  616. ; rotated left to work up the left hand side and then down the right
  617. ; hand side of the keyboard. When the reset bit drops into the carry
  618. ; then all 8 half-rows have been read. Shift is the first key to be
  619. ; read. The lower six bits of the shifts are unambiguous.
  620.  
  621. ;------------------
  622. ; Keyboard scanning
  623. ;------------------
  624. ; from keyboard and S_INKEY
  625. ; returns 1 or 2 keys in DE, most significant shift first if any
  626. ; key values 0-39 else 255
  627.  
  628.                                         ;;;$028E
  629. KEY_SCAN:       LD      L,$2F           ; initial key value
  630.                                         ; valid values are obtained by subtracting
  631.                                         ; eight five times.
  632.                 LD      DE,$FFFF        ; a buffer to receive 2 keys.
  633.                 LD      BC,$FEFE        ; the commencing port address
  634.                                         ; B holds 11111110 initially and is also
  635.                                         ; used to count the 8 half-rows
  636.                                         ;;;$0296
  637. KEY_LINE:       IN      A,(C)           ; read the port to A - bits will be reset
  638.                                         ; if a key is pressed else set.
  639.                 CPL                     ; complement - pressed key-bits are now set
  640.                 AND     $1F             ; apply 00011111 mask to pick up the
  641.                                         ; relevant set bits.
  642.                 JR      Z,KEY_DONE      ; forward to KEY_DONE if zero and therefore
  643.                                         ; no keys pressed in row at all.
  644.                 LD      H,A             ; transfer row bits to H
  645.                 LD      A,L             ; load the initial key value to A
  646.  
  647.                                         ;;;$029F
  648. KEY_3KEYS:      INC     D               ; now test the key buffer
  649.                 RET     NZ              ; if we have collected 2 keys already
  650.                                         ; then too many so quit.
  651.  
  652.                                         ;;;$02A1
  653. KEY_BITS:       SUB     $08             ; subtract 8 from the key value
  654.                                         ; cycling through key values (top = $27)
  655.                                         ; e.g. 2F>  27>1F>17>0F>07
  656.                                         ;      2E>  26>1E>16>0E>06
  657.                 SRL     H               ; shift key bits right into carry.
  658.                 JR      NC,KEY_BITS     ; back to KEY_BITS if not pressed
  659.                                         ; but if pressed we have a value (0-39d)
  660.                 LD      D,E             ; transfer a possible previous key to D
  661.                 LD      E,A             ; transfer the new key to E
  662.                 JR      NZ,KEY_3KEYS    ; back to KEY_3KEYS if there were more
  663.                                         ; set bits - H was not yet zero.
  664.  
  665.                                         ;;;$02AB
  666. KEY_DONE:       DEC     L               ; cycles 2F>2E>2D>2C>2B>2A>29>28 for
  667.                                         ; each half-row.
  668.                 RLC     B               ; form next port address e.g. FEFE > FDFE
  669.                 JR      C,KEY_LINE      ; back to KEY_LINE if still more rows to do.
  670.  
  671.                 LD      A,D             ; now test if D is still FF ?
  672.                 INC     A               ; if it is zero we have at most 1 key
  673.                                         ; range now $01-$28  (1-40d)
  674.                 RET     Z               ; return if one key or no key.
  675.  
  676.                 CP      $28             ; is it capsshift (was $27) ?
  677.                 RET     Z               ; return if so.
  678.  
  679.                 CP      $19             ; is it symbol shift (was $18) ?
  680.                 RET     Z               ; return also
  681.  
  682.                 LD      A,E             ; now test E
  683.                 LD      E,D             ; but first switch
  684.                 LD      D,A             ; the two keys.
  685.                 CP      $18             ; is it symbol shift ?
  686.                 RET                     ; return (with zero set if it was).
  687.                                         ; but with symbol shift now in D
  688.  
  689. ;-------------------------------
  690. ; Scan keyboard and decode value
  691. ;-------------------------------
  692. ; from interrupt 50 times a second
  693.  
  694.                                         ;;;$02BF
  695. KEYBOARD:       CALL    KEY_SCAN        ; routine KEY_SCAN
  696.                 RET     NZ              ; return if invalid combinations
  697.  
  698.                                         ; then decrease the counters within the two key-state maps
  699.                                         ; as this could cause one to become free.
  700.                                         ; if the keyboard has not been pressed during the last five interrupts
  701.                                         ; then both sets will be free.
  702.  
  703.  
  704.                 LD      HL,KSTATE_0     ; point to KSTATE_0
  705.  
  706.                                         ;;;$02C6
  707. K_ST_LOOP:      BIT     7,(HL)          ; is it free ?  ($FF)
  708.                 JR      NZ,K_CH_SET     ; forward to K_CH_SET if so
  709.  
  710.                 INC     HL              ; address 5-counter
  711.                 DEC     (HL)            ; decrease counter
  712.                 DEC     HL              ; step back
  713.                 JR      NZ,K_CH_SET     ; forward to K_CH_SET if not at end of count
  714.  
  715.                 LD      (HL),$FF        ; else mark it free.
  716.  
  717.                                         ;;;$02D1
  718. K_CH_SET:       LD      A,L             ; store low address byte.
  719.                 LD      HL,KSTATE_4     ; point to KSTATE_4
  720.                                         ; (ld l, $04)
  721.                 CP      L               ; have 2 been done ?
  722.                 JR      NZ,K_ST_LOOP    ; back to K_ST_LOOP to consider this 2nd set
  723.  
  724.                                         ; now the raw key (0-38) is converted to a main key (uppercase).
  725.  
  726.                 CALL    K_TEST          ; routine K_TEST to get main key in A
  727.                 RET     NC              ; return if single shift
  728.  
  729.                 LD      HL,KSTATE_0     ; point to KSTATE_0
  730.                 CP      (HL)            ; does it match ?
  731.                 JR      Z,K_REPEAT      ; forward to K_REPEAT if so
  732.  
  733.                                         ; if not consider the second key map.
  734.  
  735.                 EX      DE,HL           ; save KSTATE_0 in DE
  736.                 LD      HL,KSTATE_4     ; point to KSTATE_4
  737.                 CP      (HL)            ; does it match ?
  738.                 JR      Z,K_REPEAT      ; forward to K_REPEAT if so
  739.  
  740.                                         ; having excluded a repeating key we can now consider a new key.
  741.                                         ; the second set is always examined before the first.
  742.  
  743.                 BIT     7,(HL)          ; is it free ?
  744.                 JR      NZ,K_NEW        ; forward to K_NEW if so.
  745.  
  746.                 EX      DE,HL           ; bring back KSTATE_0
  747.                 BIT     7,(HL)          ; is it free ?
  748.                 RET     Z               ; return if not.
  749.                                         ; as we have a key but nowhere to put it yet.
  750.  
  751.                                         ; continue or jump to here if one of the buffers was free.
  752.  
  753.                                         ;;;$02F1
  754. K_NEW:          LD      E,A             ; store key in E
  755.                 LD      (HL),A          ; place in free location
  756.                 INC     HL              ; advance to interrupt counter
  757.                 LD      (HL),$05        ; and initialize to 5
  758.                 INC     HL              ; advance to delay
  759.                 LD      A,(REPDEL)      ; pick up system variable REPDEL
  760.                 LD      (HL),A          ; and insert that for first repeat delay.
  761.                 INC     HL              ; advance to last location of state map.
  762.                 LD      C,(IY+$07)      ; pick up MODE  (3 bytes)
  763.                 LD      D,(IY+$01)      ; pick up FLAGS (3 bytes)
  764.                 PUSH    HL              ; save state map location
  765.                                         ; Note. could now have used.
  766.                                         ; ld l,$41; ld c,(hl); ld l,$3B; ld d,(hl).
  767.                                         ; six and two threes of course.
  768.                 CALL    K_DECODE        ; routine K_DECODE
  769.                 POP     HL              ; restore map pointer
  770.                 LD      (HL),A          ; put decoded key in last location of map.
  771.  
  772.                                         ;;;$0308
  773. K_END:          LD      (LASTK),A       ; update LASTK system variable.
  774.                 SET     5,(IY+$01)      ; update FLAGS - signal new key.
  775.                 RET                     ; done
  776.  
  777. ;-------------------
  778. ; Repeat key routine
  779. ;-------------------
  780. ; A possible repeat has been identified. HL addresses the raw (main) key.
  781. ; The last location holds the decoded key (from the first context).
  782.  
  783.                                         ;;;$0310
  784. K_REPEAT:       INC     HL              ; advance
  785.                 LD      (HL),$05        ; maintain interrupt counter at 5
  786.                 INC     HL              ; advance
  787.                 DEC     (HL)            ; decrease REPDEL value.
  788.                 RET     NZ              ; return if not yet zero.
  789.  
  790.                 LD      A,(REPPER)      ; REPPER
  791.                 LD      (HL),A          ; but for subsequent repeats REPPER will be used.
  792.                 INC     HL              ; advance
  793.                 LD      A,(HL)          ; pick up the key decoded possibly in another context.
  794.                 JR      K_END           ; back to K_END
  795.  
  796. ;---------------
  797. ; Test key value
  798. ;---------------
  799. ; also called from S_INKEY
  800. ; begin by testing for a shift with no other.
  801.  
  802.                                         ;;;$031E
  803. K_TEST:         LD      B,D             ; load most significant key to B
  804.                                         ; will be $FF if not shift.
  805.                 LD      D,$00           ; and reset D to index into main table
  806.                 LD      A,E             ; load least significant key from E
  807.                 CP      $27             ; is it higher than 39d i.e. FF
  808.                 RET     NC              ; return with just a shift (in B now)
  809.  
  810.                 CP      $18             ; is it symbol shift ?
  811.                 JR      NZ,K_MAIN       ; forward to K_MAIN if not
  812.  
  813.                                         ; but we could have just symbol shift and no other
  814.  
  815.                 BIT     7,B             ; is other key $FF (ie not shift)
  816.                 RET     NZ              ; return with solitary symbol shift
  817.  
  818.                                         ;;;$032C
  819. K_MAIN:         LD      HL,MAIN_KEYS    ; address: MAIN_KEYS
  820.                 ADD     HL,DE           ; add offset 0-38
  821.                 LD      A,(HL)          ; pick up main key value
  822.                 SCF                     ; set carry flag
  823.                 RET                     ; return  (B has other key still)
  824.  
  825. ;------------------
  826. ; Keyboard decoding
  827. ;------------------
  828. ; also called from S_INKEY
  829.  
  830.                                         ;;;$0333
  831. K_DECODE:       LD      A,E             ; pick up the stored main key
  832.                 CP      $3A             ; an arbitrary point between digits and letters
  833.                 JR      C,K_DIGIT       ; forward to K_DIGIT with digits,space,enter
  834.  
  835.                 DEC     C               ; decrease MODE ( 0='KLC', 1='E', 2='G')
  836.                 JP      M,K_KLC_LET     ; to K_KLC_LET if was zero
  837.  
  838.                 JR      Z,K_E_LET       ; to K_E_LET if was 1 for extended letters.
  839.  
  840.                                         ; proceed with graphic codes.
  841.                                         ; Note. should selectively drop return address if code > 'U' ($55).
  842.                                         ; i.e. abort the KEYBOARD call.
  843.                                         ; e.g. cp 'V'; jr c addit; pop af; ;;addit etc. (5 bytes of instruction).
  844.                                         ; (S_INKEY never gets into graphics mode.)
  845.  
  846.                                         ;; addit
  847.                 ADD     A,$4F           ; add offset to augment 'A' to graphics A say.
  848.                 RET                     ; return.
  849.                                         ; Note. ( but [GRAPH] V gives RND, etc ).
  850.  
  851.                                         ; the jump was to here with extended mode with uppercase A-Z.
  852.  
  853.                                         ;;;$0341
  854. K_E_LET:        LD      HL,E_UNSHIFT-$41; base address of E_UNSHIFT-$41
  855.                                         ; ( $01EB in standard ROM )
  856.                 INC     B               ; test B is it empty i.e. not a shift
  857.                 JR      Z,K_LOOK_UP     ; forward to K_LOOK_UP if neither shift
  858.  
  859.                 LD      HL,EXT_SHIFT-$41; Address: $0205 EXT_SHIFT-$41 base
  860.  
  861.                                         ;;;$034A
  862. K_LOOK_UP:      LD      D,$00           ; prepare to index
  863.                 ADD     HL,DE           ; add the main key value
  864.                 LD      A,(HL)          ; pick up other mode value
  865.                 RET                     ; return
  866.  
  867.                                         ; the jump was here with mode = 0
  868.  
  869.                                         ;;;$034F
  870. K_KLC_LET:      LD      HL,SYM_CODES-$41; prepare base of SYM_CODES
  871.                 BIT     0,B             ; shift=$27 sym-shift=$18
  872.                 JR      Z,K_LOOK_UP     ; back to K_LOOK_UP with symbol-shift
  873.  
  874.                 BIT     3,D             ; test FLAGS is it 'K' mode (from OUT_CURS)
  875.                 JR      Z,K_TOKENS      ; skip to K_TOKENS if so
  876.  
  877.                 BIT     3,(IY+$30)      ; test FLAGS2 - consider CAPS LOCK ?
  878.                 RET     NZ              ; return if so with main code.
  879.  
  880.                 INC     B               ; is shift being pressed ?
  881.                                         ; result zero if not
  882.                 RET     NZ              ; return if shift pressed.
  883.  
  884.                 ADD     A,$20           ; else convert the code to lower case.
  885.                 RET                     ; return.
  886.  
  887.                                         ; the jump was here for tokens
  888.  
  889.                                         ;;;$0364
  890. K_TOKENS:       ADD     A,$A5           ; add offset to main code so that 'A'
  891.                                         ; becomes 'NEW' etc.
  892.                 RET                     ; return
  893.  
  894.                                         ; the jump was here with digits, space, enter and symbol shift (< $xx)
  895.  
  896.                                         ;;;$0367
  897. K_DIGIT:        CP      $30             ; is it '0' or higher ?
  898.                 RET     C               ; return with space, enter and symbol-shift
  899.  
  900.                 DEC     C               ; test MODE (was 0='KLC', 1='E', 2='G')
  901.                 JP      M,K_KLC_DGT     ; jump to K_KLC_DGT if was 0.
  902.  
  903.                 JR      NZ,K_GRA_DGT    ; forward to K_GRA_DGT if mode was 2.
  904.  
  905.                                         ; continue with extended digits 0-9.
  906.  
  907.                 LD      HL,E_DIGITS-$30 ; $0254 - base of E_DIGITS
  908.                 BIT     5,B             ; test - shift=$27 sym-shift=$18
  909.                 JR      Z,K_LOOK_UP     ; to K_LOOK_UP if sym-shift
  910.  
  911.                 CP      $38             ; is character '8' ?
  912.                 JR      NC,K_8_AND_9    ; to K_8_AND_9 if greater than '7'
  913.  
  914.                 SUB     $20             ; reduce to ink range $10-$17
  915.                 INC     B               ; shift ?
  916.                 RET     Z               ; return if not.
  917.  
  918.                 ADD     A,$08           ; add 8 to give paper range $18 - $1F
  919.                 RET                     ; return
  920.  
  921.                                         ; 89
  922.  
  923.                                         ;;;$0382
  924. K_8_AND_9:      SUB     $36             ; reduce to 02 and 03  bright codes
  925.                 INC     B               ; test if shift pressed.
  926.                 RET     Z               ; return if not.
  927.  
  928.                 ADD     A,$FE           ; subtract 2 setting carry
  929.                 RET                     ; to give 0 and 1 flash codes.
  930.  
  931.                                         ; graphics mode with digits
  932.  
  933.                                         ;;;$0389
  934. K_GRA_DGT:      LD      HL,CTL_CODES-$30; $0230 base address of CTL_CODES
  935.  
  936.                 CP      $39             ; is key '9' ?
  937.                 JR      Z,K_LOOK_UP     ; back to K_LOOK_UP - changed to $0F, GRAPHICS.
  938.  
  939.                 CP      $30             ; is key '0' ?
  940.                 JR      Z,K_LOOK_UP     ; back to K_LOOK_UP - changed to $0C, delete.
  941.  
  942.                                         ; for keys '0' - '7' we assign a mosaic character depending on shift.
  943.  
  944.                 AND     $07             ; convert character to number. 0 - 7.
  945.                 ADD     A,$80           ; add offset - they start at $80
  946.                 INC     B               ; destructively test for shift
  947.                 RET     Z               ; and return if not pressed.
  948.  
  949.                 XOR     $0F             ; toggle bits becomes range $88-$8F
  950.                 RET                     ; return.
  951.  
  952.                                         ; now digits in 'KLC' mode
  953.  
  954.                                         ;;;$039D
  955. K_KLC_DGT:      INC     B               ; return with digit codes if neither
  956.                 RET     Z               ; shift key pressed.
  957.  
  958.                 BIT     5,B             ; test for caps shift.
  959.                 LD      HL,CTL_CODES-$30; prepare base of table CTL_CODES.
  960.                 JR      NZ,K_LOOK_UP    ; back to K_LOOK_UP if shift pressed.
  961.  
  962.                                         ; must have been symbol shift
  963.  
  964.                 SUB     $10             ; for ascii most will now be correct
  965.                                         ; on a standard typewriter.
  966.                 CP      $22             ; but '@' is not - see below.
  967.                 JR      Z,K_AT_CHAR     ; forward to to K_AT_CHAR if so
  968.  
  969.                 CP      $20             ; '_' is the other one that fails
  970.                 RET     NZ              ; return if not.
  971.  
  972.                 LD      A,$5F           ; substitute ascii '_'
  973.                 RET                     ; return.
  974.  
  975.                                         ;;;$03B2
  976. K_AT_CHAR:      LD      A,$40           ; substitute ascii '@'
  977.                 RET                     ; return.
  978.  
  979.  
  980. ;-------------------------------------------------------------------------
  981. ; The Spectrum Input character keys. One or two are abbreviated.
  982. ; From $00 Flash 0 to $FF COPY. The routine above has decoded all these.
  983.  
  984. ;  | 00 Fl0| 01 Fl1| 02 Br0| 03 Br1| 04 In0| 05 In1| 06 CAP| 07 EDT|
  985. ;  | 08 LFT| 09 RIG| 0A DWN| 0B UP | 0C DEL| 0D ENT| 0E SYM| 0F GRA|
  986. ;  | 10 Ik0| 11 Ik1| 12 Ik2| 13 Ik3| 14 Ik4| 15 Ik5| 16 Ik6| 17 Ik7|
  987. ;  | 18 Pa0| 19 Pa1| 1A Pa2| 1B Pa3| 1C Pa4| 1D Pa5| 1E Pa6| 1F Pa7|
  988. ;  | 20 SP | 21  ! | 22  " | 23  # | 24  $ | 25  % | 26  & | 27  ' |
  989. ;  | 28  ( | 29  ) | 2A  * | 2B  + | 2C  , | 2D  - | 2E  . | 2F  / |
  990. ;  | 30  0 | 31  1 | 32  2 | 33  3 | 34  4 | 35  5 | 36  6 | 37  7 |
  991. ;  | 38  8 | 39  9 | 3A  : | 3B  ; | 3C  < | 3D  = | 3E  > | 3F  ? |
  992. ;  | 40  @ | 41  A | 42  B | 43  C | 44  D | 45  E | 46  F | 47  G |
  993. ;  | 48  H | 49  I | 4A  J | 4B  K | 4C  L | 4D  M | 4E  N | 4F  O |
  994. ;  | 50  P | 51  Q | 52  R | 53  S | 54  T | 55  U | 56  V | 57  W |
  995. ;  | 58  X | 59  Y | 5A  Z | 5B  [ | 5C  \ | 5D  ] | 5E  ^ | 5F  _ |
  996. ;  | 60 ukp| 61  a | 62  b | 63  c | 64  d | 65  e | 66  f | 67  g |
  997. ;  | 68  h | 69  i | 6A  j | 6B  k | 6C  l | 6D  m | 6E  n | 6F  o |
  998. ;  | 70  p | 71  q | 72  r | 73  s | 74  t | 75  u | 76  v | 77  w |
  999. ;  | 78  x | 79  y | 7A  z | 7B  { | 7C  | | 7D  } | 7E  ~ | 7F (c)|
  1000. ;  | 80 128| 81 129| 82 130| 83 131| 84 132| 85 133| 86 134| 87 135|
  1001. ;  | 88 136| 89 137| 8A 138| 8B 139| 8C 140| 8D 141| 8E 142| 8F 143|
  1002. ;  | 90 [A]| 91 [B]| 92 [C]| 93 [D]| 94 [E]| 95 [F]| 96 [G]| 97 [H]|
  1003. ;  | 98 [I]| 99 [J]| 9A [K]| 9B [L]| 9C [M]| 9D [N]| 9E [O]| 9F [P]|
  1004. ;  | A0 [Q]| A1 [R]| A2 [S]| A3 [T]| A4 [U]| A5 RND| A6 IK$| A7 PI |
  1005. ;  | A8 FN | A9 PNT| AA SC$| AB ATT| AC AT | AD TAB| AE VL$| AF COD|
  1006. ;  | B0 VAL| B1 LEN| B2 SIN| B3 COS| B4 TAN| B5 ASN| B6 ACS| B7 ATN|
  1007. ;  | B8 LN | B9 EXP| BA INT| BB SQR| BC SGN| BD ABS| BE PEK| BF IN |
  1008. ;  | C0 USR| C1 ST$| C2 CH$| C3 NOT| C4 BIN| C5 OR | C6 AND| C7 <= |
  1009. ;  | C8 >= | C9 <> | CA LIN| CB THN| CC TO | CD STP| CE DEF| CF CAT|
  1010. ;  | D0 FMT| D1 MOV| D2 ERS| D3 OPN| D4 CLO| D5 MRG| D6 VFY| D7 BEP|
  1011. ;  | D8 CIR| D9 INK| DA PAP| DB FLA| DC BRI| DD INV| DE OVR| DF OUT|
  1012. ;  | E0 LPR| E1 LLI| E2 STP| E3 REA| E4 DAT| E5 RES| E6 NEW| E7 BDR|
  1013. ;  | E8 CON| E9 DIM| EA REM| EB FOR| EC GTO| ED GSB| EE INP| EF LOA|
  1014. ;  | F0 LIS| F1 LET| F2 PAU| F3 NXT| F4 POK| F5 PRI| F6 PLO| F7 RUN|
  1015. ;  | F8 SAV| F9 RAN| FA IF | FB CLS| FC DRW| FD CLR| FE RET| FF CPY|
  1016.  
  1017. ; Note that for simplicity, Sinclair have located all the control codes
  1018. ; below the space character.
  1019. ; ascii DEL, $7F, has been made a copyright symbol.
  1020. ; Also $60, '`', not used in Basic but used in other languages, has been
  1021. ; allocated the local currency symbol for the relevant country -
  1022. ; ukp in most Spectrums.
  1023.  
  1024. ;-------------------------------------------------------------------------
  1025.  
  1026. ;**********************************
  1027. ;** Part 3. LOUDSPEAKER ROUTINES **
  1028. ;**********************************
  1029.  
  1030.  
  1031. ; Documented by Alvin Albrecht.
  1032.  
  1033.  
  1034. ;-------------------------------
  1035. ; Routine to control loudspeaker
  1036. ;-------------------------------
  1037. ; Outputs a square wave of given duration and frequency
  1038. ; to the loudspeaker.
  1039. ;   Enter with: DE = #cycles - 1
  1040. ;               HL = tone period as described next
  1041. ;
  1042. ; The tone period is measured in T states and consists of
  1043. ; three parts: a coarse part (H register), a medium part
  1044. ; (bits 7..2 of L) and a fine part (bits 1..0 of L) which
  1045. ; contribute to the waveform timing as follows:
  1046. ;
  1047. ;                          coarse    medium       fine
  1048. ; duration of low  = 118 + 1024*H + 16*(L>>2) + 4*(L&0x3)
  1049. ; duration of hi   = 118 + 1024*H + 16*(L>>2) + 4*(L&0x3)
  1050. ; Tp = tone period = 236 + 2048*H + 32*(L>>2) + 8*(L&0x3)
  1051. ;                  = 236 + 2048*H + 8*L = 236 + 8*HL
  1052. ;
  1053. ; As an example, to output five seconds of middle C (261.624 Hz):
  1054. ;   (a) Tone period = 1/261.624 = 3.822ms
  1055. ;   (b) Tone period in T-States = 3.822ms*fCPU = 13378
  1056. ;         where fCPU = clock frequency of the CPU = 3.5MHz
  1057. ;   (c) Find H and L for desired tone period:
  1058. ;         HL = (Tp - 236) / 8 = (13378 - 236) / 8 = 1643 = 0x066B
  1059. ;   (d) Tone duration in cycles = 5s/3.822ms = 1308 cycles
  1060. ;         DE = 1308 - 1 = 0x051B
  1061. ;
  1062. ; The resulting waveform has a duty ratio of exactly 50%.
  1063.  
  1064.                                         ;;;$03B5
  1065. BEEPER:         DI                      ; Disable Interrupts so they don't disturb timing
  1066.                 LD      A,L
  1067.                 SRL     L
  1068.                 SRL     L               ; L = medium part of tone period
  1069.                 CPL
  1070.                 AND     $03             ; A = 3 - fine part of tone period
  1071.                 LD      C,A
  1072.                 LD      B,$00
  1073.                 LD      IX,BE_IX_3      ; Address: BE_IX_3
  1074.                 ADD     IX,BC           ; IX holds address of entry into the loop
  1075.                                         ; the loop will contain 0-3 NOPs, implementing
  1076.                                         ; the fine part of the tone period.
  1077.                 LD      A,(BORDCR)      ; BORDCR
  1078.                 AND     $38             ; bits 5..3 contain border colour
  1079.                 RRCA                    ; border colour bits moved to 2..0
  1080.                 RRCA                    ; to match border bits on port #FE
  1081.                 RRCA
  1082.                 OR      $08             ; bit 3 set (tape output bit on port #FE)
  1083.                                         ; for loud sound output
  1084.                                         ;;;$03D1
  1085. BE_IX_3:        NOP                     ;(4)    ; optionally executed NOPs for small
  1086.                                         ;         adjustments to tone period
  1087.                                         ;;;$03D2
  1088. BE_IX_2:        NOP                     ;(4)
  1089.                                         ;;;$03D3
  1090. BE_IX_1:        NOP                     ;(4)
  1091.                                         ;;;$03D4
  1092. BE_IX_0:        INC     B               ;(4)
  1093.                 INC     C               ;(4)
  1094.  
  1095.                                         ;;;$03D6
  1096. BE_HL_LP:       DEC     C               ;(4)    ; timing loop for duration of
  1097.                 JR      NZ,BE_HL_LP     ;(12/7) ; high or low pulse of waveform
  1098.  
  1099.                 LD      C,$3F           ;(7)
  1100.                 DEC     B               ;(4)
  1101.                 JP      NZ,BE_HL_LP     ;(10)   ; to BE_HL_LP
  1102.  
  1103.                 XOR     $10             ;(7)    ; toggle output beep bit
  1104.                 OUT     ($FE),A         ;(11)   ; output pulse
  1105.                 LD      B,H             ;(4)    ; B = coarse part of tone period
  1106.                 LD      C,A             ;(4)    ; save port #FE output byte
  1107.                 BIT     4,A             ;(8)    ; if new output bit is high, go
  1108.                 JR      NZ,BE_AGAIN     ;(12/7) ; to BE_AGAIN
  1109.  
  1110.                 LD      A,D             ;(4)    ; one cycle of waveform has completed
  1111.                 OR      E               ;(4)    ; (low->low). if cycle countdown = 0
  1112.                 JR      Z,BE_END        ;(12/7) ; go to BE_END
  1113.  
  1114.                 LD      A,C             ;(4)    ; restore output byte for port #FE
  1115.                 LD      C,L             ;(4)    ; C = medium part of tone period
  1116.                 DEC     DE              ;(6)    ; decrement cycle count
  1117.                 JP      (IX)            ;(8)    ; do another cycle
  1118.  
  1119.                                         ;;;$03F2; halfway through cycle
  1120. BE_AGAIN:       LD      C,L             ;(4)    ; C = medium part of tone period
  1121.                 INC     C               ;(4)    ; adds 16 cycles to make duration of high = duration of low
  1122.                 JP      (IX)            ;(8)    ; do high pulse of tone
  1123.  
  1124.                                         ;;;$03F6
  1125. BE_END:         EI                      ; Enable Interrupts
  1126.                 RET
  1127.  
  1128.  
  1129. ;--------------------
  1130. ; Handle BEEP command
  1131. ;--------------------
  1132. ; BASIC interface to BEEPER subroutine.
  1133. ; Invoked in BASIC with:
  1134. ;   BEEP dur,pitch
  1135. ;   where dur   = duration in seconds
  1136. ;         pitch = # of semitones above/below middle C
  1137. ;
  1138. ; Enter with: pitch on top of calculator stack
  1139. ;             duration next on calculator stack
  1140.  
  1141.                                         ;;;$03F8
  1142. BEEP:           RST     28H             ;; FP_CALC
  1143.                 DEFB    $31             ;;DUPLICATE                     ; duplicate pitch
  1144.                 DEFB    $27             ;;INT                           ; convert to integer
  1145.                 DEFB    $C0             ;;st-mem-0                      ; store integer pitch to memory 0
  1146.                 DEFB    $03             ;;SUBTRACT                      ; calculate fractional part of pitch = fp_pitch - int_pitch
  1147.                 DEFB    $34             ;;STK_DATA                      ; push constant
  1148.                 DEFB    $EC             ;;Exponent: $7C, Bytes: 4       ; constant = 0.05762265
  1149.                 DEFB    $6C,$98,$1F,$F5 ;;($6C,$98,$1F,$F5)
  1150.                 DEFB    $04             ;;MULTIPLY                      ; compute:
  1151.                 DEFB    $A1             ;;STK_ONE                       ; 1 + 0.05762265 * fraction_part(pitch)
  1152.                 DEFB    $0F             ;;ADDITION
  1153.                 DEFB    $38             ;;END_CALC                      ; leave on calc stack
  1154.  
  1155.                 LD      HL,MEM_0        ; MEM_0: number stored here is in 16 bit integer format (pitch)
  1156.                                         ;  0, 0/FF (pos/neg), LSB, MSB, 0
  1157.                                         ;  LSB/MSB is stored in two's complement
  1158.                                         ; In the following, the pitch is checked if it is in the range -128<=p<=127
  1159.                 LD      A,(HL)          ; First byte must be zero, otherwise
  1160.                 AND     A               ; error in integer conversion
  1161.                 JR      NZ,REPORT_B     ; to REPORT_B
  1162.  
  1163.                 INC     HL
  1164.                 LD      C,(HL)          ; C = pos/neg flag = 0/FF
  1165.                 INC     HL
  1166.                 LD      B,(HL)          ; B = LSB, two's complement
  1167.                 LD      A,B
  1168.                 RLA
  1169.                 SBC     A,A             ; A = 0/FF if B is pos/neg
  1170.                 CP      C               ; must be the same as C if the pitch is -128<=p<=127
  1171.                 JR      NZ,REPORT_B     ; if no, error REPORT_B
  1172.  
  1173.                 INC     HL              ; if -128<=p<=127, MSB will be 0/FF if B is pos/neg
  1174.                 CP      (HL)            ; verify this
  1175.                 JR      NZ,REPORT_B     ; if no, error REPORT_B
  1176.                                         ; now we know -128<=p<=127
  1177.                 LD      A,B             ; A = pitch + 60
  1178.                 ADD     A,$3C           ; if -60<=pitch<=67,
  1179.                 JP      P,BE_I_OK       ; goto BE_I_OK
  1180.  
  1181.                 JP      PO,REPORT_B     ; if pitch <= 67 goto REPORT_B
  1182.                                         ; lower bound of pitch set at -60
  1183.  
  1184.                                         ;;;$0425; here, -60<=pitch<=127
  1185.                                         ;               and A=pitch+60 -> 0<=A<=187
  1186.  
  1187. BE_I_OK:        LD      B,$FA           ; 6 octaves below middle C
  1188.  
  1189.                                         ;;;$0427                                ; A=# semitones above 5 octaves below middle C
  1190. BE_OCTAVE:      INC     B               ; increment octave
  1191.                 SUB     $0C             ; 12 semitones = one octave
  1192.                 JR      NC,BE_OCTAVE    ; to BE_OCTAVE
  1193.  
  1194.                 ADD     A,$0C           ; A = # semitones above C (0-11)
  1195.                 PUSH    BC              ; B = octave displacement from middle C, 2's complement: -5<=B<=10
  1196.                 LD      HL,SEMI_TONE    ; Address: SEMI_TONE
  1197.                 CALL    LOC_MEM         ; routine LOC_MEM
  1198.                                         ;  HL = 5*A + $046E
  1199.                 CALL    STACK_NUM       ; routine STACK_NUM
  1200.                                         ;  read FP value (freq) from semitone table (HL) and push onto calc stack
  1201.  
  1202.                 RST     28H             ;; FP_CALC
  1203.                 DEFB    $04             ;;MULTIPLY      mult freq by 1 + 0.0576 * fraction_part(pitch) stacked earlier
  1204.                                         ;;              thus taking into account fractional part of pitch.
  1205.                                         ;;              the number 0.0576*frequency is the distance in Hz to the next
  1206.                                         ;;              note (verify with the frequencies recorded in the semitone
  1207.                                         ;;              table below) so that the fraction_part of the pitch does
  1208.                                         ;;              indeed represent a fractional distance to the next note.
  1209.                 DEFB    $38             ;;END_CALC      HL points to first byte of fp num on stack = middle frequency to generate
  1210.  
  1211.                 POP     AF              ; A = octave displacement from middle C, 2's complement: -5<=A<=10
  1212.                 ADD     A,(HL)          ; increase exponent by A (equivalent to multiplying by 2^A)
  1213.                 LD      (HL),A
  1214.                 RST     28H             ;; FP_CALC
  1215.                 DEFB    $C0             ;;st-mem-0              ; store frequency in memory 0
  1216.                 DEFB    $02             ;;DELETE                ; remove from calc stack
  1217.                 DEFB    $31             ;;DUPLICATE             ; duplicate duration (seconds)
  1218.                 DEFB    $38             ;;END_CALC
  1219.  
  1220.                 CALL    FIND_INT1       ; routine FIND_INT1     ; FP duration to A
  1221.                 CP      $0B             ; if dur > 10 seconds,
  1222.                 JR      NC,REPORT_B     ; goto REPORT_B
  1223.  
  1224.                 ;;; The following calculation finds the tone period for HL and the cycle count
  1225.                 ;;; for DE expected in the BEEPER subroutine.  From the example in the BEEPER comments,
  1226.                 ;;;
  1227.                 ;;; HL = ((fCPU / f) - 236) / 8 = fCPU/8/f - 236/8 = 437500/f -29.5
  1228.                 ;;; DE = duration * frequency - 1
  1229.                 ;;;
  1230.                 ;;; Note the different constant (30.125) used in the calculation of HL
  1231.                 ;;; below.  This is probably an error.
  1232.  
  1233.                 RST     28H             ;; FP_CALC
  1234.                 DEFB    $E0             ;;get-mem-0                     ; push frequency
  1235.                 DEFB    $04             ;;MULTIPLY                      ; result1: #cycles = duration * frequency
  1236.                 DEFB    $E0             ;;get-mem-0                     ; push frequency
  1237.                 DEFB    $34             ;;STK_DATA                      ; push constant
  1238.                 DEFB    $80             ;;Exponent $93, Bytes: 3        ; constant = 437500
  1239.                 DEFB    $43,$55,$9F,$80 ;;($55,$9F,$80,$00)
  1240.                 DEFB    $01             ;;EXCHANGE                      ; frequency on top
  1241.                 DEFB    $05             ;;DIVISION                      ; 437500 / frequency
  1242.                 DEFB    $34             ;;STK_DATA                      ; push constant
  1243.                 DEFB    $35             ;;Exponent: $85, Bytes: 1       ; constant = 30.125
  1244.                 DEFB    $71             ;;($71,$00,$00,$00)
  1245.                 DEFB    $03             ;;SUBTRACT                      ; result2: tone_period(HL) = 437500 / freq - 30.125
  1246.                 DEFB    $38             ;;END_CALC
  1247.  
  1248.                 CALL    FIND_INT2       ; routine FIND_INT2
  1249.                 PUSH    BC              ; BC = tone_period(HL)
  1250.                 CALL    FIND_INT2       ; routine FIND_INT2, BC = #cycles to generate
  1251.                 POP     HL              ; HL = tone period
  1252.                 LD      D,B
  1253.                 LD      E,C             ; DE = #cycles
  1254.                 LD      A,D
  1255.                 OR      E
  1256.                 RET     Z               ; if duration = 0, skip BEEP and avoid 65536 cycle
  1257.                                         ; boondoggle that would occur next
  1258.                 DEC     DE              ; DE = #cycles - 1
  1259.                 JP      BEEPER          ; to BEEPER
  1260.  
  1261.                                         ;;;$046C
  1262. REPORT_B:       RST     08H             ; ERROR_1
  1263.                 DEFB    $0A             ; Error Report: Integer out of range
  1264.  
  1265.  
  1266.  
  1267. ;----------------
  1268. ; Semi-tone table
  1269. ;----------------
  1270. ;
  1271. ; Holds frequencies corresponding to semitones in middle octave.
  1272. ; To move n octaves higher or lower, frequencies are multiplied by 2^n.
  1273.  
  1274. ;;;$046E                five byte fp              decimal freq          note (middle)
  1275. SEMI_TONE:      DEFB    $89, $02, $D0, $12, $86;  261.625565290         C
  1276.                 DEFB    $89, $0A, $97, $60, $75;  277.182631135         C#
  1277.                 DEFB    $89, $12, $D5, $17, $1F;  293.664768100         D
  1278.                 DEFB    $89, $1B, $90, $41, $02;  311.126983881         D#
  1279.                 DEFB    $89, $24, $D0, $53, $CA;  329.627557039         E
  1280.                 DEFB    $89, $2E, $9D, $36, $B1;  349.228231549         F
  1281.                 DEFB    $89, $38, $FF, $49, $3E;  369.994422674         F#
  1282.                 DEFB    $89, $43, $FF, $6A, $73;  391.995436072         G
  1283.                 DEFB    $89, $4F, $A7, $00, $54;  415.304697513         G#
  1284.                 DEFB    $89, $5C, $00, $00, $00;  440.000000000         A
  1285.                 DEFB    $89, $69, $14, $F6, $24;  466.163761616         A#
  1286.                 DEFB    $89, $76, $F1, $10, $05;  493.883301378         B
  1287.  
  1288.  
  1289. ;****************************************
  1290. ;** Part 4. CASSETTE HANDLING ROUTINES **
  1291. ;****************************************
  1292.  
  1293. ; These routines begin with the service routines followed by a single
  1294. ; command entry point.
  1295. ; The first of these service routines is a curiosity.
  1296.  
  1297. ;------------------
  1298. ; ZX81_NAME routine
  1299. ;------------------
  1300. ; This routine fetches a filename in ZX81 format.
  1301. ; and is not used by the cassette handling routines in this ROM.
  1302.  
  1303.                                         ;;;$04AA
  1304. ZX81_NAME:      CALL    SCANNING        ; routine SCANNING to evaluate expression.
  1305.                 LD      A,(FLAGS)       ; fetch system variable FLAGS.
  1306.                 ADD     A,A             ; test bit 7 - syntax, bit 6 - result type.
  1307.                 JP      M,REPORT_C      ; to REPORT_C if not string result
  1308.                                         ; 'Nonsense in Basic'.
  1309.                 POP     HL              ; drop return address.
  1310.                 RET     NC              ; return early if checking syntax.
  1311.  
  1312.                 PUSH    HL              ; re-save return address.
  1313.                 CALL    STK_FETCH       ; routine STK_FETCH fetches string parameters.
  1314.                 LD      H,D             ; transfer start of filename
  1315.                 LD      L,E             ; to the HL register.
  1316.                 DEC     C               ; adjust to point to last character and
  1317.                 RET     M               ; return if the null string.
  1318.                                         ; or multiple of 256!
  1319.                 ADD     HL,BC           ; find last character of the filename.
  1320.                                         ; and also clear carry.
  1321.                 SET     7,(HL)          ; invert it.
  1322.                 RET                     ; return.
  1323.  
  1324. ; =========================================
  1325. ;
  1326. ; PORT 254 ($FE)
  1327. ;
  1328. ;                      spk mic { border  }  
  1329. ;          ___ ___ ___ ___ ___ ___ ___ ___
  1330. ; PORT    |   |   |   |   |   |   |   |   |
  1331. ; 254     |   |   |   |   |   |   |   |   |
  1332. ; $FE     |___|___|___|___|___|___|___|___|
  1333. ;           7   6   5   4   3   2   1   0
  1334. ;
  1335.  
  1336. ;-----------------------------------
  1337. ; Save header and program/data bytes
  1338. ;-----------------------------------
  1339. ; This routine saves a section of data. It is called from SA-CTRL to save the
  1340. ; seventeen bytes of header data. It is also the exit route from that routine
  1341. ; when it is set up to save the actual data.
  1342. ; On entry -
  1343. ; HL points to start of data.
  1344. ; IX points to descriptor.
  1345. ; The accumulator is set to  $00 for a header, $FF for data.
  1346.  
  1347.                                         ;;;$04C2
  1348. SA_BYTES:       LD      HL,SA_LD_RET    ; address: SA_LD_RET
  1349.                 PUSH    HL              ; is pushed as common exit route.
  1350.                                         ; however there is only one non-terminal exit point.
  1351.                 LD      HL,$1F80        ; a timing constant H=$1F, L=$80
  1352.                                         ; inner and outer loop counters
  1353.                                         ; a five second lead-in is used for a header.
  1354.                 BIT     7,A             ; test one bit of accumulator.
  1355.                                         ; (AND A ?)
  1356.                 JR      Z,SA_FLAG       ; skip to SA_FLAG if a header is being saved.
  1357.  
  1358.                                         ; else is data bytes and a shorter lead-in is used.
  1359.  
  1360.                 LD      HL,$0C98        ; another timing value H=$0C, L=$98.
  1361.                                         ; a two second lead-in is used for the data.
  1362.  
  1363.                                         ;;;$04D0
  1364. SA_FLAG:        EX      AF,AF'          ; save flag
  1365.                 INC     DE              ; increase length by one.
  1366.                 DEC     IX              ; decrease start.
  1367.                 DI                      ; disable interrupts
  1368.                 LD      A,$02           ; select red for border, microphone bit on.
  1369.                 LD      B,A             ; also does as an initial slight counter value.
  1370.  
  1371.                                         ;;;$04D8
  1372. SA_LEADER:      DJNZ    SA_LEADER       ; self loop to SA_LEADER for delay.
  1373.                                         ; after initial loop, count is $A4 (or $A3)
  1374.                 OUT     ($FE),A         ; output byte $02/$0D to tape port.
  1375.                 XOR     $0F             ; switch from RED (mic on) to CYAN (mic off).
  1376.                 LD      B,$A4           ; hold count. also timed instruction.
  1377.                 DEC     L               ; originally $80 or $98.
  1378.                                         ; but subsequently cycles 256 times.
  1379.                 JR      NZ,SA_LEADER    ; back to SA_LEADER until L is zero.
  1380.  
  1381.                                         ; the outer loop is counted by H
  1382.  
  1383.                 DEC     B               ; decrement count
  1384.                 DEC     H               ; originally  twelve or thirty-one.
  1385.                 JP      P,SA_LEADER     ; back to SA_LEADER until H becomes $FF
  1386.  
  1387.                                         ; now send a synch pulse. At this stage mic is off and A holds value
  1388.                                         ; for mic on.
  1389.                                         ; A synch pulse is much shorter than the steady pulses of the lead-in.
  1390.  
  1391.                 LD      B,$2F           ; another short timed delay.
  1392.  
  1393.                                         ;;;$04EA
  1394. SA_SYNC_1:      DJNZ    SA_SYNC_1       ; self loop to SA_SYNC_1
  1395.                 OUT     ($FE),A         ; switch to mic on and red.
  1396.                 LD      A,$0D           ; prepare mic off - cyan
  1397.                 LD      B,$37           ; another short timed delay.
  1398.  
  1399.                                         ;;;$04F2
  1400. SA_SYNC_2:      DJNZ    SA_SYNC_2       ; self loop to SA_SYNC_2
  1401.                 OUT     ($FE),A         ; output mic off, cyan border.
  1402.                 LD      BC,$3B0E        ; B=$3B time(*), C=$0E, YELLOW, MIC OFF.
  1403.                 EX      AF,AF'          ; restore saved flag
  1404.                                         ; which is 1st byte to be saved.
  1405.                 LD      L,A             ; and transfer to L.
  1406.                                         ; the initial parity is A, $FF or $00.
  1407.                 JP      SA_START        ; jump forward to SA_START     ->
  1408.                                         ; the mid entry point of loop.
  1409.  
  1410.                                         ; -------------------------
  1411.                                         ; During the save loop a parity byte is maintained in H.
  1412.                                         ; the save loop begins by testing if reduced length is zero and if so
  1413.                                         ; the final parity byte is saved reducing count to $FFFF.
  1414.  
  1415.                                         ;;;$04FE
  1416. SA_LOOP:        LD      A,D             ; fetch high byte
  1417.                 OR      E               ; test against low byte.
  1418.                 JR      Z,SA_PARITY     ; forward to SA_PARITY if zero.
  1419.  
  1420.                 LD      L,(IX+$00)      ; load currently addressed byte to L.
  1421.  
  1422.                                         ;;;$0505
  1423. SA_LOOP_P:      LD      A,H             ; fetch parity byte.
  1424.                 XOR     L               ; exclusive or with new byte.
  1425.  
  1426.                                         ; -> the mid entry point of loop.
  1427.  
  1428.                                         ;;;$0507
  1429. SA_START:       LD      H,A             ; put parity byte in H.
  1430.                 LD      A,$01           ; prepare blue, mic=on.
  1431.                 SCF                     ; set carry flag ready to rotate in.
  1432.                 JP      SA_8_BITS       ; jump forward to SA_8_BITS    -8->
  1433.  
  1434.                                         ;;;$050E
  1435. SA_PARITY:      LD      L,H             ; transfer the running parity byte to L and
  1436.                 JR      SA_LOOP_P       ; back to SA_LOOP_P
  1437.                                         ; to output that byte before quitting normally.
  1438.  
  1439.                                         ;--------------------------
  1440.                                         ; entry point to save yellow part of bit.
  1441.                                         ; a bit consists of a period with mic on and blue border followed by
  1442.                                         ; a period of mic off with yellow border.
  1443.                                         ; Note. since the DJNZ instruction does not affect flags, the zero flag is used
  1444.                                         ; to indicate which of the two passes is in effect and the carry maintains the
  1445.                                         ; state of the bit to be saved.
  1446.  
  1447.                                         ;;;$0511
  1448. SA_BIT_2:       LD      A,C             ; fetch 'mic on and yellow' which is  held permanently in C.
  1449.                 BIT     7,B             ; set the zero flag. B holds $3E.
  1450.  
  1451.                                         ; entry point to save 1 entire bit. For first bit B holds $3B(*).
  1452.                                         ; Carry is set if saved bit is 1. zero is reset NZ on entry.
  1453.  
  1454.                                         ;;;$0514
  1455. SA_BIT_1:       DJNZ    SA_BIT_1        ; self loop for delay to SA_BIT_1
  1456.                 JR      NC,SA_OUT       ; forward to SA_OUT if bit is 0.
  1457.  
  1458.                                         ; but if bit is 1 then the mic state is held for longer.
  1459.  
  1460.                 LD      B,$42           ; set timed delay. (66 decimal)
  1461.  
  1462.                                         ;;;$051A
  1463. SA_SET:         DJNZ    SA_SET          ; self loop to SA_SET
  1464.                                         ; (roughly an extra 66*13 clock cycles)
  1465.  
  1466.                                         ;;;$051C
  1467. SA_OUT:         OUT     ($FE),A         ; blue and mic on OR  yellow and mic off.
  1468.                 LD      B,$3E           ; set up delay
  1469.                 JR      NZ,SA_BIT_2     ; back to SA_BIT_2 if zero reset NZ (first pass)
  1470.  
  1471.                                         ; proceed when the blue and yellow bands have been output.
  1472.  
  1473.                 DEC     B               ; change value $3E to $3D.
  1474.                 XOR     A               ; clear carry flag (ready to rotate in).
  1475.                 INC     A               ; reset zero flag ie. NZ.
  1476.  
  1477.                                         ; -8->
  1478.  
  1479.                                         ;;;$0525
  1480. SA_8_BITS:      RL      L               ; rotate left through carry
  1481.                                         ; C<76543210<C  
  1482.                 JP      NZ,SA_BIT_1     ; jump back to SA_BIT_1
  1483.                                         ; until all 8 bits done.
  1484.  
  1485.                                         ; when the initial set carry is passed out again then a byte is complete.
  1486.  
  1487.                 DEC     DE              ; decrease length
  1488.                 INC     IX              ; increase byte pointer
  1489.                 LD      B,$31           ; set up timing.
  1490.                 LD      A,$7F           ; test the space key and
  1491.                 IN      A,($FE)         ; return to common exit (to restore border)
  1492.                 RRA                     ; if a space is pressed
  1493.                 RET     NC              ; return to SA_LD_RET - - >
  1494.  
  1495.                                         ; now test if byte counter has reached $FFFF.
  1496.  
  1497.                 LD      A,D             ; fetch high byte
  1498.                 INC     A               ; increment.
  1499.                 JP      NZ,SA_LOOP      ; jump to SA_LOOP if more bytes.
  1500.  
  1501.                 LD      B,$3B           ; a final delay.
  1502.  
  1503.                                         ;;;$053C
  1504. SA_DELAY:       DJNZ    SA_DELAY        ; self loop to SA_DELAY
  1505.                 RET                     ; return - - >
  1506.  
  1507. ;---------------------------------------------------
  1508. ; Reset border and check BREAK key for LOAD and SAVE
  1509. ;---------------------------------------------------
  1510. ; the address of this routine is pushed on the stack prior to any load/save
  1511. ; operation and it handles normal completion with the restoration of the
  1512. ; border and also abnormal termination when the break key, or to be more
  1513. ; precise the space key is pressed during a tape operation.
  1514. ; - - >
  1515.  
  1516.                                         ;;;$053F
  1517. SA_LD_RET:      PUSH    AF              ; preserve accumulator throughout.
  1518.                 LD      A,(BORDCR)      ; fetch border colour from BORDCR.
  1519.                 AND     $38             ; mask off paper bits.
  1520.                 RRCA                    ; rotate
  1521.                 RRCA                    ; to the
  1522.                 RRCA                    ; range 0-7.
  1523.                 OUT     ($FE),A         ; change the border colour.
  1524.                 LD      A,$7F           ; read from port address $7FFE the
  1525.                 IN      A,($FE)         ; row with the space key at outside.
  1526.                 RRA                     ; test for space key pressed.
  1527.                 EI                      ; enable interrupts
  1528.                 JR      C,SA_LD_END     ; forward to SA_LD_END if not
  1529.  
  1530.                                         ;;;$0552
  1531. REPORT_DA:      RST     08H             ; ERROR_1
  1532.                 DEFB    $0C             ; Error Report: BREAK - CONT repeats
  1533.  
  1534.                                         ;;;$0554
  1535. SA_LD_END:      POP     AF              ; restore the accumulator.
  1536.                 RET                     ; return.
  1537.  
  1538. ;-------------------------------------
  1539. ; Load header or block of information
  1540. ;-------------------------------------
  1541. ; This routine is used to load bytes and on entry A is set to $00 for a
  1542. ; header or to $FF for data.  IX points to the start of receiving location
  1543. ; and DE holds the length of bytes to be loaded. If, on entry the carry flag
  1544. ; is set then data is loaded, if reset then it is verified.
  1545.  
  1546.                                         ;;;$0556
  1547. LD_BYTES:       INC     D               ; reset the zero flag without disturbing carry.
  1548.                 EX      AF,AF'          ; preserve entry flags.
  1549.                 DEC     D               ; restore high byte of length.
  1550.                 DI                      ; disable interrupts
  1551.                 LD      A,$0F           ; make the border white and mic off.
  1552.                 OUT     ($FE),A         ; output to port.
  1553.                 LD      HL,SA_LD_RET    ; Address: SA_LD_RET
  1554.                 PUSH    HL              ; is saved on stack as terminating routine.
  1555.  
  1556.                                         ; the reading of the EAR bit (D6) will always be preceded by a test of the
  1557.                                         ; space key (D0), so store the initial post-test state.
  1558.  
  1559.                 IN      A,($FE)         ; read the ear state - bit 6.
  1560.                 RRA                     ; rotate to bit 5.
  1561.                 AND     $20             ; isolate this bit.
  1562.                 OR      $02             ; combine with red border colour.
  1563.                 LD      C,A             ; and store initial state long-term in C.
  1564.                 CP      A               ; set the zero flag.
  1565.  
  1566.                                         ;;;$056B
  1567. LD_BREAK:       RET     NZ              ; return if at any time space is pressed.
  1568.  
  1569.                                         ;;;$056C
  1570. LD_START:       CALL    LD_EDGE_1       ; routine LD_EDGE_1
  1571.                 JR      NC,LD_BREAK     ; back to LD_BREAK with time out and no
  1572.                                         ; edge present on tape.
  1573.  
  1574.                                         ; but continue when a transition is found on tape.
  1575.  
  1576.                 LD      HL,$0415        ; set up 16-bit outer loop counter for
  1577.                                         ; approx 1 second delay.
  1578.  
  1579.                                         ;;;$0574
  1580. LD_WAIT:        DJNZ    LD_WAIT         ; self loop to LD_WAIT (for 256 times)
  1581.                 DEC     HL              ; decrease outer loop counter.
  1582.                 LD      A,H             ; test for
  1583.                 OR      L               ; zero.
  1584.                 JR      NZ,LD_WAIT      ; back to LD_WAIT, if not zero, with zero in B.
  1585.  
  1586.                                         ; continue after delay with H holding zero and B also.
  1587.                                         ; sample 256 edges to check that we are in the middle of a lead-in section.
  1588.  
  1589.                 CALL    LD_EDGE_2       ; routine LD_EDGE_2
  1590.                 JR      NC,LD_BREAK     ; back to LD_BREAK
  1591.                                         ; if no edges at all.
  1592.  
  1593.                                         ;;;$0580
  1594. LD_LEADER:      LD      B,$9C           ; set timing value.
  1595.                 CALL    LD_EDGE_2       ; routine LD_EDGE_2
  1596.                 JR      NC,LD_BREAK     ; back to LD_BREAK if time-out
  1597.  
  1598.                 LD      A,$C6           ; two edges must be spaced apart.
  1599.                 CP      B               ; compare
  1600.                 JR      NC,LD_START     ; back to LD_START if too close together for a
  1601.                                         ; lead-in.
  1602.                 INC     H               ; proceed to test 256 edged sample.
  1603.                 JR      NZ,LD_LEADER    ; back to LD_LEADER while more to do.
  1604.  
  1605.                                         ; sample indicates we are in the middle of a two or five second lead-in.
  1606.                                         ; Now test every edge looking for the terminal synch signal.
  1607.  
  1608.                                         ;;;$058F
  1609. LD_SYNC:        LD      B,$C9           ; initial timing value in B.
  1610.                 CALL    LD_EDGE_1       ; routine LD_EDGE_1
  1611.                 JR      NC,LD_BREAK     ; back to LD_BREAK with time-out.
  1612.  
  1613.                 LD      A,B             ; fetch augmented timing value from B.
  1614.                 CP      $D4             ; compare
  1615.                 JR      NC,LD_SYNC      ; back to LD_SYNC if gap too big, that is,
  1616.                                         ; a normal lead-in edge gap.
  1617.  
  1618.                                         ; but a short gap will be the synch pulse.
  1619.                                         ; in which case another edge should appear before B rises to $FF
  1620.  
  1621.                 CALL    LD_EDGE_1       ; routine LD_EDGE_1
  1622.                 RET     NC              ; return with time-out.
  1623.  
  1624.                                         ; proceed when the synch at the end of the lead-in is found.
  1625.                                         ; We are about to load data so change the border colours.
  1626.  
  1627.                 LD      A,C             ; fetch long-term mask from C
  1628.                 XOR     $03             ; and make blue/yellow.
  1629.                 LD      C,A             ; store the new long-term byte.
  1630.                 LD      H,$00           ; set up parity byte as zero.
  1631.                 LD      B,$B0           ; timing.
  1632.                 JR      LD_MARKER       ; forward to LD_MARKER
  1633.                                         ; the loop mid entry point with the alternate
  1634.                                         ; zero flag reset to indicate first byte
  1635.                                         ; is discarded.
  1636.  
  1637.                                         ; the loading loop loads each byte and is entered at the mid point.
  1638.  
  1639.                                         ;;;$05A9
  1640. LD_LOOP:        EX      AF,AF'          ; restore entry flags and type in A.
  1641.                 JR      NZ,LD_FLAG      ; forward to LD_FLAG if awaiting initial flag
  1642.                                         ; which is to be discarded.
  1643.                 JR      NC,LD_VERIFY    ; forward to LD_VERIFY if not to be loaded.
  1644.  
  1645.                 LD      (IX+$00),L      ; place loaded byte at memory location.
  1646.                 JR      LD_NEXT         ; forward to LD_NEXT
  1647.  
  1648.                                         ;;;$05B3
  1649. LD_FLAG:        RL      C               ; preserve carry (verify) flag in long-term
  1650.                                         ; state byte. Bit 7 can be lost.
  1651.                 XOR     L               ; compare type in A with first byte in L.
  1652.                 RET     NZ              ; return if no match e.g. CODE vs DATA.
  1653.  
  1654.                                         ; continue when data type matches.
  1655.  
  1656.                 LD      A,C             ; fetch byte with stored carry
  1657.                 RRA                     ; rotate it to carry flag again
  1658.                 LD      C,A             ; restore long-term port state.
  1659.                 INC     DE              ; increment length ??
  1660.                 JR      LD_DEC          ; forward to LD_DEC.
  1661.                                         ; but why not to location after ?
  1662.  
  1663.                                         ; for verification the byte read from tape is compared with that in memory.
  1664.  
  1665.                                         ;;;$05BD
  1666. LD_VERIFY:      LD      A,(IX+$00)      ; fetch byte from memory.
  1667.                 XOR     L               ; compare with that on tape
  1668.                 RET     NZ              ; return if not zero.
  1669.  
  1670.                                         ;;;$05C2
  1671. LD_NEXT:        INC     IX              ; increment byte pointer.
  1672.  
  1673.                                         ;;;$05C4
  1674. LD_DEC:         DEC     DE              ; decrement length.
  1675.                 EX      AF,AF'          ; store the flags.
  1676.                 LD      B,$B2           ; timing.
  1677.  
  1678.                                         ; when starting to read 8 bits the receiving byte is marked with bit at right.
  1679.                                         ; when this is rotated out again then 8 bits have been read.
  1680.  
  1681.                                         ;;;$05C8
  1682. LD_MARKER:      LD      L,$01           ; initialize as %00000001
  1683.  
  1684.                                         ;;;$05CA
  1685. LD_8_BITS:      CALL    LD_EDGE_2       ; routine LD_EDGE_2 increments B relative to
  1686.                                         ; gap between 2 edges.
  1687.                 RET     NC              ; return with time-out.
  1688.  
  1689.                 LD      A,$CB           ; the comparison byte.
  1690.                 CP      B               ; compare to incremented value of B.
  1691.                                         ; if B is higher then bit on tape was set.
  1692.                                         ; if <= then bit on tape is reset.
  1693.  
  1694.                 RL      L               ; rotate the carry bit into L.
  1695.                 LD      B,$B0           ; reset the B timer byte.
  1696.                 JP      NC,LD_8_BITS    ; jump back to LD_8_BITS
  1697.  
  1698.                                         ; when carry set then marker bit has been passed out and byte is complete.
  1699.  
  1700.                 LD      A,H             ; fetch the running parity byte.
  1701.                 XOR     L               ; include the new byte.
  1702.                 LD      H,A             ; and store back in parity register.
  1703.                 LD      A,D             ; check length of
  1704.                 OR      E               ; expected bytes.
  1705.                 JR      NZ,LD_LOOP      ; back to LD_LOOP
  1706.                                         ; while there are more.
  1707.  
  1708.                                         ; when all bytes loaded then parity byte should be zero.
  1709.  
  1710.                 LD      A,H             ; fetch parity byte.
  1711.                 CP      $01             ; set carry if zero.
  1712.                 RET                     ; return
  1713.                                         ; in no carry then error as checksum disagrees.
  1714.  
  1715. ;--------------------------
  1716. ; Check signal being loaded
  1717. ;--------------------------
  1718. ; An edge is a transition from one mic state to another.
  1719. ; More specifically a change in bit 6 of value input from port $FE.
  1720. ; Graphically it is a change of border colour, say, blue to yellow.
  1721. ; The first entry point looks for two adjacent edges. The second entry point
  1722. ; is used to find a single edge.
  1723. ; The B register holds a count, up to 256, within which the edge (or edges)
  1724. ; must be found. The gap between two edges will be more for a '1' than a '0'
  1725. ; so the value of B denotes the state of the bit (two edges) read from tape.
  1726.  
  1727.                                         ; ->
  1728.  
  1729.                                         ;;;$05E3
  1730. LD_EDGE_2:      CALL    LD_EDGE_1       ; call routine LD_EDGE_1 below.
  1731.                 RET     NC              ; return if space pressed or time-out.
  1732.                                         ; else continue and look for another adjacent
  1733.                                         ; edge which together represent a bit on the
  1734.                                         ; tape.
  1735.  
  1736.                                         ; ->
  1737.                                         ; this entry point is used to find a single edge from above but also
  1738.                                         ; when detecting a read-in signal on the tape.
  1739.  
  1740.                                         ;;;$05E7
  1741. LD_EDGE_1:      LD      A,$16           ; a delay value of twenty two.
  1742.  
  1743.                                         ;;;$05E9
  1744. LD_DELAY:       DEC     A               ; decrement counter
  1745.                 JR      NZ,LD_DELAY     ; loop back to LD_DELAY 22 times.
  1746.  
  1747.                 AND     A               ; clear carry.
  1748.  
  1749.                                         ;;;$05ED
  1750. LD_SAMPLE:      INC     B               ; increment the time-out counter.
  1751.                 RET     Z               ; return with failure when $FF passed.
  1752.  
  1753.                 LD      A,$7F           ; prepare to read keyboard and EAR port
  1754.                 IN      A,($FE)         ; row $7FFE. bit 6 is EAR, bit 0 is SPACE key.
  1755.                 RRA                     ; test outer key the space. (bit 6 moves to 5)
  1756.                 RET     NC              ; return if space pressed.  >>>
  1757.  
  1758.                 XOR     C               ; compare with initial long-term state.
  1759.                 AND     $20             ; isolate bit 5
  1760.                 JR      Z,LD_SAMPLE     ; back to LD_SAMPLE if no edge.
  1761.  
  1762.                                         ; but an edge, a transition of the EAR bit, has been found so switch the
  1763.                                         ; long-term comparison byte containing both border colour and EAR bit.
  1764.  
  1765.                 LD      A,C             ; fetch comparison value.
  1766.                 CPL                     ; switch the bits
  1767.                 LD      C,A             ; and put back in C for long-term.
  1768.                 AND     $07             ; isolate new colour bits.
  1769.                 OR      $08             ; set bit 3 - MIC off.
  1770.                 OUT     ($FE),A         ; send to port to effect change of colour.
  1771.                 SCF                     ; set carry flag signalling edge found within
  1772.                                         ; time allowed.
  1773.                 RET                     ; return.
  1774.  
  1775. ;----------------------------------
  1776. ; Entry point for all tape commands
  1777. ;----------------------------------
  1778. ; This is the single entry point for the four tape commands.
  1779. ; The routine first determines in what context it has been called by examining
  1780. ; the low byte of the Syntax table entry which was stored in T_ADDR.
  1781. ; Subtracting $EO (the present arrangement) gives a value of
  1782. ; $00 - SAVE
  1783. ; $01 - LOAD
  1784. ; $02 - VERIFY
  1785. ; $03 - MERGE
  1786. ; As with all commands the address STMT_RET is on the stack.
  1787.  
  1788.                                         ;;;$0605
  1789. SAVE_ETC:       POP     AF              ; discard address STMT_RET.
  1790.                 LD      A,(T_ADDR)      ; fetch T_ADDR
  1791.  
  1792.                                         ; Now reduce the low byte of the Syntax table entry to give command.
  1793.  
  1794.                 SUB     $E0             ; subtract the known offset - giving 0 for SAVE,
  1795.                                         ; 1 for LOAD, 2 for VERIFY and 3 for MERGE
  1796.                 LD      (T_ADDR),A      ; and put back in T_ADDR as 0,1,2, or 3
  1797.                                         ; for future reference.
  1798.                 CALL    EXPT_EXP        ; routine EXPT_EXP checks that a string
  1799.                                         ; expression follows and stacks the
  1800.                                         ; parameters in run-time.
  1801.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  1802.                 JR      Z,SA_DATA       ; forward to SA_DATA if checking syntax.
  1803.  
  1804.                 LD      BC,$0011        ; presume seventeen bytes for a header.
  1805.                 LD      A,(T_ADDR)      ; fetch command from T_ADDR.
  1806.                 AND     A               ; test for zero - SAVE.
  1807.                 JR      Z,SA_SPACE      ; forward to SA_SPACE if so.
  1808.  
  1809.                 LD      C,$22           ; else double length to thirty four.
  1810.  
  1811.                                         ;;;$0621
  1812. SA_SPACE:       RST     30H             ; BC_SPACES creates 17/34 bytes in workspace.
  1813.                 PUSH    DE              ; transfer the start of new space to
  1814.                 POP     IX              ; the available index register.
  1815.  
  1816.                                         ; ten spaces are required for the default filename but it is simpler to
  1817.                                         ; overwrite the first file-type indicator byte as well.
  1818.  
  1819.                 LD      B,$0B           ; set counter to eleven.
  1820.                 LD      A,$20           ; prepare a space.
  1821.  
  1822.                                         ;;;$0629
  1823. SA_BLANK:       LD      (DE),A          ; set workspace location to space.
  1824.                 INC     DE              ; next location.
  1825.                 DJNZ    SA_BLANK        ; loop back to SA_BLANK till all eleven done.
  1826.                 LD      (IX+$01),$FF    ; set first byte of ten character filename
  1827.                                         ; to $FF as a default to signal null string.
  1828.                 CALL    STK_FETCH       ; routine STK_FETCH fetches the filename
  1829.                                         ; parameters from the calculator stack.
  1830.                                         ; length of string in BC.
  1831.                                         ; start of string in DE.
  1832.                 LD      HL,$FFF6        ; prepare the value minus ten.
  1833.                 DEC     BC              ; decrement length.
  1834.                                         ; ten becomes nine, zero becomes $FFFF.
  1835.                 ADD     HL,BC           ; trial addition.
  1836.                 INC     BC              ; restore true length.
  1837.                 JR      NC,SA_NAME      ; forward to SA_NAME if length is one to ten.
  1838.  
  1839.                                         ; the filename is more than ten characters in length or the null string.
  1840.  
  1841.                 LD      A,(T_ADDR)      ; fetch command from T_ADDR.
  1842.                 AND     A               ; test for zero - SAVE.
  1843.                 JR      NZ,SA_NULL      ; forward to SA_NULL if not the SAVE command.
  1844.  
  1845.                                         ; but no more than ten characters are allowed for SAVE.
  1846.                                         ; The first ten characters of any other command parameter are acceptable.
  1847.                                         ; Weird, but necessary, if saving to sectors.
  1848.                                         ; Note. the golden rule that there are no restriction on anything is broken.
  1849.  
  1850.                                         ;;;$0642
  1851. REPORT_FA:      RST     08H             ; ERROR_1
  1852.                 DEFB    $0E             ; Error Report: Invalid file name
  1853.  
  1854.                                         ; continue with LOAD, MERGE, VERIFY and also SAVE within ten character limit.
  1855.  
  1856.                                         ;;;$0644
  1857. SA_NULL:        LD      A,B             ; test length of filename
  1858.                 OR      C               ; for zero.
  1859.                 JR      Z,SA_DATA       ; forward to SA_DATA if so using the 255
  1860.                                         ; indicator followed by spaces.
  1861.                 LD      BC,$000A        ; else trim length to ten.
  1862.  
  1863.                                         ; other paths rejoin here with BC holding length in range 1 - 10.
  1864.  
  1865.                                         ;;;$064B
  1866. SA_NAME:        PUSH    IX              ; push start of file descriptor.
  1867.                 POP     HL              ; and pop into HL.
  1868.                 INC     HL              ; HL now addresses first byte of filename.
  1869.                 EX      DE,HL           ; transfer destination address to DE, start
  1870.                                         ; of string in command to HL.
  1871.                 LDIR                    ; copy up to ten bytes
  1872.                                         ; if less than ten then trailing spaces follow.
  1873.  
  1874.                                         ; the case for the null string rejoins here.
  1875.  
  1876.                                         ;;;$0652
  1877. SA_DATA:        RST     18H             ; GET_CHAR
  1878.                 CP      $E4             ; is character after filename the token 'DATA' ?
  1879.                 JR      NZ,SA_SCR       ; forward to SA_SCR to consider SCREEN$ if not.
  1880.  
  1881.                                         ; continue to consider DATA.
  1882.  
  1883.                 LD      A,(T_ADDR)      ; fetch command from T_ADDR
  1884.                 CP      $03             ; is it 'VERIFY' ?
  1885.                 JP      Z,REPORT_C      ; jump forward to REPORT_C if so.
  1886.                                         ; 'Nonsense in basic'
  1887.                                         ; VERIFY "d" DATA is not allowed.
  1888.  
  1889.                                         ; continue with SAVE, LOAD, MERGE of DATA.
  1890.  
  1891.                 RST     20H             ; NEXT_CHAR
  1892.                 CALL    LOOK_VARS       ; routine LOOK_VARS searches variables area
  1893.                                         ; returning with carry reset if found or
  1894.                                         ; checking syntax.
  1895.                 SET     7,C             ; this converts a simple string to a
  1896.                                         ; string array. The test for an array or string
  1897.                                         ; comes later.
  1898.                 JR      NC,SA_V_OLD     ; forward to SA_V_OLD if variable found.
  1899.  
  1900.                 LD      HL,$0000        ; set destination to zero as not fixed.
  1901.                 LD      A,(T_ADDR)      ; fetch command from T_ADDR
  1902.                 DEC     A               ; test for 1 - LOAD
  1903.                 JR      Z,SA_V_NEW      ; forward to SA_V_NEW with LOAD DATA.
  1904.                                         ; to load a new array.
  1905.  
  1906.                                         ; otherwise the variable was not found in run-time with SAVE/MERGE.
  1907.  
  1908.                                         ;;;$0670
  1909. REPORT_2A:      RST     08H             ; ERROR_1
  1910.                 DEFB    $01             ; Error Report: Variable not found
  1911.  
  1912.                                         ; continue with SAVE/LOAD  DATA
  1913.  
  1914.                                         ;;;$0672
  1915. SA_V_OLD:       JP      NZ,REPORT_C     ; to REPORT_C if not an array variable.
  1916.                                         ; or erroneously a simple string.
  1917.                                         ; 'Nonsense in basic'
  1918.  
  1919.  
  1920.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  1921.                 JR      Z,SA_DATA_1     ; forward to SA_DATA_1 if checking syntax.
  1922.  
  1923.                 INC     HL              ; step past single character variable name.
  1924.                 LD      A,(HL)          ; fetch low byte of length.
  1925.                 LD      (IX+$0B),A      ; place in descriptor.
  1926.                 INC     HL              ; point to high byte.
  1927.                 LD      A,(HL)          ; and transfer that
  1928.                 LD      (IX+$0C),A      ; to descriptor.
  1929.                 INC     HL              ; increase pointer within variable.
  1930.  
  1931.                                         ;;;$0685
  1932. SA_V_NEW:       LD      (IX+$0E),C      ; place character array name in  header.
  1933.                 LD      A,$01           ; default to type numeric.
  1934.                 BIT     6,C             ; test result from LOOK_VARS.
  1935.                 JR      Z,SA_V_TYPE     ; forward to SA_V_TYPE if numeric.
  1936.  
  1937.                 INC     A               ; set type to 2 - string array.
  1938.  
  1939.                                         ;;;$068F
  1940. SA_V_TYPE:      LD      (IX+$00),A      ; place type 0, 1 or 2 in descriptor.
  1941.  
  1942.                                         ;;;$0692
  1943. SA_DATA_1:      EX      DE,HL           ; save var pointer in DE
  1944.  
  1945.                 RST     20H             ; NEXT_CHAR
  1946.                 CP      $29             ; is character ')' ?
  1947.                 JR      NZ,SA_V_OLD     ; back if not to SA_V_OLD to report
  1948.                                         ; 'Nonsense in basic'
  1949.  
  1950.                 RST     20H             ; NEXT_CHAR advances character address.
  1951.                 CALL    CHECK_END       ; routine CHECK_END errors if not end of the statement.
  1952.                 EX      DE,HL           ; bring back variables data pointer.
  1953.                 JP      SA_ALL          ; jump forward to SA_ALL
  1954.  
  1955.                                         ; the branch was here to consider a 'SCREEN$', the display file.
  1956.  
  1957.                                         ;;;$06A0
  1958. SA_SCR:         CP      $AA             ; is character the token 'SCREEN$' ?
  1959.                 JR      NZ,SA_CODE      ; forward to SA_CODE if not.
  1960.  
  1961.                 LD      A,(T_ADDR)      ; fetch command from T_ADDR
  1962.                 CP      $03             ; is it MERGE ?
  1963.                 JP      Z,REPORT_C      ; jump to REPORT_C if so.
  1964.                                         ; 'Nonsense in basic'
  1965.  
  1966.                                         ; continue with SAVE/LOAD/VERIFY SCREEN$.
  1967.  
  1968.                 RST     20H             ; NEXT_CHAR
  1969.                 CALL    CHECK_END       ; routine CHECK_END errors if not at end of
  1970.                                         ; statement.
  1971.  
  1972.                                         ; continue in runtime.
  1973.  
  1974.                 LD      (IX+$0B),$00    ; set descriptor length
  1975.                 LD      (IX+$0C),$1B    ; to $1b00 to include bitmaps and attributes.
  1976.                 LD      HL,$4000        ; set start to display file start.
  1977.                 LD      (IX+$0D),L      ; place start in
  1978.                 LD      (IX+$0E),H      ; the descriptor.
  1979.                 JR      SA_TYPE_3       ; forward to SA_TYPE_3
  1980.  
  1981.                                         ; the branch was here to consider CODE.
  1982.  
  1983.                                         ;;;$06C3
  1984. SA_CODE:        CP      $AF             ; is character the token 'CODE' ?
  1985.                 JR      NZ,SA_LINE      ; forward if not to SA_LINE to consider an
  1986.                                         ; auto-started basic program.
  1987.                 LD      A,(T_ADDR)      ; fetch command from T_ADDR
  1988.                 CP      $03             ; is it MERGE ?
  1989.                 JP      Z,REPORT_C      ; jump forward to REPORT_C if so.
  1990.                                         ; 'Nonsense in basic'
  1991.  
  1992.                 RST     20H             ; NEXT_CHAR advances character address.
  1993.                 CALL    PR_ST_END       ; routine PR_ST_END checks if a carriage
  1994.                                         ; return or ':' follows.
  1995.                 JR      NZ,SA_CODE_1    ; forward to SA_CODE_1 if there are parameters.
  1996.  
  1997.                 LD      A,(T_ADDR)      ; else fetch the command from T_ADDR.
  1998.                 AND     A               ; test for zero - SAVE without a specification.
  1999.                 JP      Z,REPORT_C      ; jump to REPORT_C if so.
  2000.                                         ; 'Nonsense in basic'
  2001.  
  2002.                                         ; for LOAD/VERIFY put zero on stack to signify handle at location saved from.
  2003.  
  2004.                 CALL    USE_ZERO        ; routine USE_ZERO
  2005.                 JR      SA_CODE_2       ; forward to SA_CODE_2
  2006.  
  2007.                                         ; if there are more characters after CODE expect start and possibly length.
  2008.  
  2009.                                         ;;;$06E1
  2010. SA_CODE_1:      CALL    EXPT_1NUM       ; routine EXPT_1NUM checks for numeric
  2011.                                         ; expression and stacks it in run-time.
  2012.                 RST     18H             ; GET_CHAR
  2013.                 CP      $2C             ; does a comma follow ?
  2014.                 JR      Z,SA_CODE_3     ; forward if so to SA_CODE_3
  2015.  
  2016.                                         ; else allow saved code to be loaded to a specified address.
  2017.  
  2018.                 LD      A,(T_ADDR)      ; fetch command from T_ADDR.
  2019.                 AND     A               ; is the command SAVE which requires length ?
  2020.                 JP      Z,REPORT_C      ; jump to REPORT_C if so.
  2021.                                         ; 'Nonsense in basic'
  2022.  
  2023.                                         ; the command LOAD code may rejoin here with zero stacked as start.
  2024.  
  2025.                                         ;;;$06F0
  2026. SA_CODE_2:      CALL    USE_ZERO        ; routine USE_ZERO stacks zero for length.
  2027.                 JR      SA_CODE_4       ; forward to SA_CODE_4
  2028.  
  2029.                                         ; the branch was here with SAVE CODE start,
  2030.  
  2031.                                         ;;;$06F5
  2032. SA_CODE_3:      RST     20H             ; NEXT_CHAR advances character address.
  2033.                 CALL    EXPT_1NUM       ; routine EXPT_1NUM checks for expression
  2034.                                         ; and stacks in run-time.
  2035.  
  2036.                                         ; paths converge here and nothing must follow.
  2037.  
  2038.                                         ;;;$06F9
  2039. SA_CODE_4:      CALL    CHECK_END       ; routine CHECK_END errors with extraneous
  2040.                                         ; characters and quits if checking syntax.
  2041.  
  2042.                                         ; in run-time there are two 16-bit parameters on the calculator stack.
  2043.  
  2044.                 CALL    FIND_INT2       ; routine FIND_INT2 gets length.
  2045.                 LD      (IX+$0B),C      ; place length
  2046.                 LD      (IX+$0C),B      ; in descriptor.
  2047.                 CALL    FIND_INT2       ; routine FIND_INT2 gets start.
  2048.                 LD      (IX+$0D),C      ; place start
  2049.                 LD      (IX+$0E),B      ; in descriptor.
  2050.                 LD      H,B             ; transfer the
  2051.                 LD      L,C             ; start to HL also.
  2052.  
  2053.                                         ;;;$0710
  2054. SA_TYPE_3:      LD      (IX+$00),$03    ; place type 3 - code in descriptor.
  2055.                 JR      SA_ALL          ; forward to SA_ALL.
  2056.  
  2057.  
  2058.                                         ; the branch was here with basic to consider an optional auto-start line number.
  2059.  
  2060.                                         ;;;$0716
  2061. SA_LINE:        CP      $CA             ; is character the token 'LINE' ?
  2062.                 JR      Z,SA_LINE_1     ; forward to SA_LINE_1 if so.
  2063.  
  2064.                                         ; else all possibilities have been considered and nothing must follow.
  2065.  
  2066.                 CALL    CHECK_END       ; routine CHECK_END
  2067.  
  2068.                                         ; continue in run-time to save basic without auto-start.
  2069.  
  2070.                 LD      (IX+$0E),$80    ; place high line number in descriptor to disable auto-start.
  2071.                 JR      SA_TYPE_0       ; forward to SA_TYPE_0 to save program.
  2072.  
  2073.                                         ; the branch was here to consider auto-start.
  2074.  
  2075.                                         ;;;$0723
  2076. SA_LINE_1:      LD      A,(T_ADDR)      ; fetch command from T_ADDR
  2077.                 AND     A               ; test for SAVE.
  2078.                 JP      NZ,REPORT_C     ; jump forward to REPORT_C with anything else.
  2079.                                         ; 'Nonsense in basic'
  2080.                 RST     20H             ; NEXT_CHAR
  2081.                 CALL    EXPT_1NUM       ; routine EXPT_1NUM checks for numeric
  2082.                                         ; expression and stacks in run-time.
  2083.                 CALL    CHECK_END       ; routine CHECK_END quits if syntax path.
  2084.                 CALL    FIND_INT2       ; routine FIND_INT2 fetches the numeric expression.
  2085.                 LD      (IX+$0D),C      ; place the auto-start
  2086.                 LD      (IX+$0E),B      ; line number in the descriptor.
  2087.  
  2088.                                         ; Note. this isn't checked, but is subsequently handled by the system.
  2089.                                         ; If the user typed 40000 instead of 4000 then it won't auto-start
  2090.                                         ; at line 4000, or indeed, at all.
  2091.  
  2092.                                         ; continue to save program and any variables.
  2093.  
  2094.                                         ;;;$073A
  2095. SA_TYPE_0:      LD      (IX+$00),$00    ; place type zero - program in descriptor.
  2096.                 LD      HL,(E_LINE)     ; fetch E_LINE to HL.
  2097.                 LD      DE,(PROG)       ; fetch PROG to DE.
  2098.                 SCF                     ; set carry flag to calculate from end of
  2099.                                         ; variables E_LINE -1.
  2100.                 SBC     HL,DE           ; subtract to give total length.
  2101.                 LD      (IX+$0B),L      ; place total length
  2102.                 LD      (IX+$0C),H      ; in descriptor.
  2103.                 LD      HL,(VARS)       ; load HL from system variable VARS
  2104.                 SBC     HL,DE           ; subtract to give program length.
  2105.                 LD      (IX+$0F),L      ; place length of program
  2106.                 LD      (IX+$10),H      ; in the descriptor.
  2107.                 EX      DE,HL           ; start to HL, length to DE.
  2108.  
  2109.                                         ;;;$075A
  2110. SA_ALL:         LD      A,(T_ADDR)      ; fetch command from T_ADDR
  2111.                 AND     A               ; test for zero - SAVE.
  2112.                 JP      Z,SA_CONTRL     ; jump forward to SA_CONTRL with SAVE  ->
  2113.  
  2114.                                         ; continue with LOAD, MERGE and VERIFY.
  2115.  
  2116.                 PUSH    HL              ; save start.
  2117.                 LD      BC,$0011        ; prepare to add seventeen
  2118.                 ADD     IX,BC           ; to point IX at second descriptor.
  2119.  
  2120.                                         ;;;$0767
  2121. LD_LOOK_H:      PUSH    IX              ; save IX
  2122.                 LD      DE,$0011        ; seventeen bytes
  2123.                 XOR     A               ; reset zero flag
  2124.                 SCF                     ; set carry flag
  2125.                 CALL    LD_BYTES        ; routine LD_BYTES loads a header from tape
  2126.                                         ; to second descriptor.
  2127.                 POP     IX              ; restore IX.
  2128.                 JR      NC,LD_LOOK_H    ; loop back to LD_LOOK_H until header found.
  2129.  
  2130.                 LD      A,$FE           ; select system channel 'S'
  2131.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN opens it.
  2132.                 LD      (IY+$52),$03    ; set SCR_CT to 3 lines.
  2133.                 LD      C,$80           ; C has bit 7 set to indicate type mismatch as
  2134.                                         ; a default startpoint.
  2135.                 LD      A,(IX+$00)      ; fetch loaded header type to A
  2136.                 CP      (IX-$11)        ; compare with expected type.
  2137.                 JR      NZ,LD_TYPE      ; forward to LD_TYPE with mis-match.
  2138.  
  2139.                 LD      C,$F6           ; set C to minus ten - will count characters up to zero.
  2140.  
  2141.                                         ;;;$078A
  2142. LD_TYPE:        CP      $04             ; check if type in acceptable range 0 - 3.
  2143.                 JR      NC,LD_LOOK_H    ; back to LD_LOOK_H with 4 and over.
  2144.  
  2145.                                         ; else A indicates type 0-3.
  2146.  
  2147.                 LD      DE,TAPE_MSGS2   ; address base of last 4 tape messages
  2148.                 PUSH    BC              ; save BC
  2149.                 CALL    PO_MSG          ; routine PO_MSG outputs relevant message.
  2150.                                         ; Note. all messages have a leading newline.
  2151.                 POP     BC              ; restore BC
  2152.                 PUSH    IX              ; transfer IX,
  2153.                 POP     DE              ; the 2nd descriptor, to DE.
  2154.                 LD      HL,$FFF0        ; prepare minus seventeen.
  2155.                 ADD     HL,DE           ; add to point HL to 1st descriptor.
  2156.                 LD      B,$0A           ; the count will be ten characters for the filename.
  2157.                 LD      A,(HL)          ; fetch first character and test for
  2158.                 INC     A               ; value 255.
  2159.                 JR      NZ,LD_NAME      ; forward to LD_NAME if not the wildcard.
  2160.  
  2161.                                         ; but if it is the wildcard, then add ten to C which is minus ten for a type
  2162.                                         ; match or -128 for a type mismatch. Although characters have to be counted
  2163.                                         ; bit 7 of C will not alter from state set here.
  2164.  
  2165.                 LD      A,C             ; transfer $F6 or $80 to A
  2166.                 ADD     A,B             ; add $0A
  2167.                 LD      C,A             ; place result, zero or -118, in C.
  2168.  
  2169.                                         ; At this point we have either a type mismatch, a wildcard match or ten
  2170.                                         ; characters to be counted. The characters must be shown on the screen.
  2171.  
  2172.                                         ;;;$07A6
  2173. LD_NAME:        INC     DE              ; address next input character
  2174.                 LD      A,(DE)          ; fetch character
  2175.                 CP      (HL)            ; compare to expected
  2176.                 INC     HL              ; address next expected character
  2177.                 JR      NZ,LD_CH_PR     ; forward to LD_CH_PR with mismatch
  2178.  
  2179.                 INC     C               ; increment matched character count
  2180.  
  2181.                                         ;;;$07AD
  2182. LD_CH_PR:       RST     10H             ; PRINT_A prints character
  2183.                 DJNZ    LD_NAME         ; loop back to LD_NAME for ten characters.
  2184.  
  2185.                                         ; if ten characters matched and the types previously matched then C will
  2186.                                         ; now hold zero.
  2187.  
  2188.                 BIT     7,C             ; test if all matched
  2189.                 JR      NZ,LD_LOOK_H    ; back to LD_LOOK_H if not
  2190.  
  2191.                                         ; else print a terminal carriage return.
  2192.  
  2193.                 LD      A,$0D           ; prepare carriage return.
  2194.                 RST     10H             ; PRINT_A outputs it.
  2195.  
  2196.                                         ; The various control routines for LOAD, VERIFY and MERGE are executed
  2197.                                         ; during the one-second gap following the header on tape.
  2198.  
  2199.                 POP     HL              ; restore xx
  2200.                 LD      A,(IX+$00)      ; fetch incoming type
  2201.                 CP      $03             ; compare with CODE
  2202.                 JR      Z,VR_CONTROL    ; forward to VR_CONTROL if it is CODE.
  2203.  
  2204.                                         ; type is a program or an array.
  2205.  
  2206.                 LD      A,(T_ADDR)      ; fetch command from T_ADDR
  2207.                 DEC     A               ; was it LOAD ?
  2208.                 JP      Z,LD_CONTRL     ; jump forward to LD_CONTRL if so to
  2209.                                         ; load BASIC or variables.
  2210.                 CP      $02             ; was command MERGE ?
  2211.                 JP      Z,ME_CONTRL     ; jump forward to ME_CONTRL if so.
  2212.  
  2213.                                         ; else continue into VERIFY control routine to verify.
  2214.  
  2215. ;----------------------
  2216. ; Handle VERIFY control
  2217. ;----------------------
  2218. ; There are two branches to this routine.
  2219. ; 1) From above to verify a program or array
  2220. ; 2) from earlier with no carry to load or verify code.
  2221.  
  2222.                                         ;;;$07CB
  2223. VR_CONTROL:     PUSH    HL              ; save pointer to data.
  2224.                 LD      L,(IX-$06)      ; fetch length of old data
  2225.                 LD      H,(IX-$05)      ; to HL.
  2226.                 LD      E,(IX+$0B)      ; fetch length of new data
  2227.                 LD      D,(IX+$0C)      ; to DE.
  2228.                 LD      A,H             ; check length of old
  2229.                 OR      L               ; for zero.
  2230.                 JR      Z,VR_CONT_1     ; forward to VR_CONT_1 if length unspecified
  2231.                                         ; e.g LOAD "x" CODE
  2232.  
  2233.                                         ; as opposed to, say, LOAD 'x' CODE 32768,300.
  2234.  
  2235.                 SBC     HL,DE           ; subtract the two lengths.
  2236.                 JR      C,REPORT_R      ; forward to REPORT_R if the length on tape is
  2237.                                         ; larger than that specified in command.
  2238.                                         ; 'Tape loading error'
  2239.  
  2240.                 JR      Z,VR_CONT_1     ; forward to VR_CONT_1 if lengths match.
  2241.  
  2242.                                         ; a length on tape shorter than expected is not allowed for CODE
  2243.  
  2244.                 LD      A,(IX+$00)      ; else fetch type from tape.
  2245.                 CP      $03             ; is it CODE ?
  2246.                 JR      NZ,REPORT_R     ; forward to REPORT_R if so
  2247.                                         ; 'Tape loading error'
  2248.  
  2249.                                         ;;;$07E9
  2250. VR_CONT_1:      POP     HL              ; pop pointer to data
  2251.                 LD      A,H             ; test for zero
  2252.                 OR      L               ; e.g. LOAD 'x' CODE
  2253.                 JR      NZ,VR_CONT_2    ; forward to VR_CONT_2 if destination specified.
  2254.  
  2255.                 LD      L,(IX+$0D)      ; else use the destination in the header
  2256.                 LD      H,(IX+$0E)      ; and load code at address saved from.
  2257.  
  2258.                                         ;;;$07F4
  2259. VR_CONT_2:      PUSH    HL              ; push pointer to start of data block.
  2260.                 POP     IX              ; transfer to IX.
  2261.                 LD      A,(T_ADDR)      ; fetch reduced command from T_ADDR
  2262.                 CP      $02             ; is it VERIFY ?
  2263.                 SCF                     ; prepare a set carry flag
  2264.                 JR      NZ,VR_CONT_3    ; skip to VR_CONT_3 if not
  2265.  
  2266.                 AND     A               ; clear carry flag for VERIFY so that
  2267.                                         ; data is not loaded.
  2268.  
  2269.                                         ;;;$0800
  2270. VR_CONT_3:      LD      A,$FF           ; signal data block to be loaded
  2271.  
  2272. ;------------------
  2273. ; Load a data block
  2274. ;------------------
  2275. ; This routine is called from 3 places other than above to load a data block.
  2276. ; In all cases the accumulator is first set to $FF so the routine could be
  2277. ; called at the previous instruction.
  2278.  
  2279.                                         ;;;$0802
  2280. LD_BLOCK:       CALL    LD_BYTES        ; routine LD_BYTES
  2281.                 RET     C               ; return if successful.
  2282.  
  2283.  
  2284.                                         ;;;$0806
  2285. REPORT_R:       RST     08H             ; ERROR_1
  2286.                 DEFB    $1A             ; Error Report: Tape loading error
  2287.  
  2288. ;--------------------
  2289. ; Handle LOAD control
  2290. ;--------------------
  2291. ; This branch is taken when the command is LOAD with type 0, 1 or 2.
  2292.  
  2293.                                         ;;;$0808
  2294. LD_CONTRL:      LD      E,(IX+$0B)      ; fetch length of found data block
  2295.                 LD      D,(IX+$0C)      ; from 2nd descriptor.
  2296.                 PUSH    HL              ; save destination
  2297.                 LD      A,H             ; test for zero
  2298.                 OR      L
  2299.                 JR      NZ,LD_CONT_1    ; forward if not to LD_CONT_1
  2300.  
  2301.                 INC     DE              ; increase length
  2302.                 INC     DE              ; for letter name
  2303.                 INC     DE              ; and 16-bit length
  2304.                 EX      DE,HL           ; length to HL,
  2305.                 JR      LD_CONT_2       ; forward to LD_CONT_2
  2306.  
  2307.                                         ;;;$0819
  2308. LD_CONT_1:      LD      L,(IX-$06)      ; fetch length from
  2309.                 LD      H,(IX-$05)      ; the first header.
  2310.                 EX      DE,HL
  2311.                 SCF                     ; set carry flag
  2312.                 SBC     HL,DE
  2313.                 JR      C,LD_DATA       ; to LD_DATA
  2314.  
  2315.                                         ;;;$0825
  2316. LD_CONT_2:      LD      DE,$0005        ; allow overhead of five bytes.
  2317.                 ADD     HL,DE           ; add in the difference in data lengths.
  2318.                 LD      B,H             ; transfer to
  2319.                 LD      C,L             ; the BC register pair
  2320.                 CALL    TEST_ROOM       ; routine TEST_ROOM fails if not enough room.
  2321.  
  2322.                                         ;;;$082E
  2323. LD_DATA:        POP     HL              ; pop destination
  2324.                 LD      A,(IX+$00)      ; fetch type 0, 1 or 2.
  2325.                 AND     A               ; test for program and variables.
  2326.                 JR      Z,LD_PROG       ; forward if so to LD_PROG
  2327.  
  2328.                                         ; the type is a numeric or string array.
  2329.  
  2330.                 LD      A,H             ; test the destination for zero
  2331.                 OR      L               ; indicating variable does not already exist.
  2332.                 JR      Z,LD_DATA_1     ; forward if so to LD_DATA_1
  2333.  
  2334.                                         ; else the destination is the first dimension within the array structure
  2335.  
  2336.                 DEC     HL              ; address high byte of total length
  2337.                 LD      B,(HL)          ; transfer to B.
  2338.                 DEC     HL              ; address low byte of total length.
  2339.                 LD      C,(HL)          ; transfer to C.
  2340.                 DEC     HL              ; point to letter of variable.
  2341.                 INC     BC              ; adjust length to
  2342.                 INC     BC              ; include these
  2343.                 INC     BC              ; three bytes also.
  2344.                 LD      (X_PTR),IX      ; save header pointer in X_PTR.
  2345.                 CALL    RECLAIM_2       ; routine RECLAIM_2 reclaims the old variable
  2346.                                         ; sliding workspace including the two headers downwards.
  2347.                 LD      IX,(X_PTR)      ; reload IX from X_PTR which will have been
  2348.                                         ; adjusted down by POINTERS routine.
  2349.  
  2350.                                         ;;;$084C
  2351. LD_DATA_1:      LD      HL,(E_LINE)     ; address E_LINE
  2352.                 DEC     HL              ; now point to the $80 variables end-marker.
  2353.                 LD      C,(IX+$0B)      ; fetch new data length
  2354.                 LD      B,(IX+$0C)      ; from 2nd header.
  2355.                 PUSH    BC              ; * save it.
  2356.                 INC     BC              ; adjust the
  2357.                 INC     BC              ; length to include
  2358.                 INC     BC              ; letter name and total length.
  2359.                 LD      A,(IX-$03)      ; fetch letter name from old header.
  2360.                 PUSH    AF              ; preserve accumulator though not corrupted.
  2361.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM creates space for variable
  2362.                                         ; sliding workspace up. IX no longer addresses
  2363.                                         ; anywhere meaningful.
  2364.                 INC     HL              ; point to first new location.
  2365.                 POP     AF              ; fetch back the letter name.
  2366.                 LD      (HL),A          ; place in first new location.
  2367.                 POP     DE              ; * pop the data length.
  2368.                 INC     HL              ; address 2nd location
  2369.                 LD      (HL),E          ; store low byte of length.
  2370.                 INC     HL              ; address next.
  2371.                 LD      (HL),D          ; store high byte.
  2372.                 INC     HL              ; address start of data.
  2373.                 PUSH    HL              ; transfer address
  2374.                 POP     IX              ; to IX register pair.
  2375.                 SCF                     ; set carry flag indicating load not verify.
  2376.                 LD      A,$FF           ; signal data not header.
  2377.                 JP      LD_BLOCK        ; jump back to LD_BLOCK
  2378.  
  2379.                                         ; the branch is here when a program as opposed to an array is to be loaded.
  2380.  
  2381.                                         ;;;$0873
  2382. LD_PROG:        EX      DE,HL           ; transfer dest to DE.
  2383.                 LD      HL,(E_LINE)     ; address E_LINE
  2384.                 DEC     HL              ; now variables end-marker.
  2385.                 LD      (X_PTR),IX      ; place the IX header pointer in X_PTR
  2386.                 LD      C,(IX+$0B)      ; get new length
  2387.                 LD      B,(IX+$0C)      ; from 2nd header
  2388.                 PUSH    BC              ; and save it.
  2389.                 CALL    RECLAIM_1       ; routine RECLAIM_1 reclaims program and vars.
  2390.                                         ; adjusting X_PTR.
  2391.                 POP     BC              ; restore new length.
  2392.                 PUSH    HL              ; * save start
  2393.                 PUSH    BC              ; ** and length.
  2394.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM creates the space.
  2395.                 LD      IX,(X_PTR)      ; reload IX from adjusted X_PTR
  2396.                 INC     HL              ; point to start of new area.
  2397.                 LD      C,(IX+$0F)      ; fetch length of BASIC on tape
  2398.                 LD      B,(IX+$10)      ; from 2nd descriptor
  2399.                 ADD     HL,BC           ; add to address the start of variables.
  2400.                 LD      (VARS),HL       ; set system variable VARS
  2401.                 LD      H,(IX+$0E)      ; fetch high byte of autostart line number.
  2402.                 LD      A,H             ; transfer to A
  2403.                 AND     $C0             ; test if greater than $3F.
  2404.                 JR      NZ,LD_PROG_1    ; forward to LD_PROG_1 if so with no autostart.
  2405.  
  2406.                 LD      L,(IX+$0D)      ; else fetch the low byte.
  2407.                 LD      (NEWPPC),HL     ; set sytem variable to line number NEWPPC
  2408.                 LD      (IY+$0A),$00    ; set statement NSPPC to zero.
  2409.  
  2410.                                         ;;;$08AD
  2411. LD_PROG_1:      POP     DE              ; ** pop the length
  2412.                 POP     IX              ; * and start.
  2413.                 SCF                     ; set carry flag
  2414.                 LD      A,$FF           ; signal data as opposed to a header.
  2415.                 JP      LD_BLOCK        ; jump back to LD_BLOCK
  2416.  
  2417. ;---------------------
  2418. ; Handle MERGE control
  2419. ;---------------------
  2420. ; the branch was here to merge a program and it's variables or an array.
  2421.  
  2422.                                         ;;;$08B6
  2423. ME_CONTRL:      LD      C,(IX+$0B)      ; fetch length
  2424.                 LD      B,(IX+$0C)      ; of data block on tape.
  2425.                 PUSH    BC              ; save it.
  2426.                 INC     BC              ; one for the pot.
  2427.                 RST     30H             ; BC_SPACES creates room in workspace.
  2428.                                         ; HL addresses last new location.
  2429.                 LD      (HL),$80        ; place end-marker at end.
  2430.                 EX      DE,HL           ; transfer first location to HL.
  2431.                 POP     DE              ; restore length to DE.
  2432.                 PUSH    HL              ; save start.
  2433.                 PUSH    HL              ; and transfer it
  2434.                 POP     IX              ; to IX register.
  2435.                 SCF                     ; set carry flag to load data on tape.
  2436.                 LD      A,$FF           ; signal data not a header.
  2437.                 CALL    LD_BLOCK        ; routine LD_BLOCK loads to workspace.
  2438.                 POP     HL              ; restore first location in workspace to HL.
  2439.                 LD      DE,(PROG)       ; set DE from system variable PROG.
  2440.  
  2441.                                         ; now enter a loop to merge the data block in workspace with the program and
  2442.                                         ; variables.
  2443.  
  2444.                                         ;;;$08D2
  2445. ME_NEW_LP:      LD      A,(HL)          ; fetch next byte from workspace.
  2446.                 AND     $C0             ; compare with $3F.
  2447.                 JR      NZ,ME_VAR_LP    ; forward to ME_VAR_LP if a variable.
  2448.  
  2449.                                         ; continue when HL addresses a Basic line number.
  2450.  
  2451.                                         ;;;$08D7
  2452. ME_OLD_LP:      LD      A,(DE)          ; fetch high byte from program area.
  2453.                 INC     DE              ; bump prog address.
  2454.                 CP      (HL)            ; compare with that in workspace.
  2455.                 INC     HL              ; bump workspace address.
  2456.                 JR      NZ,ME_OLD_L1    ; forward to ME_OLD_L1 if high bytes don't match
  2457.  
  2458.                 LD      A,(DE)          ; fetch the low byte of program line number.
  2459.                 CP      (HL)            ; compare with that in workspace.
  2460.  
  2461.                                         ;;;$08DF
  2462. ME_OLD_L1:      DEC     DE              ; point to start of
  2463.                 DEC     HL              ; respective lines again.
  2464.                 JR      NC,ME_NEW_L2    ; forward to ME_NEW_L2 if line number in
  2465.                                         ; workspace is less than or equal to current
  2466.                                         ; program line as has to be added to program.
  2467.                 PUSH    HL              ; else save workspace pointer.
  2468.                 EX      DE,HL           ; transfer prog pointer to HL
  2469.                 CALL    NEXT_ONE        ; routine NEXT_ONE finds next line in DE.
  2470.                 POP     HL              ; restore workspace pointer
  2471.                 JR      ME_OLD_LP       ; back to ME_OLD_LP until destination position
  2472.                                         ; in program area found.
  2473.  
  2474.                                         ; the branch was here with an insertion or replacement point.
  2475.  
  2476.                                         ;;;$08EB:
  2477. ME_NEW_L2:      CALL    ME_ENTER        ; routine ME_ENTER enters the line
  2478.                 JR      ME_NEW_LP       ; loop back to ME_NEW_LP.
  2479.  
  2480.                                         ; the branch was here when the location in workspace held a variable.
  2481.  
  2482.                                         ;;;$08F0
  2483. ME_VAR_LP:      LD      A,(HL)          ; fetch first byte of workspace variable.
  2484.                 LD      C,A             ; copy to C also.
  2485.                 CP      $80             ; is it the end-marker ?
  2486.                 RET     Z               ; return if so as complete.  >>>>>
  2487.  
  2488.                 PUSH    HL              ; save workspace area pointer.
  2489.                 LD      HL,(VARS)       ; load HL with VARS - start of variables area.
  2490.  
  2491.                                         ;;;$08F9
  2492. ME_OLD_VP:      LD      A,(HL)          ; fetch first byte.
  2493.                 CP      $80             ; is it the end-marker ?
  2494.                 JR      Z,ME_VAR_L2     ; forward if so to ME_VAR_L2 to add
  2495.                                         ; variable at end of variables area.
  2496.                 CP      C               ; compare with variable in workspace area.
  2497.                 JR      Z,ME_OLD_V2     ; forward to ME_OLD_V2 if a match to replace.
  2498.  
  2499.                                         ; else entire variables area has to be searched.
  2500.  
  2501.                                         ;;;$0901
  2502. ME_OLD_V1:      PUSH    BC              ; save character in C.
  2503.                 CALL    NEXT_ONE        ; routine NEXT_ONE gets following variable address in DE.
  2504.                 POP     BC              ; restore character in C
  2505.                 EX      DE,HL           ; transfer next address to HL.
  2506.                 JR      ME_OLD_VP       ; loop back to ME_OLD_VP
  2507.  
  2508.                                         ; the branch was here when first characters of name matched.
  2509.  
  2510.                                         ;;;$0909
  2511. ME_OLD_V2:      AND     $E0             ; keep bits 11100000
  2512.                 CP      $A0             ; compare   10100000 - a long-named variable.
  2513.                 JR      NZ,ME_VAR_L1    ; forward to ME_VAR_L1 if just one-character.
  2514.  
  2515.                                         ; but long-named variables have to be matched character by character.
  2516.  
  2517.                 POP     DE              ; fetch workspace 1st character pointer
  2518.                 PUSH    DE              ; and save it on the stack again.
  2519.                 PUSH    HL              ; save variables area pointer on stack.
  2520.  
  2521.                                         ;;;$0912
  2522. ME_OLD_V3:      INC     HL              ; address next character in vars area.
  2523.                 INC     DE              ; address next character in workspace area.
  2524.                 LD      A,(DE)          ; fetch workspace character.
  2525.                 CP      (HL)            ; compare to variables character.
  2526.                 JR      NZ,ME_OLD_V4    ; forward to ME_OLD_V4 with a mismatch.
  2527.  
  2528.                 RLA                     ; test if the terminal inverted character.
  2529.                 JR      NC,ME_OLD_V3    ; loop back to ME_OLD_V3 if more to test.
  2530.  
  2531.                                         ; otherwise the long name matches in it's entirety.
  2532.  
  2533.                 POP     HL              ; restore pointer to first character of variable
  2534.                 JR      ME_VAR_L1       ; forward to ME_VAR_L1
  2535.  
  2536.                                         ; the branch is here when two characters don't match
  2537.  
  2538.                                         ;;;$091E
  2539. ME_OLD_V4:      POP     HL              ; restore the prog/vars pointer.
  2540.                 JR      ME_OLD_V1       ; back to ME_OLD_V1 to resume search.
  2541.  
  2542.                                         ; branch here when variable is to replace an existing one
  2543.  
  2544.                                         ;;;$0921
  2545. ME_VAR_L1:      LD      A,$FF           ; indicate a replacement.
  2546.  
  2547.                                         ; this entry point is when A holds $80 indicating a new variable.
  2548.  
  2549.                                         ;;;$0923
  2550. ME_VAR_L2:      POP     DE              ; pop workspace pointer.
  2551.                 EX      DE,HL           ; now make HL workspace pointer, DE vars pointer
  2552.                 INC     A               ; zero flag set if replacement.
  2553.                 SCF                     ; set carry flag indicating a variable not a program line.
  2554.                 CALL    ME_ENTER        ; routine ME_ENTER copies variable in.
  2555.                 JR      ME_VAR_LP       ; loop back to ME_VAR_LP
  2556.  
  2557. ;-------------------------
  2558. ; Merge a Line or Variable
  2559. ;-------------------------
  2560. ; A Basic line or variable is inserted at the current point. If the line numbers
  2561. ; or variable names match (zero flag set) then a replacement takes place.
  2562.  
  2563.                                         ;;;$092C
  2564. ME_ENTER:       JR      NZ,ME_ENT_1     ; forward to ME_ENT_1 for insertion only.
  2565.  
  2566.                                         ; but the program line or variable matches so old one is reclaimed.
  2567.  
  2568.                 EX      AF,AF'          ; save flag??
  2569.                 LD      (X_PTR),HL      ; preserve workspace pointer in dynamic X_PTR
  2570.                 EX      DE,HL           ; transfer program dest pointer to HL.
  2571.                 CALL    NEXT_ONE        ; routine NEXT_ONE finds following location
  2572.                                         ; in program or variables area.
  2573.                 CALL    RECLAIM_2       ; routine RECLAIM_2 reclaims the space between.
  2574.                 EX      DE,HL           ; transfer program dest pointer back to DE.
  2575.                 LD      HL,(X_PTR)      ; fetch adjusted workspace pointer from X_PTR
  2576.                 EX      AF,AF'          ; restore flags.
  2577.  
  2578.                                         ; now the new line or variable is entered.
  2579.  
  2580.                                         ;;;$093E
  2581. ME_ENT_1:       EX      AF,AF'          ; save or re-save flags.
  2582.                 PUSH    DE              ; save dest pointer in prog/vars area.
  2583.                 CALL    NEXT_ONE        ; routine NEXT_ONE finds next in workspace.
  2584.                                         ; gets next in DE, difference in BC.
  2585.                                         ; prev addr in HL
  2586.                 LD      (X_PTR),HL      ; store pointer in X_PTR
  2587.                 LD      HL,(PROG)       ; load HL from system variable PROG
  2588.                 EX      (SP),HL         ; swap with prog/vars pointer on stack.
  2589.                 PUSH    BC              ; ** save length of new program line/variable.
  2590.                 EX      AF,AF'          ; fetch flags back.
  2591.                 JR      C,ME_ENT_2      ; skip to ME_ENT_2 if variable
  2592.  
  2593.                 DEC     HL              ; address location before pointer
  2594.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM creates room for basic line
  2595.                 INC     HL              ; address next.
  2596.                 JR      ME_ENT_3        ; forward to ME_ENT_3
  2597.  
  2598.                                         ;;;$0955
  2599. ME_ENT_2:       CALL    MAKE_ROOM       ; routine MAKE_ROOM creates room for variable.
  2600.  
  2601.                                         ;;;$0958
  2602. ME_ENT_3:       INC     HL              ; address next?
  2603.                 POP     BC              ; ** pop length
  2604.                 POP     DE              ; * pop value for PROG which may have been
  2605.                                         ; altered by POINTERS if first line.
  2606.                 LD      (PROG),DE       ; set PROG to original value.
  2607.                 LD      DE,(X_PTR)      ; fetch adjusted workspace pointer from X_PTR
  2608.                 PUSH    BC              ; save length
  2609.                 PUSH    DE              ; and workspace pointer
  2610.                 EX      DE,HL           ; make workspace pointer source, prog/vars
  2611.                                         ; pointer the destination
  2612.                 LDIR                    ; copy bytes of line or variable into new area.
  2613.                 POP     HL              ; restore workspace pointer.
  2614.                 POP     BC              ; restore length.
  2615.                 PUSH    DE              ; save new prog/vars pointer.
  2616.                 CALL    RECLAIM_2       ; routine RECLAIM_2 reclaims the space used
  2617.                                         ; by the line or variable in workspace block
  2618.                                         ; as no longer required and space could be
  2619.                                         ; useful for adding more lines.
  2620.                 POP     DE              ; restore the prog/vars pointer
  2621.                 RET                     ; return.
  2622.  
  2623. ;--------------------
  2624. ; Handle SAVE control
  2625. ;--------------------
  2626. ; A branch from the main SAVE_ETC routine at SAVE-ALL.
  2627. ; First the header data is saved. Then after a wait of 1 second
  2628. ; the data itself is saved.
  2629. ; HL points to start of data.
  2630. ; IX points to start of descriptor.
  2631.  
  2632.                                         ;;;$0970
  2633. SA_CONTRL:      PUSH    HL              ; save start of data
  2634.                 LD      A,$FD           ; select system channel 'S'
  2635.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN
  2636.                 XOR     A               ; clear to address table directly
  2637.                 LD      DE,TAPE_MSGS    ; address: TAPE_MSGS
  2638.                 CALL    PO_MSG          ; routine PO_MSG -
  2639.                                         ; 'Start tape then press any key.'
  2640.                 SET     5,(IY+$02)      ; TV_FLAG  - Signal lower screen requires  clearing
  2641.                 CALL    WAIT_KEY        ; routine WAIT_KEY
  2642.                 PUSH    IX              ; save pointer to descriptor.
  2643.                 LD      DE,$0011        ; there are seventeen bytes.
  2644.                 XOR     A               ; signal a header.
  2645.                 CALL    SA_BYTES        ; routine SA_BYTES
  2646.                 POP     IX              ; restore descriptor pointer.
  2647.                 LD      B,$32           ; wait for a second - 50 interrupts.
  2648.  
  2649.                                         ;;;$0991
  2650. SA_1_SEC:       HALT                    ; wait for interrupt
  2651.                 DJNZ    SA_1_SEC        ; back to SA_1_SEC until pause complete.
  2652.                 LD      E,(IX+$0B)      ; fetch length of bytes from the
  2653.                 LD      D,(IX+$0C)      ; descriptor.
  2654.                 LD      A,$FF           ; signal data bytes.
  2655.                 POP     IX              ; retrieve pointer to start
  2656.                 JP      SA_BYTES        ; jump back to SA_BYTES
  2657.  
  2658.  
  2659. ; Arrangement of two headers in workspace.
  2660. ; Originally IX addresses first location and only one header is required
  2661. ; when saving.
  2662. ;
  2663. ;   OLD     NEW         PROG   DATA  DATA  CODE
  2664. ;   HEADER  HEADER             num   chr          NOTES.
  2665. ;   ------  ------      ----   ----  ----  ----   -----------------------------
  2666. ;   IX-$11  IX+$00      0      1     2     3      Type.
  2667. ;   IX-$10  IX+$01      x      x     x     x      F  ($FF if filename is null).
  2668. ;   IX-$0F  IX+$02      x      x     x     x      i
  2669. ;   IX-$0E  IX+$03      x      x     x     x      l
  2670. ;   IX-$0D  IX+$04      x      x     x     x      e
  2671. ;   IX-$0C  IX+$05      x      x     x     x      n
  2672. ;   IX-$0B  IX+$06      x      x     x     x      a
  2673. ;   IX-$0A  IX+$07      x      x     x     x      m
  2674. ;   IX-$09  IX+$08      x      x     x     x      e
  2675. ;   IX-$08  IX+$09      x      x     x     x      .
  2676. ;   IX-$07  IX+$0A      x      x     x     x      (terminal spaces).
  2677. ;   IX-$06  IX+$0B      lo     lo    lo    lo     Total  
  2678. ;   IX-$05  IX+$0C      hi     hi    hi    hi     Length of datablock.
  2679. ;   IX-$04  IX+$0D      Auto   -     -     Start  Various
  2680. ;   IX-$03  IX+$0E      Start  a-z   a-z   addr   ($80 if no autostart).
  2681. ;   IX-$02  IX+$0F      lo     -     -     -      Length of Program
  2682. ;   IX-$01  IX+$10      hi     -     -     -      only i.e. without variables.
  2683.  
  2684. ;-------------------------
  2685. ; Canned cassette messages
  2686. ;-------------------------
  2687. ; The last-character-inverted Cassette messages.
  2688. ; Starts with normal initial step-over byte.
  2689.  
  2690.                                         ;;;$09A1
  2691. TAPE_MSGS:      DEFB    $80
  2692.                 DEFB    "Start tape, then press any key"
  2693. TAPE_MSGS2:     DEFB    '.'+$80
  2694.                 DEFB    $0D
  2695.                 DEFB    "Program:",' '+$80
  2696.                 DEFB    $0D
  2697.                 DEFB    "Number array:",' '+$80
  2698.                 DEFB    $0D
  2699.                 DEFB    "Character array:",' '+$80
  2700.                 DEFB    $0D
  2701.                 DEFB    "Bytes:",' '+$80
  2702.  
  2703.  
  2704.  
  2705. ;**************************************************
  2706. ;** Part 5. SCREEN AND PRINTER HANDLING ROUTINES **
  2707. ;**************************************************
  2708.  
  2709. ;----------------------
  2710. ; General PRINT routine
  2711. ;----------------------
  2712. ; This is the routine most often used by the RST 10 restart although the
  2713. ; subroutine is on two occasions called directly when it is known that
  2714. ; output will definitely be to the lower screen.
  2715.  
  2716.                                         ;;;$09F4
  2717. PRINT_OUT:      CALL    PO_FETCH        ; routine PO_FETCH fetches print position
  2718.                                         ; to HL register pair.
  2719.                 CP      $20             ; is character a space or higher ?
  2720.                 JP      NC,PO_ABLE      ; jump forward to PO_ABLE if so.
  2721.  
  2722.                 CP      $06             ; is character in range 00-05 ?
  2723.                 JR      C,PO_QUEST      ; to PO_QUEST to print '?' if so.
  2724.  
  2725.                 CP      $18             ; is character in range 24d - 31d ?
  2726.                 JR      NC,PO_QUEST     ; to PO_QUEST to also print '?' if so.
  2727.  
  2728.                 LD      HL,CTLCHRTAB - 6; address $0A0B - the base address of control
  2729.                                         ; character table - where zero would be.
  2730.                 LD      E,A             ; control character 06 - 23d
  2731.                 LD      D,$00           ; is transferred to DE.
  2732.                 ADD     HL,DE           ; index into table.
  2733.                 LD      E,(HL)          ; fetch the offset to routine.
  2734.                 ADD     HL,DE           ; add to make HL the address.
  2735.                 PUSH    HL              ; push the address.
  2736.                 JP      PO_FETCH        ; to PO_FETCH, as the screen/printer position
  2737.                                         ; has been disturbed, and indirectly to
  2738.                                         ; routine on stack.
  2739.  
  2740. ;------------------------
  2741. ; Control character table
  2742. ;------------------------
  2743. ; For control characters in the range 6 - 23d the following table
  2744. ; is indexed to provide an offset to the handling routine that
  2745. ; follows the table.
  2746.  
  2747.                                         ;;;$0A11
  2748. CTLCHRTAB:      DEFB    PO_COMMA - $    ; 06d offset $4E to Address: PO_COMMA
  2749.                 DEFB    PO_QUEST - $    ; 07d offset $57 to Address: PO_QUEST
  2750.                 DEFB    PO_BACK_1 - $   ; 08d offset $10 to Address: PO_BACK_1
  2751.                 DEFB    PO_RIGHT - $    ; 09d offset $29 to Address: PO_RIGHT
  2752.                 DEFB    PO_QUEST - $    ; 10d offset $54 to Address: PO_QUEST
  2753.                 DEFB    PO_QUEST - $    ; 11d offset $53 to Address: PO_QUEST
  2754.                 DEFB    PO_QUEST - $    ; 12d offset $52 to Address: PO_QUEST
  2755.                 DEFB    PO_ENTER - $    ; 13d offset $37 to Address: PO_ENTER
  2756.                 DEFB    PO_QUEST - $    ; 14d offset $50 to Address: PO_QUEST
  2757.                 DEFB    PO_QUEST - $    ; 15d offset $4F to Address: PO_QUEST
  2758.                 DEFB    PO_1_OPER - $   ; 16d offset $5F to Address: PO_1_OPER
  2759.                 DEFB    PO_1_OPER - $   ; 17d offset $5E to Address: PO_1_OPER
  2760.                 DEFB    PO_1_OPER - $   ; 18d offset $5D to Address: PO_1_OPER
  2761.                 DEFB    PO_1_OPER - $   ; 19d offset $5C to Address: PO_1_OPER
  2762.                 DEFB    PO_1_OPER - $   ; 20d offset $5B to Address: PO_1_OPER
  2763.                 DEFB    PO_1_OPER - $   ; 21d offset $5A to Address: PO_1_OPER
  2764.                 DEFB    PO_2_OPER - $   ; 22d offset $54 to Address: PO_2_OPER
  2765.                 DEFB    PO_2_OPER - $   ; 23d offset $53 to Address: PO_2_OPER
  2766.  
  2767.  
  2768. ;--------------------
  2769. ; Cursor left routine
  2770. ;--------------------
  2771. ; Backspace and up a line if that action is from the left of screen.
  2772. ; For ZX printer backspace up to first column but not beyond.
  2773.  
  2774.                                         ;;;$0A23
  2775. PO_BACK_1:      INC     C               ; move left one column.
  2776.                 LD      A,$22           ; value $21 is leftmost column.
  2777.                 CP      C               ; have we passed ?
  2778.                 JR      NZ,PO_BACK_3    ; to PO_BACK_3 if not and store new position.
  2779.  
  2780.                 BIT     1,(IY+$01)      ; test FLAGS  - is printer in use ?
  2781.                 JR      NZ,PO_BACK_2    ; to PO_BACK_2 if so, as we are unable to
  2782.                                         ; backspace from the leftmost position.
  2783.                 INC     B               ; move up one screen line
  2784.                 LD      C,$02           ; the rightmost column position.
  2785.                 LD      A,$18           ; Note. This should be $19
  2786.                                         ; credit. Dr. Frank O'Hara, 1982
  2787.                 CP      B               ; has position moved past top of screen ?
  2788.                 JR      NZ,PO_BACK_3    ; to PO_BACK_3 if not and store new position.
  2789.  
  2790.                 DEC     B               ; else back to $18.
  2791.  
  2792.                                         ;;;$0A38
  2793. PO_BACK_2:      LD      C,$21           ; the leftmost column position.
  2794.  
  2795.                                         ;;;$0A3A
  2796. PO_BACK_3:      JP      CL_SET          ; to CL_SET and PO_STORE to save new
  2797.                                         ; position in system variables.
  2798.  
  2799. ;---------------------
  2800. ; Cursor right routine
  2801. ;---------------------
  2802. ; This moves the print position to the right leaving a trail in the
  2803. ; current background colour.
  2804. ; "However the programmer has failed to store the new print position
  2805. ;  so CHR$ 9 will only work if the next print position is at a newly
  2806. ;  defined place.
  2807. ;   e.g. PRINT PAPER 2; CHR$ 9; AT 4,0;
  2808. ;  does work but is not very helpful"
  2809. ; - Dr. Ian Logan, Understanding Your Spectrum, 1982.
  2810.  
  2811.                                         ;;;$0A3D
  2812. PO_RIGHT:       LD      A,(P_FLAG)      ; fetch P_FLAG value
  2813.                 PUSH    AF              ; and save it on stack.
  2814.                 LD      (IY+$57),$01    ; temporarily set P_FLAG 'OVER 1'.
  2815.                 LD      A,$20           ; prepare a space.
  2816.                 CALL    PO_CHAR         ; routine PO_CHAR to print it.
  2817.                                         ; Note. could be PO_ABLE which would update
  2818.                                         ; the column position.
  2819.                 POP     AF              ; restore the permanent flag.
  2820.                 LD      (P_FLAG),A      ; and restore system variable P_FLAG
  2821.                 RET                     ; return without updating column position
  2822.  
  2823. ;------------------------
  2824. ; Perform carriage return
  2825. ;------------------------
  2826. ; A carriage return is 'printed' to screen or printer buffer.
  2827.  
  2828.                                         ;;;$0A4F
  2829. PO_ENTER:       BIT     1,(IY+$01)      ; test FLAGS  - is printer in use ?
  2830.                 JP      NZ,COPY_BUFF    ; to COPY_BUFF if so, to flush buffer and reset
  2831.                                         ; the print position.
  2832.                 LD      C,$21           ; the leftmost column position.
  2833.                 CALL    PO_SCR          ; routine PO_SCR handles any scrolling required.
  2834.                 DEC     B               ; to next screen line.
  2835.                 JP      CL_SET          ; jump forward to CL_SET to store new position.
  2836.  
  2837. ;------------
  2838. ; Print comma
  2839. ;------------
  2840. ; The comma control character. The 32 column screen has two 16 character
  2841. ; tabstops.  The routine is only reached via the control character table.
  2842.  
  2843.                                         ;;;$0A5F
  2844. PO_COMMA:       CALL    PO_FETCH        ; routine PO_FETCH - seems unnecessary.
  2845.                 LD      A,C             ; the column position. $21-$01
  2846.                 DEC     A               ; move right. $20-$00
  2847.                 DEC     A               ; and again   $1F-$00 or $FF if trailing
  2848.                 AND     $10             ; will be $00 or $10.
  2849.                 JR      PO_FILL         ; forward to PO_FILL
  2850.  
  2851. ;--------------------
  2852. ; Print question mark
  2853. ;--------------------
  2854. ; This routine prints a question mark which is commonly
  2855. ; used to print an unassigned control character in range 0-31d.
  2856. ; there are a surprising number yet to be assigned.
  2857.  
  2858.                                         ;;;$0A69
  2859. PO_QUEST:       LD      A,$3F           ; prepare the character '?'.
  2860.                 JR      PO_ABLE         ; forward to PO_ABLE.
  2861.  
  2862. ;---------------------------------
  2863. ; Control characters with operands
  2864. ;---------------------------------
  2865. ; Certain control characters are followed by 1 or 2 operands.
  2866. ; The entry points from control character table are PO_2_OPER and PO_1_OPER.
  2867. ; The routines alter the output address of the current channel so that
  2868. ; subsequent RST $10 instructions take the appropriate action
  2869. ; before finally resetting the output address back to PRINT_OUT.
  2870.  
  2871.                                         ;;;$0A6D
  2872. PO_TV_2:        LD      DE,PO_CONT      ; address: PO_CONT will be next output routine
  2873.                 LD      (TVDATA_HI),A   ; store first operand in TVDATA_HI
  2874.                 JR      PO_CHANGE       ; forward to PO_CHANGE >>
  2875.  
  2876.                                         ; -> This initial entry point deals with two operands - AT or TAB.
  2877.  
  2878.                                         ;;;$0A75
  2879. PO_2_OPER:      LD      DE,PO_TV_2      ; address: PO_TV_2 will be next output routine
  2880.                 JR      PO_TV_1         ; forward to PO_TV_1
  2881.  
  2882.                                         ; -> This initial entry point deals with one operand INK to OVER.
  2883.  
  2884.                                         ;;;$0A7A
  2885. PO_1_OPER:      LD      DE,PO_CONT      ; address: PO_CONT will be next output routine
  2886.  
  2887.                                         ;;;$0A7D
  2888. PO_TV_1:        LD      (TVDATA_LO),A   ; store control code in TVDATA_LO
  2889.  
  2890.                                         ;;;$0A80
  2891. PO_CHANGE:      LD      HL,(CURCHL)     ; use CURCHL to find current output channel.
  2892.                 LD      (HL),E          ; make it
  2893.                 INC     HL              ; the supplied
  2894.                 LD      (HL),D          ; address from DE.
  2895.                 RET                     ; Note. should clear carry before returning
  2896.  
  2897.                                         ;;;$0A87
  2898. PO_CONT:        LD      DE,PRINT_OUT    ; Address: PRINT_OUT
  2899.                 CALL    PO_CHANGE       ; routine PO_CHANGE to restore normal channel.
  2900.                 LD      HL,(TVDATA_LO)  ; TVDATA gives control code and possible
  2901.                                         ; subsequent character
  2902.                 LD      D,A             ; save current character
  2903.                 LD      A,L             ; the stored control code
  2904.                 CP      $16             ; was it INK to OVER (1 operand) ?
  2905.                 JP      C,CO_TEMP_5     ; to CO_TEMP_5
  2906.  
  2907.                 JR      NZ,PO_TAB       ; to PO_TAB if not 22d i.e. 23d TAB.
  2908.  
  2909.                                         ; else must have been 22d AT.
  2910.                 LD      B,H             ; line to   H (0-23d)
  2911.                 LD      C,D             ; column to C (0-31d)
  2912.                 LD      A,$1F           ; the value 31d
  2913.                 SUB     C               ; reverse the column number.
  2914.                 JR      C,PO_AT_ERR     ; to PO_AT_ERR if C was greater than 31d.
  2915.  
  2916.                 ADD     A,$02           ; transform to system range $02-$21
  2917.                 LD      C,A             ; and place in column register.
  2918.                 BIT     1,(IY+$01)      ; test FLAGS  - is printer in use ?
  2919.                 JR      NZ,PO_AT_SET    ; to PO_AT_SET as line can be ignored.
  2920.  
  2921.                 LD      A,$16           ; 22 decimal
  2922.                 SUB     B               ; subtract line number to reverse
  2923.                                         ; 0 - 22 becomes 22 - 0.
  2924.  
  2925.                                         ;;;$0AAC
  2926. PO_AT_ERR:      JP      C,REPORT_BB     ; to REPORT_BB if higher than 22 decimal
  2927.                                         ; Integer out of range.
  2928.                 INC     A               ; adjust for system range $01-$17
  2929.                 LD      B,A             ; place in line register
  2930.                 INC     B               ; adjust to system range  $02-$18
  2931.                 BIT     0,(IY+$02)      ; TV_FLAG  - Lower screen in use ?
  2932.                 JP      NZ,PO_SCR       ; exit to PO_SCR to test for scrolling
  2933.  
  2934.                 CP      (IY+$31)        ; Compare against DF_SZ
  2935.                 JP      C,REPORT_5      ; to REPORT_5 if too low
  2936.                                         ; Out of screen.
  2937.  
  2938.                                         ;;;$0ABF
  2939. PO_AT_SET:      JP      CL_SET          ; print position is valid so exit via CL_SET
  2940.  
  2941.                                         ; Continue here when dealing with TAB.
  2942.                                         ; Note. In basic TAB is followed by a 16-bit number and was initially
  2943.                                         ; designed to work with any output device.
  2944.  
  2945.                                         ;;;$0AC2
  2946. PO_TAB:         LD      A,H             ; transfer parameter to A
  2947.                                         ; Losing current character -
  2948.                                         ; High byte of TAB parameter.
  2949.  
  2950.                                         ;;;$0AC3
  2951. PO_FILL:        CALL    PO_FETCH        ; routine PO_FETCH, HL-addr, BC=line/column.
  2952.                                         ; column 1 (right), $21 (left)
  2953.                 ADD     A,C             ; add operand to current column
  2954.                 DEC     A               ; range 0 - 31+
  2955.                 AND     $1F             ; make range 0 - 31d
  2956.                 RET     Z               ; return if result zero
  2957.  
  2958.                 LD      D,A             ; Counter to D
  2959.                 SET     0,(IY+$01)      ; update FLAGS  - signal suppress leading space.
  2960.  
  2961.                                         ;;;$0AD0
  2962. PO_SPACE:       LD      A,$20           ; space character.
  2963.                 CALL    PO_SAVE         ; routine PO_SAVE prints the character
  2964.                                         ; using alternate set (normal output routine)
  2965.                 DEC     D               ; decrement counter.
  2966.                 JR      NZ,PO_SPACE     ; to PO_SPACE until done
  2967.  
  2968.                 RET                     ; return
  2969.  
  2970. ;-----------------------
  2971. ; Printable character(s)
  2972. ;-----------------------
  2973. ; This routine prints printable characters and continues into
  2974. ; the position store routine
  2975.  
  2976.                                         ;;;$0AD9
  2977. PO_ABLE:        CALL    PO_ANY          ; routine PO_ANY
  2978.                                         ; and continue into position store routine.
  2979.  
  2980. ;--------------------------------------
  2981. ; Store line, column, and pixel address
  2982. ;--------------------------------------
  2983. ; This routine updates the system variables associated with
  2984. ; The main screen, lower screen/input buffer or ZX printer.
  2985.  
  2986.                                         ;;;$0ADC
  2987. PO_STORE:       BIT     1,(IY+$01)      ; test FLAGS  - Is printer in use ?
  2988.                 JR      NZ,PO_ST_PR     ; to PO_ST_PR if so
  2989.  
  2990.                 BIT     0,(IY+$02)      ; TV_FLAG  - Lower screen in use ?
  2991.                 JR      NZ,PO_ST_E      ; to PO_ST_E if so
  2992.  
  2993.                 LD      (S_POSN),BC     ; S_POSN line/column upper screen
  2994.                 LD      (DF_CC),HL      ; DF_CC  display file address
  2995.                 RET
  2996.  
  2997.                                         ;;;$0AF0:
  2998. PO_ST_E:        LD      (SPOSNL),BC     ; SPOSNL line/column lower screen
  2999.                 LD      (ECHO_E),BC     ; ECHO_E line/column input buffer
  3000.                 LD      (DFCCL),HL      ; DFCCL  lower screen memory address
  3001.                 RET
  3002.  
  3003.                                         ;;;$0AFC
  3004. PO_ST_PR:       LD      (IY+$45),C      ; P_POSN column position printer
  3005.                 LD      (PR_CC),HL      ; PR_CC  full printer buffer memory address
  3006.                 RET
  3007.  
  3008. ;--------------------------
  3009. ; Fetch position parameters
  3010. ;--------------------------
  3011. ; This routine fetches the line/column and display file address
  3012. ; of the upper and lower screen or, if the printer is in use,
  3013. ; the column position and absolute memory address.
  3014. ; Note. that PR-CC-hi (23681) is used by this routine and the one above
  3015. ; and if, in accordance with the manual (that says this is unused), the
  3016. ; location has been used for other purposes, then subsequent output
  3017. ; to the printer buffer could corrupt a 256-byte section of memory.
  3018.  
  3019.                                         ;;;$0B03
  3020. PO_FETCH:       BIT     1,(IY+$01)      ; test FLAGS  - Is printer in use
  3021.                 JR      NZ,PO_F_PR      ; to PO_F_PR if so
  3022.                                         ; assume upper screen
  3023.                 LD      BC,(S_POSN)     ; S_POSN
  3024.                 LD      HL,(DF_CC)      ; DF_CC display file address
  3025.                 BIT     0,(IY+$02)      ; TV_FLAG  - Lower screen in use ?
  3026.                 RET     Z               ; return if upper screen
  3027.                                         ; ah well, was lower screen
  3028.                 LD      BC,(SPOSNL)     ; SPOSNL
  3029.                 LD      HL,(DFCCL)      ; DFCCL
  3030.                 RET                     ; return
  3031.  
  3032.                                         ;;;$0B1D
  3033. PO_F_PR:        LD      C,(IY+$45)      ; P_POSN column only
  3034.                 LD      HL,(PR_CC)      ; PR_CC printer buffer address
  3035.                 RET                     ; return
  3036.  
  3037. ;--------------------
  3038. ; Print any character
  3039. ;--------------------
  3040. ; This routine is used to print any character in range 32d - 255d
  3041. ; It is only called from PO_ABLE and continues into PO_STORE
  3042.  
  3043.                                         ;;;$0B24
  3044. PO_ANY:         CP      $80             ; ascii ?
  3045.                 JR      C,PO_CHAR       ; to PO_CHAR is so.
  3046.  
  3047.                 CP      $90             ; test if a block graphic character.
  3048.                 JR      NC,PO_T_UDG     ; to PO_T_UDG to print tokens and udg's
  3049.  
  3050.                                         ; The 16 2*2 mosaic characters 128-143 decimal are formed from
  3051.                                         ; bits 0-3 of the character.
  3052.  
  3053.                 LD      B,A             ; save character
  3054.                 CALL    PO_GR_1         ; routine PO_GR_1 to construct top half then bottom half.
  3055.                 CALL    PO_FETCH        ; routine PO_FETCH fetches print position.
  3056.                 LD      DE,MEM_0        ; MEM_0 is location of 8 bytes of character
  3057.                 JR      PR_ALL          ; to PR_ALL to print to screen or printer
  3058.  
  3059.                                         ;;;$0B38
  3060. PO_GR_1:        LD      HL,MEM_0        ; address MEM_0 - a temporary buffer in
  3061.                                         ; systems variables which is normally used by the calculator.
  3062.                 CALL    PO_GR_2         ; routine PO_GR_2 to construct top half
  3063.                                         ; and continue into routine to construct bottom half.
  3064.  
  3065.                                         ;;;$0B3E
  3066. PO_GR_2:        RR      B               ; rotate bit 0/2 to carry
  3067.                 SBC     A,A             ; result $00 or $FF
  3068.                 AND     $0F             ; mask off right hand side
  3069.                 LD      C,A             ; store part in C
  3070.                 RR      B               ; rotate bit 1/3 of original chr to carry
  3071.                 SBC     A,A             ; result $00 or $FF
  3072.                 AND     $F0             ; mask off left hand side
  3073.                 OR      C               ; combine with stored pattern
  3074.                 LD      C,$04           ; four bytes for top/bottom half
  3075.  
  3076.                                         ;;;$0B4C
  3077. PO_GR_3:        LD      (HL),A          ; store bit patterns in temporary buffer
  3078.                 INC     HL              ; next address
  3079.                 DEC     C               ; jump back to
  3080.                 JR      NZ,PO_GR_3      ; to PO_GR_3 until byte is stored 4 times
  3081.  
  3082.                 RET                     ; return
  3083.  
  3084.                                         ; Tokens and User defined graphics are now separated.
  3085.  
  3086.                                         ;;;$0B52
  3087. PO_T_UDG:       SUB     $A5             ; the 'RND' character
  3088.                 JR      NC,PO_T         ; to PO_T to print tokens
  3089.  
  3090.                 ADD     A,$15           ; add 21d to restore to 0 - 20
  3091.                 PUSH    BC              ; save current print position
  3092.                 LD      BC,(UDG)        ; fetch UDG to address bit patterns
  3093.                 JR      PO_CHAR_2       ; to PO_CHAR_2 - common code to lay down
  3094.                                         ; a bit patterned character
  3095.  
  3096.                                         ;;;$0B5F
  3097. PO_T:           CALL    PO_TOKENS       ; routine PO_TOKENS prints tokens
  3098.                 JP      PO_FETCH        ; exit via PO_FETCH as this routine must continue into PO_STORE
  3099.  
  3100.                                         ; This point is used to print ascii characters  32d - 127d.
  3101.  
  3102.                                         ;;;$0B65
  3103. PO_CHAR:        PUSH    BC              ; save print position
  3104.                 LD      BC,(CHARS)      ; address CHARS
  3105.  
  3106.                                         ; This common code is used to transfer the character bytes to memory.
  3107.  
  3108.                                         ;;;$0B6A
  3109. PO_CHAR_2:      EX      DE,HL           ; transfer destination address to DE
  3110.                 LD      HL,FLAGS        ; point to FLAGS
  3111.                 RES     0,(HL)          ; allow for leading space
  3112.                 CP      $20             ; is it a space ?
  3113.                 JR      NZ,PO_CHAR_3    ; to PO_CHAR_3 if not
  3114.  
  3115.                 SET     0,(HL)          ; signal no leading space to FLAGS
  3116.  
  3117.                                         ;;;$0B76
  3118. PO_CHAR_3:      LD      H,$00           ; set high byte to 0
  3119.                 LD      L,A             ; character to A
  3120.                                         ; 0-21 UDG or 32-127 ascii.
  3121.                 ADD     HL,HL           ; multiply
  3122.                 ADD     HL,HL           ; by
  3123.                 ADD     HL,HL           ; eight
  3124.                 ADD     HL,BC           ; HL now points to first byte of character
  3125.                 POP     BC              ; the source address CHARS or UDG
  3126.                 EX      DE,HL           ; character address to DE
  3127.  
  3128. ;---------------------
  3129. ; Print all characters
  3130. ;---------------------
  3131. ; This entry point entered from above to print ascii and UDGs
  3132. ; but also from earlier to print mosaic characters.
  3133. ; HL=destination
  3134. ; DE=character source
  3135. ; BC=line/column
  3136.  
  3137.                                         ;;;$0B7F
  3138. PR_ALL:         LD      A,C             ; column to A
  3139.                 DEC     A               ; move right
  3140.                 LD      A,$21           ; pre-load with leftmost position
  3141.                 JR      NZ,PR_ALL_1     ; but if not zero to PR_ALL_1
  3142.  
  3143.                 DEC     B               ; down one line
  3144.                 LD      C,A             ; load C with $21
  3145.                 BIT     1,(IY+$01)      ; test FLAGS  - Is printer in use
  3146.                 JR      Z,PR_ALL_1      ; to PR_ALL_1 if not
  3147.  
  3148.                 PUSH    DE              ; save source address
  3149.                 CALL    COPY_BUFF       ; routine COPY_BUFF outputs line to printer
  3150.                 POP     DE              ; restore character source address
  3151.                 LD      A,C             ; the new column number ($21) to C
  3152.  
  3153.                                         ;;;$0B93
  3154. PR_ALL_1:       CP      C               ; this test is really for screen - new line ?
  3155.                 PUSH    DE              ; save source
  3156.                 CALL    Z,PO_SCR        ; routine PO_SCR considers scrolling
  3157.                 POP     DE              ; restore source
  3158.                 PUSH    BC              ; save line/column
  3159.                 PUSH    HL              ; and destination
  3160.                 LD      A,(P_FLAG)      ; fetch P_FLAG to accumulator
  3161.                 LD      B,$FF           ; prepare OVER mask in B.
  3162.                 RRA                     ; bit 0 set if OVER 1
  3163.                 JR      C,PR_ALL_2      ; to PR_ALL_2
  3164.  
  3165.                 INC     B               ; set OVER mask to 0
  3166.  
  3167.                                         ;;;$0BA4
  3168. PR_ALL_2:       RRA                     ; skip bit 1 of P_FLAG
  3169.                 RRA                     ; bit 2 is INVERSE
  3170.                 SBC     A,A             ; will be FF for INVERSE 1 else zero
  3171.                 LD      C,A             ; transfer INVERSE mask to C
  3172.                 LD      A,$08           ; prepare to count 8 bytes
  3173.                 AND     A               ; clear carry to signal screen
  3174.                 BIT     1,(IY+$01)      ; test FLAGS  - Is printer in use ?
  3175.                 JR      Z,PR_ALL_3      ; to PR_ALL_3 if screen
  3176.  
  3177.                 SET     1,(IY+$30)      ; update FLAGS2  - Signal printer buffer has been used.
  3178.                 SCF                     ; set carry flag to signal printer.
  3179.  
  3180.                                         ;;;$0BB6
  3181. PR_ALL_3:       EX      DE,HL           ; now HL=source, DE=destination
  3182.  
  3183.                                         ;;;$0BB7
  3184. PR_ALL_4:       EX      AF,AF'          ; save printer/screen flag
  3185.                 LD      A,(DE)          ; fetch existing destination byte
  3186.                 AND     B               ; consider OVER
  3187.                 XOR     (HL)            ; now XOR with source
  3188.                 XOR     C               ; now with INVERSE MASK
  3189.                 LD      (DE),A          ; update screen/printer
  3190.                 EX      AF,AF'          ; restore flag
  3191.                 JR      C,PR_ALL_6      ; to PR_ALL_6 - printer address update
  3192.  
  3193.                 INC     D               ; gives next pixel line down screen
  3194.  
  3195.                                         ;;;$0BC1
  3196. PR_ALL_5:       INC     HL              ; address next character byte
  3197.                 DEC     A               ; the byte count is decremented
  3198.                 JR      NZ,PR_ALL_4     ; back to PR_ALL_4 for all 8 bytes
  3199.  
  3200.                 EX      DE,HL           ; destination to HL
  3201.                 DEC     H               ; bring back to last updated screen position
  3202.                 BIT     1,(IY+$01)      ; test FLAGS  - is printer in use ?
  3203.                 CALL    Z,PO_ATTR       ; if not, call routine PO_ATTR to update corresponding colour attribute.
  3204.                 POP     HL              ; restore original screen/printer position
  3205.                 POP     BC              ; and line column
  3206.                 DEC     C               ; move column to right
  3207.                 INC     HL              ; increase screen/printer position
  3208.                 RET                     ; return and continue into PO_STORE within PO_ABLE
  3209.  
  3210.                                         ; This branch is used to update the printer position by 32 places
  3211.                                         ; Note. The high byte of the address D remains constant (which it should).
  3212.  
  3213.                                         ;;;$0BD3
  3214. PR_ALL_6:       EX      AF,AF'          ; save the flag
  3215.                 LD      A,$20           ; load A with 32 decimal
  3216.                 ADD     A,E             ; add this to E
  3217.                 LD      E,A             ; and store result in E
  3218.                 EX      AF,AF'          ; fetch the flag
  3219.                 JR      PR_ALL_5        ; back to PR_ALL_5
  3220.  
  3221. ;--------------
  3222. ; Set attribute
  3223. ;--------------
  3224. ; This routine is entered with the HL register holding the last screen
  3225. ; address to be updated by PRINT or PLOT.
  3226. ; The Spectrum screen arrangement leads to the L register holding
  3227. ; the correct value for the attribute file and it is only necessary
  3228. ; to manipulate H to form the correct colour attribute address.
  3229.  
  3230.                                         ;;;$0BDB
  3231. PO_ATTR:        LD      A,H             ; fetch high byte $40 - $57
  3232.                 RRCA                    ; shift
  3233.                 RRCA                    ; bits 3 and 4
  3234.                 RRCA                    ; to right.
  3235.                 AND     $03             ; range is now 0 - 2
  3236.                 OR      $58             ; form correct high byte for third of screen
  3237.                 LD      H,A             ; HL is now correct
  3238.                 LD      DE,(ATTRT_MASKT); make D hold ATTR_T, E hold MASK-T
  3239.                 LD      A,(HL)          ; fetch existing attribute
  3240.                 XOR     E               ; apply masks
  3241.                 AND     D
  3242.                 XOR     E
  3243.                 BIT     6,(IY+$57)      ; test P_FLAG  - is this PAPER 9 ??
  3244.                 JR      Z,PO_ATTR_1     ; skip to PO_ATTR_1 if not.
  3245.  
  3246.                 AND     $C7             ; set paper
  3247.                 BIT     2,A             ; to contrast with ink
  3248.                 JR      NZ,PO_ATTR_1    ; skip to PO_ATTR_1
  3249.  
  3250.                 XOR     $38
  3251.  
  3252.                                         ;;;$0BFA
  3253. PO_ATTR_1:      BIT     4,(IY+$57)      ; test P_FLAG  - Is this INK 9 ??
  3254.                 JR      Z,PO_ATTR_2     ; skip to PO_ATTR_2 if not
  3255.  
  3256.                 AND     $F8             ; make ink
  3257.                 BIT     5,A             ; contrast with paper.
  3258.                 JR      NZ,PO_ATTR_2    ; to PO_ATTR_2
  3259.  
  3260.                 XOR     $07
  3261.  
  3262.                                         ;;;$0C08
  3263. PO_ATTR_2:      LD      (HL),A          ; save the new attribute.
  3264.                 RET                     ; return.
  3265.  
  3266. ;-----------------
  3267. ; Message printing
  3268. ;-----------------
  3269. ; This entry point is used to print tape, boot-up, scroll? and error messages
  3270. ; On entry the DE register points to an initial step-over byte or
  3271. ; the inverted end-marker of the previous entry in the table.
  3272. ; A contains the message number, often zero to print first message.
  3273. ; (HL has nothing important usually P_FLAG)
  3274.  
  3275.                                         ;;;$0C0A
  3276. PO_MSG:         PUSH    HL              ; put hi-byte zero on stack to suppress
  3277.                 LD      H,$00           ; trailing spaces
  3278.                 EX      (SP),HL         ; ld h,0; push hl would have done ?.
  3279.                 JR      PO_TABLE        ; forward to PO_TABLE.
  3280.  
  3281.                                         ; This entry point prints the basic keywords, '<>' etc. from alt set
  3282.  
  3283.                                         ;;;$0C10
  3284. PO_TOKENS:      LD      DE,TKN_TABLE    ; address: TKN_TABLE
  3285.                 PUSH    AF              ; save the token number to control
  3286.                                         ; trailing spaces - see later *
  3287.  
  3288.                                         ;;;$0C14
  3289. PO_TABLE:       CALL    PO_SEARCH       ; routine PO_SEARCH will set carry for
  3290.                                         ; all messages and function words.
  3291.                 JR      C,PO_EACH       ; forward to PO_EACH if not a command,
  3292.                                         ; '<>' etc.
  3293.  
  3294.                 LD      A,$20           ; prepare leading space
  3295.                 BIT     0,(IY+$01)      ; test FLAGS  - leading space if not set
  3296.                 CALL    Z,PO_SAVE       ; routine PO_SAVE to print a space
  3297.                                         ; without disturbing registers
  3298.  
  3299.                                         ;;;$0C22
  3300. PO_EACH:        LD      A,(DE)          ; fetch character
  3301.                 AND     $7F             ; remove any inverted bit
  3302.                 CALL    PO_SAVE         ; routine PO_SAVE to print using alternate set of registers.
  3303.                 LD      A,(DE)          ; re-fetch character.
  3304.                 INC     DE              ; address next
  3305.                 ADD     A,A             ; was character inverted? (this also doubles character)
  3306.                 JR      NC,PO_EACH      ; back to PO_EACH if not
  3307.  
  3308.                 POP     DE              ; * re-fetch trailing space flag to D (was A)
  3309.                 CP      $48             ; was last character '$' ($24*2)
  3310.                 JR      Z,PO_TR_SP      ; forward to PO_TR_SP to consider trailing space if so.
  3311.  
  3312.                 CP      $82             ; was it < 'A' i.e. '#','>','=' from tokens
  3313.                                         ; or ' ','.' (from tape) or '?' from scroll
  3314.                 RET     C               ; no trailing space
  3315.  
  3316.                                         ;;;$0C35
  3317. PO_TR_SP:       LD      A,D             ; the trailing space flag (zero if an error msg)
  3318.                 CP      $03             ; test against RND, INKEY$ and PI
  3319.                                         ; which have no parameters and
  3320.                 RET     C               ; therefore no trailing space so return.
  3321.  
  3322.                 LD      A,$20           ; else continue and print a trailing space.
  3323.  
  3324. ;--------------------------
  3325. ; Handle recursive printing
  3326. ;--------------------------
  3327. ; This routine which is part of PRINT_OUT allows RST $10 to be
  3328. ; used recursively to print tokens and the spaces associated with them.
  3329.  
  3330.                                         ;;;$0C3B
  3331. PO_SAVE:        PUSH    DE              ; save DE as CALL_SUB doesn't.
  3332.                 EXX                     ; switch in main set
  3333.                 RST     10H             ; PRINT_A prints using this alternate set.
  3334.                 EXX                     ; back to this alternate set.
  3335.                 POP     DE              ; restore initial DE.
  3336.                 RET                     ; return.
  3337.  
  3338. ;-------------
  3339. ; Table search
  3340. ;-------------
  3341. ; This subroutine searches a message or the token table for the
  3342. ; message number held in A. DE holds the address of the table.
  3343.  
  3344.                                         ;;;$0C41
  3345. PO_SEARCH:      PUSH    AF              ; save the message/token number
  3346.                 EX      DE,HL           ; transfer DE to HL
  3347.                 INC     A               ; adjust for initial step-over byte
  3348.  
  3349.                                         ;;;$0C44
  3350. PO_STEP:        BIT     7,(HL)          ; is character inverted ?
  3351.                 INC     HL              ; address next
  3352.                 JR      Z,PO_STEP       ; back to PO-STEP if not inverted.
  3353.  
  3354.                 DEC     A               ; decrease counter
  3355.                 JR      NZ,PO_STEP      ; back to PO-STEP if not zero
  3356.  
  3357.                 EX      DE,HL           ; transfer address to DE
  3358.                 POP     AF              ; restore message/token number
  3359.                 CP      $20             ; return with carry set
  3360.                 RET     C               ; for all messages and function tokens
  3361.  
  3362.                 LD      A,(DE)          ; test first character of token
  3363.                 SUB     $41             ; and return with carry set
  3364.                 RET                     ; if it is less that 'A'
  3365.                                         ; i.e. '<>', '<=', '>='
  3366.  
  3367. ;----------------
  3368. ; Test for scroll
  3369. ;----------------
  3370. ; This test routine is called when printing carriage return, when considering
  3371. ; PRINT AT and from the general PRINT ALL characters routine to test if
  3372. ; scrolling is required, prompting the user if necessary.
  3373. ; This is therefore using the alternate set.
  3374. ; The B register holds the current line.
  3375.  
  3376.                                         ;;;$0C55
  3377. PO_SCR:         BIT     1,(IY+$01)      ; test FLAGS  - is printer in use ?
  3378.                 RET     NZ              ; return immediately if so.
  3379.  
  3380.                 LD      DE,CL_SET       ; set DE to address: CL_SET
  3381.                 PUSH    DE              ; and push for return address.
  3382.                 LD      A,B             ; transfer the line to A.
  3383.                 BIT     0,(IY+$02)      ; test TV_FLAG  - Lower screen in use ?
  3384.                 JP      NZ,PO_SCR_4     ; jump forward to PO_SCR_4 if so.
  3385.  
  3386.                 CP      (IY+$31)        ; greater than DF_SZ display file size ?
  3387.                 JR      C,REPORT_5      ; forward to REPORT_5 if less.
  3388.                                         ; 'Out of screen'
  3389.                 RET     NZ              ; return (via CL_SET) if greater
  3390.  
  3391.                 BIT     4,(IY+$02)      ; test TV_FLAG  - Automatic listing ?
  3392.                 JR      Z,PO_SCR_2      ; forward to PO_SCR_2 if not.
  3393.  
  3394.                 LD      E,(IY+$2D)      ; fetch BREG - the count of scroll lines to E.
  3395.                 DEC     E               ; decrease and jump
  3396.                 JR      Z,PO_SCR_3      ; to PO_SCR_3 if zero and scrolling required.
  3397.  
  3398.                 LD      A,$00           ; explicit - select channel zero.
  3399.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN opens it.
  3400.                 LD      SP,(LIST_SP)    ; set stack pointer to LIST_SP
  3401.                 RES     4,(IY+$02)      ; reset TV_FLAG  - signal auto listing finished.
  3402.                 RET                     ; return ignoring pushed value, CL_SET
  3403.                                         ; to MAIN or EDITOR without updating
  3404.                                         ; print position                        ->
  3405.  
  3406.  
  3407.                                         ;;;$0C86
  3408. REPORT_5:       RST     08H             ; ERROR_1
  3409.                 DEFB    $04             ; Error Report: Out of screen
  3410.  
  3411.                                         ; continue here if not an automatic listing.
  3412.  
  3413.                                         ;;;$0C88
  3414. PO_SCR_2:       DEC     (IY+$52)        ; decrease SCR_CT
  3415.                 JR      NZ,PO_SCR_3     ; forward to PO_SCR_3 to scroll display if
  3416.                                         ; result not zero.
  3417.  
  3418.                                         ; now produce prompt.
  3419.  
  3420.                 LD      A,$18           ; reset
  3421.                 SUB     B               ; the
  3422.                 LD      (SCR_CT),A      ; SCR_CT scroll count
  3423.                 LD      HL,(ATTRT_MASKT); L=ATTR_T, H=MASK_T
  3424.                 PUSH    HL              ; save on stack
  3425.                 LD      A,(P_FLAG)      ; P_FLAG
  3426.                 PUSH    AF              ; save on stack to prevent lower screen
  3427.                                         ; attributes (BORDCR etc.) being applied.
  3428.                 LD      A,$FD           ; select system channel 'K'
  3429.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN opens it
  3430.                 XOR     A               ; clear to address message directly
  3431.                 LD      DE,SCRL_MSSG    ; make DE address: SCRL_MSSG
  3432.                 CALL    PO_MSG          ; routine PO_MSG prints to lower screen
  3433.                 SET     5,(IY+$02)      ; set TV_FLAG  - signal lower screen requires clearing
  3434.                 LD      HL,FLAGS        ; make HL address FLAGS
  3435.                 SET     3,(HL)          ; signal 'L' mode.
  3436.                 RES     5,(HL)          ; signal 'no new key'.
  3437.                 EXX                     ; switch to main set.
  3438.                                         ; as calling chr input from alternative set.
  3439.                 CALL    WAIT_KEY        ; routine WAIT_KEY waits for new key
  3440.                                         ; Note. this is the right routine but the
  3441.                                         ; stream in use is unsatisfactory. From the
  3442.                                         ; choices available, it is however the best.
  3443.                 EXX                     ; switch back to alternate set.
  3444.                 CP      $20             ; space is considered as BREAK
  3445.                 JR      Z,REPORT_D      ; forward to REPORT_D if so
  3446.                                         ; 'BREAK - CONT repeats'
  3447.                 CP      $E2             ; is character 'STOP' ?
  3448.                 JR      Z,REPORT_D      ; forward to REPORT_D if so
  3449.  
  3450.                 OR      $20             ; convert to lower-case
  3451.                 CP      $6E             ; is character 'n' ?
  3452.                 JR      Z,REPORT_D      ; forward to REPORT_D if so else scroll.
  3453.  
  3454.                 LD      A,$FE           ; select system channel 'S'
  3455.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN
  3456.                 POP     AF              ; restore original P_FLAG
  3457.                 LD      (P_FLAG),A      ; and save in P_FLAG.
  3458.                 POP     HL              ; restore original ATTR_T, MASK_T
  3459.                 LD      (ATTRT_MASKT),HL; and reset ATTR_T, MASK-T as 'scroll?' has been printed.
  3460.  
  3461.                                         ;;;$0CD2
  3462. PO_SCR_3:       CALL    CL_SC_ALL       ; routine CL_SC_ALL to scroll whole display
  3463.                 LD      B,(IY+$31)      ; fetch DF_SZ to B
  3464.                 INC     B               ; increase to address last line of display
  3465.                 LD      C,$21           ; set C to $21 (was $21 from above routine)
  3466.                 PUSH    BC              ; save the line and column in BC.
  3467.                 CALL    CL_ADDR         ; routine CL_ADDR finds display address.
  3468.                 LD      A,H             ; now find the corresponding attribute byte
  3469.                 RRCA                    ; (this code sequence is used twice
  3470.                 RRCA                    ; elsewhere and is a candidate for
  3471.                 RRCA                    ; a subroutine.)
  3472.                 AND     $03
  3473.                 OR      $58
  3474.                 LD      H,A
  3475.                 LD      DE,$5AE0        ; start of last 'line' of attribute area
  3476.                 LD      A,(DE)          ; get attribute for last line
  3477.                 LD      C,(HL)          ; transfer to base line of upper part
  3478.                 LD      B,$20           ; there are thirty two bytes
  3479.                 EX      DE,HL           ; swap the pointers.
  3480.  
  3481.                                         ;;;$0CF0
  3482. PO_SCR_3A:      LD      (DE),A          ; transfer
  3483.                 LD      (HL),C          ; attributes.
  3484.                 INC     DE              ; address next.
  3485.                 INC     HL              ; address next.
  3486.                 DJNZ    PO_SCR_3A       ; loop back to PO_SCR_3A for all adjacent
  3487.                                         ; attribute lines.
  3488.                 POP     BC              ; restore the line/column.
  3489.                 RET                     ; return via CL_SET (was pushed on stack).
  3490.  
  3491.                                         ; The message 'scroll?' appears here with last byte inverted.
  3492.  
  3493.                                         ;;;$0CF8
  3494. SCRL_MSSG:      DEFB    $80             ; initial step-over byte.
  3495.                 DEFB    "scroll",'?'+$80
  3496.  
  3497.                                         ;;;$0D00
  3498. REPORT_D:       RST     08H             ; ERROR_1
  3499.                 DEFB    $0C             ; Error Report: BREAK - CONT repeats
  3500.  
  3501.                                         ; continue here if using lower display - A holds line number.
  3502.  
  3503.                                         ;;;$0D02
  3504. PO_SCR_4:       CP      $02             ; is line number less than 2 ?
  3505.                 JR      C,REPORT_5      ; to REPORT_5 if so
  3506.                                         ; 'Out of Screen'.
  3507.                 ADD     A,(IY+$31)      ; add DF_SZ
  3508.                 SUB     $19
  3509.                 RET     NC              ; return if scrolling unnecessary
  3510.  
  3511.                 NEG                     ; Negate to give number of scrolls required.
  3512.                 PUSH    BC              ; save line/column
  3513.                 LD      B,A             ; count to B
  3514.                 LD      HL,(ATTRT_MASKT); fetch current ATTR_T, MASK_T to HL.
  3515.                 PUSH    HL              ; and save
  3516.                 LD      HL,(P_FLAG)     ; fetch P_FLAG
  3517.                 PUSH    HL              ; and save.
  3518.                                         ; to prevent corruption by input AT
  3519.                 CALL    TEMPS           ; routine TEMPS sets to BORDCR etc
  3520.                 LD      A,B             ; transfer scroll number to A.
  3521.  
  3522.                                         ;;;$0D1C
  3523. PO_SCR_4A:      PUSH    AF              ; save scroll number.
  3524.                 LD      HL,DF_SZ        ; address DF_SZ
  3525.                 LD      B,(HL)          ; fetch old value
  3526.                 LD      A,B             ; transfer to A
  3527.                 INC     A               ; and increment
  3528.                 LD      (HL),A          ; then put back.
  3529.                 LD      HL,S_POSN_HI    ; address S_POSN_HI - line
  3530.                 CP      (HL)            ; compare
  3531.                 JR      C,PO_SCR_4B     ; forward to PO_SCR_4B if scrolling required
  3532.  
  3533.                 INC     (HL)            ; else increment S_POSN_HI
  3534.                 LD      B,$18           ; set count to whole display ??
  3535.                                         ; Note. should be $17 and the top line
  3536.                                         ; will be scrolled into the ROM which
  3537.                                         ; is harmless on the standard set up.
  3538.  
  3539.                                         ;;;$0D2D
  3540. PO_SCR_4B:      CALL    CL_SCROLL       ; routine CL_SCROLL scrolls B lines
  3541.                 POP     AF              ; restore scroll counter.
  3542.                 DEC     A               ; decrease
  3543.                 JR      NZ,PO_SCR_4A    ; back to to PO_SCR_4A until done
  3544.  
  3545.                 POP     HL              ; restore original P_FLAG.
  3546.                 LD      (IY+$57),L      ; and overwrite system variable P_FLAG.
  3547.                 POP     HL              ; restore original ATTR_T/MASK_T.
  3548.                 LD      (ATTRT_MASKT),HL; and update system variables.
  3549.                 LD      BC,(S_POSN)     ; fetch S_POSN to BC.
  3550.                 RES     0,(IY+$02)      ; signal to TV_FLAG  - main screen in use.
  3551.                 CALL    CL_SET          ; call routine CL_SET for upper display.
  3552.                 SET     0,(IY+$02)      ; signal to TV_FLAG  - lower screen in use.
  3553.                 POP     BC              ; restore line/column
  3554.                 RET                     ; return via CL_SET for lower display.
  3555.  
  3556. ;-----------------------
  3557. ; Temporary colour items
  3558. ;-----------------------
  3559. ; This subroutine is called 11 times to copy the permanent colour items
  3560. ; to the temporary ones.
  3561.  
  3562.                                         ;;;$0D4D
  3563. TEMPS:          XOR     A               ; clear the accumulator
  3564.                 LD      HL,(ATTRP_MASKP); fetch L=ATTR_P and H=MASK_P
  3565.                 BIT     0,(IY+$02)      ; test TV_FLAG  - is lower screen in use ?
  3566.                 JR      Z,TEMPS_1       ; skip to TEMPS_1 if not
  3567.  
  3568.                 LD      H,A             ; set H, MASK P, to 00000000.
  3569.                 LD      L,(IY+$0E)      ; fetch BORDCR to L which is used for lower screen.
  3570.  
  3571.                                         ;;;$0D5B
  3572. TEMPS_1:        LD      (ATTRT_MASKT),HL; transfer values to ATTR_T and MASK_T
  3573.  
  3574.                                         ; for the print flag the permanent values are odd bits, temporary even bits.
  3575.  
  3576.                 LD      HL,P_FLAG       ; address P_FLAG.
  3577.                 JR      NZ,TEMPS_2      ; skip to TEMPS_2 if lower screen using A=0.
  3578.  
  3579.                 LD      A,(HL)          ; else pick up flag bits.
  3580.                 RRCA                    ; rotate permanent bits to temporary bits.
  3581.  
  3582.                                         ;;;$0D65
  3583. TEMPS_2:        XOR     (HL)
  3584.                 AND     $55             ; BIN 01010101
  3585.                 XOR     (HL)            ; permanent now as original
  3586.                 LD      (HL),A          ; apply permanent bits to temporary bits.
  3587.                 RET                     ; and return.
  3588.  
  3589. ;-------------------
  3590. ; Handle CLS command
  3591. ;-------------------
  3592. ; clears the display.
  3593. ; if it's difficult to write it should be difficult to read.
  3594.  
  3595.                                         ;;;$0D6B
  3596. CLS:            CALL    CL_ALL          ; routine CL_ALL  clears display and
  3597.                                         ; resets attributes to permanent.
  3598.                                         ; re-attaches it to this computer.
  3599.  
  3600.                                         ; this routine called from input, **
  3601.  
  3602.                                         ;;;$0D6E
  3603. CLS_LOWER:      LD      HL,TV_FLAG      ; address TV_FLAG
  3604.                 RES     5,(HL)          ; TV_FLAG - signal do not clear lower screen.
  3605.                 SET     0,(HL)          ; TV_FLAG - signal lower screen in use.
  3606.                 CALL    TEMPS           ; routine TEMPS picks up temporary colours.
  3607.                 LD      B,(IY+$31)      ; fetch lower screen DF_SZ
  3608.                 CALL    CL_LINE         ; routine CL_LINE clears lower part
  3609.                                         ; and sets permanent attributes.
  3610.                 LD      HL,$5AC0        ; fetch attribute address leftmost cell, second line up.
  3611.                 LD      A,(ATTRP_MASKP) ; fetch permanent attribute from ATTR_P.
  3612.                 DEC     B               ; decrement lower screen display file size
  3613.                 JR      CLS_3           ; forward to CLS_3 ->
  3614.  
  3615.                                         ;;;$0D87
  3616. CLS_1:          LD      C,$20           ; set counter to 32 characters per line
  3617.  
  3618.                                         ;;;$0D89
  3619. CLS_2:          DEC     HL              ; decrease attribute address.
  3620.                 LD      (HL),A          ; and place attributes in next line up.
  3621.                 DEC     C               ; decrease 32 counter.
  3622.                 JR      NZ,CLS_2        ; loop back to CLS_2 until all 32 done.
  3623.  
  3624.                                         ;;;$0D8E
  3625. CLS_3:          DJNZ    CLS_1           ; decrease B counter and back to CLS_1
  3626.                                         ; if not zero.
  3627.                 LD      (IY+$31),$02    ; set DF_SZ lower screen to 2
  3628.  
  3629.                                         ; This entry point is called from CL_ALL below to
  3630.                                         ; reset the system channel input and output addresses to normal.
  3631.  
  3632.                                         ;;;$0D94
  3633. CL_CHAN:        LD      A,$FD           ; select system channel 'K'
  3634.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN opens it.
  3635.                 LD      HL,(CURCHL)     ; fetch CURCHL to HL to address current channel
  3636.                 LD      DE,PRINT_OUT    ; set address to PRINT_OUT for first pass.
  3637.                 AND     A               ; clear carry for first pass.
  3638.  
  3639.                                         ;;;$0DA0
  3640. CL_CHAN_A:      LD      (HL),E          ; insert output address first pass.
  3641.                 INC     HL              ; or input address on second pass.
  3642.                 LD      (HL),D
  3643.                 INC     HL
  3644.                 LD      DE,KEY_INPUT    ; fetch address KEY_INPUT for second pass
  3645.                 CCF                     ; complement carry flag - will set on pass 1.
  3646.                 JR      C,CL_CHAN_A     ; back to CL_CHAN_A if first pass else done.
  3647.  
  3648.                 LD      BC,$1721        ; line 23 for lower screen
  3649.                 JR      CL_SET          ; exit via CL_SET to set column
  3650.                                         ; for lower display
  3651.  
  3652. ;----------------------------
  3653. ; Clearing whole display area
  3654. ;----------------------------
  3655. ; This subroutine called from CLS, AUTO_LIST and MAIN_3
  3656. ; clears 24 lines of the display and resets the relevant system variables
  3657. ; and system channels.
  3658.  
  3659.                                         ;;;$0DAF
  3660. CL_ALL:         LD      HL,$0000        ; initialize plot coordinates.
  3661.                 LD      (COORDS),HL     ; set COORDS to 0,0.
  3662.                 RES     0,(IY+$30)      ; update FLAGS2  - signal main screen is clear.
  3663.                 CALL    CL_CHAN         ; routine CL_CHAN makes channel 'K' 'normal'.
  3664.                 LD      A,$FE           ; select system channel 'S'
  3665.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN opens it
  3666.                 CALL    TEMPS           ; routine TEMPS picks up permanent values.
  3667.                 LD      B,$18           ; There are 24 lines.
  3668.                 CALL    CL_LINE         ; routine CL_LINE clears 24 text lines
  3669.                                         ; (and sets BC to $1821)
  3670.                 LD      HL,(CURCHL)     ; fetch CURCHL make HL address current channel 'S'
  3671.                 LD      DE,PRINT_OUT    ; address: PRINT_OUT
  3672.                 LD      (HL),E          ; is made
  3673.                 INC     HL              ; the normal
  3674.                 LD      (HL),D          ; output address.
  3675.                 LD      (IY+$52),$01    ; set SCR_CT - scroll count is set to default.
  3676.                                         ; Note. BC already contains $1821.
  3677.                 LD      BC,$1821        ; reset column and line to 0,0
  3678.                                         ; and continue into CL_SET, below, exiting
  3679.                                         ; via PO_STORE (for upper screen).
  3680.  
  3681. ;----------------------------
  3682. ; Set line and column numbers
  3683. ;----------------------------
  3684. ; This important subroutine is used to calculate the character output
  3685. ; address for screens or printer based on the line/column for screens
  3686. ; or the column for printer.
  3687.  
  3688.                                         ;;;$0DD9
  3689. CL_SET:         LD      HL,$5B00        ; the base address of printer buffer
  3690.                 BIT     1,(IY+$01)      ; test FLAGS  - is printer in use ?
  3691.                 JR      NZ,CL_SET_2     ; forward to CL_SET_2 if so.
  3692.  
  3693.                 LD      A,B             ; transfer line to A.
  3694.                 BIT     0,(IY+$02)      ; test TV_FLAG  - lower screen in use ?
  3695.                 JR      Z,CL_SET_1      ; skip to CL_SET_1 if handling upper part
  3696.  
  3697.                 ADD     A,(IY+$31)      ; add DF_SZ for lower screen
  3698.                 SUB     $18             ; and adjust.
  3699.  
  3700.                                         ;;;$0DEE
  3701. CL_SET_1:       PUSH    BC              ; save the line/column.
  3702.                 LD      B,A             ; transfer line to B
  3703.                                         ; (adjusted if lower screen)
  3704.                 CALL    CL_ADDR         ; routine CL_ADDR calculates address at left of screen.
  3705.                 POP     BC              ; restore the line/column.
  3706.  
  3707.                                         ;;;$0DF4
  3708. CL_SET_2:       LD      A,$21           ; the column $1-$21 is reversed
  3709.                 SUB     C               ; to range $00 - $20
  3710.                 LD      E,A             ; now transfer to DE
  3711.                 LD      D,$00           ; prepare for addition
  3712.                 ADD     HL,DE           ; and add to base address
  3713.                 JP      PO_STORE        ; exit via PO_STORE to update relevant
  3714.                                         ; system variables.
  3715. ;-----------------
  3716. ; Handle scrolling
  3717. ;-----------------
  3718. ; The routine CL_SC_ALL is called once from PO to scroll all the display
  3719. ; and from the routine CL_SCROLL, once, to scroll part of the display.
  3720.  
  3721.                                         ;;;$0DFE
  3722. CL_SC_ALL:      LD      B,$17           ; scroll 23 lines, after 'scroll?'.
  3723.  
  3724.                                         ;;;$0E00
  3725. CL_SCROLL:      CALL    CL_ADDR         ; routine CL_ADDR gets screen address in HL.
  3726.                 LD      C,$08           ; there are 8 pixel lines to scroll.
  3727.  
  3728.                                         ;;;$0E05
  3729. CL_SCR_1:       PUSH    BC              ; save counters.
  3730.                 PUSH    HL              ; and initial address.
  3731.                 LD      A,B             ; get line count.
  3732.                 AND     $07             ; will set zero if all third to be scrolled.
  3733.                 LD      A,B             ; re-fetch the line count.
  3734.                 JR      NZ,CL_SCR_3     ; forward to CL_SCR_3 if partial scroll.
  3735.  
  3736.                                         ; HL points to top line of third and must be copied to bottom of previous 3rd.
  3737.                                         ; ( so HL = $4800 or $5000 ) ( but also sometimes $4000 )
  3738.  
  3739.                                         ;;;$0E0D
  3740. CL_SCR_2:       EX      DE,HL           ; copy HL to DE.
  3741.                 LD      HL,$F8E0        ; subtract $08 from H and add $E0 to L -
  3742.                 ADD     HL,DE           ; to make destination bottom line of previous third.
  3743.                 EX      DE,HL           ; restore the source and destination.
  3744.                 LD      BC,$0020        ; thirty-two bytes are to be copied.
  3745.                 DEC     A               ; decrement the line count.
  3746.                 LDIR                    ; copy a pixel line to previous third.
  3747.  
  3748.                                         ;;;$0E19
  3749. CL_SCR_3:       EX      DE,HL           ; save source in DE.
  3750.                 LD      HL,$FFE0        ; load the value -32.
  3751.                 ADD     HL,DE           ; add to form destination in HL.
  3752.                 EX      DE,HL           ; switch source and destination
  3753.                 LD      B,A             ; save the count in B.
  3754.                 AND     $07             ; mask to find count applicable to current
  3755.                 RRCA                    ; third and
  3756.                 RRCA                    ; multiply by
  3757.                 RRCA                    ; thirty two (same as 5 RLCAs)
  3758.                 LD      C,A             ; transfer byte count to C ($E0 at most)
  3759.                 LD      A,B             ; store line count to A
  3760.                 LD      B,$00           ; make B zero
  3761.                 LDIR                    ; copy bytes (BC=0, H incremented, L=0)
  3762.                 LD      B,$07           ; set B to 7, C is zero.
  3763.                 ADD     HL,BC           ; add 7 to H to address next third.
  3764.                 AND     $F8             ; has last third been done ?
  3765.                 JR      NZ,CL_SCR_2     ; back to CL_SCR_2 if not
  3766.  
  3767.                 POP     HL              ; restore topmost address.
  3768.                 INC     H               ; next pixel line down.
  3769.                 POP     BC              ; restore counts.
  3770.                 DEC     C               ; reduce pixel line count.
  3771.                 JR      NZ,CL_SCR_1     ; back to CL_SCR_1 if all eight not done.
  3772.  
  3773.                 CALL    CL_ATTR         ; routine CL_ATTR gets address in attributes
  3774.                                         ; from current 'ninth line', count in BC.
  3775.                 LD      HL,$FFE0        ; set HL to the 16-bit value -32.
  3776.                 ADD     HL,DE           ; and add to form destination address.
  3777.                 EX      DE,HL           ; swap source and destination addresses.
  3778.                 LDIR                    ; copy bytes scrolling the linear attributes.
  3779.                 LD      B,$01           ; continue to clear the bottom line.
  3780.  
  3781. ;----------------------------
  3782. ; Clear text lines of display
  3783. ;----------------------------
  3784. ; This subroutine, called from CL_ALL, CLS_LOWER and AUTO_LIST and above,
  3785. ; clears text lines at bottom of display.
  3786. ; The B register holds on entry the number of lines to be cleared 1-24.
  3787.  
  3788.                                         ;;;$0E44
  3789. CL_LINE:        PUSH    BC              ; save line count
  3790.                 CALL    CL_ADDR         ; routine CL_ADDR gets top address
  3791.                 LD      C,$08           ; there are eight screen lines to a text line.
  3792.  
  3793.                                         ;;;$0E4A
  3794. CL_LINE_1:      PUSH    BC              ; save pixel line count
  3795.                 PUSH    HL              ; and save the address
  3796.                 LD      A,B             ; transfer the line to A (1-24).
  3797.  
  3798.                                         ;;;$0E4D
  3799. CL_LINE_2:      AND     $07             ; mask 0-7 to consider thirds at a time
  3800.                 RRCA                    ; multiply
  3801.                 RRCA                    ; by 32  (same as five RLCA instructions)
  3802.                 RRCA                    ; now 32 - 256(0)
  3803.                 LD      C,A             ; store result in C
  3804.                 LD      A,B             ; save line in A (1-24)
  3805.                 LD      B,$00           ; set high byte to 0, prepare for ldir.
  3806.                 DEC     C               ; decrement count 31-255.
  3807.                 LD      D,H             ; copy HL
  3808.                 LD      E,L             ; to DE.
  3809.                 LD      (HL),$00        ; blank the first byte.
  3810.                 INC     DE              ; make DE point to next byte.
  3811.                 LDIR                    ; ldir will clear lines.
  3812.                 LD      DE,$0701        ; now address next third adjusting
  3813.                 ADD     HL,DE           ; register E to address left hand side
  3814.                 DEC     A               ; decrease the line count.
  3815.                 AND     $F8             ; will be 16, 8 or 0  (AND $18 will do).
  3816.                 LD      B,A             ; transfer count to B.
  3817.                 JR      NZ,CL_LINE_2    ; back to CL_LINE_2 if 16 or 8 to do
  3818.                                         ; the next third.
  3819.                 POP     HL              ; restore start address.
  3820.                 INC     H               ; address next line down.
  3821.                 POP     BC              ; fetch counts.
  3822.                 DEC     C               ; decrement pixel line count
  3823.                 JR      NZ,CL_LINE_1    ; back to CL_LINE_1 till all done.
  3824.  
  3825.                 CALL    CL_ATTR         ; routine CL_ATTR gets attribute address
  3826.                                         ; in DE and B * 32 in BC.
  3827.                 LD      H,D             ; transfer the address
  3828.                 LD      L,E             ; to HL.
  3829.                 INC     DE              ; make DE point to next location.
  3830.                 LD      A,(ATTRP_MASKP) ; fetch ATTR_P - permanent attributes
  3831.                 BIT     0,(IY+$02)      ; test TV_FLAG  - lower screen in use ?
  3832.                 JR      Z,CL_LINE_3     ; skip to CL_LINE_3 if not.
  3833.  
  3834.                 LD      A,(BORDCR)      ; else lower screen uses BORDCR as attribute.
  3835.  
  3836.                                         ;;;$0E80
  3837. CL_LINE_3:      LD      (HL),A          ; put attribute in first byte.
  3838.                 DEC     BC              ; decrement the counter.
  3839.                 LDIR                    ; copy bytes to set all attributes.
  3840.                 POP     BC              ; restore the line $01-$24.
  3841.                 LD      C,$21           ; make column $21. (No use is made of this)
  3842.                 RET                     ; return to the calling routine.
  3843.  
  3844. ;-------------------
  3845. ; Attribute handling
  3846. ;-------------------
  3847. ; This subroutine is called from CL_LINE or CL_SCROLL with the HL register
  3848. ; pointing to the 'ninth' line and H needs to be decremented before or after
  3849. ; the division. Had it been done first then either present code or that used
  3850. ; at the start of PO_ATTR could have been used.
  3851. ; The Spectrum screen arrangement leads to the L register holding already
  3852. ; the correct value for the attribute file and it is only necessary
  3853. ; to manipulate H to form the correct colour attribute address.
  3854.  
  3855.                                         ;;;$0E88
  3856. CL_ATTR:        LD      A,H             ; fetch H to A - $48, $50, or $58.
  3857.                 RRCA                    ; divide by
  3858.                 RRCA                    ; eight.
  3859.                 RRCA                    ; $09, $0A or $0B.
  3860.                 DEC     A               ; $08, $09 or $0A.
  3861.                 OR      $50             ; $58, $59 or $5A.
  3862.                 LD      H,A             ; save high byte of attributes.
  3863.                 EX      DE,HL           ; transfer attribute address to DE
  3864.                 LD      H,C             ; set H to zero - from last LDIR.
  3865.                 LD      L,B             ; load L with the line from B.
  3866.                 ADD     HL,HL           ; multiply
  3867.                 ADD     HL,HL           ; by
  3868.                 ADD     HL,HL           ; thirty two
  3869.                 ADD     HL,HL           ; to give count of attribute
  3870.                 ADD     HL,HL           ; cells to end of display.
  3871.                 LD      B,H             ; transfer result
  3872.                 LD      C,L             ; to register BC.
  3873.                 RET                     ; and return.
  3874.  
  3875. ;--------------------------------
  3876. ; Handle display with line number
  3877. ;--------------------------------
  3878. ; This subroutine is called from four places to calculate the address
  3879. ; of the start of a screen character line which is supplied in B.
  3880.  
  3881.                                         ;;;$0E9B
  3882. CL_ADDR:        LD      A,$18           ; reverse the line number
  3883.                 SUB     B               ; to range $00 - $17.
  3884.                 LD      D,A             ; save line in D for later.
  3885.                 RRCA                    ; multiply
  3886.                 RRCA                    ; by
  3887.                 RRCA                    ; thirty-two.
  3888.                 AND     $E0             ; mask off low bits to make
  3889.                 LD      L,A             ; L a multiple of 32.
  3890.                 LD      A,D             ; bring back the line to A.
  3891.                 AND     $18             ; now $00, $08 or $10.
  3892.                 OR      $40             ; add the base address of screen.
  3893.                 LD      H,A             ; HL now has the correct address.
  3894.                 RET                     ; return.
  3895.  
  3896. ;--------------------
  3897. ; Handle COPY command
  3898. ;--------------------
  3899. ; This command copies the top 176 lines to the ZX Printer
  3900. ; It is popular to call this from machine code at point
  3901. ; L0EAF with B holding 192 (and interrupts disabled) for a full-screen
  3902. ; copy. This particularly applies to 16K Spectrums as time-critical
  3903. ; machine code routines cannot be written in the first 16K of RAM as
  3904. ; it is shared with the ULA which has precedence over the Z80 chip.
  3905.  
  3906.                                         ;;;$0EAC
  3907. COPY:           DI                      ; disable interrupts as this is time-critical.
  3908.                 LD      B,$B0           ; top 176 lines.
  3909. L0EAF:          LD      HL,$4000        ; address start of the display file.
  3910.  
  3911.                                         ; now enter a loop to handle each pixel line.
  3912.  
  3913.                                         ;;;$0EB2
  3914. COPY_1:         PUSH    HL              ; save the screen address.
  3915.                 PUSH    BC              ; and the line counter.
  3916.                 CALL    COPY_LINE       ; routine COPY_LINE outputs one line.
  3917.                 POP     BC              ; restore the line counter.
  3918.                 POP     HL              ; and display address.
  3919.                 INC     H               ; next line down screen within 'thirds'.
  3920.                 LD      A,H             ; high byte to A.
  3921.                 AND     $07             ; result will be zero if we have left third.
  3922.                 JR      NZ,COPY_2       ; forward to COPY_2 if not to continue loop.
  3923.  
  3924.                 LD      A,L             ; consider low byte first.
  3925.                 ADD     A,$20           ; increase by 32 - sets carry if back to zero.
  3926.                 LD      L,A             ; will be next group of 8.
  3927.                 CCF                     ; complement - carry set if more lines in the previous third.
  3928.                 SBC     A,A             ; will be FF, if more, else 00.
  3929.                 AND     $F8             ; will be F8 (-8) or 00.
  3930.                 ADD     A,H             ; that is subtract 8, if more to do in third.
  3931.                 LD      H,A             ; and reset address.
  3932.  
  3933.                                         ;;;$0EC9
  3934. COPY_2:         DJNZ    COPY_1          ; back to COPY_1 for all lines.
  3935.                 JR      COPY_END        ; forward to COPY_END to switch off the printer
  3936.                                         ; motor and enable interrupts.
  3937.                                         ; Note. Nothing else required.
  3938.  
  3939. ;-------------------------------
  3940. ; Pass printer buffer to printer
  3941. ;-------------------------------
  3942. ; This routine is used to copy 8 text lines from the printer buffer
  3943. ; to the ZX Printer. These text lines are mapped linearly so HL does
  3944. ; not need to be adjusted at the end of each line.
  3945.  
  3946.                                         ;;;$0ECD
  3947. COPY_BUFF:      DI                      ; disable interrupts
  3948.                 LD      HL,$5B00        ; the base address of the Printer Buffer.
  3949.                 LD      B,$08           ; set count to 8 lines of 32 bytes.
  3950.  
  3951.                                         ;;;$0ED3
  3952. COPY_3:         PUSH    BC              ; save counter.
  3953.                 CALL    COPY_LINE       ; routine COPY_LINE outputs 32 bytes
  3954.                 POP     BC              ; restore counter.
  3955.                 DJNZ    COPY_3          ; loop back to COPY_3 for all 8 lines.
  3956.                                         ; then stop motor and clear buffer.
  3957.  
  3958.                                         ; Note. the COPY command rejoins here, essentially to execute the next
  3959.                                         ; three instructions.
  3960.  
  3961.                                         ;;;$0EDA
  3962. COPY_END:       LD      A,$04           ; output value 4 to port
  3963.                 OUT     ($FB),A         ; to stop the slowed printer motor.
  3964.                 EI                      ; enable interrupts.
  3965.  
  3966. ;---------------------
  3967. ; Clear Printer Buffer
  3968. ;---------------------
  3969. ; This routine clears an arbitrary 256 bytes of memory.
  3970. ; Note. The routine seems designed to clear a buffer that follows the
  3971. ; system variables.
  3972. ; The routine should check a flag or HL address and simply return if COPY
  3973. ; is in use.
  3974. ; (T-ADDR-lo would work for the system but not if COPY called externally.)
  3975. ; As a consequence of this omission the buffer will needlessly
  3976. ; be cleared when COPY is used and the screen/printer position may be set to
  3977. ; the start of the buffer and the line number to 0 (B)
  3978. ; giving an 'Out of Screen' error.
  3979. ; There seems to have been an unsuccessful attempt to circumvent the use
  3980. ; of PR_CC_hi.
  3981.  
  3982.                                         ;;;$0EDF
  3983. CLEAR_PRB:      LD      HL,$5B00        ; the location of the buffer.
  3984.                 LD      (IY+$46),L      ; update PR_CC_lo - set to zero - superfluous.
  3985.                 XOR     A               ; clear the accumulator.
  3986.                 LD      B,A             ; set count to 256 bytes.
  3987.  
  3988.                                         ;;;$0EE7
  3989. PRB_BYTES:      LD      (HL),A          ; set addressed location to zero.
  3990.                 INC     HL              ; address next byte - Note. not INC L.
  3991.                 DJNZ    PRB_BYTES       ; back to PRB_BYTES. repeat for 256 bytes.
  3992.                 RES     1,(IY+$30)      ; set FLAGS2 - signal printer buffer is clear.
  3993.                 LD      C,$21           ; set the column position .
  3994.                 JP      CL_SET          ; exit via CL_SET and then PO_STORE.
  3995.  
  3996. ;------------------
  3997. ; Copy line routine
  3998. ;------------------
  3999. ; This routine is called from COPY and COPY_BUFF to output a line of
  4000. ; 32 bytes to the ZX Printer.
  4001. ; Output to port $FB -
  4002. ; bit 7 set - activate stylus.
  4003. ; bit 7 low - deactivate stylus.
  4004. ; bit 2 set - stops printer.
  4005. ; bit 2 reset - starts printer
  4006. ; bit 1 set - slows printer.
  4007. ; bit 1 reset - normal speed.
  4008.  
  4009.                                         ;;;$0EF4
  4010. COPY_LINE:      LD      A,B             ; fetch the counter 1-8 or 1-176
  4011.                 CP      $03             ; is it 01 or 02 ?.
  4012.                 SBC     A,A             ; result is $FF if so else $00.
  4013.                 AND     $02             ; result is 02 now else 00.
  4014.                                         ; bit 1 set slows the printer.
  4015.                 OUT     ($FB),A         ; slow the printer for the
  4016.                                         ; last two lines.
  4017.                 LD      D,A             ; save the mask to control the printer later.
  4018.  
  4019.                                         ;;;$0EFD
  4020. COPY_L_1:       CALL    BREAK_KEY       ; call BREAK_KEY to read keyboard immediately.
  4021.                 JR      C,COPY_L_2      ; forward to COPY_L_2 if 'break' not pressed.
  4022.  
  4023.                 LD      A,$04           ; else stop the
  4024.                 OUT     ($FB),A         ; printer motor.
  4025.                 EI                      ; enable interrupts.
  4026.                 CALL    CLEAR_PRB       ; call routine CLEAR_PRB.
  4027.                                         ; Note. should not be cleared if COPY in use.
  4028.  
  4029.                                         ;;;$0F0A
  4030. REPORT_DC:      RST     08H             ; ERROR_1
  4031.                 DEFB    $0C             ; Error Report: BREAK - CONT repeats
  4032.  
  4033.                                         ;;;$0F0C
  4034. COPY_L_2:       IN      A,($FB)         ; test now to see if
  4035.                 ADD     A,A             ; a printer is attached.
  4036.                 RET     M               ; return if not - but continue with parent
  4037.                                         ; command.
  4038.                 JR      NC,COPY_L_1     ; back to COPY_L_1 if stylus of printer not
  4039.                                         ; in position.
  4040.                 LD      C,$20           ; set count to 32 bytes.
  4041.  
  4042.                                         ;;;$0F14
  4043. COPY_L_3:       LD      E,(HL)          ; fetch a byte from line.
  4044.                 INC     HL              ; address next location. Note. not INC L.
  4045.                 LD      B,$08           ; count the bits.
  4046.  
  4047.                                         ;;;$0F18
  4048. COPY_L_4:       RL      D               ; prepare mask to receive bit.
  4049.                 RL      E               ; rotate leftmost print bit to carry
  4050.                 RR      D               ; and back to bit 7 of D restoring bit 1
  4051.  
  4052.                                         ;;;$0F1E
  4053. COPY_L_5:       IN      A,($FB)         ; read the port.
  4054.                 RRA                     ; bit 0 to carry.
  4055.                 JR      NC,COPY_L_5     ; back to COPY_L_5 if stylus not in position.
  4056.  
  4057.                 LD      A,D             ; transfer command bits to A.
  4058.                 OUT     ($FB),A         ; and output to port.
  4059.                 DJNZ    COPY_L_4        ; loop back to COPY_L_4 for all 8 bits.
  4060.                 DEC     C               ; decrease the byte count.
  4061.                 JR      NZ,COPY_L_3     ; back to COPY_L_3 until 256 bits done.
  4062.  
  4063.                 RET                     ; return to calling routine COPY/COPY_BUFF.
  4064.  
  4065.  
  4066. ;-----------------------------------
  4067. ; Editor routine for BASIC and INPUT
  4068. ;-----------------------------------
  4069. ; The editor is called to prepare or edit a basic line.
  4070. ; It is also called from INPUT to input a numeric or string expression.
  4071. ; The behaviour and options are quite different in the various modes
  4072. ; and distinguished by bit 5 of FLAGX.
  4073. ;
  4074. ; This is a compact and highly versatile routine.
  4075.  
  4076.                                         ;;;$0F2C
  4077. EDITOR:         LD      HL,(ERR_SP)     ; fetch ERR_SP
  4078.                 PUSH    HL              ; save on stack
  4079.  
  4080.                                         ;;;$0F30
  4081. ED_AGAIN:       LD      HL,ED_ERROR     ; address: ED_ERROR
  4082.                 PUSH    HL              ; save address on stack and
  4083.                 LD      (ERR_SP),SP     ; make ERR_SP point to it.
  4084.  
  4085.                                         ; Note. While in editing/input mode should an error occur then RST 08 will
  4086.                                         ; update X_PTR to the location reached by CH_ADD and jump to ED_ERROR
  4087.                                         ; where the error will be cancelled and the loop begin again from ED_AGAIN
  4088.                                         ; above. The position of the error will be apparent when the lower screen is
  4089.                                         ; reprinted. If no error then the re-iteration is to ED_LOOP below when
  4090.                                         ; input is arriving from the keyboard.
  4091.  
  4092.                                         ;;;$0F38
  4093. ED_LOOP:        CALL    WAIT_KEY        ; routine WAIT_KEY gets key possibly changing the mode.
  4094.                 PUSH    AF              ; save key.
  4095.                 LD      D,$00           ; and give a short click based
  4096.                 LD      E,(IY-$01)      ; on PIP value for duration.
  4097.                 LD      HL,$00C8        ; and pitch.
  4098.                 CALL    BEEPER          ; routine BEEPER gives click - effective with rubber keyboard.
  4099.                 POP     AF              ; get saved key value.
  4100.                 LD      HL,ED_LOOP      ; address: ED_LOOP is loaded to HL.
  4101.                 PUSH    HL              ; and pushed onto stack.
  4102.  
  4103.                                         ; At this point there is a looping return address on the stack, an error
  4104.                                         ; handler and an input stream set up to supply characters.
  4105.                                         ; The character that has been received can now be processed.
  4106.  
  4107.                 CP      $18             ; range 24 to 255 ?
  4108.                 JR      NC,ADD_CHAR     ; forward to ADD_CHAR if so.
  4109.  
  4110.                 CP      $07             ; lower than 7 ?
  4111.                 JR      C,ADD_CHAR      ; forward to ADD_CHAR also.
  4112.                                         ; Note. This is a 'bug' and CHR$ 6, the comma
  4113.                                         ; control character, should have had an
  4114.                                         ; entry in the ED_KEYS table.
  4115.                                         ; Steven Vickers, 1984, Pitman.
  4116.                 CP      $10             ; less than 16 ?
  4117.                 JR      C,ED_KEYS       ; forward to ED_KEYS if editing control
  4118.                                         ; range 7 to 15 dealt with by a table
  4119.                 LD      BC,$0002        ; prepare for ink/paper etc.
  4120.                 LD      D,A             ; save character in D
  4121.                 CP      $16             ; is it ink/paper/bright etc. ?
  4122.                 JR      C,ED_CONTR      ; forward to ED_CONTR if so
  4123.  
  4124.                                         ; leaves 22d AT and 23d TAB
  4125.                                         ; which can't be entered via KEY_INPUT.
  4126.                                         ; so this code is never normally executed
  4127.                                         ; when the keyboard is used for input.
  4128.  
  4129.                 INC     BC              ; if it was AT/TAB - 3 locations required
  4130.                 BIT     7,(IY+$37)      ; test FLAGX  - Is this INPUT LINE ?
  4131.                 JP      Z,ED_IGNORE     ; jump to ED_IGNORE if not, else
  4132.  
  4133.                 CALL    WAIT_KEY        ; routine WAIT_KEY - input address is KEY_NEXT
  4134.                                         ; but is reset to KEY_INPUT
  4135.                 LD      E,A             ; save first in E
  4136.  
  4137.                                         ;;;$0F6C
  4138. ED_CONTR:       CALL    WAIT_KEY        ; routine WAIT_KEY for control.
  4139.                                         ; input address will be KEY_NEXT.
  4140.                 PUSH    DE              ; saved code/parameters
  4141.                 LD      HL,(K_CUR)      ; fetch address of keyboard cursor from K_CUR
  4142.                 RES     0,(IY+$07)      ; set MODE to 'L'
  4143.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM makes 2/3 spaces at cursor
  4144.                 POP     BC              ; restore code/parameters
  4145.                 INC     HL              ; address first location
  4146.                 LD      (HL),B          ; place code (ink etc.)
  4147.                 INC     HL              ; address next
  4148.                 LD      (HL),C          ; place possible parameter. If only one
  4149.                                         ; then DE points to this location also.
  4150.                 JR      ADD_CH_1        ; forward to ADD_CH_1
  4151.  
  4152. ;-------------------------
  4153. ; Add code to current line
  4154. ;-------------------------
  4155. ; this is the branch used to add normal non-control characters
  4156. ; with ED_LOOP as the stacked return address.
  4157. ; it is also the OUTPUT service routine for system channel 'R'.
  4158.  
  4159.                                         ;;;$0F81
  4160. ADD_CHAR:       RES     0,(IY+$07)      ; set MODE to 'L'
  4161.                 LD      HL,(K_CUR)      ; fetch address of keyboard cursor from K_CUR
  4162.                 CALL    ONE_SPACE       ; routine ONE_SPACE creates one space.
  4163.  
  4164.                                         ; either a continuation of above or from ED_CONTR with ED_LOOP on stack.
  4165.  
  4166.                                         ;;;$0F8B
  4167. ADD_CH_1:       LD      (DE),A          ; load current character to last new location.
  4168.                 INC     DE              ; address next
  4169.                 LD      (K_CUR),DE      ; and update K_CUR system variable.
  4170.                 RET                     ; return - either a simple return
  4171.                                         ; from ADD_CHAR or to ED_LOOP on stack.
  4172.  
  4173.                                         ; a branch of the editing loop to deal with control characters
  4174.                                         ; using a look-up table.
  4175.  
  4176.                                         ;;;$0F92
  4177. ED_KEYS:        LD      E,A             ; character to E.
  4178.                 LD      D,$00           ; prepare to add.
  4179.                 LD      HL,ED_KEYS_T - 7; base address of editing keys table. $0F99
  4180.                 ADD     HL,DE           ; add E
  4181.                 LD      E,(HL)          ; fetch offset to E
  4182.                 ADD     HL,DE           ; add offset for address of handling routine.
  4183.                 PUSH    HL              ; push the address on machine stack.
  4184.                 LD      HL,(K_CUR)      ; load address of cursor from K_CUR.
  4185.                 RET                     ; an make an indirect jump forward to routine.
  4186.  
  4187. ;-------------------
  4188. ; Editing keys table
  4189. ;-------------------
  4190. ; For each code in the range $07 to $0F this table contains a
  4191. ; single offset byte to the routine that services that code.
  4192. ; Note. for what was intended there should also have been an
  4193. ; entry for CHR$ 6 with offset to ED_SYMBOL.
  4194.  
  4195.                                         ;;;$0FA0
  4196. ED_KEYS_T:      DEFB    ED_EDIT - $     ; 07d offset $09 to Address: ED_EDIT
  4197.                 DEFB    ED_LEFT - $     ; 08d offset $66 to Address: ED_LEFT
  4198.                 DEFB    ED_RIGHT - $    ; 09d offset $6A to Address: ED_RIGHT
  4199.                 DEFB    ED_DOWN - $     ; 10d offset $50 to Address: ED_DOWN
  4200.                 DEFB    ED_UP - $       ; 11d offset $B5 to Address: ED_UP
  4201.                 DEFB    ED_DELETE - $   ; 12d offset $70 to Address: ED_DELETE
  4202.                 DEFB    ED_ENTER - $    ; 13d offset $7E to Address: ED_ENTER
  4203.                 DEFB    ED_SYMBOL - $   ; 14d offset $CF to Address: ED-SYMBOL
  4204.                 DEFB    ED_GRAPH - $    ; 15d offset $D4 to Address: ED_GRAPH
  4205.  
  4206. ;----------------
  4207. ; Handle EDIT key
  4208. ;----------------
  4209. ; The user has pressed SHIFT 1 to bring edit line down to bottom of screen.
  4210. ; Alternatively the user wishes to clear the input buffer and start again.
  4211. ; Alternatively ...
  4212.  
  4213.                                         ;;;$0FA9
  4214. ED_EDIT:        LD      HL,(E_PPC)      ; fetch E_PPC the last line number entered.
  4215.                                         ; Note. may not exist and may follow program.
  4216.                 BIT     5,(IY+$37)      ; test FLAGX  - input mode ?
  4217.                 JP      NZ,CLEAR_SP     ; jump forward to CLEAR_SP if not in editor.
  4218.  
  4219.                 CALL    LINE_ADDR       ; routine LINE_ADDR to find address of line
  4220.                                         ; or following line if it doesn't exist.
  4221.                 CALL    LINE_NO         ; routine LINE_NO will get line number from
  4222.                                         ; address or previous line if at end-marker.
  4223.                 LD      A,D             ; if there is no program then DE will
  4224.                 OR      E               ; contain zero so test for this.
  4225.                 JP      Z,CLEAR_SP      ; jump to to CLEAR_SP if so.
  4226.  
  4227.                                         ; Note. at this point we have a validated line number, not just an
  4228.                                         ; approximation and it would be best to update E_PPC with the true
  4229.                                         ; cursor line value which would enable the line cursor to be suppressed
  4230.                                         ; in all situations - see shortly.
  4231.  
  4232.                 PUSH    HL              ; save address of line.
  4233.                 INC     HL              ; address low byte of length.
  4234.                 LD      C,(HL)          ; transfer to C
  4235.                 INC     HL              ; next to high byte
  4236.                 LD      B,(HL)          ; transfer to B.
  4237.                 LD      HL,$000A        ; an overhead of ten bytes
  4238.                 ADD     HL,BC           ; is added to length.
  4239.                 LD      B,H             ; transfer adjusted value
  4240.                 LD      C,L             ; to BC register.
  4241.                 CALL    TEST_ROOM       ; routine TEST_ROOM checks free memory.
  4242.                 CALL    CLEAR_SP        ; routine CLEAR_SP clears editing area.
  4243.                 LD      HL,(CURCHL)     ; address CURCHL
  4244.                 EX      (SP),HL         ; swap with line address on stack
  4245.                 PUSH    HL              ; save line address underneath
  4246.                 LD      A,$FF           ; select system channel 'R'
  4247.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN opens it
  4248.                 POP     HL              ; drop line address
  4249.                 DEC     HL              ; make it point to first byte of line num.
  4250.                 DEC     (IY+$0F)        ; decrease E_PPC_LO to suppress line cursor.
  4251.                                         ; Note. ineffective when E_PPC is one
  4252.                                         ; greater than last line of program perhaps
  4253.                                         ; as a result of a delete.
  4254.                                         ; credit. Paul Harrison 1982.
  4255.  
  4256.                 CALL    OUT_LINE        ; routine OUT_LINE outputs the BASIC line
  4257.                                         ; to the editing area.
  4258.                 INC     (IY+$0F)        ; restore E_PPC_LO to the previous value.
  4259.                 LD      HL,(E_LINE)     ; address E_LINE in editing area.
  4260.                 INC     HL              ; advance
  4261.                 INC     HL              ; past space
  4262.                 INC     HL              ; and digit characters
  4263.                 INC     HL              ; of line number.
  4264.                 LD      (K_CUR),HL      ; update K_CUR to address start of BASIC.
  4265.                 POP     HL              ; restore the address of CURCHL.
  4266.                 CALL    CHAN_FLAG       ; routine CHAN_FLAG sets flags for it.
  4267.                 RET                     ; return to ED_LOOP.
  4268.  
  4269. ;--------------------
  4270. ; Cursor down editing
  4271. ;--------------------
  4272. ; The basic lines are displayed at the top of the screen and the user
  4273. ; wishes to move the cursor down one line in edit mode.
  4274. ; In input mode this key can be used as an alternative to entering STOP.
  4275.  
  4276.                                         ;;;$0FF3
  4277. ED_DOWN:        BIT     5,(IY+$37)      ; test FLAGX  - Input Mode ?
  4278.                 JR      NZ,ED_STOP      ; skip to ED_STOP if so
  4279.  
  4280.                 LD      HL,E_PPC        ; address E_PPC - 'current line'
  4281.                 CALL    LN_FETCH        ; routine LN_FETCH fetches number of next
  4282.                                         ; line or same if at end of program.
  4283.                 JR      ED_LIST         ; forward to ED_LIST to produce an
  4284.                                         ; automatic listing.
  4285.  
  4286.                                         ;;;$1001
  4287. ED_STOP:        LD      (IY+$00),$10    ; set ERR_NR to 'STOP in INPUT' code
  4288.                 JR      ED_ENTER        ; forward to ED_ENTER to produce error.
  4289.  
  4290. ;--------------------
  4291. ; Cursor left editing
  4292. ;--------------------
  4293. ; This acts on the cursor in the lower section of the screen in both
  4294. ; editing and input mode.
  4295.  
  4296.                                         ;;;$1007
  4297. ED_LEFT:        CALL    ED_EDGE         ; routine ED_EDGE moves left if possible
  4298.                 JR      ED_CUR          ; forward to ED_CUR to update K-CUR
  4299.                                         ; and return to ED_LOOP.
  4300.  
  4301. ;---------------------
  4302. ; Cursor right editing
  4303. ;---------------------
  4304. ; This acts on the cursor in the lower screen in both editing and input
  4305. ; mode and moves it to the right.
  4306.  
  4307.                                         ;;;$100C
  4308. ED_RIGHT:       LD      A,(HL)          ; fetch addressed character.
  4309.                 CP      $0D             ; is it carriage return ?
  4310.                 RET     Z               ; return if so to ED_LOOP
  4311.  
  4312.                 INC     HL              ; address next character
  4313.  
  4314.                                         ;;;$1011
  4315. ED_CUR:         LD      (K_CUR),HL      ; update K_CUR system variable
  4316.                 RET                     ; return to ED_LOOP
  4317.  
  4318. ;---------------
  4319. ; DELETE editing
  4320. ;---------------
  4321. ; This acts on the lower screen and deletes the character to left of
  4322. ; cursor. If control characters are present these are deleted first
  4323. ; leaving the naked parameter (0-7) which appears as a '?' except in the
  4324. ; case of CHR$ 6 which is the comma control character. It is not mandatory
  4325. ; to delete these second characters.
  4326.  
  4327.                                         ;;;$1015
  4328. ED_DELETE:      CALL    ED_EDGE         ; routine ED_EDGE moves cursor to left.
  4329.                 LD      BC,$0001        ; of character to be deleted.
  4330.                 JP      RECLAIM_2       ; to RECLAIM_2 reclaim the character.
  4331.  
  4332. ;-------------------------------------------
  4333. ; Ignore next 2 codes from KEY_INPUT routine
  4334. ;-------------------------------------------
  4335. ; Since AT and TAB cannot be entered this point is never reached
  4336. ; from the keyboard. If inputting from a tape device or network then
  4337. ; the control and two following characters are ignored and processing
  4338. ; continues as if a carriage return had been received.
  4339. ; Here, perhaps, another Spectrum has said print #15; AT 0,0; "This is yellow"
  4340. ; and this one is interpreting input #15; a$.
  4341.  
  4342.                                         ;;;$101E
  4343. ED_IGNORE:      CALL    WAIT_KEY        ; routine WAIT_KEY to ignore keystroke.
  4344.                 CALL    WAIT_KEY        ; routine WAIT_KEY to ignore next key.
  4345.  
  4346. ;--------------
  4347. ; Enter/newline
  4348. ;--------------
  4349. ; The enter key has been pressed to have basic line or input accepted.
  4350.  
  4351.                                         ;;;$1024
  4352. ED_ENTER:       POP     HL              ; discard address ED_LOOP
  4353.                 POP     HL              ; drop address ED_ERROR
  4354.  
  4355.                                         ;;;$1026
  4356. ED_END:         POP     HL              ; the previous value of ERR_SP
  4357.                 LD      (ERR_SP),HL     ; is restored to ERR_SP system variable
  4358.                 BIT     7,(IY+$00)      ; is ERR_NR $FF (= 'OK') ?
  4359.                 RET     NZ              ; return if so
  4360.                 LD      SP,HL           ; else put error routine on stack
  4361.                 RET                     ; and make an indirect jump to it.
  4362.  
  4363. ;------------------------------
  4364. ; Move cursor left when editing
  4365. ;------------------------------
  4366. ; This routine moves the cursor left. The complication is that it must
  4367. ; not position the cursor between control codes and their parameters.
  4368. ; It is further complicated in that it deals with TAB and AT characters
  4369. ; which are never present from the keyboard.
  4370. ; The method is to advance from the beginning of the line each time,
  4371. ; jumping one, two, or three characters as necessary saving the original
  4372. ; position at each jump in DE. Once it arrives at the cursor then the next
  4373. ; legitimate leftmost position is in DE.
  4374.  
  4375.                                         ;;;$1031
  4376. ED_EDGE:        SCF                     ; carry flag must be set to call the nested
  4377.                 CALL    SET_DE          ; subroutine SET_DE.
  4378.                                         ; if input   then DE=WORKSP
  4379.                                         ; if editing then DE=E_LINE
  4380.                 SBC     HL,DE           ; subtract address from start of line
  4381.                 ADD     HL,DE           ; and add back.
  4382.                 INC     HL              ; adjust for carry.
  4383.                 POP     BC              ; drop return address
  4384.                 RET     C               ; return to ED_LOOP if already at left of line.
  4385.  
  4386.                 PUSH    BC              ; resave return address - ED_LOOP.
  4387.                 LD      B,H             ; transfer HL - cursor address
  4388.                 LD      C,L             ; to BC register pair.
  4389.                                         ; at this point DE addresses start of line.
  4390.  
  4391.                                         ;;;$103E
  4392. ED_EDGE_1:      LD      H,D             ; transfer DE - leftmost pointer
  4393.                 LD      L,E             ; to HL
  4394.                 INC     HL              ; address next leftmost character to advance position each time.
  4395.                 LD      A,(DE)          ; pick up previous in A
  4396.                 AND     $F0             ; lose the low bits
  4397.                 CP      $10             ; is it INK to TAB $10-$1F ?
  4398.                                         ; that is, is it followed by a parameter ?
  4399.                 JR      NZ,ED_EDGE_2    ; to ED_EDGE_2 if not
  4400.                                         ; HL has been incremented once
  4401.  
  4402.                 INC     HL              ; address next as at least one parameter.
  4403.  
  4404.                                         ; in fact since 'tab' and 'at' cannot be entered the next section seems
  4405.                                         ; superfluous.
  4406.                                         ; The test will always fail and the jump to ED_EDGE_2 will be taken.
  4407.  
  4408.                 LD      A,(DE)          ; reload leftmost character
  4409.                 SUB     $17             ; decimal 23 ('tab')
  4410.                 ADC     A,$00           ; will be 0 for 'tab' and 'at'.
  4411.                 JR      NZ,ED_EDGE_2    ; forward to ED_EDGE_2 if not
  4412.                                         ; HL has been incremented twice
  4413.                 INC     HL              ; increment a third time for 'at'/'tab'
  4414.  
  4415.                                         ;;;$1051
  4416. ED_EDGE_2:      AND     A               ; prepare for true subtraction
  4417.                 SBC     HL,BC           ; subtract cursor address from pointer
  4418.                 ADD     HL,BC           ; and add back
  4419.                                         ; Note when HL matches the cursor position BC,
  4420.                                         ; there is no carry and the previous
  4421.                                         ; position is in DE.
  4422.                 EX      DE,HL           ; transfer result to DE if looping again.
  4423.                                         ; transfer DE to HL to be used as K-CUR
  4424.                                         ; if exiting loop.
  4425.                 JR      C,ED_EDGE_1     ; back to ED_EDGE_1 if cursor not matched.
  4426.  
  4427.                 RET                     ; return.
  4428.  
  4429. ;------------------
  4430. ; Cursor up editing
  4431. ;------------------
  4432. ; The main screen displays part of the BASIC program and the user wishes
  4433. ; to move up one line scrolling if necessary.
  4434. ; This has no alternative use in input mode.
  4435.  
  4436.                                         ;;;$1059
  4437. ED_UP:          BIT     5,(IY+$37)      ; test FLAGX  - input mode ?
  4438.                 RET     NZ              ; return if not in editor - to ED_LOOP.
  4439.  
  4440.                 LD      HL,(E_PPC)      ; get current line from E_PPC
  4441.                 CALL    LINE_ADDR       ; routine LINE_ADDR gets address
  4442.                 EX      DE,HL           ; and previous in DE
  4443.                 CALL    LINE_NO         ; routine LINE_NO gets prev line number
  4444.                 LD      HL,E_PPC_HI     ; set HL to E_PPC_HI as next routine stores top first.
  4445.                 CALL    LN_STORE        ; routine LN_STORE loads DE value to HL
  4446.                                         ; high byte first - E_PPC_LO takes E
  4447.  
  4448.                                         ; this branch is also taken from ED_DOWN.
  4449.  
  4450.                                         ;;;$106E
  4451. ED_LIST:        CALL    AUTO_LIST       ; routine AUTO_LIST lists to upper screen
  4452.                                         ; including adjusted current line.
  4453.                 LD      A,$00           ; select lower screen again
  4454.                 JP      CHAN_OPEN       ; exit via CHAN_OPEN to ED_LOOP
  4455.  
  4456. ;---------------------------------
  4457. ; Use of symbol and graphics codes
  4458. ;---------------------------------
  4459. ; These will not be encountered with the keyboard but would be handled
  4460. ; otherwise as follows.
  4461. ; As noted earlier, Vickers says there should have been an entry in
  4462. ; the KEYS table for CHR$ 6 which also pointed here.
  4463. ; If, for simplicity, two Spectrums were both using #15 as a bi-directional
  4464. ; channel connected to each other:-
  4465. ; then when the other Spectrum has said PRINT #15; x, y
  4466. ; input #15; i ; j  would treat the comma control as a newline and the
  4467. ; control would skip to input j.
  4468. ; You can get round the missing CHR$ 6 handler by sending multiple print
  4469. ; items separated by a newline '.
  4470.  
  4471. ; CHR$ 14 would have the same functionality.
  4472.  
  4473. ; This is CHR$ 14.
  4474.                                         ;;;$1076
  4475. ED_SYMBOL:      BIT     7,(IY+$37)      ; test FLAGX - is this INPUT LINE ?
  4476.                 JR      Z,ED_ENTER      ; back to ED_ENTER if not to treat as if
  4477.                                         ; enter had been pressed.
  4478.                                         ; else continue and add code to buffer.
  4479.  
  4480.                                         ; Next is CHR$ 15
  4481.                                         ; Note that ADD_CHAR precedes the table so we can't offset to it directly.
  4482.  
  4483.                                         ;;;$107C
  4484. ED_GRAPH:       JP      ADD_CHAR        ; jump back to ADD_CHAR
  4485.  
  4486. ;---------------------
  4487. ; Editor error routine
  4488. ;---------------------
  4489. ; If an error occurs while editing, or inputting, then ERR_SP
  4490. ; points to the stack location holding address ED_ERROR.
  4491.  
  4492.                                         ;;;$107F
  4493. ED_ERROR:       BIT     4,(IY+$30)      ; test FLAGS2  - is K channel in use ?
  4494.                 JR      Z,ED_END        ; back to ED_END if not.
  4495.  
  4496.                                         ; but as long as we're editing lines or inputting from the keyboard, then
  4497.                                         ; we've run out of memory so give a short rasp.
  4498.  
  4499.                 LD      (IY+$00),$FF    ; reset ERR_NR to 'OK'.
  4500.                 LD      D,$00           ; prepare for beeper.
  4501.                 LD      E,(IY-$02)      ; use RASP value.
  4502.                 LD      HL,$1A90        ; set a duration.
  4503.                 CALL    BEEPER          ; routine BEEPER emits a warning rasp.
  4504.                 JP      ED_AGAIN        ; to ED_AGAIN to re-stack address of
  4505.                                         ; this routine and make ERR_SP point to it.
  4506.  
  4507. ;----------------------
  4508. ; Clear edit/work space
  4509. ;----------------------
  4510. ; The editing area or workspace is cleared depending on context.
  4511. ; This is called from ED_EDIT to clear workspace if edit key is
  4512. ; used during input, to clear editing area if no program exists
  4513. ; and to clear editing area prior to copying the edit line to it.
  4514. ; It is also used by the error routine to clear the respective
  4515. ; area depending on FLAGX.
  4516.  
  4517.                                         ;;;$1097
  4518. CLEAR_SP:       PUSH    HL              ; preserve HL
  4519.                 CALL    SET_HL          ; routine SET_HL
  4520.                                         ; if in edit   HL = WORKSP-1, DE = E_LINE
  4521.                                         ; if in input  HL = STKBOT,   DE = WORKSP
  4522.                 DEC     HL              ; adjust
  4523.                 CALL    RECLAIM_1       ; routine RECLAIM_1 reclaims space
  4524.                 LD      (K_CUR),HL      ; set K_CUR to start of empty area
  4525.                 LD      (IY+$07),$00    ; set MODE to 'KLC'
  4526.                 POP     HL              ; restore HL.
  4527.                 RET                     ; return.
  4528.  
  4529. ;----------------------
  4530. ; Handle keyboard input
  4531. ;----------------------
  4532. ; This is the service routine for the input stream of the keyboard
  4533. ; channel 'K'.
  4534.  
  4535.                                         ;;;$10A8
  4536. KEY_INPUT:      BIT     3,(IY+$02)      ; test TV_FLAG  - has a key been pressed in editor ?
  4537.                 CALL    NZ,ED_COPY      ; routine ED_COPY if so to reprint the lower
  4538.                                         ; screen at every keystroke.
  4539.                 AND     A               ; clear carry - required exit condition.
  4540.                 BIT     5,(IY+$01)      ; test FLAGS  - has a new key been pressed ?
  4541.                 RET     Z               ; return if not.
  4542.  
  4543.                 LD      A,(LASTK)       ; system variable LASTK will hold last key -
  4544.                                         ; from the interrupt routine.
  4545.                 RES     5,(IY+$01)      ; update FLAGS  - reset the new key flag.
  4546.                 PUSH    AF              ; save the input character.
  4547.                 BIT     5,(IY+$02)      ; test TV_FLAG  - clear lower screen ?
  4548.                 CALL    NZ,CLS_LOWER    ; routine CLS_LOWER if so.
  4549.                 POP     AF              ; restore the character code.
  4550.                 CP      $20             ; if space or higher then
  4551.                 JR      NC,KEY_DONE2    ; forward to KEY_DONE2 and return with carry
  4552.                                         ; set to signal key-found.
  4553.                 CP      $10             ; with 16d INK and higher skip
  4554.                 JR      NC,KEY_CONTR    ; forward to KEY_CONTR.
  4555.  
  4556.                 CP      $06             ; for 6 - 15d
  4557.                 JR      NC,KEY_M_CL     ; skip forward to KEY_M_CL to handle Modes
  4558.                                         ; and CapsLock.
  4559.  
  4560.                                         ; that only leaves 0-5, the flash bright inverse switches.
  4561.  
  4562.                 LD      B,A             ; save character in B
  4563.                 AND     $01             ; isolate the embedded parameter (0/1).
  4564.                 LD      C,A             ; and store in C
  4565.                 LD      A,B             ; re-fetch copy (0-5)
  4566.                 RRA                     ; halve it 0, 1 or 2.
  4567.                 ADD     A,$12           ; add 18d gives 'flash', 'bright' and 'inverse'.
  4568.                 JR      KEY_DATA        ; forward to KEY_DATA with the
  4569.                                         ; parameter (0/1) in C.
  4570.  
  4571.                                         ; Now separate capslock 06 from modes 7-15.
  4572.  
  4573.                                         ;;;$10DB
  4574. KEY_M_CL:       JR      NZ,KEY_MODE     ; forward to KEY_MODE if not 06 (capslock)
  4575.  
  4576.                 LD      HL,FLAGS2       ; point to FLAGS2
  4577.                 LD      A,$08           ; value 00000100
  4578.                 XOR     (HL)            ; toggle BIT 2 of FLAGS2 the capslock bit
  4579.                 LD      (HL),A          ; and store result in FLAGS2 again.
  4580.                 JR      KEY_FLAG        ; forward to KEY_FLAG to signal no-key.
  4581.  
  4582.                                         ;;;$10E6
  4583. KEY_MODE:       CP      $0E             ; compare with chr 14d
  4584.                 RET     C               ; return with carry set "key found" for
  4585.                                         ; codes 7 - 13d leaving 14d and 15d
  4586.                                         ; which are converted to mode codes.
  4587.                 SUB     $0D             ; subtract 13d leaving 1 and 2
  4588.                                         ; 1 is 'E' mode, 2 is 'G' mode.
  4589.                 LD      HL,MODE         ; address the MODE system variable.
  4590.                 CP      (HL)            ; compare with existing value before
  4591.                 LD      (HL),A          ; inserting the new value.
  4592.                 JR      NZ,KEY_FLAG     ; forward to KEY_FLAG if it has changed.
  4593.  
  4594.                 LD      (HL),$00        ; else make MODE zero - KLC mode
  4595.                                         ; Note. while in Extended/Graphics mode,
  4596.                                         ; the Extended Mode/Graphics key is pressed
  4597.                                         ; again to get out.
  4598.  
  4599.                                         ;;;$10F4
  4600. KEY_FLAG:       SET     3,(IY+$02)      ; update TV_FLAG  - show key state has changed
  4601.                 CP      A               ; clear carry and reset zero flags - no actual key returned.
  4602.                 RET                     ; make the return.
  4603.  
  4604.                                         ; now deal with colour controls - 16-23 ink, 24-31 paper
  4605.  
  4606.                                         ;;;$10FA
  4607. KEY_CONTR:      LD      B,A             ; make a copy of character.
  4608.                 AND     $07             ; mask to leave bits 0-7
  4609.                 LD      C,A             ; and store in C.
  4610.                 LD      A,$10           ; initialize to 16d - INK.
  4611.                 BIT     3,B             ; was it paper ?
  4612.                 JR      NZ,KEY_DATA     ; forward to KEY_DATA with INK 16d and colour in C.
  4613.  
  4614.                 INC     A               ; else change from INK to PAPER (17d) if so.
  4615.  
  4616.                                         ;;;$1105
  4617. KEY_DATA:       LD      (IY-$2D),C      ; put the colour (0-7)/state(0/1) in KDATA
  4618.                 LD      DE,KEY_NEXT     ; address: KEY_NEXT will be next input stream
  4619.                 JR      KEY_CHAN        ; forward to KEY_CHAN to change it ...
  4620.  
  4621.                                         ; ... so that INPUT_AD directs control to here at next call to WAIT_KEY
  4622.  
  4623.                                         ;;;$110D
  4624. KEY_NEXT:       LD      A,(KDATA)       ; pick up the parameter stored in KDATA.
  4625.                 LD      DE,KEY_INPUT    ; address: KEY_INPUT will be next input stream
  4626.                                         ; continue to restore default channel and
  4627.                                         ; make a return with the control code.
  4628.  
  4629.                                         ;;;$1113
  4630. KEY_CHAN:       LD      HL,(CHANS)      ; address start of CHANNELS area using CHANS
  4631.                                         ; Note. One might have expected CURCHL to
  4632.                                         ; have been used.
  4633.                 INC     HL              ; step over the
  4634.                 INC     HL              ; output address
  4635.                 LD      (HL),E          ; and update the input
  4636.                 INC     HL              ; routine address for
  4637.                 LD      (HL),D          ; the next call to WAIT_KEY.
  4638.  
  4639.                                         ;;;$111B
  4640. KEY_DONE2:      SCF                     ; set carry flag to show a key has been found
  4641.                 RET                     ; and return.
  4642.  
  4643. ;---------------------
  4644. ; Lower screen copying
  4645. ;---------------------
  4646. ; This subroutine is called whenever the line in the editing area or
  4647. ; input workspace is required to be printed to the lower screen.
  4648. ; It is by calling this routine after any change that the cursor, for
  4649. ; instance, appears to move to the left.
  4650. ; Remember the edit line will contain characters and tokens
  4651. ; e.g. "1000 LET a = 1" is 12 characters.
  4652.  
  4653.                                         ;;;$111D
  4654. ED_COPY:        CALL    TEMPS           ; routine TEMPS sets temporary attributes.
  4655.                 RES     3,(IY+$02)      ; update TV_FLAG - signal no change in mode
  4656.                 RES     5,(IY+$02)      ; update TV_FLAG - signal don't clear lower screen.
  4657.                 LD      HL,(SPOSNL)     ; fetch SPOSNL
  4658.                 PUSH    HL              ; and save on stack.
  4659.                 LD      HL,(ERR_SP)     ; fetch ERR_SP
  4660.                 PUSH    HL              ; and save also
  4661.                 LD      HL,ED_FULL      ; address: ED_FULL
  4662.                 PUSH    HL              ; is pushed as the error routine
  4663.                 LD      (ERR_SP),SP     ; and ERR_SP made to point to it.
  4664.                 LD      HL,(ECHO_E)     ; fetch ECHO_E
  4665.                 PUSH    HL              ; and push also
  4666.                 SCF                     ; set carry flag to control SET_DE
  4667.                 CALL    SET_DE          ; call routine SET_DE
  4668.                                         ; if in input DE = WORKSP
  4669.                                         ; if in edit  DE = E_LINE
  4670.                 EX      DE,HL           ; start address to HL
  4671.                 CALL    OUT_LINE2       ; routine OUT_LINE2 outputs entire line up to
  4672.                                         ; carriage return including initial
  4673.                                         ; characterized line number when present.
  4674.                 EX      DE,HL           ; transfer new address to DE
  4675.                 CALL    OUT_CURS        ; routine OUT_CURS considers a terminating cursor.
  4676.                 LD      HL,(SPOSNL)     ; fetch updated SPOSNL
  4677.                 EX      (SP),HL         ; exchange with ECHO_E on stack
  4678.                 EX      DE,HL           ; transfer ECHO_E to DE
  4679.                 CALL    TEMPS           ; routine TEMPS to re-set attributes
  4680.                                         ; if altered.
  4681.  
  4682.                                         ; the lower screen was not cleared, at the outset, so if deleting then old
  4683.                                         ; text from a previous print may follow this line and requires blanking.
  4684.  
  4685.                                         ;;;$1150
  4686. ED_BLANK:       LD      A,(SPOSNL_HI)   ; fetch SPOSNL_HI is current line
  4687.                 SUB     D               ; compare with old
  4688.                 JR      C,ED_C_DONE     ; forward to ED_C_DONE if no blanking
  4689.  
  4690.                 JR      NZ,ED_SPACES    ; forward to ED_SPACES if line has changed
  4691.  
  4692.                 LD      A,E             ; old column to A
  4693.                 SUB     (IY+$50)        ; subtract new in SPOSNL_lo
  4694.                 JR      NC,ED_C_DONE    ; forward to ED_C_DONE if no backfilling.
  4695.  
  4696.                                         ;;;$115E
  4697. ED_SPACES:      LD      A,$20           ; prepare a space.
  4698.                 PUSH    DE              ; save old line/column.
  4699.                 CALL    PRINT_OUT       ; routine PRINT_OUT prints a space over
  4700.                                         ; any text from previous print.
  4701.                                         ; Note. Since the blanking only occurs when
  4702.                                         ; using $09F4 to print to the lower screen,
  4703.                                         ; there is no need to vector via a RST 10
  4704.                                         ; and we can use this alternate set.
  4705.                 POP     DE              ; restore the old line column.
  4706.                 JR      ED_BLANK        ; back to ED_BLANK until all old text blanked.
  4707.  
  4708. ;--------
  4709. ; ED_FULL
  4710. ;--------
  4711. ; this is the error routine addressed by ERR_SP. This is not for the out of
  4712. ; memory situation as we're just printing. The pitch and duration are exactly
  4713. ; the same as used by ED_ERROR from which this has been augmented. The
  4714. ; situation is that the lower screen is full and a rasp is given to suggest
  4715. ; that this is perhaps not the best idea you've had that day.
  4716.  
  4717.                                         ;;;$1167
  4718. ED_FULL:        LD      D,$00           ; prepare to moan.
  4719.                 LD      E,(IY-$02)      ; fetch RASP value.
  4720.                 LD      HL,$1A90        ; set duration.
  4721.                 CALL    BEEPER          ; routine BEEPER.
  4722.                 LD      (IY+$00),$FF    ; clear ERR_NR.
  4723.                 LD      DE,(SPOSNL)     ; fetch SPOSNL.
  4724.                 JR      ED_C_END        ; forward to ED_C_END
  4725.  
  4726.                                         ; the exit point from line printing continues here.
  4727.  
  4728.                                         ;;;$117C
  4729. ED_C_DONE:      POP     DE              ; fetch new line/column.
  4730.                 POP     HL              ; fetch the error address.
  4731.  
  4732.                                         ; the error path rejoins here.
  4733.  
  4734.                                         ;;;$117E
  4735. ED_C_END:       POP     HL              ; restore the old value of ERR_SP.
  4736.                 LD      (ERR_SP),HL     ; update the system variable ERR_SP
  4737.                 POP     BC              ; old value of SPOSN_L
  4738.                 PUSH    DE              ; save new value
  4739.                 CALL    CL_SET          ; routine CL_SET and PO_STORE
  4740.                                         ; update ECHO_E and SPOSN_L from BC
  4741.                 POP     HL              ; restore new value
  4742.                 LD      (ECHO_E),HL     ; and update ECHO_E
  4743.                 LD      (IY+$26),$00    ; make error pointer X_PTR_HI out of bounds
  4744.                 RET                     ; return
  4745.  
  4746. ;------------------------------------------------
  4747. ; Point to first and last locations of work space
  4748. ;------------------------------------------------
  4749. ; These two nested routines ensure that the appropriate pointers are
  4750. ; selected for the editing area or workspace. The routines that call
  4751. ; these routines are designed to work on either area.
  4752.  
  4753. ; this routine is called once
  4754.                                         ;;;$1190
  4755. SET_HL:         LD      HL,(WORKSP)     ; fetch WORKSP to HL.
  4756.                 DEC     HL              ; point to last location of editing area.
  4757.                 AND     A               ; clear carry to limit exit points to first or last.
  4758.  
  4759.                                         ; this routine is called with carry set and exits at a conditional return.
  4760.  
  4761.                                         ;;;$1195
  4762. SET_DE:         LD      DE,(E_LINE)     ; fetch E_LINE to DE
  4763.                 BIT     5,(IY+$37)      ; test FLAGX  - Input Mode ?
  4764.                 RET     Z               ; return now if in editing mode
  4765.  
  4766.                 LD      DE,(WORKSP)     ; fetch WORKSP to DE
  4767.                 RET     C               ; return if carry set ( entry = SET_DE)
  4768.  
  4769.                 LD      HL,(STKBOT)     ; fetch STKBOT to HL as well
  4770.                 RET                     ; and return  (entry = SET_HL (in input))
  4771.  
  4772. ;--------------------------------
  4773. ; Remove floating point from line
  4774. ;--------------------------------
  4775. ; When a BASIC LINE or the INPUT BUFFER is parsed any numbers will have
  4776. ; an invisible chr 14d inserted after them and the 5-byte integer or
  4777. ; floating point form inserted after that. Similar invisible value holders
  4778. ; are also created after the numeric and string variables in a DEF FN list.
  4779. ; This routine removes these 'compiled' numbers from the edit line or
  4780. ; input workspace.
  4781.  
  4782.                                         ;;;$11A7
  4783. REMOVE_FP:      LD      A,(HL)          ; fetch character
  4784.                 CP      $0E             ; is it the number marker ?
  4785.                 LD      BC,$0006        ; prepare for six bytes
  4786.                 CALL    Z,RECLAIM_2     ; routine RECLAIM_2 reclaims space if $0E
  4787.                 LD      A,(HL)          ; reload next (or same) character
  4788.                 INC     HL              ; and advance address
  4789.                 CP      $0D             ; end of line or input buffer ?
  4790.                 JR      NZ,REMOVE_FP    ; back to REMOVE_FP until entire line done.
  4791.  
  4792.                 RET                     ; return
  4793.  
  4794.  
  4795. ;*********************************
  4796. ;** Part 6. EXECUTIVE ROUTINES  **
  4797. ;*********************************
  4798.  
  4799. ; The memory.
  4800. ;
  4801. ; +---------+-----------+------------+--------------+-------------+--
  4802. ; | BASIC   |  Display  | Attributes | ZX Printer   |    System   |
  4803. ; |  ROM    |   File    |    File    |   Buffer     |  Variables  |
  4804. ; +---------+-----------+------------+--------------+-------------+--
  4805. ; ^         ^           ^            ^              ^             ^
  4806. ; $0000   $4000       $5800        $5B00          $5C00         $5CB6 = CHANS
  4807. ;
  4808. ;
  4809. ;  --+----------+---+---------+-----------+---+------------+--+---+--
  4810. ;    | Channel  |$80|  Basic  | Variables |$80| Edit Line  |NL|$80|
  4811. ;    |   Info   |   | Program |   Area    |   | or Command |  |   |
  4812. ;  --+----------+---+---------+-----------+---+------------+--+---+--
  4813. ;    ^              ^         ^               ^                   ^
  4814. ;  CHANS           PROG      VARS           E_LINE              WORKSP
  4815. ;
  4816. ;
  4817. ;                             ---5-->         <---2---  <--3---
  4818. ;  --+-------+--+------------+-------+-------+---------+-------+-+---+------+
  4819. ;    | INPUT |NL| Temporary  | Calc. | Spare | Machine | Gosub |?|$3E| UDGs |
  4820. ;    | data  |  | Work Space | Stack |       |  Stack  | Stack | |   |      |
  4821. ;  --+-------+--+------------+-------+-------+---------+-------+-+---+------+
  4822. ;    ^                       ^       ^       ^                   ^   ^      ^
  4823. ;  WORKSP                  STKBOT  STKEND   sp               RAMTOP UDG  P_RAMT
  4824. ;                                                                        
  4825.  
  4826. ;--------------------
  4827. ; Handle NEW command
  4828. ;--------------------
  4829. ; The NEW command is about to set all RAM below RAMTOP to zero and
  4830. ; then re-initialize the system. All RAM above RAMTOP should, and will be,
  4831. ; preserved.
  4832. ; There is nowhere to store values in RAM or on the stack which becomes
  4833. ; inoperable. Similarly PUSH and CALL instructions cannot be used to
  4834. ; store values or section common code. The alternate register set is the only
  4835. ; place available to store 3 persistent 16-bit system variables.
  4836.  
  4837.                                         ;;;$11B7
  4838. NEW:            DI                      ; disable interrupts - machine stack will be cleared.
  4839.                 LD      A,$FF           ; flag coming from NEW.
  4840.                 LD      DE,(RAMTOP)     ; fetch RAMTOP as top value.
  4841.                 EXX                     ; switch in alternate set.
  4842.                 LD      BC,(P_RAMT)     ; fetch P_RAMT differs on 16K/48K machines.
  4843.                 LD      DE,(RASP_PIP)   ; fetch RASP/PIP.
  4844.                 LD      HL,(UDG)        ; fetch UDG    differs on 16K/48K machines.
  4845.                 EXX                     ; switch back to main set and continue into...
  4846.  
  4847. ;----------------------------
  4848. ; Main entry (initialization)
  4849. ;----------------------------
  4850. ; This common code tests ram and sets it to zero re-initializing
  4851. ; all the non-zero system variables and channel information.
  4852. ; The A register tells if coming from START or NEW
  4853.  
  4854.                                         ;;;$11CB
  4855. START_NEW:      LD      B,A             ; save the flag for later branching.
  4856.                 LD      A,$07           ; select a white border
  4857.                 OUT     ($FE),A         ; and set it now.
  4858.                 LD      A,$3F           ; load accumulator with last page in ROM.
  4859.                 LD      I,A             ; set the I register - this remains constant
  4860.                                         ; and can't be in range $40 - $7F as 'snow'
  4861.                                         ; appears on the screen.
  4862.                 NOP                     ; these seem unnecessary.
  4863.                 NOP
  4864.                 NOP
  4865.                 NOP
  4866.                 NOP
  4867.                 NOP
  4868.  
  4869. ;-------------
  4870. ; Check RAM
  4871. ;-------------
  4872. ; Typically a Spectrum will have 16K or 48K of Ram and this code will
  4873. ; test it all till it finds an unpopulated location or, less likely, a
  4874. ; faulty location. Usually it stops when it reaches the top $FFFF or
  4875. ; in the case of NEW the supplied top value. The entire screen turns
  4876. ; black with sometimes red stripes on black paper visible.
  4877.  
  4878.                                         ;;;$11DA
  4879. RAM_CHECK:      LD      H,D             ; transfer the top value to
  4880.                 LD      L,E             ; the HL register pair.
  4881.  
  4882.                                         ;;;$11DC
  4883. RAM_FILL:       LD      (HL),$02        ; load with 2 - red ink on black paper
  4884.                 DEC     HL              ; next lower
  4885.                 CP      H               ; have we reached ROM - $3F ?
  4886.                 JR      NZ,RAM_FILL     ; back to RAM_FILL if not.
  4887.  
  4888.                                         ;;;$11E2
  4889. RAM_READ:       AND     A               ; clear carry - prepare to subtract
  4890.                 SBC     HL,DE           ; subtract and add back setting
  4891.                 ADD     HL,DE           ; carry when back at start.
  4892.                 INC     HL              ; and increment for next iteration.
  4893.                 JR      NC,RAM_DONE     ; forward to RAM_DONE if we've got back to
  4894.                                         ; starting point with no errors.
  4895.                 DEC     (HL)            ; decrement to 1.
  4896.                 JR      Z,RAM_DONE      ; forward to RAM_DONE if faulty.
  4897.  
  4898.                 DEC     (HL)            ; decrement to zero.
  4899.                 JR      Z,RAM_READ      ; back to RAM_READ if zero flag was set.
  4900.  
  4901.                                         ;;;$11EF
  4902. RAM_DONE:       DEC     HL              ; step back to last valid location.
  4903.                 EXX                     ; regardless of state, set up possibly
  4904.                                         ; stored system variables in case from NEW.
  4905.                 LD      (P_RAMT),BC     ; insert P_RAMT.
  4906.                 LD      (RASP_PIP),DE   ; insert RASP/PIP.
  4907.                 LD      (UDG),HL        ; insert UDG.
  4908.                 EXX                     ; switch in main set.
  4909.                 INC     B               ; now test if we arrived here from NEW.
  4910.                 JR      Z,RAM_SET       ; forward to RAM_SET if we did.
  4911.  
  4912.                                         ; this section applies to START only.
  4913.  
  4914.                 LD      (P_RAMT),HL     ; set P_RAMT to the highest working RAM address.
  4915.                 LD      DE,$3EAF        ; address of last byte of 'U' bitmap in ROM.
  4916.                 LD      BC,$00A8        ; there are 21 user defined graphics.
  4917.                 EX      DE,HL           ; switch pointers and make the UDGs a
  4918.                 LDDR                    ; copy of the standard characters A - U.
  4919.                 EX      DE,HL           ; switch the pointer to HL.
  4920.                 INC     HL              ; update to start of 'A' in RAM.
  4921.                 LD      (UDG),HL        ; make UDG system variable address the first bitmap.
  4922.                 DEC     HL              ; point at RAMTOP again.
  4923.                 LD      BC,$0040        ; set the values of
  4924.                 LD      (RASP_PIP),BC   ; the PIP and RASP system variables.
  4925.  
  4926.                                         ; the NEW command path rejoins here.
  4927.  
  4928.                                         ;;;$1219
  4929. RAM_SET:        LD      (RAMTOP),HL     ; set system variable RAMTOP to HL.
  4930.                 LD      HL,$3C00        ; a strange place to set the pointer to the
  4931.                 LD      (CHARS),HL      ; character set, CHARS - as no printing yet.
  4932.                 LD      HL,(RAMTOP)     ; fetch RAMTOP to HL again as we've lost it.
  4933.                 LD      (HL),$3E        ; top of user ram holds GOSUB end marker
  4934.                                         ; an impossible line number - see RETURN.
  4935.                                         ; no significance in the number $3E. It has
  4936.                                         ; been traditional since the ZX80.
  4937.                 DEC     HL              ; followed by empty byte (not important).
  4938.                 LD      SP,HL           ; set up the machine stack pointer.
  4939.                 DEC     HL
  4940.                 DEC     HL
  4941.                 LD      (ERR_SP),HL     ; ERR_SP is where the error pointer is
  4942.                                         ; at moment empty - will take address MAIN_4
  4943.                                         ; at the call preceding that address,
  4944.                                         ; although interrupts and calls will make use
  4945.                                         ; of this location in meantime.
  4946.                 IM      1               ; select interrupt mode 1.
  4947.                 LD      IY,ERR_NR       ; set IY to ERR_NR. IY can reach all standard
  4948.                                         ; system variables but shadow ROM system
  4949.                                         ; variables will be mostly out of range.
  4950.  
  4951.                 EI                      ; enable interrupts now that we have a stack.
  4952.                 LD      HL,$5CB6        ; the address of the channels - initially
  4953.                                         ; following system variables.
  4954.                 LD      (CHANS),HL      ; set the CHANS system variable.
  4955.                 LD      DE,INIT_CHAN    ; address: INIT_CHAN in ROM.
  4956.                 LD      BC,$0015        ; there are 21 bytes of initial data in ROM.
  4957.                 EX      DE,HL           ; swap the pointers.
  4958.                 LDIR                    ; copy the bytes to RAM.
  4959.                 EX      DE,HL           ; swap pointers. HL points to program area.
  4960.                 DEC     HL              ; decrement address.
  4961.                 LD      (DATADD),HL     ; set DATADD to location before program area.
  4962.                 INC     HL              ; increment again.
  4963.                 LD      (PROG),HL       ; set PROG the location where BASIC starts.
  4964.                 LD      (VARS),HL       ; set VARS to same location with a
  4965.                 LD      (HL),$80        ; variables end-marker.
  4966.                 INC     HL              ; advance address.
  4967.                 LD      (E_LINE),HL     ; set E_LINE, where the edit line
  4968.                                         ; will be created.
  4969.                                         ; Note. it is not strictly necessary to
  4970.                                         ; execute the next fifteen bytes of code
  4971.                                         ; as this will be done by the call to SET_MIN.
  4972.  
  4973.                 LD      (HL),$0D        ; initially just has a carriage return
  4974.                 INC     HL              ; followed by
  4975.                 LD      (HL),$80        ; an end-marker.
  4976.                 INC     HL              ; address the next location.
  4977.                 LD      (WORKSP),HL     ; set WORKSP - empty workspace.
  4978.                 LD      (STKBOT),HL     ; set STKBOT - bottom of the empty stack.
  4979.                 LD      (STKEND),HL     ; set STKEND to the end of the empty stack.
  4980.                 LD      A,$38           ; the colour system is set to white paper,
  4981.                                         ; black ink, no flash or bright.
  4982.                 LD      (ATTRP_MASKP),A ; set ATTR_P permanent colour attributes.
  4983.                 LD      (ATTRT_MASKT),A ; set ATTR_T temporary colour attributes.
  4984.                 LD      (BORDCR),A      ; set BORDCR the border colour/lower screen
  4985.                                         ; attributes.
  4986.                 LD      HL,$0523        ; The keyboard repeat and delay values
  4987.                 LD      (REPDEL),HL     ; are loaded to REPDEL and REPPER.
  4988.  
  4989.                 DEC     (IY-$3A)        ; set KSTATE_0 to $FF.
  4990.                 DEC     (IY-$36)        ; set KSTATE_4 to $FF.
  4991.                                         ; thereby marking both available.
  4992.                 LD      HL,INIT_STRM    ; set source to ROM Address: INIT_STRM
  4993.                 LD      DE,STRMS_FD     ; set destination to system variable STRMS_FD
  4994.                 LD      BC,$000E        ; copy the 14 bytes of initial 7 streams data
  4995.                 LDIR                    ; from ROM to RAM.
  4996.                 SET     1,(IY+$01)      ; update FLAGS - signal printer in use.
  4997.                 CALL    CLEAR_PRB       ; call routine CLEAR_PRB to initialize system
  4998.                                         ; variables associated with printer.
  4999.                 LD      (IY+$31),$02    ; set DF_SZ the lower screen display size to
  5000.                                         ; two lines
  5001.                 CALL    CLS             ; call routine CLS to set up system
  5002.                                         ; variables associated with screen and clear
  5003.                                         ; the screen and set attributes.
  5004.                 XOR     A               ; clear accumulator so that we can address
  5005.                 LD      DE,COPYRIGHT - 1; the message table directly.
  5006.                 CALL    PO_MSG          ; routine PO_MSG puts
  5007.                                         ; '(c) 1982 Sinclair Research Ltd'
  5008.                                         ; at bottom of display.
  5009.                 SET     5,(IY+$02)      ; update TV_FLAG  - signal lower screen will
  5010.                                         ; require clearing.
  5011.                 JR      MAIN_1          ; forward to MAIN_1
  5012.  
  5013. ;--------------------
  5014. ; Main execution loop
  5015. ;--------------------
  5016.  
  5017.                                         ;;;$12A2
  5018. MAIN_EXEC:      LD      (IY+$31),$02    ; set DF_SZ lower screen display file size to 2 lines.
  5019.                 CALL    AUTO_LIST       ; routine AUTO_LIST
  5020.  
  5021.                                         ;;;$12A9
  5022. MAIN_1:         CALL    SET_MIN         ; routine SET_MIN clears work areas.
  5023.  
  5024.                                         ;;;$12AC
  5025. MAIN_2:         LD      A,$00           ; select channel 'K' the keyboard
  5026.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN opens it
  5027.                 CALL    EDITOR          ; routine EDITOR is called.
  5028.                                         ; Note the above routine is where the Spectrum
  5029.                                         ; waits for user-interaction. Perhaps the
  5030.                                         ; most common input at this stage is LOAD "".
  5031.                 CALL    LINE_SCAN       ; routine LINE_SCAN scans the input.
  5032.                 BIT     7,(IY+$00)      ; test ERR_NR - will be $FF if syntax is correct.
  5033.                 JR      NZ,MAIN_3       ; forward, if correct, to MAIN_3.
  5034.  
  5035.                 BIT     4,(IY+$30)      ; test FLAGS2 - K channel in use ?
  5036.                 JR      Z,MAIN_4        ; forward to MAIN_4 if not.
  5037.  
  5038.                 LD      HL,(E_LINE)     ; an editing error so address E_LINE.
  5039.                 CALL    REMOVE_FP       ; routine REMOVE_FP removes the hidden floating-point forms.
  5040.                 LD      (IY+$00),$FF    ; system variable ERR_NR is reset to 'OK'.
  5041.                 JR      MAIN_2          ; back to MAIN_2 to allow user to correct.
  5042.  
  5043.                                         ; the branch was here if syntax has passed test.
  5044.  
  5045.                                         ;;;$12CF
  5046. MAIN_3:         LD      HL,(E_LINE)     ; fetch the edit line address from E_LINE.
  5047.                 LD      (CH_ADD),HL     ; system variable CH_ADD is set to first
  5048.                                         ; character of edit line.
  5049.                                         ; Note. the above two instructions are a little
  5050.                                         ; inadequate.
  5051.                                         ; They are repeated with a subtle difference
  5052.                                         ; at the start of the next subroutine and are
  5053.                                         ; therefore not required above.
  5054.                 CALL    E_LINE_NO       ; routine E_LINE_NO will fetch any line
  5055.                                         ; number to BC if this is a program line.
  5056.                 LD      A,B             ; test if the number of
  5057.                 OR      C               ; the line is non-zero.
  5058.                 JP      NZ,MAIN_ADD     ; jump forward to MAIN_ADD if so to add the
  5059.                                         ; line to the BASIC program.
  5060.  
  5061.                                         ; Has the user just pressed the ENTER key ?
  5062.  
  5063.                 RST     18H             ; GET_CHAR gets character addressed by CH_ADD.
  5064.                 CP      $0D             ; is it a carriage return ?
  5065.                 JR      Z,MAIN_EXEC     ; back to MAIN_EXEC if so for an automatic
  5066.                                         ; listing.
  5067.  
  5068.                                         ; this must be a direct command.
  5069.  
  5070.                 BIT     0,(IY+$30)      ; test FLAGS2 - clear the main screen ?
  5071.                 CALL    NZ,CL_ALL       ; routine CL_ALL, if so, e.g. after listing.
  5072.                 CALL    CLS_LOWER       ; routine CLS_LOWER anyway.
  5073.                 LD      A,$19           ; compute scroll count to 25 minus
  5074.                 SUB     (IY+$4F)        ; value of S_POSN_HI.
  5075.                 LD      (SCR_CT),A      ; update SCR_CT system variable.
  5076.                 SET     7,(IY+$01)      ; update FLAGS - signal running program.
  5077.                 LD      (IY+$00),$FF    ; set ERR_NR to 'OK'.
  5078.                 LD      (IY+$0A),$01    ; set NSPPC to one for first statement.
  5079.                 CALL    LINE_RUN        ; call routine LINE_RUN to run the line.
  5080.                                         ; sysvar ERR_SP therefore addresses MAIN_4
  5081.  
  5082.                                         ; Examples of direct commands are RUN, CLS, LOAD "", PRINT USR 40000,
  5083.                                         ; LPRINT "A"; etc..
  5084.                                         ; If a user written machine-code program disables interrupts then it
  5085.                                         ; must enable them to pass the next step. We also jumped to here if the
  5086.                                         ; keyboard was not being used.
  5087.  
  5088.                                         ;;;$1303
  5089. MAIN_4:         HALT                    ; wait for interrupt.
  5090.                 RES     5,(IY+$01)      ; update FLAGS - signal no new key.
  5091.                 BIT     1,(IY+$30)      ; test FLAGS2 - is printer buffer clear ?
  5092.                 CALL    NZ,COPY_BUFF    ; call routine COPY_BUFF if not.
  5093.                                         ; Note. the programmer has neglected
  5094.                                         ; to set bit 1 of FLAGS first.
  5095.                 LD      A,(ERR_NR)      ; fetch ERR_NR
  5096.                 INC     A               ; increment to give true code.
  5097.  
  5098.                                         ; Now deal with a runtime error as opposed to an editing error.
  5099.                                         ; However if the error code is now zero then the OK message will be printed.
  5100.  
  5101.                                         ;;;$1313
  5102. MAIN_G:         PUSH    AF              ; save the error number.
  5103.                 LD      HL,$0000        ; prepare to clear some system variables.
  5104.                 LD      (IY+$37),H      ; clear all the bits of FLAGX.
  5105.                 LD      (IY+$26),H      ; blank X_PTR_HI to suppress error marker.
  5106.                 LD      (DEFADD),HL     ; blank DEFADD to signal that no defined
  5107.                                         ; function is currently being evaluated.
  5108.                 LD      HL,$0001        ; explicit - inc hl would do.
  5109.                 LD      (STRMS_00),HL   ; ensure STRMS_00 is keyboard.
  5110.                 CALL    SET_MIN         ; routine SET_MIN clears workspace etc.
  5111.                 RES     5,(IY+$37)      ; update FLAGX - signal in EDIT not INPUT mode.
  5112.                                         ; Note. all the bits were reset earlier.
  5113.  
  5114.                 CALL    CLS_LOWER       ; call routine CLS_LOWER.
  5115.                 SET     5,(IY+$02)      ; update TV_FLAG - signal lower screen
  5116.                                         ; requires clearing.
  5117.  
  5118.                 POP     AF              ; bring back the error number
  5119.                 LD      B,A             ; and make a copy in B.
  5120.                 CP      $0A             ; is it a print-ready digit ?
  5121.                 JR      C,MAIN_5        ; forward to MAIN_5 if so.
  5122.  
  5123.                 ADD     A,$07           ; add ascii offset to letters.
  5124.  
  5125.                                         ;;;$133C
  5126. MAIN_5:         CALL    OUT_CODE        ; call routine OUT_CODE to print the code.
  5127.                 LD      A,$20           ; followed by a space.
  5128.                 RST     10H             ; PRINT_A
  5129.                 LD      A,B             ; fetch stored report code.
  5130.                 LD      DE,RPT_MESGS    ; address: RPT_MESGS.
  5131.                 CALL    PO_MSG          ; call routine PO_MSG to print.
  5132.                 XOR     A               ; clear to directly
  5133.                 LD      DE,COMMA_SP - 1 ; address comma and space message.  
  5134.                 CALL    PO_MSG          ; routine PO_MSG prints them although it would
  5135.                                         ; be more succinct to use RST $10.
  5136.                 LD      BC,(PPC)        ; fetch PPC the current line number.
  5137.                 CALL    OUT_NUM_1       ; routine OUT_NUM_1 will print that
  5138.                 LD      A,$3A           ; then a ':'.
  5139.                 RST     10H             ; PRINT_A
  5140.                 LD      C,(IY+$0D)      ; then SUBPPC for statement
  5141.                 LD      B,$00           ; limited to 127
  5142.                 CALL    OUT_NUM_1       ; routine OUT_NUM_1
  5143.                 CALL    CLEAR_SP        ; routine CLEAR_SP clears editing area.
  5144.                                         ; which probably contained 'RUN'.
  5145.                 LD      A,(ERR_NR)      ; fetch ERR_NR again
  5146.                 INC     A               ; test for no error originally $FF.
  5147.                 JR      Z,MAIN_9        ; forward to MAIN_9 if no error.
  5148.  
  5149.                 CP      $09             ; is code Report 9 STOP ?
  5150.                 JR      Z,MAIN_6        ; forward to MAIN_6 if so
  5151.  
  5152.                 CP      $15             ; is code Report L Break ?
  5153.                 JR      NZ,MAIN_7       ; forward to MAIN_7 if not
  5154.  
  5155.                                         ; Stop or Break was encountered so consider CONTINUE.
  5156.  
  5157.                                         ;;;$1373
  5158. MAIN_6:         INC     (IY+$0D)        ; increment SUBPPC to next statement.
  5159.  
  5160.                                         ;;;$1376
  5161. MAIN_7:         LD      BC,$0003        ; prepare to copy 3 system variables to
  5162.                 LD      DE,OSPPC        ; address OSPPC - statement for CONTINUE.
  5163.                                         ; also updating OLDPPC line number below.
  5164.                 LD      HL,NSPPC        ; set source top to NSPPC next statement.
  5165.                 BIT     7,(HL)          ; did BREAK occur before the jump ?
  5166.                                         ; e.g. between GO TO and next statement.
  5167.                 JR      Z,MAIN_8        ; skip forward to MAIN_8, if not, as setup
  5168.                                         ; is correct.
  5169.                 ADD     HL,BC           ; set source to SUBPPC number of current
  5170.                                         ; statement/line which will be repeated.
  5171.  
  5172.                                         ;;;$1384
  5173. MAIN_8:         LDDR                    ; copy PPC to OLDPPC and SUBPPC to OSPCC
  5174.                                         ; or NSPPC to OLDPPC and NEWPPC to OSPCC
  5175.  
  5176.                                         ;;;$1386
  5177. MAIN_9:         LD      (IY+$0A),$FF    ; update NSPPC - signal 'no jump'.
  5178.                 RES     3,(IY+$01)      ; update FLAGS  - signal use 'K' mode for
  5179.                                         ; the first character in the editor and
  5180.                 JP      MAIN_2          ; jump back to MAIN_2.
  5181.  
  5182.  
  5183. ;-----------------------
  5184. ; Canned report messages
  5185. ;-----------------------
  5186. ; The Error reports with the last byte inverted. The first entry
  5187. ; is a dummy entry. The last, which begins with $7F, the Spectrum
  5188. ; character for copyright symbol, is placed here for convenience
  5189. ; as is the preceding comma and space.
  5190. ; The report line must accomodate a 4-digit line number and a 3-digit
  5191. ; statement number which limits the length of the message text to twenty
  5192. ; characters.
  5193. ; e.g.  "B Integer out of range, 1000:127"
  5194.  
  5195.                                                                 ;;;$1391
  5196. RPT_MESGS:      DEFB    $80
  5197.                 DEFB    "O",'K'+$80                             ; 0
  5198.                 DEFB    "NEXT without FO",'R'+$80               ; 1
  5199.                 DEFB    "Variable not foun",'d'+$80             ; 2
  5200.                 DEFB    "Subscript wron",'g'+$80                ; 3
  5201.                 DEFB    "Out of memor",'y'+$80                  ; 4
  5202.                 DEFB    "Out of scree",'n'+$80                  ; 5
  5203.                 DEFB    "Number too bi",'g'+$80                 ; 6
  5204.                 DEFB    "RETURN without GOSU",'B'+$80           ; 7
  5205.                 DEFB    "End of fil",'e'+$80                    ; 8
  5206.                 DEFB    "STOP statemen",'t'+$80                 ; 9
  5207.                 DEFB    "Invalid argumen",'t'+$80               ; A
  5208.                 DEFB    "Integer out of rang",'e'+$80           ; B
  5209.                 DEFB    "Nonsense in BASI",'C'+$80              ; C
  5210.                 DEFB    "BREAK - CONT repeat",'s'+$80           ; D
  5211.                 DEFB    "Out of DAT",'A'+$80                    ; E
  5212.                 DEFB    "Invalid file nam",'e'+$80              ; F
  5213.                 DEFB    "No room for lin",'e'+$80               ; G
  5214.                 DEFB    "STOP in INPU",'T'+$80                  ; H
  5215.                 DEFB    "FOR without NEX",'T'+$80               ; I
  5216.                 DEFB    "Invalid I/O devic",'e'+$80             ; J
  5217.                 DEFB    "Invalid colou",'r'+$80                 ; K
  5218.                 DEFB    "BREAK into progra",'m'+$80             ; L
  5219.                 DEFB    "RAMTOP no goo",'d'+$80                 ; M
  5220.                 DEFB    "Statement los",'t'+$80                 ; N
  5221.                 DEFB    "Invalid strea",'m'+$80                 ; O
  5222.                 DEFB    "FN without DE",'F'+$80                 ; P
  5223.                 DEFB    "Parameter erro",'r'+$80                ; Q
  5224.                 DEFB    "Tape loading erro",'r'+$80             ; R
  5225.  
  5226.                                                                 ;;;$1537       
  5227. COMMA_SP:       DEFB    ",",' '+$80                             ; used in report line.
  5228.  
  5229.                                                                 ;;;$1539
  5230. COPYRIGHT:      DEFB    $7F                                     ; copyright
  5231.                 DEFB    " 1982 Sinclair Research Lt",'d'+$80
  5232.  
  5233. ;---------
  5234. ; REPORT_G
  5235. ;---------
  5236. ; Note ERR_SP points here during line entry which allows the
  5237. ; normal 'Out of Memory' report to be augmented to the more
  5238. ; precise 'No Room for line' report.
  5239.  
  5240.                                         ;;;$1555
  5241.                                         ; No Room for line
  5242. REPORT_G:       LD      A,$10           ; i.e. 'G' -$30 -$07
  5243.                 LD      BC,$0000        ; this seems unnecessary.
  5244.                 JP      MAIN_G          ; jump back to MAIN_G
  5245.  
  5246. ;------------------------------
  5247. ; Handle addition of BASIC line
  5248. ;------------------------------
  5249. ; Note this is not a subroutine but a branch of the main execution loop.
  5250. ; System variable ERR_SP still points to editing error handler.
  5251. ; A new line is added to the Basic program at the appropriate place.
  5252. ; An existing line with same number is deleted first.
  5253. ; Entering an existing line number deletes that line.
  5254. ; Entering a non-existent line allows the subsequent line to be edited next.
  5255.  
  5256.                                         ;;;$155D
  5257. MAIN_ADD:       LD      (E_PPC),BC      ; set E_PPC to extracted line number.
  5258.                 LD      HL,(CH_ADD)     ; fetch CH_ADD - points to location after the
  5259.                                         ; initial digits (set in E_LINE_NO).
  5260.                 EX      DE,HL           ; save start of BASIC in DE.
  5261.                 LD      HL,REPORT_G     ; Address: REPORT_G
  5262.                 PUSH    HL              ; is pushed on stack and addressed by ERR_SP.
  5263.                                         ; the only error that can occur is
  5264.                                         ; 'Out of memory'.
  5265.                 LD      HL,(WORKSP)     ; fetch WORKSP - end of line.
  5266.                 SCF                     ; prepare for true subtraction.
  5267.                 SBC     HL,DE           ; find length of BASIC and
  5268.                 PUSH    HL              ; save it on stack.
  5269.                 LD      H,B             ; transfer line number
  5270.                 LD      L,C             ; to HL register.
  5271.                 CALL    LINE_ADDR       ; routine LINE_ADDR will see if
  5272.                                         ; a line with the same number exists.
  5273.                 JR      NZ,MAIN_ADD1    ; forward if no existing line to MAIN_ADD1.
  5274.  
  5275.                 CALL    NEXT_ONE        ; routine NEXT_ONE finds the existing line.
  5276.                 CALL    RECLAIM_2       ; routine RECLAIM_2 reclaims it.
  5277.  
  5278.                                         ;;;$157D
  5279. MAIN_ADD1:      POP     BC              ; retrieve the length of the new line.
  5280.                 LD      A,C             ; and test if carriage return only
  5281.                 DEC     A               ; i.e. one byte long.
  5282.                 OR      B               ; result would be zero.
  5283.                 JR      Z,MAIN_ADD2     ; forward to MAIN_ADD2 is so.
  5284.  
  5285.                 PUSH    BC              ; save the length again.
  5286.                 INC     BC              ; adjust for inclusion
  5287.                 INC     BC              ; of line number (two bytes)
  5288.                 INC     BC              ; and line length
  5289.                 INC     BC              ; (two bytes).
  5290.                 DEC     HL              ; HL points to location before the destination
  5291.                 LD      DE,(PROG)       ; fetch the address of PROG
  5292.                 PUSH    DE              ; and save it on the stack
  5293.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM creates BC spaces in
  5294.                                         ; program area and updates pointers.
  5295.                 POP     HL              ; restore old program pointer.
  5296.                 LD      (PROG),HL       ; and put back in PROG as it may have been
  5297.                                         ; altered by the POINTERS routine.
  5298.                 POP     BC              ; retrieve BASIC length
  5299.                 PUSH    BC              ; and save again.
  5300.                 INC     DE              ; points to end of new area.
  5301.                 LD      HL,(WORKSP)     ; set HL to WORKSP - location after edit line.
  5302.                 DEC     HL              ; decrement to address end marker.
  5303.                 DEC     HL              ; decrement to address carriage return.
  5304.                 LDDR                    ; copy the Basic line back to initial command.
  5305.                 LD      HL,(E_PPC)      ; fetch E_PPC - line number.
  5306.                 EX      DE,HL           ; swap it to DE, HL points to last of four locations.
  5307.                 POP     BC              ; retrieve length of line.
  5308.                 LD      (HL),B          ; high byte last.
  5309.                 DEC     HL
  5310.                 LD      (HL),C          ; then low byte of length.
  5311.                 DEC     HL
  5312.                 LD      (HL),E          ; then low byte of line number.
  5313.                 DEC     HL
  5314.                 LD      (HL),D          ; then high byte range $0 - $27 (1-9999).
  5315.  
  5316.                                         ;;;$15AB
  5317. MAIN_ADD2:      POP     AF              ; drop the address of Report G
  5318.                 JP      MAIN_EXEC       ; and back to MAIN_EXEC producing a listing
  5319.                                         ; and to reset ERR_SP in EDITOR.
  5320.  
  5321. ;----------------------------
  5322. ; Initial channel information
  5323. ;----------------------------
  5324. ; This initial channel information is copied from ROM to RAM,
  5325. ; during initialization. It's new location is after the system
  5326. ; variables and is addressed by the system variable CHANS
  5327. ; which means that it can slide up and down in memory.
  5328. ; The table is never searched and the last character which could be anything
  5329. ; other than a comma provides a convenient resting place for DATADD.
  5330.  
  5331.                                         ;;;$15AF
  5332. INIT_CHAN:      DEFW    PRINT_OUT       ; PRINT_OUT
  5333.                 DEFW    KEY_INPUT       ; KEY_INPUT
  5334.                 DEFB    $4B             ; 'K'
  5335.                 DEFW    PRINT_OUT       ; PRINT_OUT
  5336.                 DEFW    REPORT_J        ; REPORT_J
  5337.                 DEFB    $53             ; 'S'
  5338.                 DEFW    ADD_CHAR        ; ADD_CHAR
  5339.                 DEFW    REPORT_J        ; REPORT_J
  5340.                 DEFB    $52             ; 'R'
  5341.                 DEFW    PRINT_OUT       ; PRINT_OUT
  5342.                 DEFW    REPORT_J        ; REPORT_J
  5343.                 DEFB    $50             ; 'P'
  5344.  
  5345.                 DEFB    $80             ; End Marker
  5346.  
  5347.                                         ;;;$15C4
  5348. REPORT_J:       RST     08H             ; ERROR_1
  5349.                 DEFB    $12             ; Error Report: Invalid I/O device
  5350.  
  5351. ;--------------------
  5352. ; Initial stream data
  5353. ;--------------------
  5354. ; This is the initial stream data for the seven streams $FD - $03 that is
  5355. ; copied from ROM to the STRMS system variables area during initialization.
  5356. ; There are reserved locations there for another 12 streams.
  5357. ; Each location contains an offset to the second byte of a channel.
  5358. ; The first byte of a channel can't be used as that would result in an
  5359. ; offset of zero for some and zero is used to denote that a stream is closed.
  5360.  
  5361.                                         ;;;$15C6
  5362. INIT_STRM:      DEFB    $01, $00        ; stream $FD offset to channel 'K'
  5363.                 DEFB    $06, $00        ; stream $FE offset to channel 'S'
  5364.                 DEFB    $0B, $00        ; stream $FF offset to channel 'R'
  5365.                 DEFB    $01, $00        ; stream $00 offset to channel 'K'
  5366.                 DEFB    $01, $00        ; stream $01 offset to channel 'K'
  5367.                 DEFB    $06, $00        ; stream $02 offset to channel 'S'
  5368.                 DEFB    $10, $00        ; stream $03 offset to channel 'P'
  5369.  
  5370. ;-----------------------------
  5371. ; Control for input subroutine
  5372. ;-----------------------------
  5373.  
  5374.                                         ;;;$15D4
  5375. WAIT_KEY:       BIT     5,(IY+$02)      ; test TV_FLAG - clear lower screen ?
  5376.                 JR      NZ,WAIT_KEY1    ; forward to WAIT_KEY1 if so.
  5377.  
  5378.                 SET     3,(IY+$02)      ; update TV_FLAG - signal reprint the edit
  5379.                                         ; line to the lower screen.
  5380.  
  5381.                                         ;;;$15DE
  5382. WAIT_KEY1:      CALL    INPUT_AD        ; routine INPUT_AD is called.
  5383.                 RET     C               ; return with acceptable keys.
  5384.  
  5385.                 JR      Z,WAIT_KEY1     ; back to WAIT_KEY1 if no key is pressed
  5386.                                         ; or it has been handled within INPUT_AD.
  5387.  
  5388.                                         ; Note. When inputting from the keyboard all characters are returned with
  5389.                                         ; above conditions so this path is never taken.
  5390.  
  5391.                                         ;;;$15E4
  5392. REPORT_8:       RST     08H             ; ERROR_1
  5393.                 DEFB    $07             ; Error Report: End of file
  5394.  
  5395. ;-------------------------------
  5396. ; Make HL point to input address
  5397. ;-------------------------------
  5398. ; This routine fetches the address of the input stream from the current
  5399. ; channel area using system variable CURCHL.
  5400.  
  5401.                                         ;;;$15E6
  5402. INPUT_AD:       EXX                     ; switch in alternate set.
  5403.                 PUSH    HL              ; save HL register
  5404.                 LD      HL,(CURCHL)     ; fetch address of CURCHL - current channel.
  5405.                 INC     HL              ; step over output routine
  5406.                 INC     HL              ; to point to low byte of input routine.
  5407.                 JR      CALL_SUB        ; forward to CALL_SUB.
  5408.  
  5409. ;--------------------
  5410. ; Main Output Routine
  5411. ;--------------------
  5412. ; The entry point OUT_CODE is called on five occasions to print
  5413. ; the ascii equivalent of a value 0-9.
  5414. ;
  5415. ; PRINT_A_2 is a continuation of the RST 10 to print any character.
  5416. ; Both print to the current channel and the printing of control codes
  5417. ; may alter that channel to divert subsequent RST 10 instructions
  5418. ; to temporary routines. The normal channel is $09F4.
  5419.  
  5420.                                         ;;;$15EF
  5421. OUT_CODE:       LD      E,$30           ; add 48 decimal to give ascii
  5422.                 ADD     A,E             ; character '0' to '9'.
  5423.  
  5424.                                         ;;;$15F2
  5425. PRINT_A_2:      EXX                     ; switch in alternate set
  5426.                 PUSH    HL              ; save HL register
  5427.                 LD      HL,(CURCHL)     ; fetch CURCHL the current channel.
  5428.  
  5429.                                         ; INPUT_AD rejoins here also.
  5430.  
  5431.                                         ;;;$15F7
  5432. CALL_SUB:       LD      E,(HL)          ; put the low byte in E.
  5433.                 INC     HL              ; advance address.
  5434.                 LD      D,(HL)          ; put the high byte to D.
  5435.                 EX      DE,HL           ; transfer the stream to HL.
  5436.                 CALL    CALL_JUMP       ; use routine CALL_JUMP.
  5437.                                         ; in effect CALL (HL).
  5438.                 POP     HL              ; restore saved HL register.
  5439.                 EXX                     ; switch back to the main set and
  5440.                 RET                     ; return.
  5441.  
  5442. ;-------------
  5443. ; Open channel
  5444. ;-------------
  5445. ; This subroutine is used by the ROM to open a channel 'K', 'S', 'R' or 'P'.
  5446. ; This is either for it's own use or in response to a user's request, for
  5447. ; example, when '#' is encountered with output - PRINT, LIST etc.
  5448. ; or with input - INPUT, INKEY$ etc.
  5449. ; it is entered with a system stream $FD - $FF, or a user stream $00 - $0F
  5450. ; in the accumulator.
  5451.  
  5452.                                         ;;;$1601
  5453. CHAN_OPEN:      ADD     A,A             ; double the stream ($FF will become $FE etc.)
  5454.                 ADD     A,$16           ; add the offset to stream 0 from $5C00
  5455.                 LD      L,A             ; result to L
  5456.                 LD      H,$5C           ; now form the address in STRMS area.
  5457.                 LD      E,(HL)          ; fetch low byte of CHANS offset
  5458.                 INC     HL              ; address next
  5459.                 LD      D,(HL)          ; fetch high byte of offset
  5460.                 LD      A,D             ; test that the stream is open.
  5461.                 OR      E               ; zero if closed.
  5462.                 JR      NZ,CHAN_OP_1    ; forward to CHAN_OP_1 if open.
  5463.  
  5464.                                         ;;;$160E
  5465. REPORT_OA:      RST     08H             ; ERROR_1
  5466.                 DEFB    $17             ; Error Report: Invalid stream
  5467.  
  5468.                                         ; continue here if stream was open. Note that the offset is from CHANS
  5469.                                         ; to the second byte of the channel.
  5470.  
  5471.                                         ;;;$1610
  5472. CHAN_OP_1:      DEC     DE              ; reduce offset so it points to the channel.
  5473.                 LD      HL,(CHANS)      ; Fetch CHANS the location of the base of
  5474.                                         ; the channel information area
  5475.                 ADD     HL,DE           ; and add the offset to address the channel.
  5476.                                         ; and continue to set flags.
  5477.  
  5478. ;------------------
  5479. ; Set channel flags
  5480. ;------------------
  5481. ; This subroutine is used from ED_EDIT, STR$ and READ_IN to reset the
  5482. ; current channel when it has been temporarily altered.
  5483.  
  5484.                                         ;;;$1615
  5485. CHAN_FLAG:      LD      (CURCHL),HL     ; set CURCHL system variable to the address in HL
  5486.                 RES     4,(IY+$30)      ; update FLAGS2  - signal K channel not in use.
  5487.                                         ; Note. provide a default for channel 'R'.
  5488.                 INC     HL              ; advance past
  5489.                 INC     HL              ; output routine.
  5490.                 INC     HL              ; advance past
  5491.                 INC     HL              ; input routine.
  5492.                 LD      C,(HL)          ; pick up the letter.
  5493.                 LD      HL,CHN_CD_LU    ; address: CHN_CD_LU
  5494.                 CALL    INDEXER         ; routine INDEXER finds offset to a
  5495.                                         ; flag-setting routine.
  5496.                 RET     NC              ; but if the letter wasn't found in the
  5497.                                         ; table just return now. - channel 'R'.
  5498.                 LD      D,$00           ; prepare to add
  5499.                 LD      E,(HL)          ; offset to E
  5500.                 ADD     HL,DE           ; add offset to location of offset to form
  5501.                                         ; address of routine
  5502.  
  5503.                                         ;;;$L162C
  5504. CALL_JUMP:      JP      (HL)            ; jump to the routine
  5505.  
  5506.                                         ; Footnote. calling any location that holds JP (HL) is the equivalent to
  5507.                                         ; a pseudo Z80 instruction CALL (HL). The ROM uses the instruction above.
  5508.  
  5509. ;---------------------------
  5510. ; Channel code look-up table
  5511. ;---------------------------
  5512. ; This table is used by the routine above to find one of the three
  5513. ; flag setting routines below it.
  5514. ; A zero end-marker is required as channel 'R' is not present.
  5515.  
  5516.                                         ;;;$162D
  5517. CHN_CD_LU:      DEFB    'K', CHAN_K-$-1 ; offset $06 to CHAN_K
  5518.                 DEFB    'S', CHAN_S-$-1 ; offset $12 to CHAN_S
  5519.                 DEFB    'P', CHAN_P-$-1 ; offset $1B to CHAN_P
  5520.  
  5521.                 DEFB    $00             ; end marker.
  5522.  
  5523. ;---------------
  5524. ; Channel K flag
  5525. ;---------------
  5526. ; routine to set flags for lower screen/keyboard channel.
  5527.  
  5528.                                         ;;;$1634
  5529. CHAN_K:         SET     0,(IY+$02)      ; update TV_FLAG  - signal lower screen in use
  5530.                 RES     5,(IY+$01)      ; update FLAGS  - signal no new key
  5531.                 SET     4,(IY+$30)      ; update FLAGS2 - signal K channel in use
  5532.                 JR      CHAN_S_1        ; forward to CHAN_S_1 for indirect exit
  5533.  
  5534. ;---------------
  5535. ; Channel S flag
  5536. ;---------------
  5537. ; routine to set flags for upper screen channel.
  5538.  
  5539.                                         ;;;$1642
  5540. CHAN_S:         RES     0,(IY+$02)      ; TV_FLAG  - signal main screen in use
  5541.  
  5542.                                         ;;;$1646
  5543. CHAN_S_1:       RES     1,(IY+$01)      ; update FLAGS  - signal printer not in use
  5544.                 JP      TEMPS           ; jump back to TEMPS and exit via that
  5545.                                         ; routine after setting temporary attributes.
  5546. ;---------------
  5547. ; Channel P flag
  5548. ;---------------
  5549. ; This routine sets a flag so that subsequent print related commands
  5550. ; print to printer or update the relevant system variables.
  5551. ; This status remains in force until reset by the routine above.
  5552.  
  5553.                                         ;;;$164D
  5554. CHAN_P:         SET     1,(IY+$01)      ; update FLAGS  - signal printer in use
  5555.                 RET                     ; return
  5556.  
  5557. ;------------------------
  5558. ; Just one space required
  5559. ;------------------------
  5560. ; This routine is called once only to create a single space
  5561. ; in workspace by ADD_CHAR. It is slightly quicker than using a RST $30.
  5562. ; There are several instances in the calculator where the sequence
  5563. ; ld bc, 1; rst $30 could be replaced by a call to this routine but it
  5564. ; only gives a saving of one byte each time.
  5565.  
  5566.                                         ;;;$1652
  5567. ONE_SPACE:      LD      BC,$0001        ; create space for a single character.
  5568.  
  5569. ;----------
  5570. ; Make Room
  5571. ;----------
  5572. ; This entry point is used to create BC spaces in various areas such as
  5573. ; program area, variables area, workspace etc..
  5574. ; The entire free RAM is available to each BASIC statement.
  5575. ; On entry, HL addresses where the first location is to be created.
  5576. ; Afterwards, HL will point to the location before this.
  5577.  
  5578.                                         ;;;$1655
  5579. MAKE_ROOM:      PUSH    HL              ; save the address pointer.
  5580.                 CALL    TEST_ROOM       ; routine TEST_ROOM checks if room
  5581.                                         ; exists and generates an error if not.
  5582.                 POP     HL              ; restore the address pointer.
  5583.                 CALL    POINTERS        ; routine POINTERS updates the
  5584.                                         ; dynamic memory location pointers.
  5585.                                         ; DE now holds the old value of STKEND.
  5586.                 LD      HL,(STKEND)     ; fetch new STKEND the top destination.
  5587.                 EX      DE,HL           ; HL now addresses the top of the area to
  5588.                                         ; be moved up - old STKEND.
  5589.                 LDDR                    ; the program, variables, etc are moved up.
  5590.                 RET                     ; return with new area ready to be populated.
  5591.                                         ; HL points to location before new area,
  5592.                                         ; and DE to last of new locations.
  5593.  
  5594. ;------------------------------------------------
  5595. ; Adjust pointers before making or reclaiming room
  5596. ;------------------------------------------------
  5597. ; This routine is called by MAKE_ROOM to adjust upwards and by RECLAIM to
  5598. ; adjust downwards the pointers within dynamic memory.
  5599. ; The fourteen pointers to dynamic memory, starting with VARS and ending
  5600. ; with STKEND, are updated adding BC if they are higher than the position
  5601. ; in HL.  
  5602. ; The system variables are in no particular order except that STKEND, the first
  5603. ; free location after dynamic memory must be the last encountered.
  5604.  
  5605.                                         ;;;$1664
  5606. POINTERS:       PUSH    AF              ; preserve accumulator.
  5607.                 PUSH    HL              ; put pos pointer on stack.
  5608.                 LD      HL,VARS         ; address VARS the first of the
  5609.                 LD      A,$0E           ; fourteen variables to consider.
  5610.  
  5611.                                         ;;;$166B
  5612. PTR_NEXT:       LD      E,(HL)          ; fetch the low byte of the system variable.
  5613.                 INC     HL              ; advance address.
  5614.                 LD      D,(HL)          ; fetch high byte of the system variable.
  5615.                 EX      (SP),HL         ; swap pointer on stack with the variable pointer.
  5616.                 AND     A               ; prepare to subtract.
  5617.                 SBC     HL,DE           ; subtract variable address
  5618.                 ADD     HL,DE           ; and add back
  5619.                 EX      (SP),HL         ; swap pos with system variable pointer
  5620.                 JR      NC,PTR_DONE     ; forward to PTR_DONE if var before pos
  5621.  
  5622.                 PUSH    DE              ; save system variable address.
  5623.                 EX      DE,HL           ; transfer to HL
  5624.                 ADD     HL,BC           ; add the offset
  5625.                 EX      DE,HL           ; back to DE
  5626.                 LD      (HL),D          ; load high byte
  5627.                 DEC     HL              ; move back
  5628.                 LD      (HL),E          ; load low byte
  5629.                 INC     HL              ; advance to high byte
  5630.                 POP     DE              ; restore old system variable address.
  5631.  
  5632.                                         ;;;$167F
  5633. PTR_DONE:       INC     HL              ; address next system variable.
  5634.                 DEC     A               ; decrease counter.
  5635.                 JR      NZ,PTR_NEXT     ; back to PTR_NEXT if more.
  5636.                 EX      DE,HL           ; transfer old value of STKEND to HL.
  5637.                                         ; Note. this has always been updated.
  5638.                 POP     DE              ; pop the address of the position.
  5639.                 POP     AF              ; pop preserved accumulator.
  5640.                 AND     A               ; clear carry flag preparing to subtract.
  5641.                 SBC     HL,DE           ; subtract position from old stkend
  5642.                 LD      B,H             ; to give number of data bytes
  5643.                 LD      C,L             ; to be moved.
  5644.                 INC     BC              ; increment as we also copy byte at old STKEND.
  5645.                 ADD     HL,DE           ; recompute old stkend.
  5646.                 EX      DE,HL           ; transfer to DE.
  5647.                 RET                     ; return.
  5648.  
  5649. ;--------------------
  5650. ; Collect line number
  5651. ;--------------------
  5652. ; This routine extracts a line number, at an address that has previously
  5653. ; been found using LINE_ADDR, and it is entered at LINE_NO. If it encounters
  5654. ; the program 'end-marker' then the previous line is used and if that
  5655. ; should also be unacceptable then zero is used as it must be a direct
  5656. ; command. The program end-marker is the variables end-marker $80, or
  5657. ; if variables exist, then the first character of any variable name.
  5658.  
  5659.                                         ;;;$168F
  5660. LINE_ZERO:      DEFB    $00, $00        ; dummy line number used for direct commands
  5661.  
  5662.                                         ;;;$1691
  5663. LINE_NO_A:      EX      DE,HL           ; fetch the previous line to HL and set
  5664.                 LD      DE,LINE_ZERO    ; DE to LINE_ZERO should HL also fail.
  5665.  
  5666.                                         ; -> The Entry Point.
  5667.  
  5668.                                         ;;;$1695
  5669. LINE_NO:        LD      A,(HL)          ; fetch the high byte - max $2F
  5670.                 AND     $C0             ; mask off the invalid bits.
  5671.                 JR      NZ,LINE_NO_A    ; to LINE_NO_A if an end-marker.
  5672.  
  5673.                 LD      D,(HL)          ; reload the high byte.
  5674.                 INC     HL              ; advance address.
  5675.                 LD      E,(HL)          ; pick up the low byte.
  5676.                 RET                     ; return from here.
  5677.  
  5678. ;--------------------
  5679. ; Handle reserve room
  5680. ;--------------------
  5681. ; This is a continuation of the restart BC_SPACES
  5682.  
  5683.                                         ;;;$169E
  5684. RESERVE:        LD      HL,(STKBOT)     ; STKBOT first location of calculator stack
  5685.                 DEC     HL              ; make one less than new location
  5686.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM creates the room.
  5687.                 INC     HL              ; address the first new location
  5688.                 INC     HL              ; advance to second
  5689.                 POP     BC              ; restore old WORKSP
  5690.                 LD      (WORKSP),BC     ; system variable WORKSP was perhaps
  5691.                                         ; changed by POINTERS routine.
  5692.                 POP     BC              ; restore count for return value.
  5693.                 EX      DE,HL           ; switch. DE = location after first new space
  5694.                 INC     HL              ; HL now location after new space
  5695.                 RET                     ; return.
  5696.  
  5697. ;----------------------------
  5698. ; Clear various editing areas
  5699. ;----------------------------
  5700. ; This routine sets the editing area, workspace and calculator stack
  5701. ; to their minimum configurations as at initialization and indeed this
  5702. ; routine could have been relied on to perform that task.
  5703. ; This routine uses HL only and returns with that register holding
  5704. ; WORKSP/STKBOT/STKEND though no use is made of this. The routines also
  5705. ; reset MEM to it's usual place in the systems variable area should it
  5706. ; have been relocated to a FOR-NEXT variable. The main entry point
  5707. ; SET_MIN is called at the start of the MAIN_EXEC loop and prior to
  5708. ; displaying an error.
  5709.  
  5710.                                         ;;;$16B0
  5711. SET_MIN:        LD      HL,(E_LINE)     ; fetch E_LINE
  5712.                 LD      (HL),$0D        ; insert carriage return
  5713.                 LD      (K_CUR),HL      ; make K_CUR keyboard cursor point there.
  5714.                 INC     HL              ; next location
  5715.                 LD      (HL),$80        ; holds end-marker $80
  5716.                 INC     HL              ; next location becomes
  5717.                 LD      (WORKSP),HL     ; start of WORKSP
  5718.  
  5719.                                         ; This entry point is used prior to input and prior to the execution,
  5720.                                         ; or parsing, of each statement.
  5721.  
  5722.                                         ;;;$16BF
  5723. SET_WORK:       LD      HL,(WORKSP)     ; fetch WORKSP value
  5724.                 LD      (STKBOT),HL     ; and place in STKBOT
  5725.  
  5726.                                         ; This entry point is used to move the stack back to it's normal place
  5727.                                         ; after temporary relocation during line entry and also from ERROR_3
  5728.  
  5729.                                         ;;;$16C5
  5730. SET_STK:        LD      HL,(STKBOT)     ; fetch STKBOT value
  5731.                 LD      (STKEND),HL     ; and place in STKEND.
  5732.                 PUSH    HL              ; perhaps an obsolete entry point.
  5733.                 LD      HL,MEM_0        ; normal location of MEM_0
  5734.                 LD      (MEM),HL        ; is restored to system variable MEM.
  5735.                 POP     HL              ; saved value not required.
  5736.                 RET                     ; return.
  5737.  
  5738. ;-------------------
  5739. ; Reclaim edit-line?
  5740. ;-------------------
  5741. ; This seems to be legacy code from the ZX80/ZX81 as it is
  5742. ; not used in this ROM.
  5743. ; That task, in fact, is performed here by the dual-area routine CLEAR_SP.
  5744. ; This routine is designed to deal with something that is known to be in the
  5745. ; edit buffer and not workspace.
  5746. ; On entry, HL must point to the end of the something to be deleted.
  5747.  
  5748.                                         ;;;$16D4
  5749. REC_EDIT:       LD      DE,(E_LINE)     ; fetch start of edit line from E_LINE.
  5750.                 JP      RECLAIM_1       ; jump forward to RECLAIM_1.
  5751.  
  5752. ;---------------------------
  5753. ; The Table INDEXING routine
  5754. ;---------------------------
  5755. ; This routine is used to search two-byte hash tables for a character
  5756. ; held in C, returning the address of the following offset byte.
  5757. ; if it is known that the character is in the table e.g. for priorities,
  5758. ; then the table requires no zero end-marker. If this is not known at the
  5759. ; outset then a zero end-marker is required and carry is set to signal
  5760. ; success.
  5761.  
  5762.                                         ;;;$16DB
  5763. INDEXER_1:      INC     HL              ; address the next pair of values.
  5764.  
  5765.                                         ; -> The Entry Point.
  5766.  
  5767.                                         ;;;$16DC
  5768. INDEXER:        LD      A,(HL)          ; fetch the first byte of pair
  5769.                 AND     A               ; is it the end-marker ?
  5770.                 RET     Z               ; return with carry reset if so.
  5771.  
  5772.                 CP      C               ; is it the required character ?
  5773.                 INC     HL              ; address next location.
  5774.                 JR      NZ,INDEXER_1    ; back to INDEXER_1 if no match.
  5775.  
  5776.                 SCF                     ; else set the carry flag.
  5777.                 RET                     ; return with carry set
  5778.  
  5779. ;---------------------------------
  5780. ; The Channel and Streams Routines
  5781. ;---------------------------------
  5782. ; A channel is is an input/output route to a hardware device
  5783. ; and is identified to the system by a single letter e.g. 'K' for
  5784. ; the keyboard. A channel can have an input and output route
  5785. ; associated with it in which case it is bi-directional like
  5786. ; the keyboard. Others like the upper screen 'S' are output
  5787. ; only and the input routine usually points to a report message.
  5788. ; Channels 'K' and 'S' are system channels and it would be inappropriate
  5789. ; to close the associated streams so a mechanism is provided to
  5790. ; re-attach them. When the re-attachment is no longer required, then
  5791. ; closing these streams resets them as at initialization.
  5792. ; The same also would have applied to channel 'R', the RS232 channel
  5793. ; as that is used by the system. It's input stream seems to have been
  5794. ; removed and it is not available to the user. However the channel could
  5795. ; not be removed entirely as its output routine was used by the system.
  5796. ; As a result of removing this channel, channel 'P', the printer is
  5797. ; erroneously treated as a system channel.
  5798. ; Ironically the tape streamer is not accessed through streams and
  5799. ; channels.
  5800. ; Early demonstrations of the Spectrum showed a single microdrive being
  5801. ; controlled by this ROM. Adverts also said that the network and RS232
  5802. ; were in this ROM. Channels 'M' and 'N' are user channels and have been
  5803. ; removed successfully if, as seems possible, they existed.
  5804.  
  5805. ;----------------------
  5806. ; Handle CLOSE# command
  5807. ;----------------------
  5808. ; This command allows streams to be closed after use.
  5809. ; Any temporary memory areas used by the stream would be reclaimed and
  5810. ; finally flags set or reset if necessary.
  5811.  
  5812.                                         ;;;$16E5
  5813. CLOSE:          CALL    STR_DATA        ; routine STR_DATA fetches parameter
  5814.                                         ; from calculator stack and gets the
  5815.                                         ; existing STRMS data pointer address in HL
  5816.                                         ; and stream offset from CHANS in BC.
  5817.  
  5818.                                         ; Note. this offset could be zero if the
  5819.                                         ; stream is already closed. A check for this
  5820.                                         ; should occur now and an error should be
  5821.                                         ; generated, for example,
  5822.                                         ; Report S 'Stream already closed'.
  5823.  
  5824.                 CALL    CLOSE_2         ; routine CLOSE_2 would perform any actions
  5825.                                         ; peculiar to that stream without disturbing
  5826.                                         ; data pointer to STRMS entry in HL.
  5827.                 LD      BC,$0000        ; the stream is to be blanked.
  5828.                 LD      DE,$A3E2        ; the number of bytes from stream 4, $5C1E, to $10000
  5829.                 EX      DE,HL           ; transfer offset to HL, STRMS data pointer to DE.
  5830.                 ADD     HL,DE           ; add the offset to the data pointer.  
  5831.                 JR      C,CLOSE_1       ; forward to CLOSE_1 if a non-system stream.
  5832.                                         ; i.e. higher than 3.
  5833.  
  5834.                                         ; proceed with a negative result.
  5835.  
  5836.                 LD      BC,INIT_STRM+14 ; prepare the address of the byte after
  5837.                                         ; the initial stream data in ROM. ($15D4)
  5838.                 ADD     HL,BC           ; index into the data table with negative value.
  5839.                 LD      C,(HL)          ; low byte to C
  5840.                 INC     HL              ; address next.
  5841.                 LD      B,(HL)          ; high byte to B.
  5842.  
  5843.                                         ; and for streams 0 - 3 just enter the initial data back into the STRMS entry
  5844.                                         ; streams 0 - 2 can't be closed as they are shared by the operating system.
  5845.                                         ; -> for streams 4 - 15 then blank the entry.
  5846.  
  5847.                                         ;;;$16FC
  5848. CLOSE_1:        EX      DE,HL           ; address of stream to HL.
  5849.                 LD      (HL),C          ; place zero (or low byte).
  5850.                 INC     HL              ; next address.
  5851.                 LD      (HL),B          ; place zero (or high byte).
  5852.                 RET                     ; return.
  5853.  
  5854. ;-------------------
  5855. ; CLOSE_2 Subroutine
  5856. ;-------------------
  5857. ; There is not much point in coming here.
  5858. ; The purpose was once to find the offset to a special closing routine,
  5859. ; in this ROM and within 256 bytes of the close stream look up table that
  5860. ; would reclaim any buffers associated with a stream. At least one has been
  5861. ; removed.
  5862.  
  5863.                                         ;;;$1701
  5864. CLOSE_2:        PUSH    HL              ; * save address of stream data pointer
  5865.                                         ; in STRMS on the machine stack.
  5866.                 LD      HL,(CHANS)      ; fetch CHANS address to HL
  5867.                 ADD     HL,BC           ; add the offset to address the second
  5868.                                         ; byte of the output routine hopefully.
  5869.                 INC     HL              ; step past
  5870.                 INC     HL              ; the input routine.
  5871.                 INC     HL              ; to address channel's letter
  5872.                 LD      C,(HL)          ; pick it up in C.
  5873.                                         ; Note. but if stream is already closed we
  5874.                                         ; get the value $10 (the byte preceding 'K').
  5875.                 EX      DE,HL           ; save the pointer to the letter in DE.
  5876.                 LD      HL,CL_STR_LU    ; address: CL_STR_LU in ROM.
  5877.                 CALL    INDEXER         ; routine INDEXER uses the code to get
  5878.                                         ; the 8-bit offset from the current point to
  5879.                                         ; the address of the closing routine in ROM.
  5880.                                         ; Note. it won't find $10 there!
  5881.                 LD      C,(HL)          ; transfer the offset to C.
  5882.                 LD      B,$00           ; prepare to add.
  5883.                 ADD     HL,BC           ; add offset to point to the address of the
  5884.                                         ; routine that closes the stream.
  5885.                                         ; (and presumably removes any buffers that
  5886.                                         ; are associated with it.)
  5887.                 JP      (HL)            ; jump to that routine.
  5888.  
  5889. ;---------------------------
  5890. ; CLOSE stream look-up table
  5891. ;---------------------------
  5892. ; This table contains an entry for a letter found in the CHANS area.
  5893. ; followed by an 8-bit displacement, from that byte's address in the
  5894. ; table to the routine that performs any ancillary actions associated
  5895. ; with closing the stream of that channel.
  5896. ; The table doesn't require a zero end-marker as the letter has been
  5897. ; picked up from a channel that has an open stream.
  5898.  
  5899.                                                 ;;;$1716
  5900. CL_STR_LU:      DEFB    'K', CLOSE_STR-$-1      ; offset 5 to CLOSE_STR
  5901.                 DEFB    'S', CLOSE_STR-$-1      ; offset 3 to CLOSE_STR
  5902.                 DEFB    'P', CLOSE_STR-$-1      ; offset 1 to CLOSE_STR
  5903.  
  5904.  
  5905. ;-------------------------
  5906. ; Close Stream Subroutines
  5907. ;-------------------------
  5908. ; The close stream routines in fact have no ancillary actions to perform
  5909. ; which is not surprising with regard to 'K' and 'S'.
  5910.  
  5911.                                         ;;;$171C                       
  5912. CLOSE_STR:      POP     HL              ; * now just restore the stream data pointer
  5913.                 RET                     ; in STRMS and return.
  5914.  
  5915. ;------------
  5916. ; Stream data
  5917. ;------------
  5918. ; This routine finds the data entry in the STRMS area for the specified
  5919. ; stream which is passed on the calculator stack. It returns with HL
  5920. ; pointing to this system variable and BC holding a displacement from
  5921. ; the CHANS area to the second byte of the stream's channel. If BC holds
  5922. ; zero, then that signifies that the stream is closed.
  5923.  
  5924.                                         ;;;$171E
  5925. STR_DATA:       CALL    FIND_INT1       ; routine FIND_INT1 fetches parameter to A
  5926.                 CP      $10             ; is it less than 16d ?
  5927.                 JR      C,STR_DATA1     ; skip forward to STR_DATA1 if so.
  5928.  
  5929.                                         ;;;$1725
  5930. REPORT_OB:      RST     08H             ; ERROR_1
  5931.                 DEFB    $17             ; Error Report: Invalid stream
  5932.  
  5933.                                         ;;;$1727
  5934. STR_DATA1:      ADD     A,$03           ; add the offset for 3 system streams.
  5935.                                         ; range 00 - 15d becomes 3 - 18d.
  5936.                 RLCA                    ; double as there are two bytes per
  5937.                                         ; stream - now 06 - 36d
  5938.                 LD      HL,STRMS_FD     ; address STRMS_FD - the start of the streams
  5939.                                         ; data area in system variables.
  5940.                 LD      C,A             ; transfer the low byte to A.
  5941.                 LD      B,$00           ; prepare to add offset.
  5942.                 ADD     HL,BC           ; add to address the data entry in STRMS_FD.
  5943.  
  5944.                                         ; the data entry itself contains an offset from CHANS to the address of the
  5945.                                         ; stream
  5946.  
  5947.                 LD      C,(HL)          ; low byte of displacement to C.
  5948.                 INC     HL              ; address next.
  5949.                 LD      B,(HL)          ; high byte of displacement to B.
  5950.                 DEC     HL              ; step back to leave HL pointing to STRMS_FD data entry.
  5951.                 RET                     ; return with CHANS displacement in BC
  5952.                                         ; and address of stream data entry in HL.
  5953.  
  5954. ;---------------------
  5955. ; Handle OPEN# command
  5956. ;---------------------
  5957. ; Command syntax example: OPEN #5,"s"
  5958. ; On entry the channel code entry is on the calculator stack with the next
  5959. ; value containing the stream identifier. They have to swapped.
  5960.  
  5961.                                         ;;;$1736
  5962. OPEN:           RST     28H             ;; FP_CALC      ;s,c.
  5963.                 DEFB    $01             ;;EXCHANGE      ;c,s.
  5964.                 DEFB    $38             ;;END_CALC
  5965.  
  5966.                 CALL    STR_DATA        ; routine STR_DATA fetches the stream off
  5967.                                         ; the stack and returns with the CHANS
  5968.                                         ; displacement in BC and HL addressing
  5969.                                         ; the STRMS_FD data entry.
  5970.                 LD      A,B             ; test for zero which
  5971.                 OR      C               ; indicates the stream is closed.
  5972.                 JR      Z,OPEN_1        ; skip forward to OPEN_1 if so.
  5973.  
  5974.                                         ; if it is a system channel then it can re-attached.
  5975.  
  5976.                 EX      DE,HL           ; save STRMS_FD address in DE.
  5977.                 LD      HL,(CHANS)      ; fetch CHANS.
  5978.                 ADD     HL,BC           ; add the offset to address the second  byte of the channel.
  5979.                 INC     HL              ; skip over the
  5980.                 INC     HL              ; input routine.
  5981.                 INC     HL              ; and address the letter.
  5982.                 LD      A,(HL)          ; pick up the letter.
  5983.                 EX      DE,HL           ; save letter pointer and bring back the STRMS_FD pointer.
  5984.                 CP      $4B             ; is it 'K' ?
  5985.                 JR      Z,OPEN_1        ; forward to OPEN_1 if so
  5986.  
  5987.                 CP      $53             ; is it 'S' ?
  5988.                 JR      Z,OPEN_1        ; forward to OPEN_1 if so
  5989.  
  5990.                 CP      $50             ; is it 'P' ?
  5991.                 JR      NZ,REPORT_OB    ; back to REPORT_OB if not.
  5992.                                         ; to report 'Invalid stream'.
  5993.  
  5994.                                         ; continue if one of the upper-case letters was found.
  5995.                                         ; and rejoin here from above if stream was closed.
  5996.  
  5997.                                         ;;;$1756
  5998. OPEN_1:         CALL    OPEN_2          ; routine OPEN_2 opens the stream.
  5999.  
  6000.                                         ; it now remains to update the STRMS_FD variable.
  6001.  
  6002.                 LD      (HL),E          ; insert or overwrite the low byte.
  6003.                 INC     HL              ; address high byte in STRMS_FD.
  6004.                 LD      (HL),D          ; insert or overwrite the high byte.
  6005.                 RET                     ; return.
  6006.  
  6007. ;------------------
  6008. ; OPEN_2 Subroutine
  6009. ;------------------
  6010. ; There is some point in coming here as, as well as once creating buffers,
  6011. ; this routine also sets flags.
  6012.  
  6013.                                         ;;;$175D
  6014. OPEN_2:         PUSH    HL              ; * save the STRMS_FD data entry pointer.
  6015.                 CALL    STK_FETCH       ; routine STK_FETCH now fetches the
  6016.                                         ; parameters of the channel string.
  6017.                                         ; start in DE, length in BC.
  6018.                 LD      A,B             ; test that it is not
  6019.                 OR      C               ; the null string.
  6020.                 JR      NZ,OPEN_3       ; skip forward to OPEN_3 with 1 character
  6021.                                         ; or more!
  6022.  
  6023.                                         ;;;$1765
  6024. REPORT_F:       RST     08H             ; ERROR_1
  6025.                 DEFB    $0E             ; Error Report: Invalid file name
  6026.  
  6027.                                         ;;;$1767
  6028. OPEN_3:         PUSH    BC              ; save the length of the string.
  6029.                 LD      A,(DE)          ; pick up the first character.
  6030.                                         ; Note. if the second character is used to
  6031.                                         ; distinguish between a binary or text
  6032.                                         ; channel then it will be simply a matter
  6033.                                         ; of setting bit 7 of FLAGX.
  6034.                 AND     $DF             ; make it upper-case.
  6035.                 LD      C,A             ; place it in C.
  6036.                 LD      HL,OP_STR_LU    ; address: OP_STR_LU is loaded.
  6037.                 CALL    INDEXER         ; routine INDEXER will search for letter.
  6038.                 JR      NC,REPORT_F     ; back to REPORT_F if not found
  6039.                                         ; 'Invalid filename'
  6040.  
  6041.                 LD      C,(HL)          ; fetch the displacement to opening routine.
  6042.                 LD      B,$00           ; prepare to add.
  6043.                 ADD     HL,BC           ; now form address of opening routine.
  6044.                 POP     BC              ; restore the length of string.
  6045.                 JP      (HL)            ; now jump forward to the relevant routine.
  6046.  
  6047. ;--------------------------
  6048. ; OPEN stream look-up table
  6049. ;--------------------------
  6050. ; The open stream look-up table consists of matched pairs.
  6051. ; The channel letter is followed by an 8-bit displacement to the
  6052. ; associated stream-opening routine in this ROM.
  6053. ; The table requires a zero end-marker as the letter has been
  6054. ; provided by the user and not the operating system.
  6055.  
  6056.                                         ;;;$177A
  6057. OP_STR_LU:      DEFB    'K', OPEN_K-$-1 ; $06 offset to OPEN_K
  6058.                 DEFB    'S', OPEN_S-$-1 ; $08 offset to OPEN_S
  6059.                 DEFB    'P', OPEN_P-$-1 ; $0A offset to OPEN_P
  6060.  
  6061.                 DEFB    $00             ; end-marker.
  6062.  
  6063. ;-----------------------------
  6064. ; The Stream Opening Routines.
  6065. ;-----------------------------
  6066. ; These routines would have opened any buffers associated with the stream
  6067. ; before jumping forward to to OPEN_END with the displacement value in E
  6068. ; and perhaps a modified value in BC. The strange pathing does seem to
  6069. ; provide for flexibility in this respect.
  6070. ;
  6071. ; There is no need to open the printer buffer as it is there already
  6072. ; even if you are still saving up for a ZX Printer or have moved onto
  6073. ; something bigger. In any case it would have to be created after
  6074. ; the system variables but apart from that it is a simple task
  6075. ; and all but one of the ROM routines can handle a buffer in that position.
  6076. ; (PR_ALL_6 would require an extra 3 bytes of code).
  6077. ; However it wouldn't be wise to have two streams attached to the ZX Printer
  6078. ; as you can now, so one assumes that if PR_CC_hi was non-zero then
  6079. ; the OPEN_P routine would have refused to attach a stream if another
  6080. ; stream was attached.
  6081.  
  6082. ; Something of significance is being passed to these ghost routines in the
  6083. ; second character. Strings 'RB', 'RT' perhaps or a drive/station number.
  6084. ; The routine would have to deal with that and exit to OPEN_END with BC
  6085. ; containing $0001 or more likely there would be an exit within the routine.
  6086. ; Anyway doesn't matter, these routines are long gone.
  6087.  
  6088. ;------------------
  6089. ; OPEN_K Subroutine
  6090. ;------------------
  6091. ; Open Keyboard stream.
  6092.  
  6093.                                         ;;;$1781
  6094. OPEN_K:         LD      E,$01           ; 01 is offset to second byte of channel 'K'.
  6095.                 JR      OPEN_END        ; forward to OPEN_END
  6096.  
  6097. ;------------------
  6098. ; OPEN_S Subroutine
  6099. ;------------------
  6100. ; Open Screen stream.
  6101.  
  6102.                                         ;;;$1785
  6103. OPEN_S:         LD      E,$06           ; 06 is offset to 2nd byte of channel 'S'
  6104.                 JR      OPEN_END        ; to OPEN_END
  6105.  
  6106. ;------------------
  6107. ; OPEN_P Subroutine
  6108. ;------------------
  6109. ; Open Printer stream.
  6110.  
  6111.                                         ;;;$1789
  6112. OPEN_P:         LD      E,$10           ; 16d is offset to 2nd byte of channel 'P'
  6113.  
  6114.                                         ;;;$178B
  6115. OPEN_END:       DEC     BC              ; the stored length of 'K','S','P' or
  6116.                                         ; whatever is now tested. ??
  6117.                 LD      A,B             ; test now if initial or residual length
  6118.                 OR      C               ; is one character.
  6119.                 JR      NZ,REPORT_F     ; to REPORT_F 'Invalid file name' if not.
  6120.  
  6121.                 LD      D,A             ; load D with zero to form the displacement
  6122.                                         ; in the DE register.
  6123.                 POP     HL              ; * restore the saved STRMS_FD pointer.
  6124.                 RET                     ; return to update STRMS_FD entry thereby
  6125.                                         ; signalling stream is open.
  6126.  
  6127. ;-----------------------------------------
  6128. ; Handle CAT, ERASE, FORMAT, MOVE commands
  6129. ;-----------------------------------------
  6130. ; These just generate an error report as the ROM is 'incomplete'.
  6131. ;
  6132. ; Luckily this provides a mechanism for extending these in a shadow ROM
  6133. ; but without the powerful mechanisms set up in this ROM.
  6134. ; An instruction fetch on $0008 may page in a peripheral ROM,
  6135. ; e.g. the Sinclair Interface 1 ROM, to handle these commands.
  6136. ; However that wasn't the plan.
  6137. ; Development of this ROM continued for another three months until the cost
  6138. ; of replacing it and the manual became unfeasible.
  6139. ; The ultimate power of channels and streams died at birth.
  6140.  
  6141.                                         ;;;$1793
  6142. CAT_ETC:        JR      REPORT_OB       ; to REPORT_OB
  6143.  
  6144. ;------------------
  6145. ; Perform AUTO_LIST
  6146. ;------------------
  6147. ; This produces an automatic listing in the upper screen.
  6148.  
  6149.                                         ;;;$1795
  6150. AUTO_LIST:      LD      (LIST_SP),SP    ; save stack pointer in LIST_SP
  6151.                 LD      (IY+$02),$10    ; update TV_FLAG set bit 3
  6152.                 CALL    CL_ALL          ; routine CL_ALL.
  6153.                 SET     0,(IY+$02)      ; update TV_FLAG  - signal lower screen in use
  6154.                 LD      B,(IY+$31)      ; fetch DF_SZ to B.
  6155.                 CALL    CL_LINE         ; routine CL_LINE clears lower display preserving B.
  6156.                 RES     0,(IY+$02)      ; update TV_FLAG  - signal main screen in use
  6157.                 SET     0,(IY+$30)      ; update FLAGS2  - signal unnecessary to clear main screen.
  6158.                 LD      HL,(E_PPC)      ; fetch E_PPC current edit line to HL.
  6159.                 LD      DE,(S_TOP)      ; fetch S_TOP to DE, the current top line
  6160.                                         ; (initially zero)
  6161.                 AND     A               ; prepare for true subtraction.
  6162.                 SBC     HL,DE           ; subtract and
  6163.                 ADD     HL,DE           ; add back.
  6164.                 JR      C,AUTO_L_2      ; to AUTO_L_2 if S_TOP higher than E_PPC
  6165.                                         ; to set S_TOP to E_PPC
  6166.                 PUSH    DE              ; save the top line number.
  6167.                 CALL    LINE_ADDR       ; routine LINE_ADDR gets address of E_PPC.
  6168.                 LD      DE,$02C0        ; prepare known number of characters in
  6169.                                         ; the default upper screen.
  6170.                 EX      DE,HL           ; offset to HL, program address to DE.
  6171.                 SBC     HL,DE           ; subtract high value from low to obtain
  6172.                                         ; negated result used in addition.
  6173.                 EX      (SP),HL         ; swap result with top line number on stack.
  6174.                 CALL    LINE_ADDR       ; routine LINE_ADDR  gets address of that
  6175.                                         ; top line in HL and next line in DE.
  6176.                 POP     BC              ; restore the result to balance stack.
  6177.  
  6178.                                         ;;;$17CE
  6179. AUTO_L_1:       PUSH    BC              ; save the result.
  6180.                 CALL    NEXT_ONE        ; routine NEXT_ONE gets address in HL of
  6181.                                         ; line after auto-line (in DE).
  6182.                 POP     BC              ; restore result.
  6183.                 ADD     HL,BC           ; compute back.
  6184.                 JR      C,AUTO_L_3      ; to AUTO_L_3 if line 'should' appear
  6185.  
  6186.                 EX      DE,HL           ; address of next line to HL.
  6187.                 LD      D,(HL)          ; get line
  6188.                 INC     HL              ; number
  6189.                 LD      E,(HL)          ; in DE.
  6190.                 DEC     HL              ; adjust back to start.
  6191.                 LD      (S_TOP),DE      ; update S_TOP.
  6192.                 JR      AUTO_L_1        ; to AUTO_L_1 until estimate reached.
  6193.  
  6194.                                         ; the jump was to here if S_TOP was greater than E_PPC
  6195.  
  6196.                                         ;;;$17E1
  6197. AUTO_L_2:       LD      (S_TOP),HL      ; make S_TOP the same as E_PPC.
  6198.  
  6199.                                         ; continue here with valid starting point from above or good estimate
  6200.                                         ; from computation
  6201.  
  6202.                                         ;;;$17E4
  6203. AUTO_L_3:       LD      HL,(S_TOP)      ; fetch S_TOP line number to HL.
  6204.                 CALL    LINE_ADDR       ; routine LINE_ADDR gets address in HL.
  6205.                                         ; address of next in DE.
  6206.                 JR      Z,AUTO_L_4      ; to AUTO_L_4 if line exists.
  6207.  
  6208.                 EX      DE,HL           ; else use address of next line.
  6209.  
  6210.                                         ;;;$17ED
  6211. AUTO_L_4:       CALL    LIST_ALL        ; routine LIST_ALL                >>>
  6212.  
  6213.                                         ; The return will be to here if no scrolling occurred
  6214.  
  6215.                 RES     4,(IY+$02)      ; update TV_FLAG  - signal no auto listing.
  6216.                 RET                     ; return.
  6217.  
  6218. ;-------------
  6219. ; Handle LLIST
  6220. ;-------------
  6221. ; A short form of LIST #3. The listing goes to stream 3 - default printer.
  6222.  
  6223.                                         ;;;$17F5
  6224. LLIST:          LD      A,$03           ; the usual stream for ZX Printer
  6225.                 JR      LIST_1          ; forward to LIST_1
  6226.  
  6227. ;------------
  6228. ; Handle LIST
  6229. ;------------
  6230. ; List to any stream.
  6231. ; Note. While a starting line can be specified it is
  6232. ; not possible to specify an end line.
  6233. ; Just listing a line makes it the current edit line.
  6234.  
  6235.                                         ;;;$17F9
  6236. LIST:           LD      A,$02           ; default is stream 2 - the upper screen.
  6237.  
  6238.                                         ;;;$17FB
  6239. LIST_1:         LD      (IY+$02),$00    ; the TV_FLAG is initialized.
  6240.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z - checking syntax ?
  6241.                 CALL    NZ,CHAN_OPEN    ; routine CHAN_OPEN if in run-time.
  6242.                 RST     18H             ; GET_CHAR
  6243.                 CALL    STR_ALTER       ; routine STR_ALTER will alter if '#'.
  6244.                 JR      C,LIST_4        ; forward to LIST_4 not a '#' .
  6245.  
  6246.                 RST     18H             ; GET_CHAR
  6247.                 CP      $3B             ; is it ';' ?
  6248.                 JR      Z,LIST_2        ; skip to LIST_2 if so.
  6249.  
  6250.                 CP      $2C             ; is it ',' ?
  6251.                 JR      NZ,LIST_3       ; forward to LIST_3 if neither separator.
  6252.  
  6253.                                         ; we have, say,  LIST #15, and a number must follow the separator.
  6254.  
  6255.                                         ;;;$1814
  6256. LIST_2:         RST     20H             ; NEXT_CHAR
  6257.                 CALL    EXPT_1NUM       ; routine EXPT_1NUM
  6258.                 JR      LIST_5          ; forward to LIST_5
  6259.  
  6260.                                         ; the branch was here with just LIST #3 etc.
  6261.  
  6262.                                         ;;;$181A
  6263. LIST_3:         CALL    USE_ZERO        ; routine USE_ZERO
  6264.                 JR      LIST_5          ; forward to LIST_5
  6265.  
  6266.                                         ; the branch was here with LIST
  6267.  
  6268.                                         ;;;$181F
  6269. LIST_4:         CALL    FETCH_NUM       ; routine FETCH_NUM checks if a number
  6270.                                         ; follows else uses zero.
  6271.  
  6272.                                         ;;;$1822
  6273. LIST_5:         CALL    CHECK_END       ; routine CHECK_END quits if syntax OK >>>
  6274.                 CALL    FIND_INT2       ; routine FIND_INT2 fetches the number
  6275.                                         ; from the calculator stack in run-time.
  6276.                 LD      A,B             ; fetch high byte of line number and
  6277.                 AND     $3F             ; make less than $40 so that NEXT_ONE
  6278.                                         ; (from LINE_ADDR) doesn't lose context.
  6279.                                         ; Note. this is not satisfactory and the typo
  6280.                                         ; LIST 20000 will list an entirely different
  6281.                                         ; section than LIST 2000. Such typos are not
  6282.                                         ; available for checking if they are direct
  6283.                                         ; commands.
  6284.  
  6285.                 LD      H,A             ; transfer the modified
  6286.                 LD      L,C             ; line number to HL.
  6287.                 LD      (E_PPC),HL      ; update E_PPC to new line number.
  6288.                 CALL    LINE_ADDR       ; routine LINE_ADDR gets the address of the line.
  6289.  
  6290.                                         ; This routine is called from AUTO_LIST
  6291.  
  6292.                                         ;;;$1833
  6293. LIST_ALL:       LD      E,$01           ; signal current line not yet printed
  6294.  
  6295.                                         ;;;$1835
  6296. LIST_ALL_2:     CALL    OUT_LINE        ; routine OUT_LINE outputs a BASIC line
  6297.                                         ; using PRINT_OUT and makes an early return
  6298.                                         ; when no more lines to print. >>>
  6299.  
  6300.                 RST     10H             ; PRINT_A prints the carriage return (in A)
  6301.                 BIT     4,(IY+$02)      ; test TV_FLAG  - automatic listing ?
  6302.                 JR      Z,LIST_ALL_2    ; back to LIST_ALL_2 if not
  6303.                                         ; (loop exit is via OUT_LINE)
  6304.  
  6305.                                         ; continue here if an automatic listing required.
  6306.  
  6307.                 LD      A,(DF_SZ)       ; fetch DF_SZ lower display file size.
  6308.                 SUB     (IY+$4F)        ; subtract S_POSN_HI ithe current line number.
  6309.                 JR      NZ,LIST_ALL_2   ; back to LIST_ALL_2 if upper screen not full.
  6310.                 XOR     E               ; A contains zero, E contains one if the
  6311.                                         ; current edit line has not been printed
  6312.                                         ; or zero if it has (from OUT_LINE).
  6313.                 RET     Z               ; return if the screen is full and the line
  6314.                                         ; has been printed.
  6315.  
  6316.                                         ; continue with automatic listings if the screen is full and the current
  6317.                                         ; edit line is missing. OUT_LINE will scroll automatically.
  6318.  
  6319.                 PUSH    HL              ; save the pointer address.
  6320.                 PUSH    DE              ; save the E flag.
  6321.                 LD      HL,S_TOP        ; fetch S_TOP the rough estimate.
  6322.                 CALL    LN_FETCH        ; routine LN_FETCH updates S_TOP with the number of the next line.
  6323.                 POP     DE              ; restore the E flag.
  6324.                 POP     HL              ; restore the address of the next line.
  6325.                 JR      LIST_ALL_2      ; back to LIST_ALL_2.
  6326.  
  6327. ;-------------------------
  6328. ; Print a whole BASIC line
  6329. ;-------------------------
  6330. ; This routine prints a whole basic line and it is called
  6331. ; from LIST_ALL to output the line to current channel
  6332. ; and from ED_EDIT to 'sprint' the line to the edit buffer.
  6333.  
  6334.                                         ;;;$1855
  6335. OUT_LINE:       LD      BC,(E_PPC)      ; fetch E_PPC the current line which may be
  6336.                                         ; unchecked and not exist.
  6337.                 CALL    CP_LINES        ; routine CP_LINES finds match or line after.
  6338.                 LD      D,$3E           ; prepare cursor '>' in D.
  6339.                 JR      Z,OUT_LINE1     ; to OUT_LINE1 if matched or line after.
  6340.  
  6341.                 LD      DE,$0000        ; put zero in D, to suppress line cursor.
  6342.                 RL      E               ; pick up carry in E if line before current
  6343.                                         ; leave E zero if same or after.
  6344.  
  6345.                                         ;;;$1865
  6346. OUT_LINE1:      LD      (IY+$2D),E      ; save flag in BREG which is spare.
  6347.                 LD      A,(HL)          ; get high byte of line number.
  6348.                 CP      $40             ; is it too high ($2F is maximum possible) ?
  6349.                 POP     BC              ; drop the return address and
  6350.                 RET     NC              ; make an early return if so >>>
  6351.  
  6352.                 PUSH    BC              ; save return address
  6353.                 CALL    OUT_NUM_2       ; routine OUT_NUM_2 to print addressed number
  6354.                                         ; with leading space.
  6355.                 INC     HL              ; skip low number byte.
  6356.                 INC     HL              ; and the two
  6357.                 INC     HL              ; length bytes.
  6358.                 RES     0,(IY+$01)      ; update FLAGS - signal leading space required.
  6359.                 LD      A,D             ; fetch the cursor.
  6360.                 AND     A               ; test for zero.
  6361.                 JR      Z,OUT_LINE3     ; to OUT_LINE3 if zero.
  6362.  
  6363.                 RST     10H             ; PRINT_A prints '>' the current line cursor.
  6364.  
  6365.                                         ; this entry point is called from ED_COPY
  6366.  
  6367.                                         ;;;$187D
  6368. OUT_LINE2:      SET     0,(IY+$01)      ; update FLAGS - suppress leading space.
  6369.  
  6370.                                         ;;;$1881
  6371. OUT_LINE3:      PUSH    DE              ; save flag E for a return value.
  6372.                 EX      DE,HL           ; save HL address in DE.
  6373.                 RES     2,(IY+$30)      ; update FLAGS2 - signal NOT in QUOTES.
  6374.                 LD      HL,FLAGS        ; point to FLAGS.
  6375.                 RES     2,(HL)          ; signal 'K' mode. (starts before keyword)
  6376.                 BIT     5,(IY+$37)      ; test FLAGX - input mode ?
  6377.                 JR      Z,OUT_LINE4     ; forward to OUT_LINE4 if not.
  6378.  
  6379.                 SET     2,(HL)          ; signal 'L' mode. (used for input)
  6380.  
  6381.                                         ;;;$1894
  6382. OUT_LINE4:      LD      HL,(X_PTR)      ; fetch X_PTR - possibly the error pointer address.
  6383.                 AND     A               ; clear the carry flag.
  6384.                 SBC     HL,DE           ; test if an error address has been reached.
  6385.                 JR      NZ,OUT_LINE5    ; forward to OUT_LINE5 if not.
  6386.  
  6387.                 LD      A,$3F           ; load A with '?' the error marker.
  6388.                 CALL    OUT_FLASH       ; routine OUT_FLASH to print flashing marker.
  6389.  
  6390.                                         ;;;$18A1
  6391. OUT_LINE5:      CALL    OUT_CURS        ; routine OUT_CURS will print the cursor if
  6392.                                         ; this is the right position.
  6393.                 EX      DE,HL           ; restore address pointer to HL.
  6394.                 LD      A,(HL)          ; fetch the addressed character.
  6395.                 CALL    NUMBER          ; routine NUMBER skips a hidden floating
  6396.                                         ; point number if present.
  6397.                 INC     HL              ; now increment the pointer.
  6398.                 CP      $0D             ; is character end-of-line ?
  6399.                 JR      Z,OUT_LINE6     ; to OUT_LINE6, if so, as line is finished.
  6400.  
  6401.                 EX      DE,HL           ; save the pointer in DE.
  6402.                 CALL    OUT_CHAR        ; routine OUT_CHAR to output character/token.
  6403.                 JR      OUT_LINE4       ; back to OUT_LINE4 until entire line is done.
  6404.  
  6405.                                         ;;;$18B4
  6406. OUT_LINE6:      POP     DE              ; bring back the flag E, zero if current
  6407.                                         ; line printed else 1 if still to print.
  6408.                 RET                     ; return with A holding $0D
  6409.  
  6410. ;--------------------------
  6411. ; Check for a number marker
  6412. ;--------------------------
  6413. ; this subroutine is called from two processes. while outputting basic lines
  6414. ; and while searching statements within a basic line.
  6415. ; during both, this routine will pass over an invisible number indicator
  6416. ; and the five bytes floating-point number that follows it.
  6417. ; Note that this causes floating point numbers to be stripped from
  6418. ; the basic line when it is fetched to the edit buffer by OUT_LINE.
  6419. ; the number marker also appears after the arguments of a DEF FN statement
  6420. ; and may mask old 5-byte string parameters.
  6421.  
  6422.                                         ;;;$18B6
  6423. NUMBER:         CP      $0E             ; character fourteen ?
  6424.                 RET     NZ              ; return if not.
  6425.  
  6426.                 INC     HL              ; skip the character
  6427.                 INC     HL              ; and five bytes
  6428.                 INC     HL              ; following.
  6429.                 INC     HL
  6430.                 INC     HL
  6431.                 INC     HL
  6432.                 LD      A,(HL)          ; fetch the following character
  6433.                 RET                     ; for return value.
  6434.  
  6435. ;---------------------------
  6436. ; Print a flashing character
  6437. ;---------------------------
  6438. ; This subroutine is called from OUT_LINE to print a flashing error
  6439. ; marker '?' or from the next routine to print a flashing cursor e.g. 'L'.
  6440. ; However, this only gets called from OUT_LINE when printing the edit line
  6441. ; or the input buffer to the lower screen so a direct call to 09F4 can
  6442. ; be used, even though out-line outputs to other streams.
  6443. ; In fact the alternate set is used for the whole routine.
  6444.  
  6445.                                         ;;;$18C1
  6446. OUT_FLASH:      EXX                     ; switch in alternate set
  6447.                 LD      HL,(ATTRT_MASKT); fetch L = ATTR_T, H = MASK-T
  6448.                 PUSH    HL              ; save masks.
  6449.                 RES     7,H             ; reset flash mask bit so active.
  6450.                 SET     7,L             ; make attribute FLASH.
  6451.                 LD      (ATTRT_MASKT),HL; resave ATTR_T and MASK-T
  6452.                 LD      HL,P_FLAG       ; address P_FLAG
  6453.                 LD      D,(HL)          ; fetch to D
  6454.                 PUSH    DE              ; and save.
  6455.                 LD      (HL),$00        ; clear inverse, over, ink/paper 9
  6456.                 CALL    PRINT_OUT       ; routine PRINT_OUT outputs character
  6457.                                         ; without the need to vector via RST 10.
  6458.                 POP     HL              ; pop P_FLAG to H.
  6459.                 LD      (IY+$57),H      ; and restore system variable P_FLAG.
  6460.                 POP     HL              ; restore temporary masks
  6461.                 LD      (ATTRT_MASKT),HL; and restore system variables ATTR_T/MASK_T
  6462.                 EXX                     ; switch back to main set
  6463.                 RET                     ; return
  6464.  
  6465. ;-----------------
  6466. ; Print the cursor
  6467. ;-----------------
  6468. ; This routine is called before any character is output while outputting
  6469. ; a basic line or the input buffer. This includes listing to a printer
  6470. ; or screen, copying a basic line to the edit buffer and printing the
  6471. ; input buffer or edit buffer to the lower screen. It is only in the
  6472. ; latter two cases that it has any relevance and in the last case it
  6473. ; performs another very important function also.
  6474.  
  6475.                                         ;;;$18E1
  6476. OUT_CURS:       LD      HL,(K_CUR)      ; fetch K_CUR the current cursor address
  6477.                 AND     A               ; prepare for true subtraction.
  6478.                 SBC     HL,DE           ; test against pointer address in DE and
  6479.                 RET     NZ              ; return if not at exact position.
  6480.  
  6481.                                         ; the value of MODE, maintained by KEY_INPUT, is tested and if non-zero
  6482.                                         ; then this value 'E' or 'G' will take precedence.
  6483.  
  6484.                 LD      A,(MODE)        ; fetch MODE  0='KLC', 1='E', 2='G'.
  6485.                 RLC     A               ; double the value and set flags.
  6486.                 JR      Z,OUT_C_1       ; to OUT_C_1 if still zero ('KLC').
  6487.  
  6488.                 ADD     A,$43           ; add 'C' - will become 'E' if originally 1
  6489.                                         ; or 'G' if originally 2.
  6490.                 JR      OUT_C_2         ; forward to OUT_C_2 to print.
  6491.  
  6492.                                         ; If mode was zero then, while printing a basic line, bit 2 of flags has been
  6493.                                         ; set if 'THEN' or ':' was encountered as a main character and reset otherwise.
  6494.                                         ; This is now used to determine if the 'K' cursor is to be printed but this
  6495.                                         ; transient state is also now transferred permanently to bit 3 of FLAGS
  6496.                                         ; to let the interrupt routine know how to decode the next key.
  6497.  
  6498.                                         ;;;$18F3
  6499. OUT_C_1:        LD      HL,FLAGS        ; Address FLAGS
  6500.                 RES     3,(HL)          ; signal 'K' mode initially.
  6501.                 LD      A,$4B           ; prepare letter 'K'.
  6502.                 BIT     2,(HL)          ; test FLAGS - was the
  6503.                                         ; previous main character ':' or 'THEN' ?
  6504.                 JR      Z,OUT_C_2       ; forward to OUT_C_2 if so to print.
  6505.  
  6506.                 SET     3,(HL)          ; signal 'L' mode to interrupt routine.
  6507.                                         ; Note. transient bit has been made permanent.
  6508.                 INC     A               ; augment from 'K' to 'L'.
  6509.                 BIT     3,(IY+$30)      ; test FLAGS2 - consider caps lock ?
  6510.                                         ; which is maintained by KEY_INPUT.
  6511.                 JR      Z,OUT_C_2       ; forward to OUT_C_2 if not set to print.
  6512.  
  6513.                 LD      A,$43           ; alter 'L' to 'C'.
  6514.  
  6515.                                         ;;;$1909
  6516. OUT_C_2:        PUSH    DE              ; save address pointer but OK as OUT_FLASH
  6517.                                         ; uses alternate set without RST 10.
  6518.                 CALL    OUT_FLASH       ; routine OUT_FLASH to print.
  6519.                 POP     DE              ; restore and
  6520.                 RET                     ; return.
  6521.  
  6522. ;-----------------------------
  6523. ; Get line number of next line
  6524. ;-----------------------------
  6525. ; These two subroutines are called while editing.
  6526. ; This entry point is from ED_DOWN with HL addressing E_PPC
  6527. ; to fetch the next line number.
  6528. ; Also from AUTO_LIST with HL addressing S_TOP just to update S_TOP
  6529. ; with the value of the next line number. It gets fetched but is discarded.
  6530. ; These routines never get called while the editor is being used for input.
  6531.  
  6532.                                         ;;;$190F
  6533. LN_FETCH:       LD      E,(HL)          ; fetch low byte
  6534.                 INC     HL              ; address next
  6535.                 LD      D,(HL)          ; fetch high byte.
  6536.                 PUSH    HL              ; save system variable hi pointer.
  6537.                 EX      DE,HL           ; line number to HL,
  6538.                 INC     HL              ; increment as a starting point.
  6539.                 CALL    LINE_ADDR       ; routine LINE_ADDR gets address in HL.
  6540.                 CALL    LINE_NO         ; routine LINE_NO gets line number in DE.
  6541.                 POP     HL              ; restore system variable hi pointer.
  6542.  
  6543.                                         ; This entry point is from the ED_UP with HL addressing E_PPC_HI
  6544.  
  6545.                                         ;;;$191C
  6546. LN_STORE:       BIT     5,(IY+$37)      ; test FLAGX - input mode ?
  6547.                 RET     NZ              ; return if so.
  6548.                                         ; Note. above already checked by ED_UP/ED_DOWN.
  6549.  
  6550.                 LD      (HL),D          ; save high byte of line number.
  6551.                 DEC     HL              ; address lower
  6552.                 LD      (HL),E          ; save low byte of line number.
  6553.                 RET                     ; return.
  6554.  
  6555. ;------------------------------------------
  6556. ; Outputting numbers at start of BASIC line
  6557. ;------------------------------------------
  6558. ; This routine entered at OUT_SP_NO is used to compute then output the first
  6559. ; three digits of a 4-digit basic line printing a space if necessary.
  6560. ; The line number, or residual part, is held in HL and the BC register
  6561. ; holds a subtraction value -1000, -100 or -10.
  6562. ; Note. for example line number 200 -
  6563. ; space(out_char), 2(out_code), 0(out_char) final number always out-code.
  6564.  
  6565.                                         ;;;$1925
  6566. OUT_SP_2:       LD      A,E             ; will be space if OUT_CODE not yet called.
  6567.                                         ; or $FF if spaces are suppressed.
  6568.                                         ; else $30 ('0').
  6569.                                         ; (from the first instruction at OUT_CODE)
  6570.                                         ; this guy is just too clever.
  6571.                 AND     A               ; test bit 7 of A.
  6572.                 RET     M               ; return if $FF, as leading spaces not
  6573.                                         ; required. This is set when printing line
  6574.                                         ; number and statement in MAIN_5.
  6575.  
  6576.                 JR      OUT_CHAR        ; forward to exit via OUT_CHAR.
  6577.  
  6578.                                         ; -> the single entry point.
  6579.  
  6580.                                         ;;;$192A
  6581. OUT_SP_NO:      XOR     A               ; initialize digit to 0
  6582.  
  6583.                                         ;;;$192B
  6584. OUT_SP_1:       ADD     HL,BC           ; add negative number to HL.
  6585.                 INC     A               ; increment digit
  6586.                 JR      C,OUT_SP_1      ; back to OUT_SP_1 until no carry from
  6587.                                         ; the addition.
  6588.                 SBC     HL,BC           ; cancel the last addition
  6589.                 DEC     A               ; and decrement the digit.
  6590.                 JR      Z,OUT_SP_2      ; back to OUT_SP_2 if it is zero.
  6591.  
  6592.                 JP      OUT_CODE        ; jump back to exit via OUT_CODE.       ->
  6593.  
  6594.  
  6595. ;--------------------------------------
  6596. ; Outputting characters in a BASIC line
  6597. ;--------------------------------------
  6598. ; This subroutine ...
  6599.  
  6600.                                         ;;;$1937
  6601. OUT_CHAR:       CALL    NUMERIC         ; routine NUMERIC tests if it is a digit ?
  6602.                 JR      NC,OUT_CH_3     ; to OUT_CH_3 to print digit without
  6603.                                         ; changing mode. Will be 'K' mode if digits
  6604.                                         ; are at beginning of edit line.
  6605.                 CP      $21             ; less than quote character ?
  6606.                 JR      C,OUT_CH_3      ; to OUT_CH_3 to output controls and space.
  6607.  
  6608.                 RES     2,(IY+$01)      ; initialize FLAGS to 'K' mode and leave
  6609.                                         ; unchanged if this character would precede a keyword.
  6610.                 CP      $CB             ; is character 'THEN' token ?
  6611.                 JR      Z,OUT_CH_3      ; to OUT_CH_3 to output if so.
  6612.  
  6613.                 CP      $3A             ; is it ':' ?
  6614.                 JR      NZ,OUT_CH_1     ; to OUT_CH_1 if not statement separator
  6615.                                         ; to change mode back to 'L'.
  6616.                 BIT     5,(IY+$37)      ; FLAGX  - Input Mode ??
  6617.                 JR      NZ,OUT_CH_2     ; to OUT_CH_2 if in input as no statements.
  6618.                                         ; Note. this check should seemingly be at
  6619.                                         ; the start. Commands seem inappropriate in
  6620.                                         ; INPUT mode and are rejected by the syntax checker anyway.
  6621.                                         ; unless INPUT LINE is being used.
  6622.                 BIT     2,(IY+$30)      ; test FLAGS2 - is the ':' within quotes ?
  6623.                 JR      Z,OUT_CH_3      ; to OUT_CH_3 if ':' is outside quoted text.
  6624.  
  6625.                 JR      OUT_CH_2        ; to OUT_CH_2 as ':' is within quotes
  6626.  
  6627.                                         ;;;$195A
  6628. OUT_CH_1:       CP      $22             ; is it quote character '"'  ?
  6629.                 JR      NZ,OUT_CH_2     ; to OUT_CH_2 with others to set 'L' mode.
  6630.  
  6631.                 PUSH    AF              ; save character.
  6632.                 LD      A,(FLAGS2)      ; fetch FLAGS2.
  6633.                 XOR     $04             ; toggle the quotes flag.
  6634.                 LD      (FLAGS2),A      ; update FLAGS2
  6635.                 POP     AF              ; and restore character.
  6636.  
  6637.                                         ;;;$1968
  6638. OUT_CH_2:       SET     2,(IY+$01)      ; update FLAGS - signal L mode if the cursor
  6639.                                         ; is next.
  6640.  
  6641.                                         ;;;$196C
  6642. OUT_CH_3:       RST     10H             ; PRINT_A vectors the character to
  6643.                                         ; channel 'S', 'K', 'R' or 'P'.
  6644.                 RET                     ; return.
  6645.  
  6646. ;--------------------------------------------
  6647. ; Get starting address of line, or line after
  6648. ;--------------------------------------------
  6649. ; This routine is used often to get the address, in HL, of a basic line
  6650. ; number supplied in HL, or failing that the address of the following line
  6651. ; and the address of the previous line in DE.
  6652.  
  6653.                                         ;;;$196E
  6654. LINE_ADDR:      PUSH    HL              ; save line number in HL register
  6655.                 LD      HL,(PROG)       ; fetch start of program from PROG
  6656.                 LD      D,H             ; transfer address to
  6657.                 LD      E,L             ; the DE register pair.
  6658.  
  6659.                                         ;;;$1974
  6660. LINE_AD_1:      POP     BC              ; restore the line number to BC
  6661.                 CALL    CP_LINES        ; routine CP_LINES compares with that addressed by HL
  6662.                 RET     NC              ; return if line has been passed or matched.
  6663.                                         ; if NZ, address of previous is in DE
  6664.                 PUSH    BC              ; save the current line number
  6665.                 CALL    NEXT_ONE        ; routine NEXT_ONE finds address of next line number in DE, previous in HL.
  6666.                 EX      DE,HL           ; switch so next in HL
  6667.                 JR      LINE_AD_1       ; back to LINE_AD_1 for another comparison
  6668.  
  6669. ;---------------------
  6670. ; Compare line numbers
  6671. ;---------------------
  6672. ; This routine compares a line number supplied in BC with an addressed
  6673. ; line number pointed to by HL.
  6674.  
  6675.                                         ;;;$1980
  6676. CP_LINES:       LD      A,(HL)          ; Load the high byte of line number and
  6677.                 CP      B               ; compare with that of supplied line number.
  6678.                 RET     NZ              ; return if yet to match (carry will be set).
  6679.  
  6680.                 INC     HL              ; address low byte of
  6681.                 LD      A,(HL)          ; number and pick up in A.
  6682.                 DEC     HL              ; step back to first position.
  6683.                 CP      C               ; now compare.
  6684.                 RET                     ; zero set if exact match.
  6685.                                         ; carry set if yet to match.
  6686.                                         ; no carry indicates a match or
  6687.                                         ; next available basic line or
  6688.                                         ; program end marker.
  6689.  
  6690. ;--------------------
  6691. ; Find each statement
  6692. ;--------------------
  6693. ; The single entry point EACH_STMT is used to
  6694. ; 1) To find the D'th statement in a line.
  6695. ; 2) To find a token in held E.
  6696.  
  6697.                                         ;;;$1988
  6698. NOT_USED:       INC     HL
  6699.                 INC     HL
  6700.                 INC     HL
  6701.                                         ; -> entry point.
  6702.  
  6703.                                         ;;;$198B
  6704. EACH_STMT:      LD      (CH_ADD),HL     ; save HL in CH_ADD
  6705.                 LD      C,$00           ; initialize quotes flag
  6706.  
  6707.                                         ;;;$1990
  6708. EACH_S_1:       DEC     D               ; decrease statement count
  6709.                 RET     Z               ; return if zero
  6710.  
  6711.                 RST     20H             ; NEXT_CHAR
  6712.                 CP      E               ; is it the search token ?
  6713.                 JR      NZ,EACH_S_3     ; forward to EACH_S_3 if not
  6714.  
  6715.                 AND     A               ; clear carry
  6716.                 RET                     ; return signalling success.
  6717.  
  6718.                                         ;;;$1998
  6719. EACH_S_2:       INC     HL              ; next address
  6720.                 LD      A,(HL)          ; next character
  6721.  
  6722.                                         ;;;$199A
  6723. EACH_S_3:       CALL    NUMBER          ; routine NUMBER skips if number marker
  6724.                 LD      (CH_ADD),HL     ; save in CH_ADD
  6725.                 CP      $22             ; is it quotes '"' ?
  6726.                 JR      NZ,EACH_S_4     ; to EACH_S_4 if not
  6727.  
  6728.                 DEC     C               ; toggle bit 0 of C
  6729.  
  6730.                                         ;;;$19A5
  6731. EACH_S_4:       CP      $3A             ; is it ':'
  6732.                 JR      Z,EACH_S_5      ; to EACH_S_5
  6733.  
  6734.                 CP      $CB             ; 'THEN'
  6735.                 JR      NZ,EACH_S_6     ; to EACH_S_6
  6736.  
  6737.                                         ;;;$19AD
  6738. EACH_S_5:       BIT     0,C             ; is it in quotes
  6739.                 JR      Z,EACH_S_1      ; to EACH_S_1 if not
  6740.  
  6741.                                         ;;;$19B1
  6742. EACH_S_6:       CP      $0D             ; end of line ?
  6743.                 JR      NZ,EACH_S_2     ; to EACH_S_2
  6744.  
  6745.                 DEC     D               ; decrease the statement counter
  6746.                                         ; which should be zero else
  6747.                                         ; 'Statement Lost'.
  6748.                 SCF                     ; set carry flag - not found
  6749.                 RET                     ; return
  6750.  
  6751. ;------------------------------------------------------------------------
  6752. ; Storage of variables. For full details - see chapter 24.
  6753. ; ZX Spectrum BASIC Programming by Steven Vickers 1982.
  6754. ; It is bits 7-5 of the first character of a variable that allow
  6755. ; the six types to be distinguished. Bits 4-0 are the reduced letter.
  6756. ; So any variable name is higher that $3F and can be distinguished
  6757. ; also from the variables area end-marker $80.
  6758. ;
  6759. ; 76543210 meaning                               brief outline of format.
  6760. ; -------- ------------------------              -----------------------
  6761. ; 010      string variable.                      2 byte length + contents.
  6762. ; 110      string array.                         2 byte length + contents.
  6763. ; 100      array of numbers.                     2 byte length + contents.
  6764. ; 011      simple numeric variable.              5 bytes.
  6765. ; 101      variable length named numeric.        5 bytes.
  6766. ; 111      for-next loop variable.               18 bytes.
  6767. ; 10000000 the variables area end-marker.
  6768. ;
  6769. ; Note. any of the above seven will serve as a program end-marker.
  6770. ;
  6771. ; -----------------------------------------------------------------------
  6772.  
  6773. ;-------------
  6774. ; Get next one
  6775. ;-------------
  6776. ; This versatile routine is used to find the address of the next line
  6777. ; in the program area or the next variable in the variables area.
  6778. ; The reason one routine is made to handle two apparently unrelated tasks
  6779. ; is that it can be called indiscriminately when merging a line or a
  6780. ; variable.
  6781.  
  6782.                                         ;;;$19B8
  6783. NEXT_ONE:       PUSH    HL              ; save the pointer address.
  6784.                 LD      A,(HL)          ; get first byte.
  6785.                 CP      $40             ; compare with upper limit for line numbers.
  6786.                 JR      C,NEXT_O_3      ; forward to NEXT_O_3 if within basic area.
  6787.  
  6788.                                         ; the continuation here is for the next variable unless the supplied
  6789.                                         ; line number was erroneously over 16383. see RESTORE command.
  6790.  
  6791.                 BIT     5,A             ; is it a string or an array variable ?
  6792.                 JR      Z,NEXT_O_4      ; forward to NEXT_O_4 to compute length.
  6793.  
  6794.                 ADD     A,A             ; test bit 6 for single-character variables.
  6795.                 JP      M,NEXT_O_1      ; forward to NEXT_O_1 if so
  6796.  
  6797.                 CCF                     ; clear the carry for long-named variables.
  6798.                                         ; it remains set for for-next loop variables.
  6799.  
  6800.                                         ;;;$19C7
  6801. NEXT_O_1:       LD      BC,$0005        ; set BC to 5 for floating point number
  6802.                 JR      NC,NEXT_O_2     ; forward to NEXT_O_2 if not a for/next
  6803.                                         ; variable.
  6804.                 LD      C,$12           ; set BC to eighteen locations.
  6805.                                         ; value, limit, step, line and statement.
  6806.  
  6807.                                         ; now deal with long-named variables
  6808.  
  6809.                                         ;;;$19CE
  6810. NEXT_O_2:       RLA                     ; test if character inverted. carry will also
  6811.                                         ; be set for single character variables
  6812.                 INC     HL              ; address next location.
  6813.                 LD      A,(HL)          ; and load character.
  6814.                 JR      NC,NEXT_O_2     ; back to NEXT_O_2 if not inverted bit.
  6815.                                         ; forward immediately with single character
  6816.                                         ; variable names.
  6817.                 JR      NEXT_O_5        ; forward to NEXT_O_5 to add length of
  6818.                                         ; floating point number(s etc.).
  6819.  
  6820.                                         ; this branch is for line numbers.
  6821.  
  6822.                                         ;;;$19D5
  6823. NEXT_O_3:       INC     HL              ; increment pointer to low byte of line no.
  6824.  
  6825.                                         ; strings and arrays rejoin here
  6826.  
  6827.                                         ;;;$19D6
  6828. NEXT_O_4:       INC     HL              ; increment to address the length low byte.
  6829.                 LD      C,(HL)          ; transfer to C and
  6830.                 INC     HL              ; point to high byte of length.
  6831.                 LD      B,(HL)          ; transfer that to B
  6832.                 INC     HL              ; point to start of basic/variable contents.
  6833.  
  6834.                                         ; the three types of numeric variables rejoin here
  6835.  
  6836.                                         ;;;$19DB
  6837. NEXT_O_5:       ADD     HL,BC           ; add the length to give address of next line/variable in HL.
  6838.                 POP     DE              ; restore previous address to DE.
  6839.  
  6840. ;-------------------
  6841. ; Difference routine
  6842. ;-------------------
  6843. ; This routine terminates the above routine and is also called from the
  6844. ; start of the next routine to calculate the length to reclaim.
  6845.  
  6846.                                         ;;;$19DD
  6847. DIFFER:         AND     A               ; prepare for true subtraction.
  6848.                 SBC     HL,DE           ; subtract the two pointers.
  6849.                 LD      B,H             ; transfer result
  6850.                 LD      C,L             ; to BC register pair.
  6851.                 ADD     HL,DE           ; add back
  6852.                 EX      DE,HL           ; and switch pointers
  6853.                 RET                     ; return values are the length of area in BC,
  6854.                                         ; low pointer (previous) in HL,
  6855.                                         ; high pointer (next) in DE.
  6856.  
  6857. ;------------------------
  6858. ; Handle reclaiming space
  6859. ;------------------------
  6860. ;
  6861.  
  6862.                                         ;;;$19E5
  6863. RECLAIM_1:      CALL    DIFFER          ; routine DIFFER immediately above
  6864.  
  6865.                                         ;;;$19E8
  6866. RECLAIM_2:      PUSH    BC
  6867.                 LD      A,B
  6868.                 CPL
  6869.                 LD      B,A
  6870.                 LD      A,C
  6871.                 CPL
  6872.                 LD      C,A
  6873.                 INC     BC
  6874.                 CALL    POINTERS        ; routine POINTERS
  6875.                 EX      DE,HL
  6876.                 POP     HL
  6877.                 ADD     HL,DE
  6878.                 PUSH    DE
  6879.                 LDIR                    ; copy bytes
  6880.                 POP     HL
  6881.                 RET
  6882.  
  6883. ;-----------------------------------------
  6884. ; Read line number of line in editing area
  6885. ;-----------------------------------------
  6886. ; This routine reads a line number in the editing area returning the number
  6887. ; in the BC register or zero if no digits exist before commands.
  6888. ; It is called from LINE_SCAN to check the syntax of the digits.
  6889. ; It is called from MAIN_3 to extract the line number in preparation for
  6890. ; inclusion of the line in the BASIC program area.
  6891. ;
  6892. ; Interestingly the calculator stack is moved from it's normal place at the
  6893. ; end of dynamic memory to an adequate area within the system variables area.
  6894. ; This ensures that in a low memory situation, that valid line numbers can
  6895. ; be extracted without raising an error and that memory can be reclaimed
  6896. ; by deleting lines. If the stack was in it's normal place then a situation
  6897. ; arises whereby the Spectrum becomes locked with no means of reclaiming space.
  6898.  
  6899.                                         ;;;$19FB
  6900. E_LINE_NO:      LD      HL,(E_LINE)     ; load HL from system variable E_LINE.
  6901.                 DEC     HL              ; decrease so that NEXT_CHAR can be used
  6902.                                         ; without skipping the first digit.
  6903.                 LD      (CH_ADD),HL     ; store in the system variable CH_ADD.
  6904.                 RST     20H             ; NEXT_CHAR skips any noise and white-space
  6905.                                         ; to point exactly at the first digit.
  6906.                 LD      HL,MEM_0        ; use MEM_0 as a temporary calculator stack
  6907.                                         ; an overhead of three locations are needed.
  6908.                 LD      (STKEND),HL     ; set new STKEND.
  6909.                 CALL    INT_TO_FP       ; routine INT_TO_FP will read digits till
  6910.                                         ; a non-digit found.
  6911.                 CALL    FP_TO_BC        ; routine FP_TO_BC will retrieve number from stack at membot.
  6912.                 JR      C,E_L_1         ; forward to E_L_1 if overflow i.e. > 65535.
  6913.                                         ; 'Nonsense in basic'
  6914.                 LD      HL,$D8F0        ; load HL with value -9999
  6915.                 ADD     HL,BC           ; add to line number in BC
  6916.  
  6917.                                         ;;;$1A15
  6918. E_L_1:          JP      C,REPORT_C      ; to REPORT_C 'Nonsense in Basic' if over.
  6919.                                         ; Note. As ERR_SP points to ED_ERROR
  6920.                                         ; the report is never produced although
  6921.                                         ; the RST $08 will update X_PTR leading to
  6922.                                         ; the error marker being displayed when
  6923.                                         ; the ED_LOOP is reiterated.
  6924.                                         ; in fact, since it is immediately
  6925.                                         ; cancelled, any report will do.
  6926.  
  6927.                                         ; a line in the range 0 - 9999 has been entered.
  6928.  
  6929.                 JP      SET_STK         ; jump back to SET_STK to set the calculator
  6930.                                         ; stack back to it's normal place and exit
  6931.                                         ; from there.
  6932.  
  6933. ;----------------------------------
  6934. ; Report and line number outputting
  6935. ;----------------------------------
  6936. ; Entry point OUT_NUM_1 is used by the Error Reporting code to print
  6937. ; the line number and later the statement number held in BC.
  6938. ; If the statement was part of a direct command then -2 is used as a
  6939. ; dummy line number so that zero will be printed in the report.
  6940. ; This routine is also used to print the exponent of E-format numbers.
  6941. ;
  6942. ; Entry point OUT_NUM_2 is used from OUT_LINE to output the line number
  6943. ; addressed by HL with leading spaces if necessary.
  6944.  
  6945.                                         ;;;$1A1B
  6946. OUT_NUM_1:      PUSH    DE              ; save the
  6947.                 PUSH    HL              ; registers.
  6948.                 XOR     A               ; set A to zero.
  6949.                 BIT     7,B             ; is the line number minus two ?
  6950.                 JR      NZ,OUT_NUM_4    ; forward to OUT_NUM_4 if so to print zero
  6951.                                         ; for a direct command.
  6952.                 LD      H,B             ; transfer the
  6953.                 LD      L,C             ; number to HL.
  6954.                 LD      E,$FF           ; signal 'no leading zeros'.
  6955.                 JR      OUT_NUM_3       ; forward to continue at OUT_NUM_3
  6956.  
  6957.                                         ; from OUT_LINE - HL addresses line number.
  6958.  
  6959.                                         ;;;$1A28
  6960. OUT_NUM_2:      PUSH    DE              ; save flags
  6961.                 LD      D,(HL)          ; high byte to D
  6962.                 INC     HL              ; address next
  6963.                 LD      E,(HL)          ; low byte to E
  6964.                 PUSH    HL              ; save pointer
  6965.                 EX      DE,HL           ; transfer number to HL
  6966.                 LD      E,$20           ; signal 'output leading spaces'
  6967.  
  6968.                                         ;;;$1A30
  6969. OUT_NUM_3:      LD      BC,$FC18        ; value -1000
  6970.                 CALL    OUT_SP_NO       ; routine OUT_SP_NO outputs space or number
  6971.                 LD      BC,$FF9C        ; value -100
  6972.                 CALL    OUT_SP_NO       ; routine OUT_SP_NO
  6973.                 LD      C,$F6           ; value -10 ( B is still $FF )
  6974.                 CALL    OUT_SP_NO       ; routine OUT_SP_NO
  6975.                 LD      A,L             ; remainder to A.
  6976.  
  6977.                                         ;;;$1A42
  6978. OUT_NUM_4:      CALL    OUT_CODE        ; routine OUT_CODE for final digit.
  6979.                                         ; else report code zero wouldn't get printed.
  6980.                 POP     HL              ; restore the
  6981.                 POP     DE              ; registers and
  6982.                 RET                     ; return.
  6983.  
  6984.  
  6985. ;***************************************************
  6986. ;** Part 7. BASIC LINE AND COMMAND INTERPRETATION **
  6987. ;***************************************************
  6988.  
  6989. ;-----------------
  6990. ; The offset table
  6991. ;-----------------
  6992. ; The BASIC interpreter has found a command code $CE - $FF
  6993. ; which is then reduced to range $00 - $31 and added to the base address
  6994. ; of this table to give the address of an offset which, when added to
  6995. ; the offset therein, gives the location in the following parameter table
  6996. ; where a list of class codes, separators and addresses relevant to the
  6997. ; command exists.
  6998.  
  6999.                                         ;;;$1A48
  7000. OFFST_TBL:      DEFB    P_DEF_FN - $    ; B1 offset to Address: P_DEF_FN
  7001.                 DEFB    P_CAT - $       ; CB offset to Address: P_CAT
  7002.                 DEFB    P_FORMAT - $    ; BC offset to Address: P_FORMAT
  7003.                 DEFB    P_MOVE - $      ; BF offset to Address: P_MOVE
  7004.                 DEFB    P_ERASE - $     ; C4 offset to Address: P_ERASE
  7005.                 DEFB    P_OPEN - $      ; AF offset to Address: P_OPEN
  7006.                 DEFB    P_CLOSE - $     ; B4 offset to Address: P_CLOSE
  7007.                 DEFB    P_MERGE - $     ; 93 offset to Address: P_MERGE
  7008.                 DEFB    P_VERIFY - $    ; 91 offset to Address: P_VERIFY
  7009.                 DEFB    P_BEEP - $      ; 92 offset to Address: P_BEEP
  7010.                 DEFB    P_CIRCLE - $    ; 95 offset to Address: P_CIRCLE
  7011.                 DEFB    P_INK - $       ; 98 offset to Address: P_INK
  7012.                 DEFB    P_PAPER - $     ; 98 offset to Address: P_PAPER
  7013.                 DEFB    P_FLASH - $     ; 98 offset to Address: P_FLASH
  7014.                 DEFB    P_BRIGHT - $    ; 98 offset to Address: P_BRIGHT
  7015.                 DEFB    P_INVERSE - $   ; 98 offset to Address: P_INVERSE
  7016.                 DEFB    P_OVER - $      ; 98 offset to Address: P_OVER
  7017.                 DEFB    P_OUT - $       ; 98 offset to Address: P_OUT
  7018.                 DEFB    P_LPRINT - $    ; 7F offset to Address: P_LPRINT
  7019.                 DEFB    P_LLIST - $     ; 81 offset to Address: P_LLIST
  7020.                 DEFB    P_STOP - $      ; 2E offset to Address: P_STOP
  7021.                 DEFB    P_READ - $      ; 6C offset to Address: P_READ
  7022.                 DEFB    P_DATA - $      ; 6E offset to Address: P_DATA
  7023.                 DEFB    P_RESTORE - $   ; 70 offset to Address: P_RESTORE
  7024.                 DEFB    P_NEW - $       ; 48 offset to Address: P_NEW
  7025.                 DEFB    P_BORDER - $    ; 94 offset to Address: P_BORDER
  7026.                 DEFB    P_CONT - $      ; 56 offset to Address: P_CONT
  7027.                 DEFB    P_DIM - $       ; 3F offset to Address: P_DIM
  7028.                 DEFB    P_REM - $       ; 41 offset to Address: P_REM
  7029.                 DEFB    P_FOR - $       ; 2B offset to Address: P_FOR
  7030.                 DEFB    P_GO_TO - $     ; 17 offset to Address: P_GO_TO
  7031.                 DEFB    P_GO_SUB - $    ; 1F offset to Address: P_GO_SUB
  7032.                 DEFB    P_INPUT - $     ; 37 offset to Address: P_INPUT
  7033.                 DEFB    P_LOAD - $      ; 77 offset to Address: P_LOAD
  7034.                 DEFB    P_LIST - $      ; 44 offset to Address: P_LIST
  7035.                 DEFB    P_LET - $       ; 0F offset to Address: P_LET
  7036.                 DEFB    P_PAUSE - $     ; 59 offset to Address: P_PAUSE
  7037.                 DEFB    P_NEXT - $      ; 2B offset to Address: P_NEXT
  7038.                 DEFB    P_POKE - $      ; 43 offset to Address: P_POKE
  7039.                 DEFB    P_PRINT - $     ; 2D offset to Address: P_PRINT
  7040.                 DEFB    P_PLOT - $      ; 51 offset to Address: P_PLOT
  7041.                 DEFB    P_RUN - $       ; 3A offset to Address: P_RUN
  7042.                 DEFB    P_SAVE - $      ; 6D offset to Address: P_SAVE
  7043.                 DEFB    P_RANDOM - $    ; 42 offset to Address: P_RANDOM
  7044.                 DEFB    P_IF - $        ; 0D offset to Address: P_IF
  7045.                 DEFB    P_CLS - $       ; 49 offset to Address: P_CLS
  7046.                 DEFB    P_DRAW - $      ; 5C offset to Address: P_DRAW
  7047.                 DEFB    P_CLEAR - $     ; 44 offset to Address: P_CLEAR
  7048.                 DEFB    P_RETURN - $    ; 15 offset to Address: P_RETURN
  7049.                 DEFB    P_COPY - $      ; 5D offset to Address: P_COPY
  7050.  
  7051. ;--------------------------------
  7052. ; The parameter or "Syntax" table
  7053. ;--------------------------------
  7054. ; For each command there exists a variable list of parameters.
  7055. ; If the character is greater than a space it is a required separator.
  7056. ; If less, then it is a command class in the range 00 - 0B.
  7057. ; Note that classes 00, 03 and 05 will fetch the addresses from this table.
  7058. ; Some classes e.g. 07 and 0B have the same address in all invocations
  7059. ; and the command is re-computed from the low-byte of the parameter address.
  7060. ; Some e.g. 02 are only called once so a call to the command is made from
  7061. ; within the class routine rather than holding the address within the table.
  7062. ; Some class routines check syntax entirely and some leave this task for the
  7063. ; command itself.
  7064. ; Others for example CIRCLE (x,y,z) check the first part (x,y) using the
  7065. ; class routine and the final part (,z) within the command.
  7066. ; The last few commands appear to have been added in a rush but their syntax
  7067. ; is rather simple e.g. MOVE "M1","M2"
  7068.  
  7069.                                         ;;;$1A7A
  7070. P_LET:          DEFB    $01             ; CLASS_01 - A variable is required.
  7071.                 DEFB    $3D             ; Separator:  '='
  7072.                 DEFB    $02             ; CLASS_02 - An expression, numeric or string, must follow.
  7073.  
  7074.                                         ;;;$1A7D
  7075. P_GO_TO:        DEFB    $06             ; CLASS_06 - A numeric expression must follow.
  7076.                 DEFB    $00             ; CLASS_00 - No further operands.
  7077.                 DEFW    GO_TO           ; Address: $1E67; Address: GO_TO
  7078.  
  7079.                                         ;;;$1A81
  7080. P_IF:           DEFB    $06             ; CLASS_06 - A numeric expression must follow.
  7081.                 DEFB    $CB             ; Separator:  'THEN'
  7082.                 DEFB    $05             ; CLASS_05 - Variable syntax checked by routine.
  7083.                 DEFW    IF_CMD          ; Address: $1CF0; Address: IF
  7084.  
  7085.                                         ;;;$1A86
  7086. P_GO_SUB:       DEFB    $06             ; CLASS_06 - A numeric expression must follow.
  7087.                 DEFB    $00             ; CLASS_00 - No further operands.
  7088.                 DEFW    GO_SUB          ; Address: $1EED; Address: GO_SUB
  7089.  
  7090.                                         ;;;$1A8A
  7091. P_STOP:         DEFB    $00             ; CLASS_00 - No further operands.
  7092.                 DEFW    STOP            ; Address: $1CEE; Address: STOP
  7093.  
  7094.                                         ;;;$1A8D
  7095. P_RETURN:       DEFB    $00             ; CLASS_00 - No further operands.
  7096.                 DEFW    RETURN          ; Address: $1F23; Address: RETURN
  7097.  
  7098.                                         ;;;$1A90
  7099. P_FOR:          DEFB    $04             ; CLASS_04 - A single character variable must follow.
  7100.                 DEFB    $3D             ; Separator:  '='
  7101.                 DEFB    $06             ; CLASS_06 - A numeric expression must follow.
  7102.                 DEFB    $CC             ; Separator:  'TO'
  7103.                 DEFB    $06             ; CLASS_06 - A numeric expression must follow.
  7104.                 DEFB    $05             ; CLASS_05 - Variable syntax checked by routine.
  7105.                 DEFW    FOR             ; Address: $1D03; Address: FOR
  7106.  
  7107.                                         ;;;$1A98
  7108. P_NEXT:         DEFB    $04             ; CLASS_04 - A single character variable must follow.
  7109.                 DEFB    $00             ; CLASS_00 - No further operands.
  7110.                 DEFW    NEXT            ; Address: $1DAB; Address: NEXT
  7111.  
  7112.                                         ;;;$1A9C
  7113. P_PRINT:        DEFB    $05             ; CLASS_05 - Variable syntax checked entirely by routine.
  7114.                 DEFW    PRINT           ; Address: $1FCD; Address: PRINT
  7115.  
  7116.                                         ;;;$1A9F
  7117. P_INPUT:        DEFB    $05             ; CLASS_05 - Variable syntax checked entirely by routine.
  7118.                 DEFW    INPUT           ; Address: $2089; Address: INPUT
  7119.  
  7120.                                         ;;;$1AA2
  7121. P_DIM:          DEFB    $05             ; CLASS_05 - Variable syntax checked entirely by routine.
  7122.                 DEFW    DIM             ; Address: $2C02; Address: DIM
  7123.  
  7124.                                         ;;;$1AA5
  7125. P_REM:          DEFB    $05             ; CLASS_05 - Variable syntax checked entirely by routine.
  7126.                 DEFW    REM             ; Address: $1BB2; Address: REM
  7127.  
  7128.                                         ;;;$1AA8
  7129. P_NEW:          DEFB    $00             ; CLASS_00 - No further operands.
  7130.                 DEFW    NEW             ; Address: $11B7; Address: NEW
  7131.  
  7132.                                         ;;;$1AAB
  7133. P_RUN:          DEFB    $03             ; CLASS_03 - A numeric expression may follow else default to zero.
  7134.                 DEFW    RUN             ; Address: $1EA1; Address: RUN
  7135.  
  7136.                                         ;;;$1AAE
  7137. P_LIST:         DEFB    $05             ; CLASS_05 - Variable syntax checked entirely by routine.
  7138.                 DEFW    LIST            ; Address: $17F9; Address: LIST
  7139.  
  7140.                                         ;;;$1AB1
  7141. P_POKE:         DEFB    $08             ; CLASS_08 - Two comma-separated numeric expressions required.
  7142.                 DEFB    $00             ; CLASS_00 - No further operands.
  7143.                 DEFW    POKE            ; Address: $1E80; Address: POKE
  7144.  
  7145.                                         ;;;$1AB5
  7146. P_RANDOM:       DEFB    $03             ; CLASS_03 - A numeric expression may follow else default to zero.
  7147.                 DEFW    RANDOMIZE       ; Address: $1E4F; Address: RANDOMIZE
  7148.  
  7149.                                         ;;;$1AB8
  7150. P_CONT:         DEFB    $00             ; CLASS_00 - No further operands.
  7151.                 DEFW    CONTINUE        ; Address: $1E5F; Address: CONTINUE
  7152.  
  7153.                                         ;;;$1ABB
  7154. P_CLEAR:        DEFB    $03             ; CLASS_03 - A numeric expression may follow else default to zero.
  7155.                 DEFW    CLEAR           ; Address: $1EAC; Address: CLEAR
  7156.  
  7157.                                         ;;;$1ABE
  7158. P_CLS:          DEFB    $00             ; CLASS_00 - No further operands.
  7159.                 DEFW    CLS             ; Address: $0D6B; Address: CLS
  7160.  
  7161.                                         ;;;$1AC1
  7162. P_PLOT:         DEFB    $09             ; CLASS_09 - Two comma-separated numeric expressions required with optional colour items.
  7163.                 DEFB    $00             ; CLASS_00 - No further operands.
  7164.                 DEFW    PLOT            ; Address: $22DC; Address: PLOT
  7165.  
  7166.                                         ;;;$1AC5
  7167. P_PAUSE:        DEFB    $06             ; CLASS_06 - A numeric expression must follow.
  7168.                 DEFB    $00             ; CLASS_00 - No further operands.
  7169.                 DEFW    PAUSE           ; Address: $1F3A; Address: PAUSE
  7170.  
  7171.                                         ;;;$1AC9
  7172. P_READ:         DEFB    $05             ; CLASS_05 - Variable syntax checked entirely by routine.
  7173.                 DEFW    READ            ; Address: $1DED; Address: READ
  7174.  
  7175.                                         ;;;$1ACC
  7176. P_DATA:         DEFB    $05             ; CLASS_05 - Variable syntax checked entirely by routine.
  7177.                 DEFW    DATA            ; Address: $1E27; Address: DATA
  7178.  
  7179.                                         ;;;$1ACF
  7180. P_RESTORE:      DEFB    $03             ; CLASS_03 - A numeric expression may follow else default to zero.
  7181.                 DEFW    RESTORE         ; Address: $1E42; Address: RESTORE
  7182.  
  7183.                                         ;;;$1AD2
  7184. P_DRAW:         DEFB    $09             ; CLASS_09 - Two comma-separated numeric expressions required with optional colour items.
  7185.                 DEFB    $05             ; CLASS_05 - Variable syntax checked by routine.
  7186.                 DEFW    DRAW            ; Address: $2382; Address: DRAW
  7187.  
  7188.                                         ;;;$1AD6
  7189. P_COPY:         DEFB    $00             ; CLASS_00 - No further operands.
  7190.                 DEFW    COPY            ; Address: $0EAC; Address: COPY
  7191.  
  7192.                                         ;;;$1AD9
  7193. P_LPRINT:       DEFB    $05             ; CLASS_05 - Variable syntax checked entirely by routine.
  7194.                 DEFW    LPRINT          ; Address: $1FC9; Address: LPRINT
  7195.  
  7196.                                         ;;;$1ADC
  7197. P_LLIST:        DEFB    $05             ; CLASS_05 - Variable syntax checked entirely by routine.
  7198.                 DEFW    LLIST           ; Address: $17F5; Address: LLIST
  7199.  
  7200.                                         ;;;$1ADF
  7201. P_SAVE:         DEFB    $0B             ; CLASS_0B - Offset address converted to tape command.
  7202.  
  7203.                                         ;;;$L1AE0
  7204. P_LOAD:         DEFB    $0B             ; CLASS_0B - Offset address converted to tape command.
  7205.  
  7206.                                         ;;;$1AE1
  7207. P_VERIFY:       DEFB    $0B             ; CLASS_0B - Offset address converted to tape command.
  7208.  
  7209.                                         ;;;$1AE2
  7210. P_MERGE:        DEFB    $0B             ; CLASS_0B - Offset address converted to tape command.
  7211.  
  7212.                                         ;;;$1AE3
  7213. P_BEEP:         DEFB    $08             ; CLASS_08 - Two comma-separated numeric expressions required.
  7214.                 DEFB    $00             ; CLASS_00 - No further operands.
  7215.                 DEFW    BEEP            ; Address: $03F8; Address: BEEP
  7216.  
  7217.                                         ;;;$1AE7
  7218. P_CIRCLE:       DEFB    $09             ; CLASS_09 - Two comma-separated numeric expressions required with optional colour items.
  7219.                 DEFB    $05             ; CLASS_05 - Variable syntax checked by routine.
  7220.                 DEFW    CIRCLE          ; Address: $2320; Address: CIRCLE
  7221.  
  7222.                                         ;;;$1AEB
  7223. P_INK:          DEFB    $07             ; CLASS_07 - Offset address is converted to colour code.
  7224.                                         ;
  7225.  
  7226.                                         ;;;$1AEC
  7227. P_PAPER:        DEFB    $07             ; CLASS_07 - Offset address is converted to colour code.
  7228.  
  7229.                                         ;;;$1AED
  7230. P_FLASH:        DEFB    $07             ; CLASS_07 - Offset address is converted to colour code.
  7231.  
  7232.                                         ;;;$1AEE
  7233. P_BRIGHT:       DEFB    $07             ; CLASS_07 - Offset address is converted to colour code.
  7234.  
  7235.                                         ;;;$1AEF
  7236. P_INVERSE:      DEFB    $07             ; CLASS_07 - Offset address is converted to colour code.
  7237.  
  7238.                                         ;;;$1AF0
  7239. P_OVER:         DEFB    $07             ; CLASS_07 - Offset address is converted to colour code.
  7240.  
  7241.                                         ;;;$1AF1
  7242. P_OUT:          DEFB    $08             ; CLASS_08 - Two comma-separated numeric expressions required.
  7243.                 DEFB    $00             ; CLASS_00 - No further operands.
  7244.                 DEFW    OUT_CMD         ; Address: $1E7A; Address: OUT
  7245.  
  7246.                                         ;;;$1AF5
  7247. P_BORDER:       DEFB    $06             ; CLASS_06 - A numeric expression must follow.
  7248.                 DEFB    $00             ; CLASS_00 - No further operands.
  7249.                 DEFW    BORDER          ; Address: $2294; Address: BORDER
  7250.  
  7251.                                         ;;;$1AF9
  7252. P_DEF_FN:       DEFB    $05             ; CLASS_05 - Variable syntax checked entirely by routine.
  7253.                 DEFW    DEF_FN          ; Address: $1F60; Address: DEF_FN
  7254.  
  7255.                                         ;;;$1AFC
  7256. P_OPEN:         DEFB    $06             ; CLASS_06 - A numeric expression must follow.
  7257.                 DEFB    $2C             ; Separator:  ','               see Footnote *
  7258.                 DEFB    $0A             ; CLASS_0A - A string expression must follow.
  7259.                 DEFB    $00             ; CLASS_00 - No further operands.
  7260.                 DEFW    OPEN            ; Address: $1736; Address: OPEN
  7261.  
  7262.                                         ;;;$1B02
  7263. P_CLOSE:        DEFB    $06             ; CLASS_06 - A numeric expression must follow.
  7264.                 DEFB    $00             ; CLASS_00 - No further operands.
  7265.                 DEFW    CLOSE           ; Address: $16E5; Address: CLOSE
  7266.  
  7267.                                         ;;;$1B06
  7268. P_FORMAT:       DEFB    $0A             ; CLASS_0A - A string expression must follow.
  7269.                 DEFB    $00             ; CLASS_00 - No further operands.
  7270.                 DEFW    CAT_ETC         ; Address: $1793; Address: CAT_ETC
  7271.  
  7272.                                         ;;;$1B0A
  7273. P_MOVE:         DEFB    $0A             ; CLASS_0A - A string expression must follow.
  7274.                 DEFB    $2C             ; Separator:  ','
  7275.                 DEFB    $0A             ; CLASS_0A - A string expression must follow.
  7276.                 DEFB    $00             ; CLASS_00 - No further operands.
  7277.                 DEFW    CAT_ETC         ; Address: $1793; Address: CAT_ETC
  7278.  
  7279.                                         ;;;$1B10
  7280. P_ERASE:        DEFB    $0A             ; CLASS_0A - A string expression must follow.
  7281.                 DEFB    $00             ; CLASS_00 - No further operands.
  7282.                 DEFW    CAT_ETC         ; Address: $1793; Address: CAT_ETC
  7283.  
  7284.                                         ;;;$1B14
  7285. P_CAT:          DEFB    $00             ; CLASS_00 - No further operands.
  7286.                 DEFW    CAT_ETC         ; Address: $1793; Address: CAT_ETC
  7287.  
  7288.                                         ; * Note that a comma is required as a separator with the OPEN command
  7289.                                         ; but the Interface 1 programmers relaxed this allowing ';' as an
  7290.                                         ; alternative for their channels creating a confusing mixture of
  7291.                                         ; allowable syntax as it is this ROM which opens or re-opens the
  7292.                                         ; normal channels.
  7293.  
  7294. ;--------------------------------
  7295. ; Main parser (BASIC interpreter)
  7296. ;--------------------------------
  7297. ; This routine is called once from MAIN_2 when the Basic line is to
  7298. ; be entered or re-entered into the Program area and the syntax
  7299. ; requires checking.
  7300.  
  7301.                                         ;;;$1B17
  7302. LINE_SCAN:      RES     7,(IY+$01)      ; update FLAGS - signal checking syntax
  7303.                 CALL    E_LINE_NO       ; routine E_LINE_NO             >>
  7304.                                         ; fetches the line number if in range.
  7305.                 XOR     A               ; clear the accumulator.
  7306.                 LD      (SUBPPC),A      ; set statement number SUBPPC to zero.
  7307.                 DEC     A               ; set accumulator to $FF.
  7308.                 LD      (ERR_NR),A      ; set ERR_NR to 'OK' - 1.
  7309.                 JR      STMT_L_1        ; forward to continue at STMT_L_1.
  7310.  
  7311. ;---------------
  7312. ; Statement loop
  7313. ;---------------
  7314.  
  7315.                                         ;;;$1B28
  7316. STMT_LOOP:      RST     20H             ; NEXT_CHAR
  7317.  
  7318.                                         ; -> the entry point from above or LINE_RUN
  7319.                                         ;;;$1B29
  7320. STMT_L_1:       CALL    SET_WORK        ; routine SET_WORK clears workspace etc.
  7321.                 INC     (IY+$0D)        ; increment statement number SUBPPC
  7322.                 JP      M,REPORT_C      ; to REPORT_C to raise
  7323.                                         ; 'Nonsense in basic' if over 127.
  7324.                 RST     18H             ; GET_CHAR
  7325.                 LD      B,$00           ; set B to zero for later indexing.
  7326.                                         ; early so any other reason ???
  7327.                 CP      $0D             ; is character carriage return ?
  7328.                                         ; i.e. an empty statement.
  7329.                 JR      Z,LINE_END      ; forward to LINE_END if so.
  7330.  
  7331.                 CP      $3A             ; is it statement end marker ':' ?
  7332.                                         ; i.e. another type of empty statement.
  7333.                 JR      Z,STMT_LOOP     ; back to STMT_LOOP if so.
  7334.  
  7335.                 LD      HL,STMT_RET     ; address: STMT_RET
  7336.                 PUSH    HL              ; is now pushed as a return address
  7337.                 LD      C,A             ; transfer the current character to C.
  7338.  
  7339.                                         ; advance CH_ADD to a position after command and test if it is a command.
  7340.  
  7341.                 RST     20H             ; NEXT_CHAR to advance pointer
  7342.                 LD      A,C             ; restore current character
  7343.                 SUB     $CE             ; subtract 'DEF FN' - first command
  7344.                 JP      C,REPORT_C      ; jump to REPORT_C if less than a command raising
  7345.                                         ; 'Nonsense in basic'
  7346.                 LD      C,A             ; put the valid command code back in C.
  7347.                                         ; register B is zero.
  7348.                 LD      HL,OFFST_TBL    ; address: OFFST_TBL
  7349.                 ADD     HL,BC           ; index into table with one of 50 commands.
  7350.                 LD      C,(HL)          ; pick up displacement to syntax table entry.
  7351.                 ADD     HL,BC           ; add to address the relevant entry.
  7352.                 JR      GET_PARAM       ; forward to continue at GET_PARAM
  7353.  
  7354. ;-----------------------
  7355. ; The main scanning loop
  7356. ;-----------------------
  7357. ; not documented properly
  7358.  
  7359.                                         ;;;$1B52
  7360. SCAN_LOOP:      LD      HL,(T_ADDR)     ; fetch temporary address from T_ADDR
  7361.                                         ; during subsequent loops.
  7362.  
  7363.                                         ; -> the initial entry point with HL addressing start of syntax table entry.
  7364.  
  7365.                                         ;;;$1B55
  7366. GET_PARAM:      LD      A,(HL)          ; pick up the parameter.
  7367.                 INC     HL              ; address next one.
  7368.                 LD      (T_ADDR),HL     ; save pointer in system variable T_ADDR
  7369.                 LD      BC,SCAN_LOOP    ; address: SCAN_LOOP
  7370.                 PUSH    BC              ; is now pushed on stack as looping address.
  7371.                 LD      C,A             ; store parameter in C.
  7372.                 CP      $20             ; is it greater than ' '  ?
  7373.                 JR      NC,SEPARATOR    ; forward to SEPARATOR to check that correct
  7374.                                         ; separator appears in statement if so.
  7375.                 LD      HL,CLASS_TBL    ; address: CLASS_TBL.
  7376.                 LD      B,$00           ; prepare to index into the class table.
  7377.                 ADD     HL,BC           ; index to find displacement to routine.
  7378.                 LD      C,(HL)          ; displacement to BC
  7379.                 ADD     HL,BC           ; add to address the CLASS routine.
  7380.                 PUSH    HL              ; push the address on the stack.
  7381.                 RST     18H             ; GET_CHAR - HL points to place in statement.
  7382.                 DEC     B               ; reset the zero flag - the initial state
  7383.                                         ; for all class routines.
  7384.                 RET                     ; and make an indirect jump to routine
  7385.                                         ; and then SCAN_LOOP (also on stack).
  7386.  
  7387.                                         ; Note. one of the class routines will eventually drop the return address
  7388.                                         ; off the stack breaking out of the above seemingly endless loop.
  7389.  
  7390. ;-----------------
  7391. ; Verify separator
  7392. ;-----------------
  7393. ; This routine is called once to verify that the mandatory separator
  7394. ; present in the parameter table is also present in the correct
  7395. ; location following the command. For example, the 'THEN' token after
  7396. ; the 'IF' token and expression.
  7397.  
  7398.                                         ;;;$1B6F
  7399. SEPARATOR:      RST     18H             ; GET_CHAR
  7400.                 CP      C               ; does it match the character in C ?
  7401.                 JP      NZ,REPORT_C     ; jump forward to REPORT_C if not
  7402.                                         ; 'Nonsense in basic'.
  7403.  
  7404.                 RST     20H             ; NEXT_CHAR advance to next character
  7405.                 RET                     ; return.
  7406.  
  7407. ;-------------------------------
  7408. ; Come here after interpretation
  7409. ;-------------------------------
  7410.  
  7411.                                         ;;;$1B76
  7412. STMT_RET:       CALL    BREAK_KEY       ; routine BREAK_KEY is tested after every statement.
  7413.                 JR      C,STMT_R_1      ; step forward to STMT_R_1 if not pressed.
  7414.  
  7415.                                         ;;;$1B7B
  7416. REPORT_L:       RST     08H             ; ERROR_1
  7417.                 DEFB    $14             ; Error Report: BREAK into program
  7418.  
  7419.                                         ;;;$1B7D
  7420. STMT_R_1:       BIT     7,(IY+$0A)      ; test NSPPC - will be set if $FF - no jump to be made.
  7421.                 JR      NZ,STMT_NEXT    ; forward to STMT_NEXT if a program line.
  7422.  
  7423.                 LD      HL,(NEWPPC)     ; fetch line number from NEWPPC
  7424.                 BIT     7,H             ; will be set if minus two - direct command(s)
  7425.                 JR      Z,LINE_NEW      ; forward to LINE_NEW if a jump is to be
  7426.                                         ; made to a new program line/statement.
  7427.  
  7428. ;---------------------
  7429. ; Run a direct command
  7430. ;---------------------
  7431. ; A direct command is to be run or, if continuing from above,
  7432. ; the next statement of a direct command is to be considered.
  7433.  
  7434.                                         ;;;$1B8A
  7435. LINE_RUN:       LD      HL,$FFFE        ; The dummy value minus two
  7436.                 LD      (PPC),HL        ; is set/reset as line number in PPC.
  7437.                 LD      HL,(WORKSP)     ; point to end of line + 1 - WORKSP.
  7438.                 DEC     HL              ; now point to $80 end-marker.
  7439.                 LD      DE,(E_LINE)     ; address the start of line E_LINE.
  7440.                 DEC     DE              ; now location before - for GET_CHAR.
  7441.                 LD      A,(NSPPC)       ; load statement to A from NSPPC.
  7442.                 JR      NEXT_LINE       ; forward to NEXT_LINE.
  7443.  
  7444. ;-------------------------------
  7445. ; Find start address of new line
  7446. ;-------------------------------
  7447. ; The branch was to here if a jump is to made to a new line number
  7448. ; and statement.
  7449. ; That is the previous statement was a GO TO, GO SUB, RUN, RETURN, NEXT etc..
  7450.  
  7451.                                         ;;;$1B9E
  7452. LINE_NEW:       CALL    LINE_ADDR       ; routine LINE_ADDR gets address of line
  7453.                                         ; returning zero flag set if line found.
  7454.                 LD      A,(NSPPC)       ; fetch new statement from NSPPC
  7455.                 JR      Z,LINE_USE      ; forward to LINE_USE if line matched.
  7456.  
  7457.                                         ; continue as must be a direct command.
  7458.  
  7459.                 AND     A               ; test statement which should be zero
  7460.                 JR      NZ,REPORT_N     ; forward to REPORT_N if not.
  7461.                                         ; 'Statement lost'
  7462.                 LD      B,A             ; save statement in B. ?
  7463.                 LD      A,(HL)          ; fetch high byte of line number.
  7464.                 AND     $C0             ; test if using direct command
  7465.                                         ; a program line is less than $3F
  7466.                 LD      A,B             ; retrieve statement.
  7467.                                         ; (we can assume it is zero).
  7468.                 JR      Z,LINE_USE      ; forward to LINE_USE if was a program line
  7469.  
  7470.                                         ; Alternatively a direct statement has finished correctly.
  7471.  
  7472.                                         ;;;$1BB0
  7473. REPORT_0:       RST     08H             ; ERROR_1
  7474.                 DEFB    $FF             ; Error Report: OK
  7475.  
  7476. ;-------------------
  7477. ; Handle REM command
  7478. ;-------------------
  7479. ; The REM command routine.
  7480. ; The return address STMT_RET is dropped and the rest of line ignored.
  7481.  
  7482.                                         ;;;$1BB2
  7483. REM:            POP     BC              ; drop return address STMT_RET and
  7484.                                         ; continue ignoring rest of line.
  7485.  
  7486. ;-------------
  7487. ; End of line?
  7488. ;-------------
  7489.  
  7490.                                         ;;;$1BB3
  7491. LINE_END:       CALL    SYNTAX_Z        ; routine SYNTAX_Z  (UNSTACK_Z?)
  7492.                 RET     Z               ; return if checking syntax.
  7493.  
  7494.                 LD      HL,(NXTLIN)     ; fetch NXTLIN to HL.
  7495.                 LD      A,$C0           ; test against the
  7496.                 AND     (HL)            ; system limit $3F.
  7497.                 RET     NZ              ; return if more as must be end of program.
  7498.                                         ; (or direct command)
  7499.  
  7500.                 XOR     A               ; set statement to zero.
  7501.  
  7502.                                         ; and continue to set up the next following line and then consider this new one.
  7503.  
  7504. ;----------------------
  7505. ; General line checking
  7506. ;----------------------
  7507. ; The branch was here from LINE_NEW if Basic is branching.
  7508. ; or a continuation from above if dealing with a new sequential line.
  7509. ; First make statement zero number one leaving others unaffected.
  7510.  
  7511.                                         ;;;$1BBF
  7512. LINE_USE:       CP      $01             ; will set carry if zero.
  7513.                 ADC     A,$00           ; add in any carry.
  7514.                 LD      D,(HL)          ; high byte of line number to D.
  7515.                 INC     HL              ; advance pointer.
  7516.                 LD      E,(HL)          ; low byte of line number to E.
  7517.                 LD      (PPC),DE        ; set system variable PPC.
  7518.                 INC     HL              ; advance pointer.
  7519.                 LD      E,(HL)          ; low byte of line length to E.
  7520.                 INC     HL              ; advance pointer.
  7521.                 LD      D,(HL)          ; high byte of line length to D.
  7522.                 EX      DE,HL           ; swap pointer to DE before
  7523.                 ADD     HL,DE           ; adding to address the end of line.
  7524.                 INC     HL              ; advance to start of next line.
  7525.  
  7526. ;------------------------------
  7527. ; Update NEXT LINE but consider
  7528. ; previous line or edit line.
  7529. ;------------------------------
  7530. ; The pointer will be the next line if continuing from above or to
  7531. ; edit line end-marker ($80) if from LINE_RUN.
  7532.  
  7533.                                         ;;;$1BD1
  7534. NEXT_LINE:      LD      (NXTLIN),HL     ; store pointer in system variable NXTLIN
  7535.                 EX      DE,HL           ; bring back pointer to previous or edit line
  7536.                 LD      (CH_ADD),HL     ; and update CH_ADD with character address.
  7537.                 LD      D,A             ; store statement in D.
  7538.                 LD      E,$00           ; set E to zero to suppress token searching if EACH_STMT is to be called.
  7539.                 LD      (IY+$0A),$FF    ; set statement NSPPC to $FF signalling no jump to be made.
  7540.                 DEC     D               ; decrement and test statement
  7541.                 LD      (IY+$0D),D      ; set SUBPPC to decremented statement number.
  7542.                 JP      Z,STMT_LOOP     ; to STMT_LOOP if result zero as statement is
  7543.                                         ; at start of line and address is known.
  7544.                 INC     D               ; else restore statement.
  7545.                 CALL    EACH_STMT       ; routine EACH_STMT finds the D'th statement address as E does not contain a token.
  7546.                 JR      Z,STMT_NEXT     ; forward to STMT_NEXT if address found.
  7547.  
  7548.                                         ;;;$1BEC
  7549. REPORT_N:       RST     08H             ; ERROR_1
  7550.                 DEFB    $16             ; Error Report: Statement lost
  7551.  
  7552. ;------------------
  7553. ; End of statement?
  7554. ;------------------
  7555. ; This combination of routines is called from 20 places when
  7556. ; the end of a statement should have been reached and all preceding
  7557. ; syntax is in order.
  7558.  
  7559.                                         ;;;$1BEE
  7560. CHECK_END:      CALL    SYNTAX_Z        ; routine SYNTAX_Z
  7561.                 RET     NZ              ; return immediately in runtime
  7562.  
  7563.                 POP     BC              ; drop address of calling routine.
  7564.                 POP     BC              ; drop address STMT_RET.
  7565.                                         ; and continue to find next statement.
  7566.  
  7567. ;---------------------
  7568. ; Go to next statement
  7569. ;---------------------
  7570. ; Acceptable characters at this point are carriage return and ':'.
  7571. ; If so go to next statement which in the first case will be on next line.
  7572.  
  7573.                                         ;;;$1BF4
  7574. STMT_NEXT:      RST     18H             ; GET_CHAR - ignoring white space etc.
  7575.                 CP      $0D             ; is it carriage return ?
  7576.                 JR      Z,LINE_END      ; back to LINE_END if so.
  7577.  
  7578.                 CP      $3A             ; is it ':' ?
  7579.                 JP      Z,STMT_LOOP     ; jump back to STMT_LOOP to consider
  7580.                                         ; further statements
  7581.                 JP      REPORT_C        ; jump to REPORT_C with any other character
  7582.                                         ; 'Nonsense in BASIC'.
  7583.  
  7584. ; Note. the two-byte sequence 'rst 08; defb $0b' could replace the above jp.
  7585.  
  7586. ;--------------------
  7587. ; Command class table
  7588. ;--------------------
  7589.  
  7590.                                         ;;;$1C01
  7591. CLASS_TBL:      DEFB    CLASS_00 - $    ; 0F offset to Address: CLASS_00
  7592.                 DEFB    CLASS_01 - $    ; 1D offset to Address: CLASS_01
  7593.                 DEFB    CLASS_02 - $    ; 4B offset to Address: CLASS_02
  7594.                 DEFB    CLASS_03 - $    ; 09 offset to Address: CLASS_03
  7595.                 DEFB    CLASS_04 - $    ; 67 offset to Address: CLASS_04
  7596.                 DEFB    CLASS_05 - $    ; 0B offset to Address: CLASS_05
  7597.                 DEFB    CLASS_06 - $    ; 7B offset to Address: CLASS_06
  7598.                 DEFB    CLASS_07 - $    ; 8E offset to Address: CLASS_07
  7599.                 DEFB    CLASS_08 - $    ; 71 offset to Address: CLASS_08
  7600.                 DEFB    CLASS_09 - $    ; B4 offset to Address: CLASS_09
  7601.                 DEFB    CLASS_0A - $    ; 81 offset to Address: CLASS_0A
  7602.                 DEFB    CLASS_0B - $    ; CF offset to Address: CLASS_0B
  7603.  
  7604.  
  7605. ;-------------------------------
  7606. ; Command classes 00, 03, and 05
  7607. ;-------------------------------
  7608. ; CLASS_03 e.g RUN or RUN 200           ;  optional operand
  7609. ; CLASS_00 e.g CONTINUE                 ;  no operand
  7610. ; CLASS_05 e.g PRINT                    ;  variable syntax checked by routine
  7611.  
  7612.                                         ;;;$1C0D
  7613. CLASS_03:       CALL    FETCH_NUM       ; routine FETCH_NUM
  7614.  
  7615.                                         ;;;$1C10
  7616. CLASS_00:       CP      A               ; reset zero flag.
  7617.  
  7618.                                         ; if entering here then all class routines are entered with zero reset.
  7619.  
  7620.                                         ;;;$1C11
  7621. CLASS_05:       POP     BC              ; drop address SCAN_LOOP.
  7622.                 CALL    Z,CHECK_END     ; if zero set then call routine CHECK_END >>>
  7623.                                         ; as should be no further characters.
  7624.                 EX      DE,HL           ; save HL to DE.
  7625.                 LD      HL,(T_ADDR)     ; fetch T_ADDR
  7626.                 LD      C,(HL)          ; fetch low byte of routine
  7627.                 INC     HL              ; address next.
  7628.                 LD      B,(HL)          ; fetch high byte of routine.
  7629.                 EX      DE,HL           ; restore HL from DE
  7630.                 PUSH    BC              ; push the address
  7631.                 RET                     ; and make an indirect jump to the command.
  7632.  
  7633. ;-------------------------------
  7634. ; Command classes 01, 02, and 04
  7635. ;-------------------------------
  7636. ; CLASS_01  e.g LET A = 2*3             ; a variable is reqd
  7637.  
  7638. ; This class routine is also called from INPUT and READ to find the
  7639. ; destination variable for an assignment.
  7640.  
  7641.                                         ;;;$1C1F
  7642. CLASS_01:       CALL    LOOK_VARS       ; routine LOOK_VARS returns carry set if not
  7643.                                         ; found in runtime.
  7644.  
  7645. ;-----------------------
  7646. ; Variable in assignment
  7647. ;-----------------------
  7648.  
  7649.                                         ;;;$1C22
  7650. VAR_A_1:        LD      (IY+$37),$00    ; set FLAGX to zero
  7651.                 JR      NC,VAR_A_2      ; forward to VAR_A_2 if found or checking syntax.
  7652.  
  7653.                 SET     1,(IY+$37)      ; FLAGX  - Signal a new variable
  7654.                 JR      NZ,VAR_A_3      ; to VAR_A_3 if not assigning to an array
  7655.                                         ; e.g. LET a$(3,3) = "X"
  7656.  
  7657.                                         ;;;$1C2E
  7658. REPORT_2:       RST     08H             ; ERROR_1
  7659.                 DEFB    $01             ; Error Report: Variable not found
  7660.  
  7661.                                         ;;;$1C30
  7662. VAR_A_2:        CALL    Z,STK_VAR               ; routine STK_VAR considers a subscript/slice
  7663.                 BIT     6,(IY+$01)      ; test FLAGS  - Numeric or string result ?
  7664.                 JR      NZ,VAR_A_3      ; to VAR_A_3 if numeric
  7665.  
  7666.                 XOR     A               ; default to array/slice - to be retained.
  7667.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  7668.                 CALL    NZ,STK_FETCH    ; routine STK_FETCH is called in runtime
  7669.                                         ; may overwrite A with 1.
  7670.                 LD      HL,FLAGX        ; address system variable FLAGX
  7671.                 OR      (HL)            ; set bit 0 if simple variable to be reclaimed
  7672.                 LD      (HL),A          ; update FLAGX
  7673.                 EX      DE,HL           ; start of string/subscript to DE
  7674.  
  7675.                                         ;;;$1C46
  7676. VAR_A_3:        LD      (STRLEN),BC     ; update STRLEN
  7677.                 LD      (DEST),HL       ; and DEST of assigned string.
  7678.                 RET                     ; return.
  7679.  
  7680. ; ---------------------------
  7681. ; CLASS_02 e.g. LET a = 1 + 1           ; an expression must follow
  7682.  
  7683.                                         ;;;$1C4E
  7684. CLASS_02:       POP     BC              ; drop return address SCAN_LOOP
  7685.                 CALL    VAL_FET_1       ; routine VAL_FET_1 is called to check
  7686.                                         ; expression and assign result in runtime
  7687.                 CALL    CHECK_END       ; routine CHECK_END checks nothing else
  7688.                                         ; is present in statement.
  7689.                 RET                     ; return
  7690.  
  7691. ;--------------
  7692. ; Fetch a value
  7693. ;--------------
  7694.  
  7695.                                         ;;;$1C56
  7696. VAL_FET_1:      LD      A,(FLAGS)       ; initial FLAGS to A
  7697.  
  7698.                                         ;;;$LC59
  7699. VAL_FET_2:      PUSH    AF              ; save A briefly
  7700.                 CALL    SCANNING        ; routine SCANNING evaluates expression.
  7701.                 POP     AF              ; restore A
  7702.                 LD      D,(IY+$01)      ; post-SCANNING FLAGS to D
  7703.                 XOR     D               ; xor the two sets of flags
  7704.                 AND     $40             ; pick up bit 6 of xored FLAGS should be zero
  7705.                 JR      NZ,REPORT_C     ; forward to REPORT_C if not zero
  7706.                                         ; 'Nonsense in Basic' - results don't agree.
  7707.                 BIT     7,D             ; test FLAGS - is syntax being checked ?
  7708.                 JP      NZ,LET          ; jump forward to LET to make the assignment
  7709.                                         ; in runtime.
  7710.                 RET                     ; but return from here if checking syntax.
  7711.  
  7712. ;-------------------
  7713. ; Command CLASS_--04
  7714. ;-------------------
  7715. ; CLASS_04 e.g. FOR i                   ; a single character variable must follow
  7716.  
  7717.                                         ;;;$1C6C
  7718. CLASS_04:       CALL    LOOK_VARS       ; routine LOOK_VARS
  7719.                 PUSH    AF              ; preserve flags.
  7720.                 LD      A,C             ; fetch type - should be 011xxxxx
  7721.                 OR      $9F             ; combine with 10011111.
  7722.                 INC     A               ; test if now $FF by incrementing.
  7723.                 JR      NZ,REPORT_C     ; forward to REPORT_C if result not zero.
  7724.  
  7725.                 POP     AF              ; else restore flags.
  7726.                 JR      VAR_A_1         ; back to VAR_A_1
  7727.  
  7728.  
  7729. ;---------------------------------
  7730. ; Expect numeric/string expression
  7731. ;---------------------------------
  7732. ; This routine is used to get the two coordinates of STRING$, ATTR and POINT.
  7733. ; It is also called from PRINT_ITEM to get the two numeric expressions that
  7734. ; follow the AT ( in PRINT AT, INPUT AT).
  7735.  
  7736.                                         ;;;$1C79
  7737. NEXT_2NUM:      RST     20H             ; NEXT_CHAR advance past 'AT' or '('.
  7738.  
  7739. ; -------------------------
  7740. ; CLASS_08 e.g POKE 65535,2             ; two numeric expressions separated by comma
  7741.  
  7742.                                         ;;;$1C7A
  7743. CLASS_08:
  7744. EXPT_2NUM:      CALL    EXPT_1NUM       ; routine EXPT_1NUM is called for first
  7745.                                         ; numeric expression
  7746.                 CP      $2C             ; is character ',' ?
  7747.                 JR      NZ,REPORT_C     ; to REPORT_C if not required separator.
  7748.                                         ; 'Nonsense in basic'.
  7749.  
  7750.                 RST     20H             ; NEXT_CHAR
  7751.  
  7752. ; ---------------------------
  7753. ;  CLASS_06  e.g. GOTO a*1000           ; a numeric expression must follow
  7754.  
  7755.                                         ;;;$1C82
  7756. CLASS_06:
  7757. EXPT_1NUM:      CALL    SCANNING        ; routine SCANNING
  7758.                 BIT     6,(IY+$01)      ; test FLAGS  - Numeric or string result ?
  7759.                 RET     NZ              ; return if result is numeric.
  7760.  
  7761.                                         ;;;$1C8A
  7762. REPORT_C:       RST     08H             ; ERROR_1
  7763.                 DEFB    $0B             ; Error Report: Nonsense in BASIC
  7764.  
  7765. ; --------------------------
  7766. ; CLASS_0A e.g. ERASE "????"            ; a string expression must follow.
  7767. ;                                       ; these only occur in unimplemented commands
  7768. ;                                       ; although the routine EXPT_EXP is called
  7769. ;                                       ; from SAVE_ETC
  7770.  
  7771.                                         ;;;$1C8C
  7772. CLASS_0A:
  7773. EXPT_EXP:       CALL    SCANNING        ; routine SCANNING
  7774.                 BIT     6,(IY+$01)      ; test FLAGS  - Numeric or string result ?
  7775.                 RET     Z               ; return if string result.
  7776.  
  7777.                 JR      REPORT_C        ; back to REPORT_C if numeric.
  7778.  
  7779. ;----------------------
  7780. ; Set permanent colours
  7781. ; class 07
  7782. ;----------------------
  7783. ; CLASS_07 e.g PAPER 6                  ; a single class for a collection of
  7784. ;                                       ; similar commands. Clever.
  7785. ;
  7786. ; Note. these commands should ensure that current channel is 'S'
  7787.  
  7788.                                         ;;;$1C96
  7789. CLASS_07:       BIT     7,(IY+$01)      ; test FLAGS - checking syntax only ?
  7790.                 RES     0,(IY+$02)      ; TV_FLAG - signal main screen in use
  7791.                 CALL    NZ,TEMPS        ; routine TEMPS is called in runtime.
  7792.                 POP     AF              ; drop return address SCAN_LOOP
  7793.                 LD      A,(T_ADDR)      ; T_ADDR_lo to accumulator.
  7794.                                         ; points to '$07' entry + 1
  7795.                                         ; e.g. for INK points to $EC now
  7796.  
  7797.                                         ; Note if you move alter the syntax table next line may have to be altered.
  7798.  
  7799.                 SUB     $13             ; convert $EB to $D8 ('INK') etc.
  7800.                                         ; ( is SUB $13 in standard ROM )
  7801.                 CALL    CO_TEMP_4       ; routine CO_TEMP_4
  7802.                 CALL    CHECK_END       ; routine CHECK_END check that nothing else in statement.
  7803.  
  7804.                                         ; return here in runtime.
  7805.  
  7806.                 LD      HL,(ATTRT_MASKT); pick up ATTR_T and MASK_T
  7807.                 LD      (ATTRP_MASKP),HL; and store in ATTR_P and MASK_P
  7808.                 LD      HL,P_FLAG       ; point to P_FLAG.
  7809.                 LD      A,(HL)          ; pick up in A
  7810.                 RLCA                    ; rotate to left
  7811.                 XOR     (HL)            ; combine with HL
  7812.                 AND     $AA             ; 10101010
  7813.                 XOR     (HL)            ; only permanent bits affected
  7814.                 LD      (HL),A          ; reload into P_FLAG.
  7815.                 RET                     ; return.
  7816.  
  7817. ;-----------------
  7818. ; Command CLASS 09
  7819. ;-----------------
  7820. ; e.g. PLOT PAPER 0; 128,88             ; two coordinates preceded by optional
  7821. ;                                       ; embedded colour items.
  7822. ;
  7823. ; Note. this command should ensure that current channel is 'S'.
  7824.  
  7825.                                         ;;;$1CBE
  7826. CLASS_09:       CALL    SYNTAX_Z        ; routine SYNTAX_Z
  7827.                 JR      Z,CL_09_1       ; forward to CL_09_1 if checking syntax.
  7828.  
  7829.                 RES     0,(IY+$02)      ; update TV_FLAG - signal main screen in use
  7830.                 CALL    TEMPS           ; routine TEMPS is called.
  7831.                 LD      HL,MASK_T       ; point to MASK_T
  7832.                 LD      A,(HL)          ; fetch mask to accumulator.
  7833.                 OR      $F8             ; or with 11111000 paper/bright/flash 8
  7834.                 LD      (HL),A          ; mask back to MASK_T system variable.
  7835.                 RES     6,(IY+$57)      ; reset P_FLAG  - signal NOT PAPER 9 ?
  7836.                 RST     18H             ; GET_CHAR
  7837.  
  7838.                                         ;;;$1CD6
  7839. CL_09_1:        CALL    CO_TEMP_2       ; routine CO_TEMP_2 deals with embedded colour items.
  7840.                 JR      EXPT_2NUM       ; exit via EXPT_2NUM to check for x,y.
  7841.  
  7842. ;-----------------
  7843. ; Command CLASS 0B
  7844. ;-----------------
  7845. ; Again a single class for four commands.
  7846. ; This command just jumps back to SAVE_ETC to handle the four tape commands.
  7847. ; The routine itself works out which command has called it by examining the
  7848. ; address in T_ADDR_lo. Note therefore that the syntax table has to be
  7849. ; located where these and other sequential command addresses are not split
  7850. ; over a page boundary.
  7851.  
  7852.                                         ;;;$1CDB
  7853. CLASS_0B:       JP      SAVE_ETC        ; jump way back to SAVE_ETC
  7854.  
  7855. ;---------------
  7856. ; Fetch a number
  7857. ;---------------
  7858. ; This routine is called from CLASS_03 when a command may be followed by
  7859. ; an optional numeric expression e.g. RUN. If the end of statement has
  7860. ; been reached then zero is used as the default.
  7861. ; Also called from LIST_4.
  7862.  
  7863.                                         ;;;$1CDE
  7864. FETCH_NUM:      CP      $0D             ; is character a carriage return ?
  7865.                 JR      Z,USE_ZERO      ; forward to USE_ZERO if so
  7866.  
  7867.                 CP      $3A             ; is it ':' ?
  7868.                 JR      NZ,EXPT_1NUM    ; forward to EXPT_1NUM if not.
  7869.                                         ; else continue and use zero.
  7870.  
  7871. ;-----------------
  7872. ; Use zero routine
  7873. ;-----------------
  7874. ; This routine is called four times to place the value zero on the
  7875. ; calculator stack as a default value in runtime.
  7876.  
  7877.                                         ;;;$1CE6
  7878. USE_ZERO:       CALL    SYNTAX_Z        ; routine SYNTAX_Z  (UNSTACK_Z?)
  7879.                 RET     Z               ;
  7880.  
  7881.                 RST     28H             ;; FP_CALC
  7882.                 DEFB    $A0             ;;STK_ZERO      ;0.
  7883.                 DEFB    $38             ;;END_CALC
  7884.  
  7885.                 RET                     ; return.
  7886.  
  7887. ;--------------------
  7888. ; Handle STOP command
  7889. ;--------------------
  7890. ; Command Syntax: STOP
  7891. ; One of the shortest and least used commands. As with 'OK' not an error.
  7892.  
  7893.                                         ;;;$1CEE
  7894. STOP:           RST     08H             ; ERROR_1
  7895.                 DEFB    $08             ; Error Report: STOP statement
  7896.  
  7897. ;------------------
  7898. ; Handle IF command
  7899. ;------------------
  7900. ; e.g. IF score>100 THEN PRINT "You Win"
  7901. ; The parser has already checked the expression the result of which is on
  7902. ; the calculator stack. The presence of the 'THEN' separator has also been
  7903. ; checked and CH-ADD points to the command after THEN.
  7904.  
  7905.                                         ;;;$1CF0
  7906. IF_CMD:         POP     BC              ; drop return address - STMT_RET
  7907.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  7908.                 JR      Z,IF_1          ; forward to IF_1 if checking syntax
  7909.                                         ; to check syntax of PRINT "You Win"
  7910.                 RST     28H             ;; FP_CALC      score>100 (1=TRUE 0=FALSE)
  7911.                 DEFB    $02             ;;DELETE
  7912.                 DEFB    $38             ;;END_CALC
  7913.  
  7914.                 EX      DE,HL           ; make HL point to deleted value
  7915.                 CALL    TEST_ZERO       ; routine TEST_ZERO
  7916.                 JP      C,LINE_END      ; jump to LINE_END if FALSE (0)
  7917.  
  7918.                                         ;;;$1D00
  7919. IF_1:   JP      STMT_L_1                ; to STMT_L_1, if true (1) to execute command
  7920.                                         ; after 'THEN' token.
  7921.  
  7922. ;-------------------
  7923. ; Handle FOR command
  7924. ;-------------------
  7925. ; e.g. FOR i = 0 TO 1 STEP 0.1
  7926. ; Using the syntax tables, the parser has already checked for a start and
  7927. ; limit value and also for the intervening separator.
  7928. ; the two values v,l are on the calculator stack.
  7929. ; CLASS_04 has also checked the variable and the name is in STRLEN_lo.
  7930. ; The routine begins by checking for an optional STEP.
  7931.  
  7932.                                         ;;;$1D03
  7933. FOR:            CP      $CD             ; is there a 'STEP' ?
  7934.                 JR      NZ,F_USE_1      ; to F_USE_1 if not to use 1 as default.
  7935.  
  7936.                 RST     20H             ; NEXT_CHAR
  7937.                 CALL    EXPT_1NUM       ; routine EXPT_1NUM
  7938.                 CALL    CHECK_END       ; routine CHECK_END
  7939.                 JR      F_REORDER       ; to F_REORDER
  7940.  
  7941.                                         ;;;$1D10
  7942. F_USE_1:        CALL    CHECK_END       ; routine CHECK_END
  7943.                 RST     28H             ;; FP_CALC      v,l.
  7944.                 DEFB    $A1             ;;STK_ONE       v,l,1=s.
  7945.                 DEFB    $38             ;;END_CALC
  7946.  
  7947.                                         ;;;$1D16
  7948. F_REORDER:      RST     28H             ;; FP_CALC      v,l,s.
  7949.                 DEFB    $C0             ;;st-mem-0      v,l,s.
  7950.                 DEFB    $02             ;;DELETE        v,l.
  7951.                 DEFB    $01             ;;EXCHANGE      l,v.
  7952.                 DEFB    $E0             ;;get-mem-0     l,v,s.
  7953.                 DEFB    $01             ;;EXCHANGE      l,s,v.
  7954.                 DEFB    $38             ;;END_CALC
  7955.  
  7956.                 CALL    LET             ; routine LET assigns the initial value v to
  7957.                                         ; the variable altering type if necessary.
  7958.                 LD      (MEM),HL        ; The system variable MEM is made to point to
  7959.                                         ; the variable instead of it's normal location MEMBOT
  7960.                 DEC     HL              ; point to single-character name
  7961.                 LD      A,(HL)          ; fetch name
  7962.                 SET     7,(HL)          ; set bit 7 at location
  7963.                 LD      BC,$0006        ; add six to HL
  7964.                 ADD     HL,BC           ; to address where limit should be.
  7965.                 RLCA                    ; test bit 7 of original name.
  7966.                 JR      C,F_L_S         ; forward to F_L_S if already a FOR/NEXT
  7967.                                         ; variable
  7968.                 LD      C,$0D           ; otherwise an additional 13 bytes are needed.
  7969.                                         ; 5 for each value, two for line number and
  7970.                                         ; 1 byte for looping statement.
  7971.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM creates them.
  7972.                 INC     HL              ; make HL address limit.
  7973.  
  7974.                                         ;;;$1D34
  7975. F_L_S:          PUSH    HL              ; save position.
  7976.  
  7977.                 RST     28H             ;; FP_CALC              l,s.
  7978.                 DEFB    $02             ;;DELETE                l.
  7979.                 DEFB    $02             ;;DELETE                .
  7980.                 DEFB    $38             ;;END_CALC
  7981.                                         ; DE points to STKEND,          l.
  7982.  
  7983.                 POP     HL              ; restore variable position
  7984.                 EX      DE,HL           ; swap pointers
  7985.                 LD      C,$0A           ; ten bytes to move
  7986.                 LDIR                    ; Copy 'deleted' values to variable.
  7987.                 LD      HL,(PPC)        ; Load with current line number from PPC
  7988.                 EX      DE,HL           ; exchange pointers.
  7989.                 LD      (HL),E          ; save the looping line
  7990.                 INC     HL              ; in the next
  7991.                 LD      (HL),D          ; two locations.
  7992.                 LD      D,(IY+$0D)      ; fetch statement from SUBPPC system variable.
  7993.                 INC     D               ; increment statement.
  7994.                 INC     HL              ; and pointer
  7995.                 LD      (HL),D          ; and store the looping statement.                                      ;
  7996.                 CALL    NEXT_LOOP       ; routine NEXT_LOOP considers an initial
  7997.                 RET     NC              ; iteration. Return to STMT_RET if a loop is
  7998.                                         ; possible to execute next statement.
  7999.  
  8000.                                         ; no loop is possible so execution continues after the matching 'NEXT'
  8001.  
  8002.                 LD      B,(IY+$38)      ; get single-character name from STRLEN_lo
  8003.                 LD      HL,(PPC)        ; get the current line from PPC
  8004.                 LD      (NEWPPC),HL     ; and store it in NEWPPC
  8005.                 LD      A,(SUBPPC)      ; fetch current statement from SUBPPC
  8006.                 NEG                     ; Negate as counter decrements from zero
  8007.                                         ; initially and we are in the middle of a line.
  8008.                 LD      D,A             ; Store result in D.
  8009.                 LD      HL,(CH_ADD)     ; get current address from CH_ADD
  8010.                 LD      E,$F3           ; search will be for token 'NEXT'
  8011.  
  8012.                                         ;;;$1D64
  8013. F_LOOP:         PUSH    BC              ; save variable name.
  8014.                 LD      BC,(NXTLIN)     ; fetch NXTLIN
  8015.                 CALL    LOOK_PROG       ; routine LOOK_PROG searches for 'NEXT' token.
  8016.                 LD      (NXTLIN),BC     ; update NXTLIN
  8017.                 POP     BC              ; and fetch the letter
  8018.                 JR      C,REPORT_I      ; forward to REPORT_I if the end of program
  8019.                                         ; was reached by LOOK_PROG.
  8020.                                         ; 'FOR without NEXT'
  8021.  
  8022.                 RST     20H             ; NEXT_CHAR fetches character after NEXT
  8023.                 OR      $20             ; ensure it is upper-case.
  8024.                 CP      B               ; compare with FOR variable name
  8025.                 JR      Z,F_FOUND       ; forward to F_FOUND if it matches.
  8026.  
  8027.                                         ; but if no match i.e. nested FOR/NEXT loops then continue search.
  8028.  
  8029.                 RST     20H             ; NEXT_CHAR
  8030.                 JR      F_LOOP          ; back to F_LOOP
  8031.  
  8032.                                         ;;;$1D7C
  8033. F_FOUND:        RST     20H             ; NEXT_CHAR
  8034.                 LD      A,$01           ; subtract the negated counter from 1
  8035.                 SUB     D               ; to give the statement after the NEXT
  8036.                 LD      (NSPPC),A       ; set system variable NSPPC
  8037.                 RET                     ; return to STMT_RET to branch to new
  8038.                                         ; line and statement. ->
  8039.  
  8040.                                         ;;;$1D84
  8041. REPORT_I:       RST     08H             ; ERROR_1
  8042.                 DEFB    $11             ; Error Report: FOR without NEXT
  8043.  
  8044. ;----------
  8045. ; LOOK_PROG
  8046. ;----------
  8047. ; Find DATA, DEF FN or NEXT.
  8048. ; This routine searches the program area for one of the above three keywords.
  8049. ; On entry, HL points to start of search area.
  8050. ; The token is in E, and D holds a statement count, decremented from zero.
  8051.  
  8052.                                         ;;;$1D86
  8053. LOOK_PROG:      LD      A,(HL)          ; fetch current character
  8054.                 CP      $3A             ; is it ':' a statement separator ?
  8055.                 JR      Z,LOOK_P_2      ; forward to LOOK_P_2 if so.
  8056.  
  8057.                                         ; The starting point was PROG - 1 or the end of a line.
  8058.  
  8059.                                         ;;;$1D8B
  8060. LOOK_P_1:       INC     HL              ; increment pointer to address
  8061.                 LD      A,(HL)          ; the high byte of line number
  8062.                 AND     $C0             ; test for program end marker $80 or a variable
  8063.                 SCF                     ; Set Carry Flag
  8064.                 RET     NZ              ; return with carry set if at end
  8065.                                         ; of program.           ->
  8066.                 LD      B,(HL)          ; high byte of line number to B
  8067.                 INC     HL
  8068.                 LD      C,(HL)          ; low byte to C.
  8069.                 LD      (NEWPPC),BC     ; set system variable NEWPPC.
  8070.                 INC     HL
  8071.                 LD      C,(HL)          ; low byte of line length to C.
  8072.                 INC     HL
  8073.                 LD      B,(HL)          ; high byte to B.
  8074.                 PUSH    HL              ; save address
  8075.                 ADD     HL,BC           ; add length to position.
  8076.                 LD      B,H             ; and save result
  8077.                 LD      C,L             ; in BC.
  8078.                 POP     HL              ; restore address.
  8079.                 LD      D,$00           ; initialize statement counter to zero.
  8080.  
  8081.                                         ;;;$1DA3
  8082. LOOK_P_2:       PUSH    BC              ; save address of next line
  8083.                 CALL    EACH_STMT       ; routine EACH_STMT searches current line.
  8084.                 POP     BC              ; restore address.
  8085.                 RET     NC              ; return if match was found. ->
  8086.  
  8087.                 JR      LOOK_P_1        ; back to LOOK_P_1 for next line.
  8088.  
  8089. ;--------------------
  8090. ; Handle NEXT command
  8091. ;--------------------
  8092. ; e.g. NEXT i
  8093. ; The parameter tables have already evaluated the presence of a variable
  8094.  
  8095.                                         ;;;$1DAB
  8096. NEXT:           BIT     1,(IY+$37)      ; test FLAGX - handling a new variable ?
  8097.                 JP      NZ,REPORT_2     ; jump back to REPORT_2 if so
  8098.                                         ; 'Variable not found'
  8099.  
  8100.                                         ; now test if found variable is a simple variable uninitialized by a FOR.
  8101.  
  8102.                 LD      HL,(DEST)       ; load address of variable from DEST
  8103.                 BIT     7,(HL)          ; is it correct type ?
  8104.                 JR      Z,REPORT_1      ; forward to REPORT_1 if not
  8105.                                         ; 'NEXT without FOR'
  8106.  
  8107.                 INC     HL              ; step past variable name
  8108.                 LD      (MEM),HL        ; and set MEM to point to three 5-byte values
  8109.                                         ; value, limit, step.
  8110.  
  8111.                 RST     28H             ;; FP_CALC      add step and re-store
  8112.                 DEFB    $E0             ;;get-mem-0     v.
  8113.                 DEFB    $E2             ;;get-mem-2     v,s.
  8114.                 DEFB    $0F             ;;ADDITION      v+s.
  8115.                 DEFB    $C0             ;;st-mem-0      v+s.
  8116.                 DEFB    $02             ;;DELETE        .
  8117.                 DEFB    $38             ;;END_CALC
  8118.  
  8119.                 CALL    NEXT_LOOP       ; routine NEXT_LOOP tests against limit.
  8120.                 RET     C               ; return if no more iterations possible.
  8121.  
  8122.                 LD      HL,(MEM)        ; find start of variable contents from MEM.
  8123.                 LD      DE,$000F        ; add 3*5 to
  8124.                 ADD     HL,DE           ; address the looping line number
  8125.                 LD      E,(HL)          ; low byte to E
  8126.                 INC     HL
  8127.                 LD      D,(HL)          ; high byte to D
  8128.                 INC     HL              ; address looping statement
  8129.                 LD      H,(HL)          ; and store in H
  8130.                 EX      DE,HL           ; swap registers
  8131.                 JP      GO_TO_2         ; exit via GO_TO_2 to execute another loop.
  8132.  
  8133.                                         ;;;$1DD8
  8134. REPORT_1:       RST     08H             ; ERROR_1
  8135.                 DEFB    $00             ; Error Report: NEXT without FOR
  8136.  
  8137.  
  8138. ;------------------
  8139. ; Perform NEXT loop
  8140. ;------------------
  8141. ; This routine is called from the FOR command to test for an initial
  8142. ; iteration and from the NEXT command to test for all subsequent iterations.
  8143. ; the system variable MEM addresses the variable's contents which, in the
  8144. ; latter case, have had the step, possibly negative, added to the value.
  8145.  
  8146.                                         ;;;$1DDA
  8147. NEXT_LOOP:      RST     28H             ;; FP_CALC
  8148.                 DEFB    $E1             ;;get-mem-1             l.
  8149.                 DEFB    $E0             ;;get-mem-0             l,v.
  8150.                 DEFB    $E2             ;;get-mem-2             l,v,s.
  8151.                 DEFB    $36             ;;LESS_0                l,v,(1/0) negative step ?
  8152.                 DEFB    $00             ;;JUMP_TRUE             l,v.(1/0)
  8153.  
  8154.                 DEFB    $02             ;;to NEXT_1 if step negative
  8155.  
  8156.                 DEFB    $01             ;;EXCHANGE              v,l.
  8157.  
  8158.                                         ;;;$1DE2
  8159. NEXT_1:         DEFB    $03             ;;SUBTRACT              l-v OR v-l.
  8160.                 DEFB    $37             ;;GREATER_0             (1/0)
  8161.                 DEFB    $00             ;;JUMP_TRUE             .
  8162.  
  8163.                 DEFB    $04             ;;to NEXT_2 if no more iterations.
  8164.  
  8165.                 DEFB    $38             ;;END_CALC              .
  8166.  
  8167.                 AND     A               ; clear carry flag signalling another loop.
  8168.                 RET                     ; return
  8169.  
  8170.                                         ;;;$1DE9
  8171. NEXT_2:         DEFB    $38             ;;END_CALC              .
  8172.  
  8173.                 SCF                     ; set carry flag signalling looping exhausted.
  8174.                 RET                     ; return
  8175.  
  8176.  
  8177. ;--------------------
  8178. ; Handle READ command
  8179. ;--------------------
  8180. ; e.g. READ a, b$, c$(1000 TO 3000)
  8181. ; A list of comma-separated variables is assigned from a list of
  8182. ; comma-separated expressions.
  8183. ; As it moves along the first list, the character address CH_ADD is stored
  8184. ; in X_PTR while CH_ADD is used to read the second list.
  8185.  
  8186.                                         ;;;$1DEC
  8187. READ_3:         RST     20H             ; NEXT_CHAR
  8188.  
  8189.                                         ; -> Entry point.
  8190.                                         ;;;$1DED
  8191. READ:           CALL    CLASS_01        ; routine CLASS_01 checks variable.
  8192.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  8193.                 JR      Z,READ_2        ; forward to READ_2 if checking syntax
  8194.  
  8195.                 RST     18H             ; GET_CHAR
  8196.                 LD      (X_PTR),HL      ; save character position in X_PTR.
  8197.                 LD      HL,(DATADD)     ; load HL with Data Address DATADD, which is
  8198.                                         ; the start of the program or the address
  8199.                                         ; after the last expression that was read or
  8200.                                         ; the address of the line number of the
  8201.                                         ; last RESTORE command.
  8202.                 LD      A,(HL)          ; fetch character
  8203.                 CP      $2C             ; is it a comma ?
  8204.                 JR      Z,READ_1        ; forward to READ_1 if so.
  8205.  
  8206.                                         ; else all data in this statement has been read so look for next DATA token
  8207.  
  8208.                 LD      E,$E4           ; token 'DATA'
  8209.                 CALL    LOOK_PROG       ; routine LOOK_PROG
  8210.                 JR      NC,READ_1       ; forward to READ_1 if DATA found
  8211.  
  8212.                                         ; else report the error.
  8213.  
  8214.                                         ;;;$1E08
  8215. REPORT_E:       RST     08H             ; ERROR_1
  8216.                 DEFB    $0D             ; Error Report: Out of DATA
  8217.  
  8218.                                         ;;;$1E0A
  8219. READ_1:         CALL    TEMP_PTR1       ; routine TEMP_PTR1 advances updating CH_ADD with new DATADD position.
  8220.                 CALL    VAL_FET_1       ; routine VAL_FET_1 assigns value to variable
  8221.                                         ; checking type match and adjusting CH_ADD.
  8222.                 RST     18H             ; GET_CHAR fetches adjusted character position
  8223.                 LD      (DATADD),HL     ; store back in DATADD
  8224.                 LD      HL,(X_PTR)      ; fetch X_PTR  the original READ CH_ADD
  8225.                 LD      (IY+$26),$00    ; now nullify X_PTR_HI
  8226.                 CALL    TEMP_PTR2       ; routine TEMP_PTR2 restores READ CH_ADD
  8227.  
  8228.                                         ;;;$1E1E
  8229. READ_2:         RST     18H             ; GET_CHAR
  8230.                 CP      $2C             ; is it ',' indicating more variables to read ?
  8231.                 JR      Z,READ_3        ; back to READ_3 if so
  8232.  
  8233.                 CALL    CHECK_END       ; routine CHECK_END
  8234.                 RET                     ; return from here in runtime to STMT_RET.
  8235.  
  8236. ;--------------------
  8237. ; Handle DATA command
  8238. ;--------------------
  8239. ; In runtime this 'command' is passed by but the syntax is checked when such
  8240. ; a statement is found while parsing a line.
  8241. ; e.g. DATA 1, 2, "text", score-1, a$(location, room, object), FN r(49),
  8242. ;               wages - tax, TRUE, The meaning of life
  8243.  
  8244.                                         ;;;$1E27
  8245. DATA:           CALL    SYNTAX_Z        ; routine SYNTAX_Z to check status
  8246.                 JR      NZ,DATA_2       ; forward to DATA_2 if in runtime
  8247.  
  8248.                                         ;;;$1E2C
  8249. DATA_1:         CALL    SCANNING        ; routine SCANNING to check syntax of expression
  8250.                 CP      $2C             ; is it a comma ?
  8251.                 CALL    NZ,CHECK_END    ; routine CHECK_END checks that statement
  8252.                                         ; is complete. Will make an early exit if
  8253.                                         ; so. >>>
  8254.                 RST     20H             ; NEXT_CHAR
  8255.                 JR      DATA_1          ; back to DATA_1
  8256.  
  8257.                                         ;;;$1E37
  8258. DATA_2:         LD      A,$E4           ; set token to 'DATA' and continue into
  8259.                                         ; the the PASS_BY routine.
  8260.  
  8261.  
  8262. ;-----------------------------------
  8263. ; Check statement for DATA or DEF FN
  8264. ;-----------------------------------
  8265. ; This routine is used to backtrack to a command token and then
  8266. ; forward to the next statement in runtime.
  8267.  
  8268.                                         ;;;$1E39
  8269. PASS_BY:        LD      B,A             ; Give BC enough space to find token.
  8270.                 CPDR                    ; Compare decrement and repeat. (Only use).
  8271.                                         ; Work backwards till keyword is found which
  8272.                                         ; is start of statement before any quotes.
  8273.                                         ; HL points to location before keyword.
  8274.                 LD      DE,$0200        ; count 1+1 statements, dummy value in E to
  8275.                                         ; inhibit searching for a token.
  8276.                 JP      EACH_STMT       ; to EACH_STMT to find next statement
  8277.  
  8278. ;------------------------------------------------------------------------
  8279. ; A General Note on Invalid Line Numbers.
  8280. ; =======================================
  8281. ; One of the revolutionary concepts of Sinclair Basic was that it supported
  8282. ; virtual line numbers. That is the destination of a GO TO, RESTORE etc. need
  8283. ; not exist. It could be a point before or after an actual line number.
  8284. ; Zero suffices for a before but the after should logically be infinity.
  8285. ; Since the maximum actual line limit is 9999 then the system limit, 16383
  8286. ; when variables kick in, would serve fine as a virtual end point.
  8287. ; However, ironically, only the LOAD command gets it right. It will not
  8288. ; autostart a program that has been saved with a line higher than 16383.
  8289. ; All the other commands deal with the limit unsatisfactorily.
  8290. ; LIST, RUN, GO TO, GO SUB and RESTORE have problems and the latter may
  8291. ; crash the machine when supplied with an inappropriate virtual line number.
  8292. ; This is puzzling as very careful consideration must have been given to
  8293. ; this point when the new variable types were allocated their masks and also
  8294. ; when the routine NEXT-ONE was successfully re-written to reflect this.
  8295. ; An enigma.
  8296. ;--------------------------------------------------------------------------
  8297.  
  8298. ;-----------------------
  8299. ; Handle RESTORE command
  8300. ;-----------------------
  8301. ; The restore command sets the system variable for the data address to
  8302. ; point to the location before the supplied line number or first line
  8303. ; thereafter.
  8304. ; This alters the position where subsequent READ commands look for data.
  8305. ; Note. If supplied with inappropriate high numbers the system may crash
  8306. ; in the LINE-ADDR routine as it will pass the program/variables end-marker
  8307. ; and then lose control of what it is looking for - variable or line number.
  8308. ; - observation, Steven Vickers, 1984, Pitman.
  8309.  
  8310.                                         ;;;$1E42
  8311. RESTORE:        CALL    FIND_INT2       ; routine FIND_INT2 puts integer in BC.
  8312.                                         ; Note. B should be checked against limit $3F
  8313.                                         ; and an error generated if higher.
  8314.  
  8315.                                         ; this entry point is used from RUN command with BC holding zero
  8316.  
  8317.                                         ;;;$1E45
  8318. REST_RUN:       LD      H,B             ; transfer the line
  8319.                 LD      L,C             ; number to the HL register.
  8320.                 CALL    LINE_ADDR       ; routine LINE_ADDR to fetch the address.
  8321.                 DEC     HL              ; point to the location before the line.
  8322.                 LD      (DATADD),HL     ; update system variable DATADD.
  8323.                 RET                     ; return to STMT_RET (or RUN)
  8324.  
  8325. ;-------------------------
  8326. ; Handle RANDOMIZE command
  8327. ;-------------------------
  8328. ; This command sets the SEED for the RND function to a fixed value.
  8329. ; With the parameter zero, a random start point is used depending on
  8330. ; how long the computer has been switched on.
  8331.  
  8332.                                         ;;;$1E4F
  8333. RANDOMIZE:      CALL    FIND_INT2       ; routine FIND_INT2 puts parameter in BC.
  8334.                 LD      A,B             ; test this
  8335.                 OR      C               ; for zero.
  8336.                 JR      NZ,RAND_1       ; forward to RAND_1 if not zero.
  8337.  
  8338.                 LD      BC,(FRAMES1)    ; use the lower two bytes at FRAMES1.
  8339.  
  8340.                                         ;;;$1E5A
  8341. RAND_1:         LD      (SEED),BC       ; place in SEED system variable.
  8342.                 RET                     ; return to STMT_RET
  8343.  
  8344. ;------------------------
  8345. ; Handle CONTINUE command
  8346. ;------------------------
  8347. ; The CONTINUE command transfers the OLD (but incremented) values of
  8348. ; line number and statement to the equivalent "NEW VALUE" system variables
  8349. ; by using the last part of GO TO and exits indirectly to STMT_RET.
  8350.  
  8351.                                         ;;;$1E5F
  8352. CONTINUE:       LD      HL,(OLDPPC)     ; fetch OLDPPC line number.
  8353.                 LD      D,(IY+$36)      ; fetch OSPPC statement.
  8354.                 JR      GO_TO_2         ; forward to GO_TO_2
  8355.  
  8356. ;---------------------
  8357. ; Handle GO TO command
  8358. ;---------------------
  8359. ; The GO TO command routine is also called by GO SUB and RUN routines
  8360. ; to evaluate the parameters of both commands.
  8361. ; It updates the system variables used to fetch the next line/statement.
  8362. ; It is at STMT_RET that the actual change in control takes place.
  8363. ; Unlike some BASICs the line number need not exist.
  8364. ; Note. the high byte of the line number is incorrectly compared with $F0
  8365. ; instead of $3F. This leads to commands with operands greater than 32767
  8366. ; being considered as having been run from the editing area and the
  8367. ; error report 'Statement Lost' is given instead of 'OK'.
  8368. ; - Steven Vickers, 1984.
  8369.  
  8370.                                         ;;;$1E67
  8371. GO_TO:          CALL    FIND_INT2       ; routine FIND_INT2 puts operand in BC
  8372.                 LD      H,B             ; transfer line
  8373.                 LD      L,C             ; number to HL.
  8374.                 LD      D,$00           ; set statement to 0 - first.
  8375.                 LD      A,H             ; compare high byte only
  8376.                 CP      $F0             ; to $F0 i.e. 61439 in full.
  8377.                 JR      NC,REPORT_BB    ; forward to REPORT_BB if above.
  8378.  
  8379.                                         ; This call entry point is used to update the system variables e.g. by RETURN.
  8380.  
  8381.                                         ;;;$1E73
  8382. GO_TO_2:        LD      (NEWPPC),HL     ; save line number in NEWPPC
  8383.                 LD      (IY+$0A),D      ; and statement in NSPPC
  8384.                 RET                     ; to STMT_RET (or GO_SUB command)
  8385.  
  8386. ;-------------------
  8387. ; Handle OUT command
  8388. ;-------------------
  8389. ; Syntax has been checked and the two comma-separated values are on the
  8390. ; calculator stack.
  8391.  
  8392.                                         ;;;$1E7A
  8393. OUT_CMD:        CALL    TWO_PARAM       ; routine TWO_PARAM fetches values to BC and A.
  8394.                 OUT     (C),A           ; perform the operation.
  8395.                 RET                     ; return to STMT_RET.
  8396.  
  8397. ;--------------------
  8398. ; Handle POKE command
  8399. ;--------------------
  8400. ; This routine alters a single byte in the 64K address space.
  8401. ; Happily no check is made as to whether ROM or RAM is addressed.
  8402. ; Sinclair Basic requires no poking of system variables.
  8403.  
  8404.                                         ;;;$1E80
  8405. POKE:           CALL    TWO_PARAM       ; routine TWO_PARAM fetches values to BC and A.
  8406.                 LD      (BC),A          ; load memory location with A.
  8407.                 RET                     ; return to STMT_RET.
  8408.  
  8409. ;--------------------------------------------
  8410. ; Fetch two  parameters from calculator stack
  8411. ;--------------------------------------------
  8412. ; This routine fetches a byte and word from the calculator stack
  8413. ; producing an error if either is out of range.
  8414.  
  8415.                                         ;;;$1E85
  8416. TWO_PARAM:      CALL    FP_TO_A         ; routine FP_TO_A
  8417.                 JR      C,REPORT_BB     ; forward to REPORT_BB if overflow occurred
  8418.  
  8419.                 JR      Z,TWO_P_1       ; forward to TWO_P_1 if positive
  8420.  
  8421.                 NEG                     ; negative numbers are made positive
  8422.  
  8423.                                         ;;;$1E8E
  8424. TWO_P_1:        PUSH    AF              ; save the value
  8425.                 CALL    FIND_INT2       ; routine FIND_INT2 gets integer to BC
  8426.                 POP     AF              ; restore the value
  8427.                 RET                     ; return
  8428.  
  8429. ;--------------
  8430. ; Find integers
  8431. ;--------------
  8432. ; The first of these routines fetches a 8-bit integer (range 0-255) from the
  8433. ; calculator stack to the accumulator and is used for colours, streams,
  8434. ; durations and coordinates.
  8435. ; The second routine fetches 16-bit integers to the BC register pair
  8436. ; and is used to fetch command and function arguments involving line numbers
  8437. ; or memory addresses and also array subscripts and tab arguments.
  8438. ; ->
  8439.  
  8440.                                         ;;;$1E94
  8441. FIND_INT1:      CALL    FP_TO_A         ; routine FP_TO_A
  8442.                 JR      FIND_I_1        ; forward to FIND_I_1 for common exit routine.
  8443.  
  8444.                                         ; ->
  8445.  
  8446.                                         ;;;$1E99
  8447. FIND_INT2:      CALL    FP_TO_BC        ; routine FP_TO_BC
  8448.  
  8449.                                         ;;;$1E9C
  8450. FIND_I_1:       JR      C,REPORT_BB     ; to REPORT_BB with overflow.
  8451.  
  8452.                 RET     Z               ; return if positive.
  8453.  
  8454.  
  8455.                                         ;;;$1E9F
  8456. REPORT_BB:      RST     08H             ; ERROR_1
  8457.                 DEFB    $0A             ; Error Report: Integer out of range
  8458.  
  8459. ;-------------------
  8460. ; Handle RUN command
  8461. ;-------------------
  8462. ; This command runs a program starting at an optional line.
  8463. ; It performs a 'RESTORE 0' then CLEAR
  8464.  
  8465.                                         ;;;$1EA1
  8466. RUN:            CALL    GO_TO           ; routine GO_TO puts line number in system variables.
  8467.                 LD      BC,$0000        ; prepare to set DATADD to first line.
  8468.                 CALL    REST_RUN        ; routine REST_RUN does the 'restore'.
  8469.                                         ; Note BC still holds zero.
  8470.                 JR      CLEAR_RUN       ; forward to CLEAR_RUN to clear variables
  8471.                                         ; without disturbing RAMTOP and
  8472.                                         ; exit indirectly to STMT_RET
  8473.  
  8474. ;---------------------
  8475. ; Handle CLEAR command
  8476. ;---------------------
  8477. ; This command reclaims the space used by the variables.
  8478. ; It also clears the screen and the GO SUB stack.
  8479. ; With an integer expression, it sets the uppermost memory
  8480. ; address within the BASIC system.
  8481. ; "Contrary to the manual, CLEAR doesn't execute a RESTORE" -
  8482. ; Steven Vickers, Pitman Pocket Guide to the Spectrum, 1984.
  8483.  
  8484.                                         ;;;$1EAC
  8485. CLEAR:          CALL    FIND_INT2       ; routine FIND_INT2 fetches to BC.
  8486.  
  8487.                                         ;;;$1EAF
  8488. CLEAR_RUN:      LD      A,B             ; test for
  8489.                 OR      C               ; zero.
  8490.                 JR      NZ,CLEAR_1      ; skip to CLEAR_1 if not zero.
  8491.  
  8492.                 LD      BC,(RAMTOP)     ; use the existing value of RAMTOP if zero.
  8493.  
  8494.                                         ;;;$1EB7
  8495. CLEAR_1:        PUSH    BC              ; save ramtop value.
  8496.                 LD      DE,(VARS)       ; fetch VARS
  8497.                 LD      HL,(E_LINE)     ; fetch E_LINE
  8498.                 DEC     HL              ; adjust to point at variables end-marker.
  8499.                 CALL    RECLAIM_1       ; routine RECLAIM_1 reclaims the space used by the variables.
  8500.                 CALL    CLS             ; routine CLS to clear screen.
  8501.                 LD      HL,(STKEND)     ; fetch STKEND the start of free memory.
  8502.                 LD      DE,$0032        ; allow for another 50 bytes.
  8503.                 ADD     HL,DE           ; add the overhead to HL.
  8504.                 POP     DE              ; restore the ramtop value.
  8505.                 SBC     HL,DE           ; if HL is greater than the value then jump
  8506.                 JR      NC,REPORT_M     ; forward to REPORT_M
  8507.                                         ; 'RAMTOP no good'
  8508.                 LD      HL,(P_RAMT)     ; now P_RAMT ($7FFF on 16K RAM machine)
  8509.                 AND     A               ; exact this time.
  8510.                 SBC     HL,DE           ; new ramtop must be lower or the same.
  8511.                 JR      NC,CLEAR_2      ; skip to CLEAR_2 if in actual RAM.
  8512.  
  8513.                                         ;;;$1EDA
  8514. REPORT_M:       RST     08H             ; ERROR_1
  8515.                 DEFB    $15             ; Error Report: RAMTOP no good
  8516.  
  8517.                                         ;;;$1EDC
  8518. CLEAR_2:        EX      DE,HL           ; transfer ramtop value to HL.
  8519.                 LD      (RAMTOP),HL     ; update system variable RAMTOP.
  8520.                 POP     DE              ; pop the return address STMT_RET.
  8521.                 POP     BC              ; pop the Error Address.
  8522.                 LD      (HL),$3E        ; now put the GO SUB end-marker at RAMTOP.
  8523.                 DEC     HL              ; leave a location beneath it.
  8524.                 LD      SP,HL           ; initialize the machine stack pointer.
  8525.                 PUSH    BC              ; push the error address.
  8526.                 LD      (ERR_SP),SP     ; make ERR_SP point to location.
  8527.                 EX      DE,HL           ; put STMT_RET in HL.
  8528.                 JP      (HL)            ; and go there directly.
  8529.  
  8530. ;----------------------
  8531. ; Handle GO SUB command
  8532. ;----------------------
  8533. ; The GO SUB command diverts Basic control to a new line number
  8534. ; in a very similar manner to GO TO but
  8535. ; the current line number and current statement + 1
  8536. ; are placed on the GO SUB stack as a RETURN point.
  8537.  
  8538.                                         ;;;$1EED
  8539. GO_SUB:         POP     DE              ; drop the address STMT_RET
  8540.                 LD      H,(IY+$0D)      ; fetch statement from SUBPPC and
  8541.                 INC     H               ; increment it
  8542.                 EX      (SP),HL         ; swap - error address to HL,
  8543.                                         ; H (statement) at top of stack,
  8544.                                         ; L (unimportant) beneath.
  8545.                 INC     SP              ; adjust to overwrite unimportant byte
  8546.                 LD      BC,(PPC)        ; fetch the current line number from PPC
  8547.                 PUSH    BC              ; and PUSH onto GO SUB stack.
  8548.                                         ; the empty machine-stack can be rebuilt
  8549.                 PUSH    HL              ; push the error address.
  8550.                 LD      (ERR_SP),SP     ; make system variable ERR_SP point to it.
  8551.                 PUSH    DE              ; push the address STMT_RET.
  8552.                 CALL    GO_TO           ; call routine GO_TO to update the system
  8553.                                         ; variables NEWPPC and NSPPC.
  8554.                                         ; then make an indirect exit to STMT_RET via
  8555.                 LD      BC,$0014        ; a 20-byte overhead memory check.
  8556.  
  8557. ;-----------------------
  8558. ; Check available memory
  8559. ;-----------------------
  8560. ; This routine is used on many occasions when extending a dynamic area
  8561. ; upwards or the GO SUB stack downwards.
  8562.  
  8563.                                         ;;;$1F05
  8564. TEST_ROOM:      LD      HL,(STKEND)     ; fetch STKEND
  8565.                 ADD     HL,BC           ; add the supplied test value
  8566.                 JR      C,REPORT_4      ; forward to REPORT_4 if over $FFFF
  8567.  
  8568.                 EX      DE,HL           ; was less so transfer to DE
  8569.                 LD      HL,$0050        ; test against another 80 bytes
  8570.                 ADD     HL,DE           ; anyway
  8571.                 JR      C,REPORT_4      ; forward to REPORT_4 if this passes $FFFF
  8572.  
  8573.                 SBC     HL,SP           ; if less than the machine stack pointer
  8574.                 RET     C               ; then return - OK.
  8575.  
  8576.                                         ;;;$1F15
  8577. REPORT_4:       LD      L,$03           ; prepare 'Out of Memory'
  8578.                 JP      ERROR_3         ; jump back to ERROR_3 at $0055
  8579.                                         ; Note. this error can't be trapped at $0008
  8580.  
  8581. ;------------
  8582. ; Free memory
  8583. ;------------
  8584. ; This routine is not used by the ROM but allows users to evaluate
  8585. ; approximate free memory with PRINT 65536 - USR 7962.
  8586.  
  8587.                                         ;;$1F1A
  8588. FREE_MEM:       LD      BC,$0000        ; allow no overhead.
  8589.                 CALL    TEST_ROOM       ; routine TEST_ROOM.
  8590.                 LD      B,H             ; transfer the result
  8591.                 LD      C,L             ; to BC register.
  8592.                 RET                     ; USR function returns value of BC.
  8593.  
  8594. ;----------------------
  8595. ; Handle RETURN command
  8596. ;----------------------
  8597. ; As with any command, there are two values on the
  8598. ; machine stack at the time it is invoked.
  8599. ; The machine stack is below the GOSUB stack
  8600. ; Both grow downwards, the machine stack by two bytes,
  8601. ; the gosub stack by 3 bytes. Highest is statement byte
  8602. ; then a two-byte line number.
  8603.  
  8604.                                         ;;;$1F23
  8605. RETURN:         POP     BC              ; drop the address STMT_RET.
  8606.                 POP     HL              ; now the error address.
  8607.                 POP     DE              ; now a possible basic return line.
  8608.                 LD      A,D             ; the high byte $00 - $27 is
  8609.                 CP      $3E             ; compared with the traditional end-marker $3E.
  8610.                 JR      Z,REPORT_7      ; forward to REPORT_7 with a match.
  8611.                                         ; 'RETURN without GOSUB'
  8612.  
  8613.                                         ; It was not the end-marker so a single statement byte remains at the base of
  8614.                                         ; the calculator stack. It can't be popped off.
  8615.  
  8616.                 DEC     SP              ; adjust stack pointer to create room for two  bytes.
  8617.                 EX      (SP),HL         ; statement to H, error address to base of
  8618.                                         ; new machine stack.
  8619.                 EX      DE,HL           ; statement to D,  basic line number to HL.
  8620.                 LD      (ERR_SP),SP     ; adjust ERR_SP to point to new stack pointer
  8621.                 PUSH    BC              ; now re-stack the address STMT_RET
  8622.                 JP      GO_TO_2         ; to GO_TO_2 to update statement and line
  8623.                                         ; system variables and exit indirectly to the
  8624.                                         ; address just pushed on stack.
  8625.  
  8626.                                         ;;;$1F36
  8627. REPORT_7:       PUSH    DE              ; replace the end-marker.
  8628.                 PUSH    HL              ; now restore the error address
  8629.                                         ; as required in a few clock cycles.
  8630.                 RST     08H             ; ERROR_1
  8631.                 DEFB    $06             ; Error Report: RETURN without GOSUB
  8632.  
  8633. ;---------------------
  8634. ; Handle PAUSE command
  8635. ;---------------------
  8636. ; The pause command takes as it's parameter the number of interrupts
  8637. ; for which to wait. PAUSE 50 pauses for about a second.
  8638. ; PAUSE 0 pauses indefinitely.
  8639. ; Both forms can be finished by pressing a key.
  8640.  
  8641.                                         ;;;$1F3A
  8642. PAUSE:  CALL    FIND_INT2               ; routine FIND_INT2 puts value in BC
  8643.  
  8644.                                         ;;;$1F3D
  8645. PAUSE_1:        HALT                    ; wait for interrupt.
  8646.                 DEC     BC              ; decrease counter.
  8647.                 LD      A,B             ; test if
  8648.                 OR      C               ; result is zero.
  8649.                 JR      Z,PAUSE_END     ; forward to PAUSE_END if so.
  8650.  
  8651.                 LD      A,B             ; test if
  8652.                 AND     C               ; now $FFFF
  8653.                 INC     A               ; that is, initially zero.
  8654.                 JR      NZ,PAUSE_2      ; skip forward to PAUSE_2 if not.
  8655.  
  8656.                 INC     BC              ; restore counter to zero.
  8657.  
  8658.                                         ;;;$1F49
  8659. PAUSE_2:        BIT     5,(IY+$01)      ; test FLAGS - has a new key been pressed ?
  8660.                 JR      Z,PAUSE_1       ; back to PAUSE_1 if not.
  8661.  
  8662.                                         ;;;$1F4F
  8663. PAUSE_END:      RES     5,(IY+$01)      ; update FLAGS - signal no new key
  8664.                 RET                     ; and return.
  8665.  
  8666. ;--------------------
  8667. ; Check for BREAK key
  8668. ;--------------------
  8669. ; This routine is called from COPY_LINE, when interrupts are disabled,
  8670. ; to test if BREAK (SHIFT - SPACE) is being pressed.
  8671. ; It is also called at STMT_RET after every statement.
  8672.  
  8673.                                         ;;;$1F54
  8674. BREAK_KEY:      LD      A,$7F           ; Input address: $7FFE
  8675.                 IN      A,($FE)         ; read lower right keys
  8676.                 RRA                     ; rotate bit 0 - SPACE
  8677.                 RET     C               ; return if not reset
  8678.  
  8679.                 LD      A,$FE           ; Input address: $FEFE
  8680.                 IN      A,($FE)         ; read lower left keys
  8681.                 RRA                     ; rotate bit 0 - SHIFT
  8682.                 RET                     ; carry will be set if not pressed.
  8683.                                         ; return with no carry if both keys pressed.
  8684.  
  8685. ;----------------------
  8686. ; Handle DEF FN command
  8687. ;----------------------
  8688. ; e.g DEF FN r$(a$,a) = a$(a TO )
  8689. ; this 'command' is ignored in runtime but has it's syntax checked
  8690. ; during line-entry.
  8691.  
  8692.                                         ;;;$1F60
  8693. DEF_FN:         CALL    SYNTAX_Z        ; routine SYNTAX_Z
  8694.                 JR      Z,DEF_FN_1      ; forward to DEF_FN_1 if parsing
  8695.  
  8696.                 LD      A,$CE           ; else load A with 'DEF FN' and
  8697.                 JP      PASS_BY         ; jump back to PASS_BY
  8698.  
  8699.                                         ; continue here if checking syntax.
  8700.  
  8701.                                         ;;;$1F6A
  8702. DEF_FN_1:       SET     6,(IY+$01)      ; set FLAGS  - Assume numeric result
  8703.                 CALL    ALPHA           ; call routine ALPHA
  8704.                 JR      NC,DEF_FN_4     ; if not then to DEF_FN_4 to jump to
  8705.                                         ; 'Nonsense in Basic'
  8706.                 RST     20H             ; NEXT_CHAR
  8707.                 CP      $24             ; is it '$' ?
  8708.                 JR      NZ,DEF_FN_2     ; to DEF_FN_2 if not as numeric.
  8709.  
  8710.                 RES     6,(IY+$01)      ; set FLAGS  - Signal string result
  8711.                 RST     20H             ; get NEXT_CHAR
  8712.  
  8713.                                         ;;;$1F7D
  8714. DEF_FN_2:       CP      $28             ; is it '(' ?
  8715.                 JR      NZ,DEF_FN_7     ; to DEF_FN_7 'Nonsense in Basic'
  8716.  
  8717.                 RST     20H             ; NEXT_CHAR
  8718.                 CP      $29             ; is it ')' ?
  8719.                 JR      Z,DEF_FN_6      ; to DEF_FN_6 if null argument
  8720.  
  8721.                                         ;;;$1F86
  8722. DEF_FN_3:       CALL    ALPHA           ; routine ALPHA checks that it is the expected  alphabetic character.
  8723.  
  8724.                                         ;;;$1F89
  8725. DEF_FN_4:       JP      NC,REPORT_C     ; to REPORT_C  if not
  8726.                                         ; 'Nonsense in Basic'.
  8727.  
  8728.                 EX      DE,HL           ; save pointer in DE
  8729.                 RST     20H             ; NEXT_CHAR re-initializes HL from CH_ADD and advances.
  8730.                 CP      $24             ; '$' ? is it a string argument.
  8731.                 JR      NZ,DEF_FN_5     ; forward to DEF_FN_5 if not.
  8732.  
  8733.                 EX      DE,HL           ; save pointer to '$' in DE
  8734.  
  8735.                 RST     20H             ; NEXT_CHAR re-initializes HL and advances
  8736.  
  8737.                                         ;;;$1F94
  8738. DEF_FN_5:       EX      DE,HL           ; bring back pointer.
  8739.                 LD      BC,$0006        ; the function requires six hidden bytes for
  8740.                                         ; each parameter passed.
  8741.                                         ; The first byte will be $0E
  8742.                                         ; then 5-byte numeric value
  8743.                                         ; or 5-byte string pointer.
  8744.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM creates space in program area.
  8745.                 INC     HL              ; adjust HL (set by LDDR)
  8746.                 INC     HL              ; to point to first location.
  8747.                 LD      (HL),$0E        ; insert the 'hidden' marker.
  8748.  
  8749.                                         ; Note. these invisible storage locations hold nothing meaningful for the
  8750.                                         ; moment. They will be used every time the corresponding function is
  8751.                                         ; evaluated in runtime.
  8752.                                         ; Now consider the following character fetched earlier.
  8753.  
  8754.                 CP      $2C             ; is it ',' ? (more than one parameter)
  8755.                 JR      NZ,DEF_FN_6     ; to DEF_FN_6 if not
  8756.  
  8757.                 RST     20H             ; else NEXT_CHAR
  8758.                 JR      DEF_FN_3        ; and back to DEF_FN_3
  8759.  
  8760.                                         ;;;$1FA6
  8761. DEF_FN_6:       CP      $29             ; should close with a ')'
  8762.                 JR      NZ,DEF_FN_7     ; to DEF_FN_7 if not
  8763.                                         ; 'Nonsense in Basic'
  8764.                 RST     20H             ; get NEXT_CHAR
  8765.                 CP      $3D             ; is it '=' ?
  8766.                 JR      NZ,DEF_FN_7     ; to DEF_FN_7 if not 'Nonsense...'
  8767.  
  8768.                 RST     20H             ; address NEXT_CHAR
  8769.                 LD      A,(FLAGS)       ; get FLAGS which has been set above
  8770.                 PUSH    AF              ; and save while
  8771.                 CALL    SCANNING        ; routine SCANNING checks syntax of expression and sets flags also
  8772.                 POP     AF              ; restore previous flags
  8773.                 XOR     (IY+$01)        ; xor with FLAGS - bit 6 should be same,  therefore will be reset.
  8774.                 AND     $40             ; isolate bit 6.
  8775.  
  8776.                                         ;;;$1FBD
  8777. DEF_FN_7:       JP      NZ,REPORT_C     ; jump back to REPORT_C if the expected result is not the same.
  8778.                                         ; 'Nonsense in Basic'
  8779.                 CALL    CHECK_END       ; routine CHECK_END will return early if
  8780.                                         ; at end of statement and move onto next
  8781.                                         ; else produce error report. >>>
  8782.                                         ; There will be no return to here.
  8783.  
  8784. ;--------------------------------
  8785. ; Returning early from subroutine
  8786. ;--------------------------------
  8787. ; All routines are capable of being run in two modes - syntax checking mode
  8788. ; and runtime mode.
  8789. ; This routine is called often to allow a routine to return early
  8790. ; if checking syntax.
  8791.  
  8792.                                         ;;;$1FC3
  8793. UNSTACK_Z:      CALL    SYNTAX_Z        ; routine SYNTAX_Z sets zero flag if syntax is being checked.
  8794.                 POP     HL              ; drop the return address.
  8795.                 RET     Z               ; return to previous call in chain if checking syntax.
  8796.  
  8797.                 JP      (HL)            ; jump to return address as Basic program is
  8798.                                         ; actually running.
  8799.  
  8800. ;----------------------
  8801. ; Handle LPRINT command
  8802. ;----------------------
  8803. ; A simple form of 'PRINT #3' although it can output to 16 streams.
  8804. ; Probably for compatibility with other basics particularly ZX81 Basic.
  8805. ; An extra UDG might have been better.
  8806.  
  8807.                                         ;;;$1FC9
  8808. LPRINT:         LD      A,$03           ; the printer channel
  8809.                 JR      PRINT_1         ; forward to PRINT_1
  8810.  
  8811. ;----------------------
  8812. ; Handle PRINT commands
  8813. ;----------------------
  8814. ; The Spectrum's main stream output command.
  8815. ; The default stream is stream 2 which is normally the upper screen
  8816. ; of the computer. However the stream can be altered in range 0 - 15.
  8817.  
  8818.                                         ;;;$1FCD
  8819. PRINT:          LD      A,$02           ; the stream for the upper screen.
  8820.  
  8821.                                         ; The LPRINT command joins here.
  8822.  
  8823.                                         ;;;$1FCF
  8824. PRINT_1:        CALL    SYNTAX_Z        ; routine SYNTAX_Z checks if program running
  8825.                 CALL    NZ,CHAN_OPEN    ; routine CHAN_OPEN if so
  8826.                 CALL    TEMPS           ; routine TEMPS sets temporary colours.
  8827.                 CALL    PRINT_2         ; routine PRINT_2 - the actual item
  8828.                 CALL    CHECK_END       ; routine CHECK_END gives error if not at end of statement
  8829.                 RET                     ; and return >>>
  8830.  
  8831.                                         ; this subroutine is called from above
  8832.                                         ; and also from INPUT.
  8833.  
  8834.                                         ;;;$1FDF
  8835. PRINT_2:        RST     18H             ; GET_CHAR gets printable character
  8836.                 CALL    PR_END_Z        ; routine PR_END_Z checks if more printing
  8837.                 JR      Z,PRINT_4       ; to PRINT_4 if not     e.g. just 'PRINT :'
  8838.  
  8839.                                         ; This tight loop deals with combinations of positional controls and
  8840.                                         ; print items. An early return can be made from within the loop
  8841.                                         ; if the end of a print sequence is reached.
  8842.  
  8843.                                         ;;;$1FE5
  8844. PRINT_3:        CALL    PR_POSN_1       ; routine PR_POSN_1 returns zero if more
  8845.                                         ; but returns early at this point if
  8846.                                         ; at end of statement!
  8847.                 JR      Z,PRINT_3       ; to PRINT_3 if consecutive positioners
  8848.  
  8849.                 CALL    PR_ITEM_1       ; routine PR_ITEM_1 deals with strings etc.
  8850.                 CALL    PR_POSN_1       ; routine PR_POSN_1 for more position codes
  8851.                 JR      Z,PRINT_3       ; loop back to PRINT_3 if so
  8852.  
  8853.                                         ;;;$1FF2
  8854. PRINT_4:        CP      $29             ; return now if this is ')' from input-item.
  8855.                                         ; (see INPUT.)
  8856.                 RET     Z               ; or continue and print carriage return in
  8857.                                         ; runtime
  8858.  
  8859. ;----------------------
  8860. ; Print carriage return
  8861. ;----------------------
  8862. ; This routine which continues from above prints a carriage return
  8863. ; in run-time. It is also called once from PRINT_POSN.
  8864.  
  8865.                                         ;;;$1FF5
  8866. PRINT_CR:       CALL    UNSTACK_Z       ; routine UNSTACK_Z
  8867.                 LD      A,$0D           ; prepare a carriage return
  8868.                 RST     10H             ; PRINT_A
  8869.                 RET                     ; return
  8870.  
  8871. ;------------
  8872. ; Print items
  8873. ;------------
  8874. ; This routine deals with print items as in
  8875. ; PRINT AT 10,0;"The value of A is ";a
  8876. ; It returns once a single item has been dealt with as it is part
  8877. ; of a tight loop that considers sequences of positional and print items
  8878.  
  8879.                                         ;;;$1FFC
  8880. PR_ITEM_1:      RST     18H             ; GET_CHAR
  8881.                 CP      $AC             ; is character 'AT' ?
  8882.                 JR      NZ,PR_ITEM_2    ; forward to PR_ITEM_2 if not.
  8883.  
  8884.                 CALL    NEXT_2NUM       ; routine NEXT_2NUM  check for two comma
  8885.                                         ; separated numbers placing them on the
  8886.                                         ; calculator stack in runtime.
  8887.                 CALL    UNSTACK_Z       ; routine UNSTACK_Z quits if checking syntax.
  8888.                 CALL    STK_TO_BC       ; routine STK_TO_BC get the numbers in B and C.
  8889.                 LD      A,$16           ; prepare the 'at' control.
  8890.                 JR      PR_AT_TAB       ; forward to PR_AT_TAB to print the sequence.
  8891.  
  8892.                                         ;;;$200E
  8893. PR_ITEM_2:      CP      $AD             ; is character 'TAB' ?
  8894.                 JR      NZ,PR_ITEM_3    ; to PR_ITEM_3 if not
  8895.  
  8896.                 RST     20H             ; NEXT_CHAR to address next character
  8897.                 CALL    EXPT_1NUM       ; routine EXPT_1NUM
  8898.                 CALL    UNSTACK_Z       ; routine UNSTACK_Z quits if checking syntax.
  8899.                 CALL    FIND_INT2       ; routine FIND_INT2 puts integer in BC.
  8900.                 LD      A,$17           ; prepare the 'tab' control.
  8901.  
  8902.                                         ;;;$201E
  8903. PR_AT_TAB:      RST     10H             ; PRINT_A outputs the control
  8904.                 LD      A,C             ; first value to A
  8905.                 RST     10H             ; PRINT_A outputs it.
  8906.                 LD      A,B             ; second value
  8907.                 RST     10H             ; PRINT_A
  8908.                 RET                     ; return - item finished >>>
  8909.  
  8910.                                         ; Now consider paper 2; #2; a$
  8911.  
  8912.                                         ;;;$2024
  8913. PR_ITEM_3:      CALL    CO_TEMP_3       ; routine CO_TEMP_3 will print any colour
  8914.                 RET     NC              ; items - return if success.
  8915.  
  8916.                 CALL    STR_ALTER       ; routine STR_ALTER considers new stream
  8917.                 RET     NC              ; return if altered.
  8918.  
  8919.                 CALL    SCANNING        ; routine SCANNING now to evaluate expression
  8920.                 CALL    UNSTACK_Z       ; routine UNSTACK_Z if not runtime.
  8921.                 BIT     6,(IY+$01)      ; test FLAGS  - Numeric or string result ?
  8922.                 CALL    Z,STK_FETCH     ; routine STK_FETCH if string.
  8923.                                         ; note no flags affected.
  8924.                 JP      NZ,PRINT_FP     ; to PRINT_FP to print if numeric >>>
  8925.  
  8926.                                         ; It was a string expression - start in DE, length in BC
  8927.                                         ; Now enter a loop to print it
  8928.  
  8929.                                         ;;;$203C
  8930. PR_STRING:      LD      A,B             ; this tests if the
  8931.                 OR      C               ; length is zero and sets flag accordingly.
  8932.                 DEC     BC              ; this doesn't but decrements counter.
  8933.                 RET     Z               ; return if zero.
  8934.  
  8935.                 LD      A,(DE)          ; fetch character.
  8936.                 INC     DE              ; address next location.
  8937.                 RST     10H             ; PRINT_A.
  8938.                 JR      PR_STRING       ; loop back to PR_STRING.
  8939.  
  8940. ;----------------
  8941. ; End of printing
  8942. ;----------------
  8943. ; This subroutine returns zero if no further printing is required
  8944. ; in the current statement.
  8945. ; The first terminator is found in escaped input items only,
  8946. ; the others in print_items.
  8947.  
  8948.                                         ;;;$2045
  8949. PR_END_Z:       CP      $29             ; is character a ')' ?
  8950.                 RET     Z               ; return if so - e.g. INPUT (p$); a$
  8951.  
  8952.                                         ;;;$2048
  8953. PR_ST_END:      CP      $0D             ; is it a carriage return ?
  8954.                 RET     Z               ; return also -  e.g. PRINT a
  8955.  
  8956.                 CP      $3A             ; is character a ':' ?
  8957.                 RET                     ; return - zero flag will be set if so.
  8958.                                         ;                e.g. PRINT a :
  8959.  
  8960. ;---------------
  8961. ; Print position
  8962. ;---------------
  8963. ; This routine considers a single positional character ';', ',', '''
  8964.  
  8965.                                         ;;;$204E
  8966. PR_POSN_1:      RST     18H             ; GET_CHAR
  8967.                 CP      $3B             ; is it ';' ?          
  8968.                                         ; i.e. print from last position.
  8969.                 JR      Z,PR_POSN_3     ; forward to PR_POSN_3 if so.
  8970.                                         ; i.e. do nothing.
  8971.                 CP      $2C             ; is it ',' ?
  8972.                                         ; i.e. print at next tabstop.
  8973.                 JR      NZ,PR_POSN_2    ; forward to PR_POSN_2 if anything else.
  8974.  
  8975.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  8976.                 JR      Z,PR_POSN_3     ; forward to PR_POSN_3 if checking syntax.
  8977.  
  8978.                 LD      A,$06           ; prepare the 'comma' control character.
  8979.                 RST     10H             ; PRINT_A  outputs to current channel in run-time.
  8980.                 JR      PR_POSN_3       ; skip to PR_POSN_3.
  8981.  
  8982.                                         ; check for newline.
  8983.  
  8984.                                         ;;;$2061
  8985. PR_POSN_2:      CP      $27             ; is character a "'" ? (newline)
  8986.                 RET     NZ              ; return if no match            >>>
  8987.  
  8988.                 CALL    PRINT_CR        ; routine PRINT_CR outputs a carriage return in runtime only.
  8989.  
  8990.                                         ;;;$2067
  8991. PR_POSN_3:      RST     20H             ; NEXT_CHAR to A.
  8992.                 CALL    PR_END_Z        ; routine PR_END_Z checks if at end.
  8993.                 JR      NZ,PR_POSN_4    ; to PR_POSN_4 if not.
  8994.  
  8995.                 POP     BC              ; drop return address if at end.
  8996.  
  8997.                                         ;;;$206E
  8998. PR_POSN_4:      CP      A               ; reset the zero flag.
  8999.                 RET                     ; and return to loop or quit.
  9000.  
  9001. ;-------------
  9002. ; Alter stream
  9003. ;-------------
  9004. ; This routine is called from PRINT ITEMS above, and also LIST as in
  9005. ; LIST #15
  9006.  
  9007.                                         ;;;$2070
  9008. STR_ALTER:      CP      $23             ; is character '#' ?
  9009.                 SCF                     ; set carry flag.
  9010.                 RET     NZ              ; return if no match.
  9011.  
  9012.                 RST     20H             ; NEXT_CHAR
  9013.                 CALL    EXPT_1NUM       ; routine EXPT_1NUM gets stream number
  9014.                 AND     A               ; prepare to exit early with carry reset
  9015.                 CALL    UNSTACK_Z       ; routine UNSTACK_Z exits early if parsing
  9016.                 CALL    FIND_INT1       ; routine FIND_INT1 gets number off stack
  9017.                 CP      $10             ; must be range 0 - 15 decimal.
  9018.                 JP      NC,REPORT_OA    ; jump back to REPORT_OA if not
  9019.                                         ; 'Invalid stream'.
  9020.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN
  9021.                 AND     A               ; clear carry - signal item dealt with.
  9022.                 RET                     ; return
  9023.  
  9024. ;---------------------
  9025. ; Handle INPUT command
  9026. ;---------------------
  9027. ; This command
  9028. ;
  9029.  
  9030.                                         ;;;$2089
  9031. INPUT:          CALL    SYNTAX_Z        ; routine SYNTAX_Z to check if in runtime.
  9032.                 JR      Z,INPUT_1       ; forward to INPUT_1 if checking syntax.
  9033.  
  9034.                 LD      A,$01           ; select channel 'K' the keyboard for input.
  9035.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN opens it.
  9036.                 CALL    CLS_LOWER       ; routine CLS_LOWER clears the lower screen.
  9037.  
  9038.                                         ;;;$2096
  9039. INPUT_1:        LD      (IY+$02),$01    ; set TV_FLAG - signal lower screen in use and clear the other bits.
  9040.                 CALL    IN_ITEM_1       ; routine IN_ITEM_1 to handle the input.
  9041.                 CALL    CHECK_END       ; routine CHECK_END will make an early exit  if checking syntax. >>>
  9042.  
  9043.                                         ; keyboard input has been made and it remains to adjust the upper
  9044.                                         ; screen in case the lower two lines have been extended upwards.
  9045.  
  9046.                 LD      BC,(S_POSN)     ; fetch S_POSN current line/column of the upper screen.
  9047.                 LD      A,(DF_SZ)       ; fetch DF_SZ the display file size of the lower screen.
  9048.                 CP      B               ; test that lower screen does not overlap
  9049.                 JR      C,INPUT_2       ; forward to INPUT_2 if not.
  9050.  
  9051.                                         ; the two screens overlap so adjust upper screen.
  9052.  
  9053.                 LD      C,$21           ; set column of upper screen to leftmost.
  9054.                 LD      B,A             ; and line to one above lower screen.
  9055.                                         ; continue forward to update upper screen
  9056.                                         ; print position.
  9057.  
  9058.                                         ;;;$20AD
  9059. INPUT_2:        LD      (S_POSN),BC     ; set S_POSN update upper screen line/column.
  9060.                 LD      A,$19           ; subtract from twenty five
  9061.                 SUB     B               ; the new line number.
  9062.                 LD      (SCR_CT),A      ; and place result in SCR_CT - scroll count.
  9063.                 RES     0,(IY+$02)      ; update TV_FLAG - signal main screen in use.
  9064.                 CALL    CL_SET          ; routine CL_SET sets the print position
  9065.                                         ; system variables for the upper screen.
  9066.                 JP      CLS_LOWER       ; jump back to CLS_LOWER and make
  9067.                                         ; an indirect exit >>.
  9068.  
  9069. ;----------------------
  9070. ; INPUT ITEM subroutine
  9071. ;----------------------
  9072. ; This subroutine deals with the input items and print items.
  9073. ; from  the current input channel.
  9074. ; It is only called from the above INPUT routine but was obviously
  9075. ; once called from somewhere else in another context.
  9076.  
  9077.                                         ;;;$20C1
  9078. IN_ITEM_1:      CALL    PR_POSN_1       ; routine PR_POSN_1 deals with a single
  9079.                                         ; position item at each call.
  9080.                 JR      Z,IN_ITEM_1     ; back to IN_ITEM_1 until no more in a sequence.
  9081.  
  9082.                 CP      $28             ; is character '(' ?
  9083.                 JR      NZ,IN_ITEM_2    ; forward to IN_ITEM_2 if not.
  9084.  
  9085.                                         ; any variables within braces will be treated as part, or all, of the prompt
  9086.                                         ; instead of being used as destination variables.
  9087.  
  9088.                 RST     20H             ; NEXT_CHAR
  9089.                 CALL    PRINT_2         ; routine PRINT_2 to output the dynamic prompt.
  9090.                 RST     18H             ; GET_CHAR
  9091.                 CP      $29             ; is character a matching ')' ?
  9092.                 JP      NZ,REPORT_C     ; jump back to REPORT_C if not.
  9093.                                         ; 'Nonsense in basic'.
  9094.                 RST     20H             ; NEXT_CHAR
  9095.                 JP      IN_NEXT_2       ; forward to IN_NEXT_2
  9096.  
  9097.                                         ;;;$20D8
  9098. IN_ITEM_2:      CP      $CA             ; is the character the token 'LINE' ?
  9099.                 JR      NZ,IN_ITEM_3    ; forward to IN_ITEM_3 if not.
  9100.  
  9101.                 RST     20H             ; NEXT_CHAR - variable must come next.
  9102.                 CALL    CLASS_01        ; routine CLASS_01 returns destination
  9103.                                         ; address of variable to be assigned.
  9104.                                         ; or generates an error if no variable
  9105.                                         ; at this position.
  9106.  
  9107.                 SET     7,(IY+$37)      ; update FLAGX  - signal handling INPUT LINE
  9108.                 BIT     6,(IY+$01)      ; test FLAGS  - numeric or string result ?
  9109.                 JP      NZ,REPORT_C     ; jump back to REPORT_C if not string
  9110.                                         ; 'Nonsense in basic'.
  9111.  
  9112.                 JR      IN_PROMPT       ; forward to IN_PROMPT to set up workspace.
  9113.  
  9114.                                         ; the jump was here for other variables.
  9115.  
  9116.                                         ;;;$20ED
  9117. IN_ITEM_3:      CALL    ALPHA           ; routine ALPHA checks if character is
  9118.                                         ; a suitable variable name.
  9119.                 JP      NC,IN_NEXT_1    ; forward to IN_NEXT_1 if not
  9120.  
  9121.                 CALL    CLASS_01        ; routine CLASS_01 returns destination
  9122.                                         ; address of variable to be assigned.
  9123.                 RES     7,(IY+$37)      ; update FLAGX  - signal not INPUT LINE.
  9124.  
  9125.                                         ;;;$20FA
  9126. IN_PROMPT:      CALL    SYNTAX_Z        ; routine SYNTAX_Z
  9127.                 JP      Z,IN_NEXT_2     ; forward to IN_NEXT_2 if checking syntax.
  9128.  
  9129.                 CALL    SET_WORK        ; routine SET_WORK clears workspace.
  9130.                 LD      HL,FLAGX        ; point to system variable FLAGX
  9131.                 RES     6,(HL)          ; signal string result.
  9132.                 SET     5,(HL)          ; signal in Input Mode for editor.
  9133.                 LD      BC,$0001        ; initialize space required to one for
  9134.                                         ; the carriage return.
  9135.                 BIT     7,(HL)          ; test FLAGX - INPUT LINE in use ?
  9136.                 JR      NZ,IN_PR_2      ; forward to IN_PR_2 if so as that is  all the space that is required.
  9137.  
  9138.                 LD      A,(FLAGS)       ; load accumulator from FLAGS
  9139.                 AND     $40             ; mask to test BIT 6 of FLAGS and clear the other bits in A.
  9140.                                         ; numeric result expected ?
  9141.                 JR      NZ,IN_PR_1      ; forward to IN_PR_1 if so
  9142.  
  9143.                 LD      C,$03           ; increase space to three bytes for the pair of surrounding quotes.
  9144.  
  9145.                                         ;;;$211A
  9146. IN_PR_1:        OR      (HL)            ; if numeric result, set bit 6 of FLAGX.
  9147.                 LD      (HL),A          ; and update system variable
  9148.  
  9149.                                         ;;;$211C
  9150. IN_PR_2:        RST     30H             ; BC_SPACES opens 1 or 3 bytes in workspace
  9151.                 LD      (HL),$0D        ; insert carriage return at last new location.
  9152.                 LD      A,C             ; fetch the length, one or three.
  9153.                 RRCA                    ; lose bit 0.
  9154.                 RRCA                    ; test if quotes required.
  9155.                 JR      NC,IN_PR_3      ; forward to IN_PR_3 if not.
  9156.  
  9157.                 LD      A,$22           ; load the '"' character
  9158.                 LD      (DE),A          ; place quote in first new location at DE.
  9159.                 DEC     HL              ; decrease HL - from carriage return.
  9160.                 LD      (HL),A          ; and place a quote in second location.
  9161.  
  9162.                                         ;;;$2129
  9163. IN_PR_3:        LD      (K_CUR),HL      ; set keyboard cursor K_CUR to HL
  9164.                 BIT     7,(IY+$37)      ; test FLAGX  - is this INPUT LINE ??
  9165.                 JR      NZ,IN_VAR_3     ; forward to IN_VAR_3 if so as input will
  9166.                                         ; be accepted without checking it's syntax.
  9167.                 LD      HL,(CH_ADD)     ; fetch CH_ADD
  9168.                 PUSH    HL              ; and save on stack.
  9169.                 LD      HL,(ERR_SP)     ; fetch ERR_SP
  9170.                 PUSH    HL              ; and save on stack
  9171.  
  9172.                                         ;;;$213A
  9173. IN_VAR_1:       LD      HL,IN_VAR_1     ; address: IN_VAR_1 - this address
  9174.                 PUSH    HL              ; is saved on stack to handle errors.
  9175.                 BIT     4,(IY+$30)      ; test FLAGS2  - is K channel in use ?
  9176.                 JR      Z,IN_VAR_2      ; forward to IN_VAR_2 if not using the keyboard for input. (??)
  9177.  
  9178.                 LD      (ERR_SP),SP     ; set ERR_SP to point to IN_VAR_1 on stack.
  9179.  
  9180.                                         ;;;$2148
  9181. IN_VAR_2:       LD      HL,(WORKSP)     ; set HL to WORKSP - start of workspace.
  9182.                 CALL    REMOVE_FP       ; routine REMOVE_FP removes floating point
  9183.                                         ; forms when looping in error condition.
  9184.                 LD      (IY+$00),$FF    ; set ERR_NR to 'OK' cancelling the error.
  9185.                                         ; but X_PTR causes flashing error marker
  9186.                                         ; to be displayed at each call to the editor.
  9187.                 CALL    EDITOR          ; routine EDITOR allows input to be entered
  9188.                                         ; or corrected if this is second time around.
  9189.  
  9190.                                         ; if we pass to next then there are no system errors
  9191.  
  9192.                 RES     7,(IY+$01)      ; update FLAGS  - signal checking syntax
  9193.                 CALL    IN_ASSIGN       ; routine IN_ASSIGN checks syntax using
  9194.                                         ; the VAL_FET_2 and powerful SCANNING routines.
  9195.                                         ; any syntax error and it's back to IN_VAR_1.
  9196.                                         ; but with the flashing error marker showing
  9197.                                         ; where the error is.
  9198.                                         ; Note. the syntax of string input has to be
  9199.                                         ; checked as the user may have removed the
  9200.                                         ; bounding quotes or escaped them as with
  9201.                                         ; "hat" + "stand" for example.
  9202.                                         ; proceed if syntax passed.
  9203.  
  9204.                 JR      IN_VAR_4        ; jump forward to IN_VAR_4
  9205.  
  9206.                                         ; the jump was to here when using INPUT LINE.
  9207.  
  9208.                                         ;;;$215E
  9209. IN_VAR_3:       CALL    EDITOR          ; routine EDITOR is called for input
  9210.  
  9211.                                         ; when ENTER received rejoin other route but with no syntax check.
  9212.  
  9213.                                         ; INPUT and INPUT LINE converge here.
  9214.  
  9215.                                         ;;;$2161
  9216. IN_VAR_4:       LD      (IY+$22),$00    ; set K_CUR_hi to a low value so that the cursor
  9217.                                         ; no longer appears in the input line.
  9218.                 CALL    IN_CHAN_K       ; routine IN_CHAN_K tests if the keyboard
  9219.                                         ; is being used for input.
  9220.                 JR      NZ,IN_VAR_5     ; forward to IN_VAR_5 if using another input channel.
  9221.  
  9222.                                         ; continue here if using the keyboard.
  9223.  
  9224.                 CALL    ED_COPY         ; routine ED_COPY overprints the edit line
  9225.                                         ; to the lower screen. The only visible
  9226.                                         ; affect is that the cursor disappears.
  9227.                                         ; if you're inputting more than one item in
  9228.                                         ; a statement then that becomes apparent.
  9229.                 LD      BC,(ECHO_E)     ; fetch line and column from ECHO_E
  9230.                 CALL    CL_SET          ; routine CL_SET sets S-POSNL to those values.
  9231.  
  9232.                                         ; if using another input channel rejoin here.
  9233.  
  9234.                                         ;;;$2174
  9235. IN_VAR_5:       LD      HL,FLAGX        ; point HL to FLAGX
  9236.                 RES     5,(HL)          ; signal not in input mode
  9237.                 BIT     7,(HL)          ; is this INPUT LINE ?
  9238.                 RES     7,(HL)          ; cancel the bit anyway.
  9239.                 JR      NZ,IN_VAR_6     ; forward to IN_VAR_6 if INPUT LINE.
  9240.  
  9241.                 POP     HL              ; drop the looping address
  9242.                 POP     HL              ; drop the the address of previous error handler.
  9243.                 LD      (ERR_SP),HL     ; set ERR_SP to point to it.
  9244.                 POP     HL              ; drop original CH_ADD which points to INPUT command in BASIC line.
  9245.                 LD      (X_PTR),HL      ; save in X_PTR while input is assigned.
  9246.                 SET     7,(IY+$01)      ; update FLAGS - Signal running program
  9247.                 CALL    IN_ASSIGN       ; routine IN_ASSIGN is called again
  9248.                                         ; this time the variable will be assigned
  9249.                                         ; the input value without error.
  9250.                                         ; Note. the previous example now
  9251.                                         ; becomes "hatstand"
  9252.                 LD      HL,(X_PTR)      ; fetch stored CH_ADD value from X_PTR.
  9253.                 LD      (IY+$26),$00    ; set X_PTR_HI so that no longer relevant.
  9254.                 LD      (CH_ADD),HL     ; put restored value back in CH_ADD
  9255.                 JR      IN_NEXT_2       ; forward to IN_NEXT_2 to see if anything
  9256.                                         ; more in the INPUT list.
  9257.  
  9258.                                         ; the jump was to here with INPUT LINE only
  9259.  
  9260.                                         ;;;$219B
  9261. IN_VAR_6:       LD      HL,(STKBOT)     ; STKBOT points to the end of the input.
  9262.                 LD      DE,(WORKSP)     ; WORKSP points to the beginning.
  9263.                 SCF                     ; prepare for true subtraction.
  9264.                 SBC     HL,DE           ; subtract to get length
  9265.                 LD      B,H             ; transfer it to
  9266.                 LD      C,L             ; the BC register pair.
  9267.                 CALL    STK_STO_D       ; routine STK_STO_D stores parameters on
  9268.                                         ; the calculator stack.
  9269.                 CALL    LET             ; routine LET assigns it to destination.
  9270.                 JR      IN_NEXT_2       ; forward to IN_NEXT_2 as print items
  9271.                                         ; not allowed with INPUT LINE.
  9272.                                         ; Note. that "hat" + "stand" will, for
  9273.                                         ; example, be unchanged as also would
  9274.                                         ; 'PRINT "Iris was here"'.
  9275.  
  9276.                                         ; the jump was to here when ALPHA found more items while looking for
  9277.                                         ; a variable name.
  9278.  
  9279.                                         ;;;$21AF
  9280. IN_NEXT_1:      CALL    PR_ITEM_1       ; routine PR_ITEM_1 considers further items.
  9281.  
  9282.                                         ;;;$21B2
  9283. IN_NEXT_2:      CALL    PR_POSN_1       ; routine PR_POSN_1 handles a position item.
  9284.                 JP      Z,IN_ITEM_1     ; jump back to IN_ITEM_1 if the zero flag
  9285.                                         ; indicates more items are present.
  9286.  
  9287.                 RET                     ; return.
  9288.  
  9289. ;----------------------------
  9290. ; INPUT ASSIGNMENT Subroutine
  9291. ;----------------------------
  9292. ; This subroutine is called twice from the INPUT command when normal
  9293. ; keyboard input is assigned. On the first occasion syntax is checked
  9294. ; using SCANNING. The final call with the syntax flag reset is to make
  9295. ; the assignment.
  9296.  
  9297.                                         ;;;$21B9
  9298. IN_ASSIGN:      LD      HL,(WORKSP)     ; fetch WORKSP start of input
  9299.                 LD      (CH_ADD),HL     ; set CH_ADD to first character
  9300.                 RST     18H             ; GET_CHAR ignoring leading white-space.
  9301.                 CP      $E2             ; is it 'STOP'
  9302.                 JR      Z,IN_STOP       ; forward to IN_STOP if so.
  9303.  
  9304.                 LD      A,(FLAGX)       ; load accumulator from FLAGX
  9305.                 CALL    VAL_FET_2       ; routine VAL_FET_2 makes assignment
  9306.                                         ; or goes through the motions if checking
  9307.                                         ; syntax. SCANNING is used.
  9308.                 RST     18H             ; GET_CHAR
  9309.                 CP      $0D             ; is it carriage return ?
  9310.                 RET     Z               ; return if so
  9311.                                         ; either syntax is OK
  9312.                                         ; or assignment has been made.
  9313.  
  9314.                                         ; if another character was found then raise an error.
  9315.                                         ; User doesn't see report but the flashing error marker
  9316.                                         ; appears in the lower screen.
  9317.  
  9318.                                         ;;;$21CE
  9319. REPORT_CB:      RST     08H             ; ERROR_1
  9320.                 DEFB    $0B             ; Error Report: Nonsense in BASIC
  9321.  
  9322.                                         ;;;$21D0
  9323. IN_STOP:        CALL    SYNTAX_Z        ; routine SYNTAX_Z (UNSTACK_Z?)
  9324.                 RET     Z               ; return if checking syntax
  9325.                                         ; as user wouldn't see error report.
  9326.                                         ; but generate visible error report
  9327.                                         ; on second invocation.
  9328.  
  9329.                                         ;;;$21D4
  9330. REPORT_H:       RST     08H             ; ERROR_1
  9331.                 DEFB    $10             ; Error Report: STOP in INPUT
  9332.  
  9333. ;-------------------
  9334. ; Test for channel K
  9335. ;-------------------
  9336. ; This subroutine is called once from the keyboard
  9337. ; INPUT command to check if the input routine in
  9338. ; use is the one for the keyboard.
  9339.  
  9340.                                         ;;;$21D6
  9341. IN_CHAN_K:      LD      HL,(CURCHL)     ; fetch address of current channel CURCHL
  9342.                 INC     HL
  9343.                 INC     HL              ; advance past
  9344.                 INC     HL              ; input and
  9345.                 INC     HL              ; output streams
  9346.                 LD      A,(HL)          ; fetch the channel identifier.
  9347.                 CP      $4B             ; test for 'K'
  9348.                 RET                     ; return with zero set if keyboard is use.
  9349.  
  9350. ;---------------------
  9351. ; Colour Item Routines
  9352. ;---------------------
  9353. ;
  9354. ; These routines have 3 entry points -
  9355. ; 1) CO_TEMP_2 to handle a series of embedded Graphic colour items.
  9356. ; 2) CO_TEMP_3 to handle a single embedded print colour item.
  9357. ; 3) CO_TEMP_4 to handle a colour command such as FLASH 1
  9358. ;
  9359. ; "Due to a bug, if you bring in a peripheral channel and later use a colour
  9360. ;  statement, colour controls will be sent to it by mistake." - Steven Vickers
  9361. ;  Pitman Pocket Guide, 1984.
  9362. ;
  9363. ; To be fair, this only applies if the last channel was other than 'K', 'S'
  9364. ; or 'P', which are all that are supported by this ROM, but if that last
  9365. ; channel was a microdrive file, network channel etc. then
  9366. ; PAPER 6; CLS will not turn the screen yellow and
  9367. ; CIRCLE INK 2; 128,88,50 will not draw a red circle.
  9368. ;
  9369. ; This bug does not apply to embedded PRINT items as it is quite permissible
  9370. ; to mix stream altering commands and colour items.
  9371. ; The fix therefore would be to ensure that CLASS_07 and CLASS_09 make
  9372. ; PRINT_OUT the current channel when not checking syntax.
  9373. ; -----------------------------------------------------------------
  9374.  
  9375.                                         ;;;$21E1
  9376. CO_TEMP_1:      RST     20H             ; NEXT_CHAR
  9377.  
  9378.                                         ; -> Entry point from CLASS_09. Embedded Graphic colour items.
  9379.                                         ; e.g. PLOT INK 2; PAPER 8; 128,88
  9380.                                         ; Loops till all colour items output, finally addressing the coordinates.
  9381.  
  9382.                                         ;;;$21E2
  9383. CO_TEMP_2:      CALL    CO_TEMP_3       ; routine CO_TEMP_3 to output colour control.
  9384.                 RET     C               ; return if nothing more to output. ->
  9385.  
  9386.                 RST     18H             ; GET_CHAR
  9387.                 CP      $2C             ; is it ',' separator ?
  9388.                 JR      Z,CO_TEMP_1     ; back if so to CO_TEMP_1
  9389.  
  9390.                 CP      $3B             ; is it ';' separator ?
  9391.                 JR      Z,CO_TEMP_1     ; back to CO_TEMP_1 for more.
  9392.  
  9393.                 JP      REPORT_C        ; to REPORT_C (REPORT_CB is within range)
  9394.                                         ; 'Nonsense in Basic'
  9395.  
  9396. ; -------------------
  9397. ; CO_TEMP_3
  9398. ; -------------------
  9399. ; -> this routine evaluates and outputs a colour control and parameter.
  9400. ; It is called from above and also from PR_ITEM_3 to handle a single embedded
  9401. ; print item e.g. PRINT PAPER 6; "Hi". In the latter case, the looping for
  9402. ; multiple items is within the PR-ITEM routine.
  9403. ; It is quite permissible to send these to any stream.
  9404.  
  9405.                                         ;;;$21F2
  9406. CO_TEMP_3:      CP      $D9             ; is it 'INK' ?
  9407.                 RET     C               ; return if less.
  9408.  
  9409.                 CP      $DF             ; compare with 'OUT'
  9410.                 CCF                     ; Complement Carry Flag
  9411.                 RET     C               ; return if greater than 'OVER', $DE.
  9412.  
  9413.                 PUSH    AF              ; save the colour token.
  9414.                 RST     20H             ; address NEXT_CHAR
  9415.                 POP     AF              ; restore token and continue.
  9416.  
  9417.                                         ; -> this entry point used by CLASS_07. e.g. the command PAPER 6.
  9418.  
  9419.                                         ;;;$21FC
  9420. CO_TEMP_4:      SUB     $C9             ; reduce to control character $10 (INK) thru $15 (OVER).
  9421.                 PUSH    AF              ; save control.
  9422.                 CALL    EXPT_1NUM       ; routine EXPT_1NUM stacks addressed
  9423.                                         ; parameter on calculator stack.
  9424.                 POP     AF              ; restore control.
  9425.                 AND     A               ; clear carry
  9426.                 CALL    UNSTACK_Z       ; routine UNSTACK_Z returns if checking syntax.
  9427.                 PUSH    AF              ; save again
  9428.                 CALL    FIND_INT1       ; routine FIND_INT1 fetches parameter to A.
  9429.                 LD      D,A             ; transfer now to D
  9430.                 POP     AF              ; restore control.
  9431.                 RST     10H             ; PRINT_A outputs the control to current channel.
  9432.                 LD      A,D             ; transfer parameter to A.
  9433.                 RST     10H             ; PRINT_A outputs parameter.
  9434.                 RET                     ; return. ->
  9435.  
  9436. ; -------------------------------------------------------------------------
  9437. ;
  9438. ;         {fl}{br}{   paper   }{  ink    }    The temporary colour attributes
  9439. ;          ___ ___ ___ ___ ___ ___ ___ ___    system variable.
  9440. ; ATTR_T  |   |   |   |   |   |   |   |   |
  9441. ;         |   |   |   |   |   |   |   |   |
  9442. ; 23695   |___|___|___|___|___|___|___|___|
  9443. ;           7   6   5   4   3   2   1   0
  9444. ;
  9445. ;
  9446. ;         {fl}{br}{   paper   }{  ink    }    The temporary mask used for
  9447. ;          ___ ___ ___ ___ ___ ___ ___ ___    transparent colours. Any bit
  9448. ; MASK_T  |   |   |   |   |   |   |   |   |   that is 1 shows that the
  9449. ;         |   |   |   |   |   |   |   |   |   corresponding attribute is
  9450. ; 23696   |___|___|___|___|___|___|___|___|   taken not from ATTR-T but from
  9451. ;           7   6   5   4   3   2   1   0     what is already on the screen.
  9452. ;
  9453. ;
  9454. ;         {paper9 }{ ink9 }{ inv1 }{ over1}   The print flags. Even bits are
  9455. ;          ___ ___ ___ ___ ___ ___ ___ ___    temporary flags. The odd bits
  9456. ; P_FLAG  |   |   |   |   |   |   |   |   |   are the permanent flags.
  9457. ;         | p | t | p | t | p | t | p | t |
  9458. ; 23697   |___|___|___|___|___|___|___|___|
  9459. ;           7   6   5   4   3   2   1   0
  9460. ;
  9461. ; -----------------------------------------------------------------------
  9462.  
  9463.  
  9464. ; ------------------------------------
  9465. ;  The colour system variable handler.
  9466. ; ------------------------------------
  9467. ; This is an exit branch from PO_1_OPER, PO_2_OPER
  9468. ; A holds control $10 (INK) to $15 (OVER)
  9469. ; D holds parameter 0-9 for ink/paper 0,1 or 8 for bright/flash,
  9470. ; 0 or 1 for over/inverse.
  9471.  
  9472.                                         ;;;$2211
  9473. CO_TEMP_5:      SUB     $11             ; reduce range $FF-$04
  9474.                 ADC     A,$00           ; add in carry if INK
  9475.                 JR      Z,CO_TEMP_7     ; forward to CO_TEMP_7 with INK and PAPER.
  9476.  
  9477.                 SUB     $02             ; reduce range $FF-$02
  9478.                 ADC     A,$00           ; add carry if FLASH
  9479.                 JR      Z,CO_TEMP_C     ; forward to CO_TEMP_C with FLASH and BRIGHT.
  9480.  
  9481.                 CP      $01             ; is it 'INVERSE' ?
  9482.                 LD      A,D             ; fetch parameter for INVERSE/OVER
  9483.                 LD      B,$01           ; prepare OVER mask setting bit 0.
  9484.                 JR      NZ,CO_TEMP_6    ; forward to CO_TEMP_6 if OVER
  9485.  
  9486.                 RLCA                    ; shift bit 0
  9487.                 RLCA                    ; to bit 2
  9488.                 LD      B,$04           ; set bit 2 of mask for inverse.
  9489.  
  9490.                                         ;;;$2228
  9491. CO_TEMP_6:      LD      C,A             ; save the A
  9492.                 LD      A,D             ; re-fetch parameter
  9493.                 CP      $02             ; is it less than 2
  9494.                 JR      NC,REPORT_K     ; to REPORT_K if not 0 or 1.
  9495.                                         ; 'Invalid colour'.
  9496.                 LD      A,C             ; restore A
  9497.                 LD      HL,P_FLAG       ; address system variable P_FLAG
  9498.                 JR      CO_CHANGE       ; forward to exit via routine CO_CHANGE
  9499.  
  9500.                                         ; the branch was here with INK/PAPER and carry set for INK.
  9501.  
  9502.                                         ;;;$2234
  9503. CO_TEMP_7:      LD      A,D             ; fetch parameter
  9504.                 LD      B,$07           ; set ink mask 00000111
  9505.                 JR      C,CO_TEMP_8     ; forward to CO_TEMP_8 with INK
  9506.  
  9507.                 RLCA                    ; shift bits 0-2
  9508.                 RLCA                    ; to
  9509.                 RLCA                    ; bits 3-5
  9510.                 LD      B,$38           ; set paper mask 00111000
  9511.  
  9512.                                         ; both paper and ink rejoin here
  9513.  
  9514.                                         ;;;$223E
  9515. CO_TEMP_8:      LD      C,A             ; value to C
  9516.                 LD      A,D             ; fetch parameter
  9517.                 CP      $0A             ; is it less than 10d ?
  9518.                 JR      C,CO_TEMP_9     ; forward to CO_TEMP_9 if so.
  9519.  
  9520.                                         ; ink 10 etc. is not allowed.
  9521.  
  9522.                                         ;;;$2244
  9523. REPORT_K:       RST     08H             ; ERROR_1
  9524.                 DEFB    $13             ; Error Report: Invalid colour
  9525.  
  9526.                                         ;;;$2246
  9527. CO_TEMP_9:      LD      HL,ATTRT_MASKT  ; address system variable ATTR_T initially.
  9528.                 CP      $08             ; compare with 8
  9529.                 JR      C,CO_TEMP_B     ; forward to CO_TEMP_B with 0-7.
  9530.  
  9531.                 LD      A,(HL)          ; fetch temporary attribute as no change.
  9532.                 JR      Z,CO_TEMP_A     ; forward to CO_TEMP_A with INK/PAPER 8
  9533.  
  9534.                                         ; it is either ink 9 or paper 9 (contrasting)
  9535.  
  9536.                 OR      B               ; or with mask to make white
  9537.                 CPL                     ; make black and change other to dark
  9538.                 AND     $24             ; 00100100
  9539.                 JR      Z,CO_TEMP_A     ; forward to CO_TEMP_A if black and
  9540.                                         ; originally light.
  9541.                 LD      A,B             ; else just use the mask (white)
  9542.  
  9543.                                         ;;;$2257
  9544. CO_TEMP_A:      LD      C,A             ; save A in C
  9545.  
  9546.                                         ;;;$2258
  9547. CO_TEMP_B:      LD      A,C             ; load colour to A
  9548.                 CALL    CO_CHANGE       ; routine CO_CHANGE addressing ATTR-T
  9549.                 LD      A,$07           ; put 7 in accumulator
  9550.                 CP      D               ; compare with parameter
  9551.                 SBC     A,A             ; $00 if 0-7, $FF if 8
  9552.                 CALL    CO_CHANGE       ; routine CO_CHANGE addressing MASK-T
  9553.                                         ; mask returned in A.
  9554.  
  9555.                                         ; now consider P-FLAG.
  9556.  
  9557.                 RLCA                    ; 01110000 or 00001110
  9558.                 RLCA                    ; 11100000 or 00011100
  9559.                 AND     $50             ; 01000000 or 00010000  (AND 01010000)
  9560.                 LD      B,A             ; transfer to mask
  9561.                 LD      A,$08           ; load A with 8
  9562.                 CP      D               ; compare with parameter
  9563.                 SBC     A,A             ; $FF if was 9,  $00 if 0-8
  9564.                                         ; continue while addressing P-FLAG
  9565.                                         ; setting bit 4 if ink 9
  9566.                                         ; setting bit 6 if paper 9
  9567.  
  9568. ;------------------------
  9569. ; Handle change of colour
  9570. ;------------------------
  9571. ; This routine addresses a system variable ATTR_T, MASK_T or P-FLAG in HL.
  9572. ; colour value in A, mask in B.
  9573.  
  9574.                                         ;;;$226C
  9575. CO_CHANGE:      XOR     (HL)            ; impress bits specified
  9576.                 AND     B               ; by mask
  9577.                 XOR     (HL)            ; on system variable.
  9578.                 LD      (HL),A          ; update system variable.
  9579.                 INC     HL              ; address next location.
  9580.                 LD      A,B             ; put current value of mask in A
  9581.                 RET                     ; return.
  9582.  
  9583.                                         ; the branch was here with flash and bright
  9584.  
  9585.                                         ;;;$2273
  9586. CO_TEMP_C:      SBC     A,A             ; set zero flag for bright.
  9587.                 LD      A,D             ; fetch original parameter 0,1 or 8
  9588.                 RRCA                    ; rotate bit 0 to bit 7
  9589.                 LD      B,$80           ; mask for flash 10000000
  9590.                 JR      NZ,CO_TEMP_D    ; forward to CO_TEMP_D if flash
  9591.  
  9592.                 RRCA                    ; rotate bit 7 to bit 6
  9593.                 LD      B,$40           ; mask for bright 01000000
  9594.  
  9595.                                         ;;;$227D
  9596. CO_TEMP_D:      LD      C,A             ; store value in C
  9597.                 LD      A,D             ; fetch parameter
  9598.                 CP      $08             ; compare with 8
  9599.                 JR      Z,CO_TEMP_E     ; forward to CO_TEMP_E if 8
  9600.  
  9601.                 CP      $02             ; test if 0 or 1
  9602.                 JR      NC,REPORT_K     ; back to REPORT_K if not
  9603.                                         ; 'Invalid colour'
  9604.  
  9605.                                         ;;;$2287
  9606. CO_TEMP_E:      LD      A,C             ; value to A
  9607.                 LD      HL,ATTRT_MASKT  ; address ATTR_T
  9608.                 CALL    CO_CHANGE       ; routine CO_CHANGE addressing ATTR_T
  9609.                 LD      A,C             ; fetch value
  9610.                 RRCA                    ; for flash8/bright8 complete
  9611.                 RRCA                    ; rotations to put set bit in
  9612.                 RRCA                    ; bit 7 (flash) bit 6 (bright)
  9613.                 JR      CO_CHANGE       ; back to CO_CHANGE addressing MASK_T
  9614.                                         ; and indirect return.
  9615.  
  9616. ;----------------------
  9617. ; Handle BORDER command
  9618. ;----------------------
  9619. ; Command syntax example: BORDER 7
  9620. ; This command routine sets the border to one of the eight colours.
  9621. ; The colours used for the lower screen are based on this.
  9622.  
  9623.                                         ;;;$2294
  9624. BORDER:         CALL    FIND_INT1       ; routine FIND_INT1
  9625.                 CP      $08             ; must be in range 0 (black) to 7 (white)
  9626.                 JR      NC,REPORT_K     ; back to REPORT_K if not
  9627.                                         ; 'Invalid colour'.
  9628.                 OUT     ($FE),A         ; outputting to port effects an immediate
  9629.                                         ; change.
  9630.                 RLCA                    ; shift the colour to
  9631.                 RLCA                    ; the paper bits setting the
  9632.                 RLCA                    ; ink colour black.
  9633.                 BIT     5,A             ; is the number light coloured ?
  9634.                                         ; i.e. in the range green to white.
  9635.                 JR      NZ,BORDER_1     ; skip to BORDER_1 if so
  9636.  
  9637.                 XOR     $07             ; make the ink white.
  9638.  
  9639.                                         ;;;$22A6
  9640. BORDER_1:       LD      (BORDCR),A      ; update BORDCR with new paper/ink
  9641.                 RET                     ; return.
  9642.  
  9643. ;------------------
  9644. ; Get pixel address
  9645. ;------------------
  9646.  
  9647.                                         ;;;$22AA
  9648. PIXEL_ADD:      LD      A,$AF           ; load with 175 decimal.
  9649.                 SUB     B               ; subtract the y value.
  9650.                 JP      C,REPORT_BC     ; jump forward to REPORT_BC if greater.
  9651.                                         ; 'Integer out of range'
  9652.  
  9653.                                         ; the high byte is derived from Y only.
  9654.                                         ; the first 3 bits are always 010
  9655.                                         ; the next 2 bits denote in which third of the screen the byte is.
  9656.                                         ; the last 3 bits denote in which of the 8 scan lines within a third
  9657.                                         ; the byte is located. There are 24 discrete values.
  9658.  
  9659.  
  9660.                 LD      B,A             ; the line number from top of screen to B.
  9661.                 AND     A               ; clear carry (already clear)
  9662.                 RRA                     ;                       0xxxxxxx
  9663.                 SCF                     ; set carry flag
  9664.                 RRA                     ;                       10xxxxxx
  9665.                 AND     A               ; clear carry flag
  9666.                 RRA                     ;                       010xxxxx
  9667.                 XOR     B
  9668.                 AND     $F8             ; keep the top 5 bits   11111000
  9669.                 XOR     B               ;                       010xxbbb
  9670.                 LD      H,A             ; transfer high byte to H.
  9671.  
  9672.                                         ; the low byte is derived from both X and Y.
  9673.  
  9674.                 LD      A,C             ; the x value 0-255.
  9675.                 RLCA
  9676.                 RLCA
  9677.                 RLCA
  9678.                 XOR     B               ; the y value
  9679.                 AND     $C7             ; apply mask            11000111
  9680.                 XOR     B               ; restore unmasked bits xxyyyxxx
  9681.                 RLCA                    ; rotate to             xyyyxxxx
  9682.                 RLCA                    ; required position.    yyyxxxxx
  9683.                 LD      L,A             ; low byte to L.
  9684.  
  9685.                                         ; finally form the pixel position in A.
  9686.  
  9687.                 LD      A,C             ; x value to A
  9688.                 AND     $07             ; mod 8
  9689.                 RET                     ; return
  9690.  
  9691. ;-----------------
  9692. ; Point Subroutine
  9693. ;-----------------
  9694. ; The point subroutine is called from S_POINT via the scanning functions
  9695. ; table.
  9696.  
  9697.                                         ;;;$22CB
  9698. POINT_SUB:      CALL    STK_TO_BC       ; routine STK_TO_BC
  9699.                 CALL    PIXEL_ADD       ; routine PIXEL_ADD finds address of pixel.
  9700.                 LD      B,A             ; pixel position to B, 0-7.
  9701.                 INC     B               ; increment to give rotation count 1-8.
  9702.                 LD      A,(HL)          ; fetch byte from screen.
  9703.  
  9704.                                         ;;;$22D4
  9705. POINT_LP:       RLCA                    ; rotate and loop back
  9706.                 DJNZ    POINT_LP        ; to POINT_LP until pixel at right.
  9707.                 AND     $01             ; test to give zero or one.
  9708.                 JP      STACK_A         ; jump forward to STACK_A to save result.
  9709.  
  9710. ;--------------------
  9711. ; Handle PLOT command
  9712. ;--------------------
  9713. ; Command Syntax example: PLOT 128,88
  9714.  
  9715.                                         ;;;$22DC
  9716. PLOT:           CALL    STK_TO_BC       ; routine STK_TO_BC
  9717.                 CALL    PLOT_SUB        ; routine PLOT_SUB
  9718.                 JP      TEMPS           ; to TEMPS
  9719.  
  9720. ; -------------------
  9721. ; The Plot subroutine
  9722. ; -------------------
  9723. ; A screen byte holds 8 pixels so it is necessary to rotate a mask
  9724. ; into the correct position to leave the other 7 pixels unaffected.
  9725. ; However all 64 pixels in the character cell take any embedded colour items.
  9726. ; A pixel can be reset (inverse 1), toggled (over 1), or set ( with inverse
  9727. ; and over switches off). With both switches on, the byte is simply put
  9728. ; back on the screen though the colours may change.
  9729.  
  9730.                                         ;;;$22E5
  9731. PLOT_SUB:       LD      (COORDS),BC     ; store new x/y values in COORDS
  9732.                 CALL    PIXEL_ADD       ; routine PIXEL_ADD gets address in HL,
  9733.                                         ; count from left 0-7 in B.
  9734.                 LD      B,A             ; transfer count to B.
  9735.                 INC     B               ; increase 1-8.
  9736.                 LD      A,$FE           ; 11111110 in A.
  9737.  
  9738.                                         ;;;$22F0
  9739. PLOT_LOOP:      RRCA                    ; rotate mask.
  9740.                 DJNZ    PLOT_LOOP       ; to PLOT_LOOP until B circular rotations.
  9741.                 LD      B,A             ; load mask to B
  9742.                 LD      A,(HL)          ; fetch screen byte to A
  9743.                 LD      C,(IY+$57)      ; P_FLAG to C
  9744.                 BIT     0,C             ; is it to be OVER 1 ?
  9745.                 JR      NZ,PL_TST_IN    ; forward to PL_TST_IN if so.
  9746.  
  9747.                                         ; was over 0
  9748.  
  9749.                 AND     B               ; combine with mask to blank pixel.
  9750.  
  9751.                                         ;;;$22FD
  9752. PL_TST_IN:      BIT     2,C             ; is it inverse 1 ?
  9753.                 JR      NZ,PLOT_END     ; to PLOT_END if so.
  9754.  
  9755.                 XOR     B               ; switch the pixel
  9756.                 CPL                     ; restore other 7 bits
  9757.  
  9758.                                         ;;;$2303
  9759. PLOT_END:       LD      (HL),A          ; load byte to the screen.
  9760.                 JP      PO_ATTR         ; exit to PO_ATTR to set colours for cell.
  9761.  
  9762. ;-------------------------------
  9763. ; Put two numbers in BC register
  9764. ;-------------------------------
  9765.  
  9766.                                         ;;;$2307
  9767. STK_TO_BC:      CALL    STK_TO_A        ; routine STK_TO_A
  9768.                 LD      B,A
  9769.                 PUSH    BC
  9770.                 CALL    STK_TO_A        ; routine STK_TO_A
  9771.                 LD      E,C
  9772.                 POP     BC
  9773.                 LD      D,C
  9774.                 LD      C,A
  9775.                 RET
  9776.  
  9777. ;------------------------
  9778. ; Put stack in A register
  9779. ;------------------------
  9780. ; This routine puts the last value on the calculator stack into the accumulator
  9781. ; deleting the last value.
  9782.  
  9783.                                         ;;;$2314
  9784. STK_TO_A:       CALL    FP_TO_A         ; routine FP_TO_A compresses last value into
  9785.                                         ; accumulator. e.g. PI would become 3.
  9786.                                         ; zero flag set if positive.
  9787.                 JP      C,REPORT_BC     ; jump forward to REPORT_BC if >= 255.5.
  9788.  
  9789.                 LD      C,$01           ; prepare a positive sign byte.
  9790.                 RET     Z               ; return if FP_TO_BC indicated positive.
  9791.  
  9792.                 LD      C,$FF           ; prepare negative sign byte and
  9793.                 RET                     ; return.
  9794.  
  9795.  
  9796. ;----------------------
  9797. ; Handle CIRCLE command
  9798. ;----------------------
  9799. ;
  9800. ; syntax has been partly checked using the class for draw command.
  9801.  
  9802.                                         ;;;$2320
  9803. CIRCLE:         RST     18H             ; GET_CHAR
  9804.                 CP      $2C             ; is it required comma ?
  9805.                 JP      NZ,REPORT_C     ; jump to REPORT_C if not
  9806.  
  9807.                 RST     20H             ; NEXT_CHAR
  9808.                 CALL    EXPT_1NUM       ; routine EXPT_1NUM fetches radius
  9809.                 CALL    CHECK_END       ; routine CHECK_END will return here if
  9810.                                         ; nothing follows command.
  9811.                 RST     28H             ;; FP_CALC
  9812.                 DEFB    $2A             ;;ABS           ; make radius positive
  9813.                 DEFB    $3D             ;;RE_STACK      ; in full floating point form
  9814.                 DEFB    $38             ;;END_CALC
  9815.  
  9816.                 LD      A,(HL)          ; fetch first floating point byte
  9817.                 CP      $81             ; compare to one
  9818.                 JR      NC,C_R_GRE_1    ; forward to C_R_GRE_1 if circle radius
  9819.                                         ; is greater than one.
  9820.                 RST     28H             ;; FP_CALC
  9821.                 DEFB    $02             ;;DELETE        ; delete the radius from stack.
  9822.                 DEFB    $38             ;;END_CALC
  9823.  
  9824.                 JR      PLOT            ; to PLOT to just plot x,y.
  9825.  
  9826.  
  9827.                                         ;;;$233B
  9828. C_R_GRE_1:      RST     28H             ;; FP_CALC      ; x, y, r
  9829.                 DEFB    $A3             ;;STK_PI_2      ; x, y, r, pi/2.
  9830.                 DEFB    $38             ;;END_CALC
  9831.  
  9832.                 LD      (HL),$83                        ; x, y, r, 2*PI
  9833.                 RST     28H             ;; FP_CALC
  9834.                 DEFB    $C5             ;;st-mem-5      ; store 2*PI in mem-5
  9835.                 DEFB    $02             ;;DELETE        ; x, y, z.
  9836.                 DEFB    $38             ;;END_CALC
  9837.  
  9838.                 CALL    CD_PRMS1        ; routine CD_PRMS1
  9839.                 PUSH    BC
  9840.                 RST     28H             ;; FP_CALC
  9841.                 DEFB    $31             ;;DUPLICATE
  9842.                 DEFB    $E1             ;;get-mem-1
  9843.                 DEFB    $04             ;;MULTIPLY
  9844.                 DEFB    $38             ;;END_CALC
  9845.  
  9846.                 LD      A,(HL)
  9847.                 CP      $80
  9848.                 JR      NC,C_ARC_GE1    ; to C_ARC_GE1
  9849.  
  9850.                 RST     28H             ;; FP_CALC
  9851.                 DEFB    $02             ;;DELETE
  9852.                 DEFB    $02             ;;DELETE
  9853.                 DEFB    $38             ;;END_CALC
  9854.  
  9855.                 POP     BC
  9856.                 JP      PLOT            ; to PLOT
  9857.  
  9858.  
  9859.                                         ;;;$235A
  9860. C_ARC_GE1:      RST     28H             ;; FP_CALC
  9861.                 DEFB    $C2             ;;st-mem-2
  9862.                 DEFB    $01             ;;EXCHANGE
  9863.                 DEFB    $C0             ;;st-mem-0
  9864.                 DEFB    $02             ;;DELETE
  9865.                 DEFB    $03             ;;SUBTRACT
  9866.                 DEFB    $01             ;;EXCHANGE
  9867.                 DEFB    $E0             ;;get-mem-0
  9868.                 DEFB    $0F             ;;ADDITION
  9869.                 DEFB    $C0             ;;st-mem-0
  9870.                 DEFB    $01             ;;EXCHANGE
  9871.                 DEFB    $31             ;;DUPLICATE
  9872.                 DEFB    $E0             ;;get-mem-0
  9873.                 DEFB    $01             ;;EXCHANGE
  9874.                 DEFB    $31             ;;DUPLICATE
  9875.                 DEFB    $E0             ;;get-mem-0
  9876.                 DEFB    $A0             ;;STK_ZERO
  9877.                 DEFB    $C1             ;;st-mem-1
  9878.                 DEFB    $02             ;;DELETE
  9879.                 DEFB    $38             ;;END_CALC
  9880.  
  9881.                 INC     (IY+$62)        ; MEM-2-1st
  9882.                 CALL    FIND_INT1       ; routine FIND_INT1
  9883.                 LD      L,A
  9884.                 PUSH    HL
  9885.                 CALL    FIND_INT1       ; routine FIND_INT1
  9886.                 POP     HL
  9887.                 LD      H,A
  9888.                 LD      (COORDS),HL     ; COORDS
  9889.                 POP     BC
  9890.                 JP      DRW_STEPS       ; to DRW_STEPS
  9891.  
  9892.  
  9893. ;--------------------
  9894. ; Handle DRAW command
  9895. ;--------------------
  9896.  
  9897.                                         ;;;$2382
  9898. DRAW:           RST     18H             ; GET_CHAR
  9899.                 CP      $2C
  9900.                 JR      Z,DR_3_PRMS     ; to DR_3_PRMS
  9901.  
  9902.                 CALL    CHECK_END       ; routine CHECK_END
  9903.                 JP      LINE_DRAW       ; to LINE_DRAW
  9904.  
  9905.  
  9906.                                         ;;;$238D
  9907. DR_3_PRMS:      RST     20H             ; NEXT_CHAR
  9908.                 CALL    EXPT_1NUM       ; routine EXPT_1NUM
  9909.                 CALL    CHECK_END       ; routine CHECK_END
  9910.  
  9911.                 RST     28H             ;; FP_CALC
  9912.                 DEFB    $C5             ;;st-mem-5
  9913.                 DEFB    $A2             ;;STK_HALF
  9914.                 DEFB    $04             ;;MULTIPLY
  9915.                 DEFB    $1F             ;;SIN_
  9916.                 DEFB    $31             ;;DUPLICATE
  9917.                 DEFB    $30             ;;NOT
  9918.                 DEFB    $30             ;;NOT
  9919.                 DEFB    $00             ;;JUMP_TRUE
  9920.  
  9921.                 DEFB    $06             ;;to DR_SIN_NZ
  9922.  
  9923.                 DEFB    $02             ;;DELETE
  9924.                 DEFB    $38             ;;END_CALC
  9925.  
  9926.                 JP      LINE_DRAW       ; to LINE_DRAW
  9927.  
  9928.                                         ;;;$23A3
  9929. DR_SIN_NZ:      DEFB    $C0             ;;st-mem-0
  9930.                 DEFB    $02             ;;DELETE
  9931.                 DEFB    $C1             ;;st-mem-1
  9932.                 DEFB    $02             ;;DELETE
  9933.                 DEFB    $31             ;;DUPLICATE
  9934.                 DEFB    $2A             ;;ABS
  9935.                 DEFB    $E1             ;;get-mem-1
  9936.                 DEFB    $01             ;;EXCHANGE
  9937.                 DEFB    $E1             ;;get-mem-1
  9938.                 DEFB    $2A             ;;ABS
  9939.                 DEFB    $0F             ;;ADDITION
  9940.                 DEFB    $E0             ;;get-mem-0
  9941.                 DEFB    $05             ;;DIVISION
  9942.                 DEFB    $2A             ;;ABS
  9943.                 DEFB    $E0             ;;get-mem-0
  9944.                 DEFB    $01             ;;EXCHANGE
  9945.                 DEFB    $3D             ;;RE_STACK
  9946.                 DEFB    $38             ;;END_CALC
  9947.  
  9948.                 LD      A,(HL)
  9949.                 CP      $81
  9950.                 JR      NC,DR_PRMS      ; to DR_PRMS
  9951.  
  9952.                 RST     28H             ;; FP_CALC
  9953.                 DEFB    $02             ;;DELETE
  9954.                 DEFB    $02             ;;DELETE
  9955.                 DEFB    $38             ;;END_CALC
  9956.  
  9957.                 JP      LINE_DRAW       ; to LINE_DRAW
  9958.  
  9959.                                         ;;;$23C1
  9960. DR_PRMS:        CALL    CD_PRMS1        ; routine CD_PRMS1
  9961.                 PUSH    BC              ;
  9962.                 RST     28H             ;; FP_CALC
  9963.                 DEFB    $02             ;;DELETE
  9964.                 DEFB    $E1             ;;get-mem-1
  9965.                 DEFB    $01             ;;EXCHANGE
  9966.                 DEFB    $05             ;;DIVISION
  9967.                 DEFB    $C1             ;;st-mem-1
  9968.                 DEFB    $02             ;;DELETE
  9969.                 DEFB    $01             ;;EXCHANGE
  9970.                 DEFB    $31             ;;DUPLICATE
  9971.                 DEFB    $E1             ;;get-mem-1
  9972.                 DEFB    $04             ;;MULTIPLY
  9973.                 DEFB    $C2             ;;st-mem-2
  9974.                 DEFB    $02             ;;DELETE
  9975.                 DEFB    $01             ;;EXCHANGE
  9976.                 DEFB    $31             ;;DUPLICATE
  9977.                 DEFB    $E1             ;;get-mem-1
  9978.                 DEFB    $04             ;;MULTIPLY
  9979.                 DEFB    $E2             ;;get-mem-2
  9980.                 DEFB    $E5             ;;get-mem-5
  9981.                 DEFB    $E0             ;;get-mem-0
  9982.                 DEFB    $03             ;;SUBTRACT
  9983.                 DEFB    $A2             ;;STK_HALF
  9984.                 DEFB    $04             ;;MULTIPLY
  9985.                 DEFB    $31             ;;DUPLICATE
  9986.                 DEFB    $1F             ;;SIN_
  9987.                 DEFB    $C5             ;;st-mem-5
  9988.                 DEFB    $02             ;;DELETE
  9989.                 DEFB    $20             ;;COS_
  9990.                 DEFB    $C0             ;;st-mem-0
  9991.                 DEFB    $02             ;;DELETE
  9992.                 DEFB    $C2             ;;st-mem-2
  9993.                 DEFB    $02             ;;DELETE
  9994.                 DEFB    $C1             ;;st-mem-1
  9995.                 DEFB    $E5             ;;get-mem-5
  9996.                 DEFB    $04             ;;MULTIPLY
  9997.                 DEFB    $E0             ;;get-mem-0
  9998.                 DEFB    $E2             ;;get-mem-2
  9999.                 DEFB    $04             ;;MULTIPLY
  10000.                 DEFB    $0F             ;;ADDITION
  10001.                 DEFB    $E1             ;;get-mem-1
  10002.                 DEFB    $01             ;;EXCHANGE
  10003.                 DEFB    $C1             ;;st-mem-1
  10004.                 DEFB    $02             ;;DELETE
  10005.                 DEFB    $E0             ;;get-mem-0
  10006.                 DEFB    $04             ;;MULTIPLY
  10007.                 DEFB    $E2             ;;get-mem-2
  10008.                 DEFB    $E5             ;;get-mem-5
  10009.                 DEFB    $04             ;;MULTIPLY
  10010.                 DEFB    $03             ;;SUBTRACT
  10011.                 DEFB    $C2             ;;st-mem-2
  10012.                 DEFB    $2A             ;;ABS
  10013.                 DEFB    $E1             ;;get-mem-1
  10014.                 DEFB    $2A             ;;ABS
  10015.                 DEFB    $0F             ;;ADDITION
  10016.                 DEFB    $02             ;;DELETE
  10017.                 DEFB    $38             ;;END_CALC
  10018.  
  10019.                 LD      A,(DE)
  10020.                 CP      $81
  10021.                 POP     BC
  10022.                 JP      C,LINE_DRAW     ; to LINE_DRAW
  10023.  
  10024.                 PUSH    BC
  10025.                 RST     28H             ;; FP_CALC
  10026.                 DEFB    $01             ;;EXCHANGE
  10027.                 DEFB    $38             ;;END_CALC
  10028.  
  10029.                 LD      A,(COORDS)      ; COORDS-x
  10030.                 CALL    STACK_A         ; routine STACK_A
  10031.                 RST     28H             ;; FP_CALC
  10032.                 DEFB    $C0             ;;st-mem-0
  10033.                 DEFB    $0F             ;;ADDITION
  10034.                 DEFB    $01             ;;EXCHANGE
  10035.                 DEFB    $38             ;;END_CALC
  10036.  
  10037.                 LD      A,(COORDS_Y)    ; COORDS_Y
  10038.                 CALL    STACK_A         ; routine STACK_A
  10039.                 RST     28H             ;; FP_CALC
  10040.                 DEFB    $C5             ;;st-mem-5
  10041.                 DEFB    $0F             ;;ADDITION
  10042.                 DEFB    $E0             ;;get-mem-0
  10043.                 DEFB    $E5             ;;get-mem-5
  10044.                 DEFB    $38             ;;END_CALC
  10045.  
  10046.                 POP     BC
  10047.  
  10048.                                         ;;;$2420
  10049. DRW_STEPS:      DEC     B
  10050.                 JR      Z,ARC_END       ; to ARC_END
  10051.  
  10052.                 JR      ARC_START       ; to ARC_START
  10053.  
  10054.                                         ;;;$2425
  10055. ARC_LOOP:       RST     28H             ;; FP_CALC
  10056.                 DEFB    $E1             ;;get-mem-1
  10057.                 DEFB    $31             ;;DUPLICATE
  10058.                 DEFB    $E3             ;;get-mem-3
  10059.                 DEFB    $04             ;;MULTIPLY
  10060.                 DEFB    $E2             ;;get-mem-2
  10061.                 DEFB    $E4             ;;get-mem-4
  10062.                 DEFB    $04             ;;MULTIPLY
  10063.                 DEFB    $03             ;;SUBTRACT
  10064.                 DEFB    $C1             ;;st-mem-1
  10065.                 DEFB    $02             ;;DELETE
  10066.                 DEFB    $E4             ;;get-mem-4
  10067.                 DEFB    $04             ;;MULTIPLY
  10068.                 DEFB    $E2             ;;get-mem-2
  10069.                 DEFB    $E3             ;;get-mem-3
  10070.                 DEFB    $04             ;;MULTIPLY
  10071.                 DEFB    $0F             ;;ADDITION
  10072.                 DEFB    $C2             ;;st-mem-2
  10073.                 DEFB    $02             ;;DELETE
  10074.                 DEFB    $38             ;;END_CALC
  10075.  
  10076.                                         ;;;$2439
  10077. ARC_START:      PUSH    BC
  10078.                 RST     28H             ;; FP_CALC
  10079.                 DEFB    $C0             ;;st-mem-0
  10080.                 DEFB    $02             ;;DELETE
  10081.                 DEFB    $E1             ;;get-mem-1
  10082.                 DEFB    $0F             ;;ADDITION
  10083.                 DEFB    $31             ;;DUPLICATE
  10084.                 DEFB    $38             ;;END_CALC
  10085.  
  10086.                 LD      A,(COORDS)      ; COORDS-x
  10087.                 CALL    STACK_A         ; routine STACK_A
  10088.                 RST     28H             ;; FP_CALC
  10089.                 DEFB    $03             ;;SUBTRACT
  10090.                 DEFB    $E0             ;;get-mem-0
  10091.                 DEFB    $E2             ;;get-mem-2
  10092.                 DEFB    $0F             ;;ADDITION
  10093.                 DEFB    $C0             ;;st-mem-0
  10094.                 DEFB    $01             ;;EXCHANGE
  10095.                 DEFB    $E0             ;;get-mem-0
  10096.                 DEFB    $38             ;;END_CALC
  10097.  
  10098.                 LD      A,(COORDS_Y)    ; COORDS_Y
  10099.                 CALL    STACK_A         ; routine STACK_A
  10100.                 RST     28H             ;; FP_CALC
  10101.                 DEFB    $03             ;;SUBTRACT
  10102.                 DEFB    $38             ;;END_CALC
  10103.  
  10104.                 CALL    DRAW_LINE       ; routine DRAW_LINE
  10105.                 POP     BC
  10106.                 DJNZ    ARC_LOOP        ; to ARC_LOOP
  10107.  
  10108.                                         ;;;$245F
  10109. ARC_END:        RST     28H             ;; FP_CALC
  10110.                 DEFB    $02             ;;DELETE
  10111.                 DEFB    $02             ;;DELETE
  10112.                 DEFB    $01             ;;EXCHANGE
  10113.                 DEFB    $38             ;;END_CALC
  10114.  
  10115.                 LD      A,(COORDS)      ; COORDS-x
  10116.                 CALL    STACK_A         ; routine STACK_A
  10117.                 RST     28H             ;; FP_CALC
  10118.                 DEFB    $03             ;;SUBTRACT
  10119.                 DEFB    $01             ;;EXCHANGE
  10120.                 DEFB    $38             ;;END_CALC
  10121.  
  10122.                 LD      A,(COORDS_Y)    ; COORDS_Y
  10123.                 CALL    STACK_A         ; routine STACK_A
  10124.                 RST     28H             ;; FP_CALC
  10125.                 DEFB    $03             ;;SUBTRACT
  10126.                 DEFB    $38             ;;END_CALC
  10127.  
  10128.                                         ;;;$2477
  10129. LINE_DRAW:      CALL    DRAW_LINE       ; routine DRAW_LINE
  10130.                 JP      TEMPS           ; to TEMPS
  10131.  
  10132. ;-------------------
  10133. ; Initial parameters
  10134. ;-------------------
  10135.  
  10136.                                         ;;;$247D
  10137. CD_PRMS1:       RST     28H             ;; FP_CALC
  10138.                 DEFB    $31             ;;DUPLICATE
  10139.                 DEFB    $28             ;;SQR
  10140.                 DEFB    $34             ;;STK_DATA
  10141.                 DEFB    $32             ;;Exponent: $82, Bytes: 1
  10142.                 DEFB    $00             ;;(+00,+00,+00)
  10143.                 DEFB    $01             ;;EXCHANGE
  10144.                 DEFB    $05             ;;DIVISION
  10145.                 DEFB    $E5             ;;get-mem-5
  10146.                 DEFB    $01             ;;EXCHANGE
  10147.                 DEFB    $05             ;;DIVISION
  10148.                 DEFB    $2A             ;;ABS
  10149.                 DEFB    $38             ;;END_CALC
  10150.  
  10151.                 CALL    FP_TO_A         ; routine FP_TO_A
  10152.                 JR      C,USE_252       ; to USE_252
  10153.  
  10154.                 AND     $FC
  10155.                 ADD     A,$04
  10156.                 JR      NC,DRAW_SAVE    ; to DRAW_SAVE
  10157.  
  10158.                                         ;;;$2495
  10159. USE_252:        LD      A,$FC
  10160.  
  10161.                                         ;;;$2497
  10162. DRAW_SAVE:      PUSH    AF
  10163.                 CALL    STACK_A         ; routine STACK_A
  10164.                 RST     28H             ;; FP_CALC
  10165.                 DEFB    $E5             ;;get-mem-5
  10166.                 DEFB    $01             ;;EXCHANGE
  10167.                 DEFB    $05             ;;DIVISION
  10168.                 DEFB    $31             ;;DUPLICATE
  10169.                 DEFB    $1F             ;;SIN_
  10170.                 DEFB    $C4             ;;st-mem-4
  10171.                 DEFB    $02             ;;DELETE
  10172.                 DEFB    $31             ;;DUPLICATE
  10173.                 DEFB    $A2             ;;STK_HALF
  10174.                 DEFB    $04             ;;MULTIPLY
  10175.                 DEFB    $1F             ;;SIN_
  10176.                 DEFB    $C1             ;;st-mem-1
  10177.                 DEFB    $01             ;;EXCHANGE
  10178.                 DEFB    $C0             ;;st-mem-0
  10179.                 DEFB    $02             ;;DELETE
  10180.                 DEFB    $31             ;;DUPLICATE
  10181.                 DEFB    $04             ;;MULTIPLY
  10182.                 DEFB    $31             ;;DUPLICATE
  10183.                 DEFB    $0F             ;;ADDITION
  10184.                 DEFB    $A1             ;;STK_ONE
  10185.                 DEFB    $03             ;;SUBTRACT
  10186.                 DEFB    $1B             ;;NEGATE
  10187.                 DEFB    $C3             ;;st-mem-3
  10188.                 DEFB    $02             ;;DELETE
  10189.                 DEFB    $38             ;;END_CALC
  10190.  
  10191.                 POP     BC
  10192.                 RET
  10193.  
  10194. ;-------------
  10195. ; Line drawing
  10196. ;-------------
  10197.  
  10198.                                         ;;;$24B7
  10199. DRAW_LINE:      CALL    STK_TO_BC       ; routine STK_TO_BC
  10200.                 LD      A,C
  10201.                 CP      B
  10202.                 JR      NC,DL_X_GE_Y    ; to DL_X_GE_Y
  10203.  
  10204.                 LD      L,C
  10205.                 PUSH    DE
  10206.                 XOR     A
  10207.                 LD      E,A
  10208.                 JR      DL_LARGER       ; to DL_LARGER
  10209.  
  10210.                                         ;;;$24C4
  10211. DL_X_GE_Y:      OR      C
  10212.                 RET     Z
  10213.  
  10214.                 LD      L,B
  10215.                 LD      B,C
  10216.                 PUSH    DE
  10217.                 LD      D,$00
  10218.  
  10219.                                         ;;;$24CB
  10220. DL_LARGER:      LD      H,B
  10221.                 LD      A,B
  10222.                 RRA
  10223.  
  10224.                                         ;;;$24CE
  10225. D_L_LOOP:       ADD     A,L             ;
  10226.                 JR      C,D_L_DIAG      ; to D_L_DIAG
  10227.  
  10228.                 CP      H               ;
  10229.                 JR      C,D_L_HR_VT     ; to D_L_HR_VT
  10230.  
  10231.                                         ;;;$24D4
  10232. D_L_DIAG:       SUB     H
  10233.                 LD      C,A
  10234.                 EXX
  10235.                 POP     BC
  10236.                 PUSH    BC
  10237.                 JR      D_L_STEP        ; to D_L_STEP
  10238.  
  10239.                                         ;;;$24DB
  10240. D_L_HR_VT:      LD      C,A
  10241.                 PUSH    DE
  10242.                 EXX
  10243.                 POP     BC
  10244.  
  10245.                                         ;;;$24DF
  10246. D_L_STEP:       LD      HL,(COORDS)
  10247.                 LD      A,B
  10248.                 ADD     A,H
  10249.                 LD      B,A
  10250.                 LD      A,C
  10251.                 INC     A
  10252.                 ADD     A,L
  10253.                 JR      C,D_L_RANGE     ; to D_L_RANGE
  10254.  
  10255.                 JR      Z,REPORT_BC     ; to REPORT_BC
  10256.  
  10257.                                         ;;;$24EC
  10258. D_L_PLOT:       DEC     A
  10259.                 LD      C,A
  10260.                 CALL    PLOT_SUB        ; routine PLOT_SUB
  10261.                 EXX
  10262.                 LD      A,C
  10263.                 DJNZ    D_L_LOOP        ; to D_L_LOOP
  10264.                 POP     DE
  10265.                 RET
  10266.  
  10267.                                         ;;;$24F7
  10268. D_L_RANGE:      JR      Z,D_L_PLOT      ; to D_L_PLOT
  10269.  
  10270.                                         ;;;$24F9
  10271. REPORT_BC:      RST     08H             ; ERROR_1
  10272.                 DEFB    $0A             ; Error Report: Integer out of range
  10273.  
  10274. ;***********************************
  10275. ;** Part 8. EXPRESSION EVALUATION **
  10276. ;***********************************
  10277. ;
  10278. ; It is a this stage of the ROM that the Spectrum ceases altogether to be
  10279. ; just a colourful novelty. One remarkable feature is that in all previous
  10280. ; commands when the Spectrum is expecting a number or a string then an
  10281. ; expression of the same type can be substituted ad infinitum.
  10282. ; This is the routine that evaluates that expression.
  10283. ; This is what causes 2 + 2 to give the answer 4.
  10284. ; That is quite easy to understand. However you don't have to make it much
  10285. ; more complex to start a remarkable juggling act.
  10286. ; e.g. PRINT 2 * (VAL "2+2" + TAN 3)
  10287. ; In fact, provided there is enough free RAM, the Spectrum can evaluate
  10288. ; an expression of unlimited complexity.
  10289. ; Apart from a couple of minor glitches, which you can now correct, the
  10290. ; system is remarkably robust.
  10291.  
  10292. ;----------------------------------
  10293. ; Scan expression or sub-expression
  10294. ;----------------------------------
  10295.  
  10296.                                         ;;;$24FB
  10297. SCANNING:       RST     18H             ; GET_CHAR
  10298.                 LD      B,$00           ; priority marker zero is pushed on stack
  10299.                                         ; to signify end of expression when it is  popped off again.
  10300.                 PUSH    BC              ; put in on stack.
  10301.                                         ; and proceed to consider the first character
  10302.                                         ; of the expression.
  10303.  
  10304.                                         ;;;$24FF
  10305. S_LOOP_1:       LD      C,A             ; store the character while a look up is done.
  10306.                 LD      HL,SCAN_FUNC    ; Address: SCAN_FUNC
  10307.                 CALL    INDEXER         ; routine INDEXER is called to see if it is
  10308.                                         ; part of a limited range '+', '(', 'ATTR' etc.
  10309.                 LD      A,C             ; fetch the character back
  10310.                 JP      NC,S_ALPHNUM    ; jump forward to S_ALPHNUM if not in primary
  10311.                                         ; operators and functions to consider in the
  10312.                                         ; first instance a digit or a variable and
  10313.                                         ; then anything else.                   >>>
  10314.                 LD      B,$00           ; but here if it was found in table so
  10315.                 LD      C,(HL)          ; fetch offset from table and make B zero.
  10316.                 ADD     HL,BC           ; add the offset to position found
  10317.                 JP      (HL)            ; and jump to the routine e.g. S_BIN
  10318.                                         ; making an indirect exit from there.
  10319.  
  10320. ;--------------------------------------------------------------------------
  10321. ; The four service subroutines for routines in the scannings function table
  10322. ;--------------------------------------------------------------------------
  10323. ; PRINT """Hooray!"" he cried."
  10324.  
  10325.                                         ;;;$250F
  10326. S_QUOTE_S:      CALL    CH_ADD_1        ; routine CH_ADD_1 points to next character
  10327.                                         ; and fetches that character.
  10328.                 INC     BC              ; increase length counter.
  10329.                 CP      $0D             ; is it carriage return ?
  10330.                                         ; inside a quote.
  10331.                 JP      Z,REPORT_C      ; jump back to REPORT_C if so.
  10332.                                         ; 'Nonsense in basic'.
  10333.                 CP      $22             ; is it a quote '"' ?
  10334.                 JR      NZ,S_QUOTE_S    ; back to S_QUOTE_S if not for more.
  10335.  
  10336.                 CALL    CH_ADD_1        ; routine CH_ADD_1
  10337.                 CP      $22             ; compare with possible adjacent quote
  10338.                 RET                     ; return. with zero set if two together.
  10339.  
  10340.                                         ; This subroutine is used to get two coordinate expressions for the three
  10341.                                         ; functions SCREEN$, ATTR and POINT that have two fixed parameters and
  10342.                                         ; therefore require surrounding braces.
  10343.  
  10344.                                         ;;;$2522
  10345. S_2_COORD:      RST     20H             ; NEXT_CHAR
  10346.                 CP      $28             ; is it the opening '(' ?
  10347.                 JR      NZ,S_RPORT_C    ; forward to S_RPORT_C if not
  10348.                                         ; 'Nonsense in Basic'.
  10349.                 CALL    NEXT_2NUM       ; routine NEXT_2NUM gets two comma-separated
  10350.                                         ; numeric expressions. Note. this could cause
  10351.                                         ; many more recursive calls to SCANNING but
  10352.                                         ; the parent function will be evaluated fully
  10353.                                         ; before rejoining the main juggling act.
  10354.                 RST     18H             ; GET_CHAR
  10355.                 CP      $29             ; is it the closing ')' ?
  10356.  
  10357.                                         ;; S_RPORT_C
  10358. S_RPORT_C:      JP      NZ,REPORT_C     ; jump back to REPORT_C if not.
  10359.                                         ; 'Nonsense in Basic'.
  10360.  
  10361. ;-------------
  10362. ; Check syntax
  10363. ;-------------
  10364. ; This routine is called on a number of occasions to check if syntax is being
  10365. ; checked or if the program is being run. To test the flag inline would use
  10366. ; four bytes of code, but a call instruction only uses 3 bytes of code.
  10367.  
  10368.                                         ;;;$2530
  10369. SYNTAX_Z:       BIT     7,(IY+$01)      ; test FLAGS  - checking syntax only ?
  10370.                 RET                     ; return.
  10371.  
  10372. ;-----------------
  10373. ; Scanning SCREEN$
  10374. ;-----------------
  10375. ; This function returns the code of a bit-mapped character at screen
  10376. ; position at line C, column B. It is unable to detect the mosaic characters
  10377. ; which are not bit-mapped but detects the ascii 32 - 127 range.
  10378. ; The bit-mapped UDGs are ignored which is curious as it requires only a
  10379. ; few extra bytes of code. As usual, anything to do with CHARS is weird.
  10380. ; If no match is found a null string is returned.
  10381. ; No actual check on ranges is performed - that's up to the Basic programmer.
  10382. ; No real harm can come from SCREEN$(255,255) although the Basic manual
  10383. ; says that invalid values will be trapped.
  10384. ; Interestingly, in the Pitman pocket guide, 1984, Vickers says that the
  10385. ; range checking will be performed.
  10386.  
  10387.                                         ;;;$2535
  10388. S_SCRN_S:       CALL    STK_TO_BC       ; routine STK_TO_BC.
  10389.                 LD      HL,(CHARS)      ; fetch address of CHARS.
  10390.                 LD      DE,$0100        ; fetch offset to CHR$ 32
  10391.                 ADD     HL,DE           ; and find start of bitmaps.
  10392.                                         ; Note. not inc h. ??
  10393.                 LD      A,C             ; transfer line to A.
  10394.                 RRCA                    ; multiply
  10395.                 RRCA                    ; by
  10396.                 RRCA                    ; thirty-two.
  10397.                 AND     $E0             ; and with 11100000
  10398.                 XOR     B               ; combine with column $00 - $1F
  10399.                 LD      E,A             ; to give the low byte of top line
  10400.                 LD      A,C             ; column to A range 00000000 to 00011111
  10401.                 AND     $18             ; and with 00011000
  10402.                 XOR     $40             ; xor with 01000000 (high byte screen start)
  10403.                 LD      D,A             ; register DE now holds start address of cell.
  10404.                 LD      B,$60           ; there are 96 characters in ascii set.
  10405.  
  10406.                                         ;;;$254F
  10407. S_SCRN_LP:      PUSH    BC              ; save count
  10408.                 PUSH    DE              ; save screen start address
  10409.                 PUSH    HL              ; save bitmap start
  10410.                 LD      A,(DE)          ; first byte of screen to A
  10411.                 XOR     (HL)            ; xor with corresponding character byte
  10412.                 JR      Z,S_SC_MTCH     ; forward to S_SC_MTCH if they match
  10413.                                         ; if inverse result would be $FF
  10414.                                         ; if any other then mismatch
  10415.                 INC     A               ; set to $00 if inverse
  10416.                 JR      NZ,S_SCR_NXT    ; forward to S_SCR_NXT if a mismatch
  10417.  
  10418.                 DEC     A               ; restore $FF
  10419.  
  10420.                                         ; a match has been found so seven more to test.
  10421.  
  10422.                                         ;;;$255A
  10423. S_SC_MTCH:      LD      C,A             ; load C with inverse mask $00 or $FF
  10424.                 LD      B,$07           ; count seven more bytes
  10425.  
  10426.                                         ;;;$255D
  10427. S_SC_ROWS:      INC     D               ; increment screen address.
  10428.                 INC     HL              ; increment bitmap address.
  10429.                 LD      A,(DE)          ; byte to A
  10430.                 XOR     (HL)            ; will give $00 or $FF (inverse)
  10431.                 XOR     C               ; xor with inverse mask
  10432.                 JR      NZ,S_SCR_NXT    ; forward to S_SCR_NXT if no match.
  10433.  
  10434.                 DJNZ    S_SC_ROWS       ; back to S_SC_ROWS until all eight matched.
  10435.  
  10436.                                         ; continue if a match of all eight bytes was found
  10437.  
  10438.                 POP     BC              ; discard the
  10439.                 POP     BC              ; saved
  10440.                 POP     BC              ; pointers
  10441.                 LD      A,$80           ; the endpoint of character set
  10442.                 SUB     B               ; subtract the counter
  10443.                                         ; to give the code 32-127
  10444.                 LD      BC,$0001        ; make one space in workspace.
  10445.                 RST     30H             ; BC_SPACES creates the space sliding
  10446.                                         ; the calculator stack upwards.
  10447.                 LD      (DE),A          ; start is addressed by DE, so insert code
  10448.                 JR      S_SCR_STO       ; forward to S_SCR_STO
  10449.  
  10450.                                         ; the jump was here if no match and more bitmaps to test.
  10451.  
  10452.                                         ;;;$2573
  10453. S_SCR_NXT:      POP     HL              ; restore the last bitmap start
  10454.                 LD      DE,$0008        ; and prepare to add 8.
  10455.                 ADD     HL,DE           ; now addresses next character bitmap.
  10456.                 POP     DE              ; restore screen address
  10457.                 POP     BC              ; and character counter in B
  10458.                 DJNZ    S_SCRN_LP       ; back to S_SCRN_LP if more characters.
  10459.                 LD      C,B             ; B is now zero, so BC now zero.
  10460.  
  10461.                                         ;;;$257D
  10462. S_SCR_STO:      JP      STK_STO_D       ; to STK_STO_D to store the string in
  10463.                                         ; workspace or a string with zero length.
  10464.                                         ; (value of DE doesn't matter in last case)
  10465.  
  10466.                                         ; Note. this exit seems correct but the general-purpose routine S_STRING
  10467.                                         ; that calls this one will also stack any of it's string results so this
  10468.                                         ; leads to a double storing of the result in this case.
  10469.                                         ; The instruction at S_SCR_STO should just be a RET.
  10470.                                         ; credit Stephen Kelly and others, 1982.
  10471.  
  10472. ;--------------
  10473. ; Scanning ATTR
  10474. ;--------------
  10475. ; This function subroutine returns the attributes of a screen location -
  10476. ; a numeric result.
  10477. ; Again it's up to the Basic programmer to supply valid values of line/column.
  10478.  
  10479.                                         ;;;$2580
  10480. S_ATTR_S:       CALL    STK_TO_BC       ; routine STK_TO_BC fetches line to C, and column to B.
  10481.                 LD      A,C             ; line to A $00 - $17   (max 00010111)
  10482.                 RRCA                    ; rotate
  10483.                 RRCA                    ; bits
  10484.                 RRCA                    ; left.
  10485.                 LD      C,A             ; store in C as an intermediate value.
  10486.                 AND     $E0             ; pick up bits 11100000 ( was 00011100 )
  10487.                 XOR     B               ; combine with column $00 - $1F
  10488.                 LD      L,A             ; low byte now correct.
  10489.                 LD      A,C             ; bring back intermediate result from C
  10490.                 AND     $03             ; mask to give correct third of
  10491.                                         ; screen $00 - $02
  10492.                 XOR     $58             ; combine with base address.
  10493.                 LD      H,A             ; high byte correct.
  10494.                 LD      A,(HL)          ; pick up the colour attribute.
  10495.                 JP      STACK_A         ; forward to STACK_A to store result
  10496.                                         ; and make an indirect exit.
  10497.  
  10498. ;------------------------
  10499. ; Scanning function table
  10500. ;------------------------
  10501. ; This table is used by INDEXER routine to find the offsets to
  10502. ; four operators and eight functions. e.g. $A8 is the token 'FN'.
  10503. ; This table is used in the first instance for the first character of an
  10504. ; expression or by a recursive call to SCANNING for the first character of
  10505. ; any sub-expression. It eliminates functions that have no argument or
  10506. ; functions that can have more than one argument and therefore require
  10507. ; braces. By eliminating and dealing with these now it can later take a
  10508. ; simplistic approach to all other functions and assume that they have
  10509. ; one argument.
  10510. ; Similarly by eliminating BIN and '.' now it is later able to assume that
  10511. ; all numbers begin with a digit and that the presence of a number or
  10512. ; variable can be detected by a call to ALPHANUM.
  10513. ; By default all expressions are positive and the spurious '+' is eliminated
  10514. ; now as in print +2. This should not be confused with the operator '+'.
  10515. ; Note. this does allow a degree of nonsense to be accepted as in
  10516. ; PRINT +"3 is the greatest.".
  10517. ; An acquired programming skill is the ability to include brackets where
  10518. ; they are not necessary.
  10519. ; A bracket at the start of a sub-expression may be spurious or necessary
  10520. ; to denote that the contained expression is to be evaluated as an entity.
  10521. ; In either case this is dealt with by recursive calls to SCANNING.
  10522. ; An expression that begins with a quote requires special treatment.
  10523.  
  10524.                                                 ;;;$2596
  10525. SCAN_FUNC:      DEFB    $22, S_QUOTE-$-1        ; $1C offset to S_QUOTE
  10526.                 DEFB    '(', S_BRACKET-$-1      ; $4F offset to S_BRACKET
  10527.                 DEFB    '.', S_DECIMAL-$-1      ; $F2 offset to S_DECIMAL
  10528.                 DEFB    '+', S_U_PLUS-$-1       ; $12 offset to S_U_PLUS
  10529.                 DEFB    $A8, S_FN-$-1           ; $56 offset to S_FN
  10530.                 DEFB    $A5, S_RND-$-1          ; $57 offset to S_RND
  10531.                 DEFB    $A7, S_PI-$-1           ; $84 offset to S_PI
  10532.                 DEFB    $A6, S_INKEY-$-1        ; $8F offset to S_INKEY
  10533.                 DEFB    $C4, S_BIN-$-1          ; $E6 offset to S_BIN
  10534.                 DEFB    $AA, S_SCREEN-$-1       ; $BF offset to S_SCREEN
  10535.                 DEFB    $AB, S_ATTR-$-1         ; $C7 offset to S_ATTR
  10536.                 DEFB    $A9, S_POINT-$-1        ; $CE offset to S_POINT
  10537.  
  10538.                 DEFB    $00                     ; zero end marker
  10539.  
  10540. ;---------------------------
  10541. ; Scanning function routines
  10542. ;---------------------------
  10543. ; These are the 11 subroutines accessed by the above table.
  10544. ; S_BIN and S_DECIMAL are the same
  10545. ; The 1-byte offset limits their location to within 255 bytes of their
  10546. ; entry in the table.
  10547.  
  10548.                                         ; ->
  10549.                                         ;;;$25AF
  10550. S_U_PLUS:       RST     20H             ; NEXT_CHAR just ignore
  10551.                 JP      S_LOOP_1        ; to S_LOOP_1
  10552.  
  10553.                                         ; ->
  10554.                                         ;;;$25B3
  10555. S_QUOTE:        RST     18H             ; GET_CHAR
  10556.                 INC     HL              ; address next character (first in quotes)
  10557.                 PUSH    HL              ; save start of quoted text.
  10558.                 LD      BC,$0000        ; initialize length of string to zero.
  10559.                 CALL    S_QUOTE_S       ; routine S_QUOTE_S
  10560.                 JR      NZ,S_Q_PRMS     ; forward to S_Q_PRMS if
  10561.  
  10562.                                         ;;;$25BE
  10563. S_Q_AGAIN:      CALL    S_QUOTE_S       ; routine S_QUOTE_S copies string until a
  10564.                                         ; quote is encountered
  10565.                 JR      Z,S_Q_AGAIN     ; back to S_Q_AGAIN if two quotes WERE
  10566.                                         ; together.
  10567.  
  10568.                                         ; but if just an isolated quote then that terminates the string.
  10569.  
  10570.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  10571.                 JR      Z,S_Q_PRMS      ; forward to S_Q_PRMS if checking syntax.
  10572.  
  10573.  
  10574.                 RST     30H             ; BC_SPACES creates the space for true
  10575.                                         ; copy of string in workspace.
  10576.                 POP     HL              ; re-fetch start of quoted text.
  10577.                 PUSH    DE              ; save start in workspace.
  10578.  
  10579.                                         ;;;$25CB
  10580. S_Q_COPY:       LD      A,(HL)          ; fetch a character from source.
  10581.                 INC     HL              ; advance source address.
  10582.                 LD      (DE),A          ; place in destination.
  10583.                 INC     DE              ; advance destination address.
  10584.                 CP      $22             ; was it a '"' just copied ?
  10585.                 JR      NZ,S_Q_COPY     ; back to S_Q_COPY to copy more if not
  10586.  
  10587.                 LD      A,(HL)          ; fetch adjacent character from source.
  10588.                 INC     HL              ; advance source address.
  10589.                 CP      $22             ; is this '"' ? - i.e. two quotes together ?
  10590.                 JR      Z,S_Q_COPY      ; to S_Q_COPY if so including just one of the
  10591.                                         ; pair of quotes.
  10592.  
  10593.                                         ; proceed when terminating quote encountered.
  10594.  
  10595.                                         ;;;$25D9
  10596. S_Q_PRMS:       DEC     BC              ; decrease count by 1.
  10597.                 POP     DE              ; restore start of string in workspace.
  10598.  
  10599.                                         ;;;$25DB
  10600. S_STRING:       LD      HL,FLAGS        ; Address FLAGS system variable.
  10601.                 RES     6,(HL)          ; signal string result.
  10602.                 BIT     7,(HL)          ; is syntax being checked.
  10603.                 CALL    NZ,STK_STO_D    ; routine STK_STO_D is called in runtime.
  10604.                 JP      S_CONT_2        ; jump forward to S_CONT_2              ===>
  10605.  
  10606.                                         ; ->
  10607.                                         ;;;$25E8
  10608. S_BRACKET:      RST     20H             ; NEXT_CHAR
  10609.                 CALL    SCANNING        ; routine SCANNING is called recursively.
  10610.                 CP      $29             ; is it the closing ')' ?
  10611.                 JP      NZ,REPORT_C     ; jump back to REPORT_C if not
  10612.                                         ; 'Nonsense in basic'
  10613.  
  10614.                 RST     20H             ; NEXT_CHAR
  10615.                 JP      S_CONT_2        ; jump forward to S_CONT_2              ===>
  10616.                                         ; ->
  10617.                                         ;;$25F5
  10618. S_FN:           JP      S_FN_SBRN       ; jump forward to S_FN_SBRN.
  10619.  
  10620.                                         ; ->
  10621.                                         ;;;$25F8
  10622. S_RND:          CALL    SYNTAX_Z        ; routine SYNTAX_Z
  10623.                 JR      Z,S_RND_END     ; forward to S_RND_END if checking syntax.
  10624.  
  10625.                 LD      BC,(SEED)       ; fetch system variable SEED
  10626.                 CALL    STACK_BC        ; routine STACK_BC places on calculator stack
  10627.                 RST     28H             ;; FP_CALC              ;s.
  10628.                 DEFB    $A1             ;;STK_ONE               ;s,1.
  10629.                 DEFB    $0F             ;;ADDITION              ;s+1.
  10630.                 DEFB    $34             ;;STK_DATA              ;
  10631.                 DEFB    $37             ;;Exponent: $87,
  10632.                                         ;;Bytes: 1
  10633.                 DEFB    $16             ;;(+00,+00,+00)         ;s+1,75.
  10634.                 DEFB    $04             ;;MULTIPLY              ;(s+1)*75 = v
  10635.                 DEFB    $34             ;;STK_DATA              ;v.
  10636.                 DEFB    $80             ;;Bytes: 3
  10637.                 DEFB    $41             ;;Exponent $91
  10638.                 DEFB    $00,$00,$80     ;;(+00)                 ;v,65537.
  10639.                 DEFB    $32             ;;N_MOD_M               ;remainder,result.
  10640.                 DEFB    $02             ;;DELETE                ;remainder.
  10641.                 DEFB    $A1             ;;STK_ONE               ;remainder,1.
  10642.                 DEFB    $03             ;;SUBTRACT              ;remainder - 1. = rnd
  10643.                 DEFB    $31             ;;DUPLICATE             ;rnd,rnd.
  10644.                 DEFB    $38             ;;END_CALC
  10645.  
  10646.                 CALL    FP_TO_BC        ; routine FP_TO_BC
  10647.                 LD      (SEED),BC       ; store in SEED for next starting point.
  10648.                 LD      A,(HL)          ; fetch exponent
  10649.                 AND     A               ; is it zero ?
  10650.                 JR      Z,S_RND_END     ; forward if so to S_RND_END
  10651.  
  10652.                 SUB     $10             ; reduce exponent by 2^16
  10653.                 LD      (HL),A          ; place back
  10654.  
  10655.                                         ;;;$2625
  10656. S_RND_END:      JR      S_PI_END        ; forward to S_PI_END
  10657.  
  10658.                                         ; the number PI 3.14159...
  10659.  
  10660.                                         ; ->
  10661.                                         ;;;$2627
  10662. S_PI:           CALL    SYNTAX_Z        ; routine SYNTAX_Z
  10663.                 JR      Z,S_PI_END      ; to S_PI_END if checking syntax.
  10664.  
  10665.                 RST     28H             ;; FP_CALC
  10666.                 DEFB    $A3             ;;STK_PI_2                              pi/2.
  10667.                 DEFB    $38             ;;END_CALC
  10668.  
  10669.                 INC     (HL)            ; increment the exponent leaving pi
  10670.                                         ; on the calculator stack.
  10671.  
  10672.                                         ;;;$2630
  10673. S_PI_END:       RST     20H             ; NEXT_CHAR
  10674.                 JP      S_NUMERIC       ; jump forward to S_NUMERIC
  10675.  
  10676.                                         ; ->
  10677.                                         ;;;$2634
  10678. S_INKEY:        LD      BC,$105A        ; priority $10, operation code $1A ('READ_IN')
  10679.                                         ; +$40 for string result, numeric operand.
  10680.                                         ; set this up now in case we need to use the calculator.
  10681.                 RST     20H             ; NEXT_CHAR
  10682.                 CP      $23             ; '#' ?
  10683.                 JP      Z,S_PUSH_PO     ; to S_PUSH_PO if so to use the calculator
  10684.                                         ; single operation
  10685.                                         ; to read from network/RS232 etc. .
  10686.  
  10687.                                         ; else read a key from the keyboard.
  10688.  
  10689.                 LD      HL,FLAGS        ; fetch FLAGS
  10690.                 RES     6,(HL)          ; signal string result.
  10691.                 BIT     7,(HL)          ; checking syntax ?
  10692.                 JR      Z,S_INK_EN      ; forward to S_INK_EN if so
  10693.  
  10694.                 CALL    KEY_SCAN        ; routine KEY_SCAN key in E, shift in D.
  10695.                 LD      C,$00           ; the length of an empty string
  10696.                 JR      NZ,S_IK_STK     ; to S_IK_STK to store empty string if no key returned.
  10697.  
  10698.                 CALL    K_TEST          ; routine K_TEST get main code in A
  10699.                 JR      NC,S_IK_STK     ; to S_IK_STK to stack null string if invalid
  10700.  
  10701.                 DEC     D               ; D is expected to be FLAGS so set bit 3 $FF
  10702.                                         ; 'L' Mode so no keywords.
  10703.                 LD      E,A             ; main key to A
  10704.                                         ; C is MODE 0 'KLC' from above still.
  10705.                 CALL    K_DECODE        ; routine K_DECODE
  10706.                 PUSH    AF              ; save the code
  10707.                 LD      BC,$0001        ; make room for one character
  10708.                 RST     30H             ; BC_SPACES
  10709.                 POP     AF              ; bring the code back
  10710.                 LD      (DE),A          ; put the key in workspace
  10711.                 LD      C,$01           ; set C length to one
  10712.  
  10713.                                         ;;;$2660
  10714. S_IK_STK:       LD      B,$00           ; set high byte of length to zero
  10715.                 CALL    STK_STO_D       ; routine STK_STO_D
  10716.  
  10717.                                         ;;;$2665
  10718. S_INK_EN:       JP      S_CONT_2        ; to S_CONT_2           ===>
  10719.  
  10720.                                         ; ->
  10721.                                         ;;;$2668
  10722. S_SCREEN:       CALL    S_2_COORD       ; routine S_2_COORD
  10723.                 CALL    NZ,S_SCRN_S     ; routine S_SCRN_S
  10724.                 RST     20H             ; NEXT_CHAR
  10725.                 JP      S_STRING        ; forward to S_STRING to stack result
  10726.  
  10727.                                         ; ->
  10728.                                         ;;;$2672
  10729. S_ATTR:         CALL    S_2_COORD       ; routine S_2_COORD
  10730.                 CALL    NZ,S_ATTR_S     ; routine S_ATTR_S
  10731.                 RST     20H             ; NEXT_CHAR
  10732.                 JR      S_NUMERIC       ; forward to S_NUMERIC
  10733.  
  10734.                                         ; ->
  10735.                                         ;;;$267B
  10736. S_POINT:        CALL    S_2_COORD       ; routine S_2_COORD
  10737.                 CALL    NZ,POINT_SUB    ; routine POINT_SUB
  10738.                 RST     20H             ; NEXT_CHAR
  10739.                 JR      S_NUMERIC       ; forward to S_NUMERIC
  10740.  
  10741.                                         ; ==> The branch was here if not in table.
  10742.  
  10743.                                         ;;;$2684
  10744. S_ALPHNUM:      CALL    ALPHANUM        ; routine ALPHANUM checks if variable or
  10745.                                         ; a digit.
  10746.                 JR      NC,S_NEGATE     ; forward to S_NEGATE if not to consider
  10747.                                         ; a '-' character then functions.
  10748.                 CP      $41             ; compare 'A'
  10749.                 JR      NC,S_LETTER     ; forward to S_LETTER if alpha  ->
  10750.                                         ; else must have been numeric so continue
  10751.                                         ; into that routine.
  10752.  
  10753.                                         ; This important routine is called during runtime and from LINE_SCAN
  10754.                                         ; when a BASIC line is checked for syntax. It is this routine that
  10755.                                         ; inserts, during syntax checking, the invisible floating point numbers
  10756.                                         ; after the numeric expression. During runtime it just picks these
  10757.                                         ; numbers up. It also handles BIN format numbers.
  10758.  
  10759.                                         ; ->
  10760.                                         ;;;$268D
  10761. S_DECIMAL:
  10762. S_BIN:          CALL    SYNTAX_Z        ; routine SYNTAX_Z
  10763.                 JR      NZ,S_STK_DEC    ; to S_STK_DEC in runtime
  10764.  
  10765.                                         ; this route is taken when checking syntax.
  10766.  
  10767.                 CALL    DEC_TO_FP       ; routine DEC_TO_FP to evaluate number
  10768.                 RST     18H             ; GET_CHAR to fetch HL
  10769.                 LD      BC,$0006        ; six locations required
  10770.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM
  10771.                 INC     HL              ; to first new location
  10772.                 LD      (HL),$0E        ; insert number marker
  10773.                 INC     HL              ; address next
  10774.                 EX      DE,HL           ; make DE destination.
  10775.                 LD      HL,(STKEND)     ; STKEND points to end of stack.
  10776.                 LD      C,$05           ; result is five locations lower
  10777.                 AND     A               ; prepare for true subtraction
  10778.                 SBC     HL,BC           ; point to start of value.
  10779.                 LD      (STKEND),HL     ; update STKEND as we are taking number.
  10780.                 LDIR                    ; Copy five bytes to program location
  10781.                 EX      DE,HL           ; transfer pointer to HL
  10782.                 DEC     HL              ; adjust
  10783.                 CALL    TEMP_PTR1       ; routine TEMP_PTR1 sets CH-ADD
  10784.                 JR      S_NUMERIC       ; to S_NUMERIC to record nature of result
  10785.  
  10786.                                         ; branch here in runtime.
  10787.  
  10788.                                         ;;;$26B5
  10789. S_STK_DEC:      RST     18H             ; GET_CHAR positions HL at digit.
  10790.  
  10791.                                         ;;;$26B6
  10792. S_SD_SKIP:      INC     HL              ; advance pointer
  10793.                 LD      A,(HL)          ; until we find
  10794.                 CP      $0E             ; chr 14d - the number indicator
  10795.                 JR      NZ,S_SD_SKIP    ; to S_SD_SKIP until a match it has to be here.
  10796.  
  10797.                 INC     HL              ; point to first byte of number
  10798.                 CALL    STACK_NUM       ; routine STACK_NUM stacks it
  10799.                 LD      (CH_ADD),HL     ; update system variable CH_ADD
  10800.  
  10801.                                         ;;;$26C3
  10802. S_NUMERIC:      SET     6,(IY+$01)      ; update FLAGS  - Signal numeric result
  10803.                 JR      S_CONT_1        ; forward to S_CONT_1                   ===>
  10804.                                         ; actually S_CONT_2 is destination but why
  10805.                                         ; waste a byte on a jump when a JR will do.
  10806.                                         ; actually a JR S_CONT_2 can be used. Rats.
  10807.  
  10808.                                         ; end of functions accessed from scanning functions table.
  10809.  
  10810. ;---------------------------
  10811. ; Scanning variable routines
  10812. ;---------------------------
  10813.  
  10814.                                         ;;;$26C9
  10815. S_LETTER:       CALL    LOOK_VARS       ; routine LOOK_VARS
  10816.                 JP      C,REPORT_2      ; jump back to REPORT_2 if not found
  10817.                                         ; 'Variable not found'
  10818.                                         ; but a variable is always 'found' if syntax
  10819.                                         ; is being checked.
  10820.  
  10821.                 CALL    Z,STK_VAR       ; routine STK_VAR considers a subscript/slice
  10822.                 LD      A,(FLAGS)       ; fetch FLAGS value
  10823.                 CP      $C0             ; compare 11000000
  10824.                 JR      C,S_CONT_1      ; step forward to S_CONT_1 if string    ===>
  10825.  
  10826.                 INC     HL              ; advance pointer
  10827.                 CALL    STACK_NUM       ; routine STACK_NUM
  10828.  
  10829.                                         ;;;$26DD
  10830. S_CONT_1:       JR      S_CONT_2        ; forward to S_CONT_2                   ===>
  10831.  
  10832.                                         ;-----------------------------------------
  10833.                                         ; -> the scanning branch was here if not alphanumeric.
  10834.                                         ; All the remaining functions will be evaluated by a single call to the
  10835.                                         ; calculator. The correct priority for the operation has to be placed in
  10836.                                         ; the B register and the operation code, calculator literal in the C register.
  10837.                                         ; the operation code has bit 7 set if result is numeric and bit 6 is
  10838.                                         ; set if operand is numeric. so
  10839.                                         ; $C0 = numeric result, numeric operand.        e.g. 'SIN'
  10840.                                         ; $80 = numeric result, string operand.         e.g. 'CODE'
  10841.                                         ; $40 = string result, numeric operand.         e.g. 'STR$'
  10842.                                         ; $00 = string result, string operand.          e.g. 'VAL$'
  10843.  
  10844.                                         ;;;$26DF
  10845. S_NEGATE:       LD      BC,$09DB        ; prepare priority 09, operation code $C0 +
  10846.                                         ; 'NEGATE' ($1B) - bits 6 and 7 set for numeric
  10847.                                         ; result and numeric operand.
  10848.  
  10849.                 CP      $2D             ; is it '-' ?
  10850.                 JR      Z,S_PUSH_PO     ; forward if so to S_PUSH_PO
  10851.  
  10852.                 LD      BC,$1018        ; prepare priority $10, operation code 'VAL$' -
  10853.                                         ; bits 6 and 7 reset for string result and  string operand.
  10854.                 CP      $AE             ; is it 'VAL$' ?
  10855.                 JR      Z,S_PUSH_PO     ; forward if so to S_PUSH_PO
  10856.  
  10857.                 SUB     $AF             ; subtract token 'CODE' value to reduce
  10858.                                         ; functions 'CODE' to 'NOT' although the
  10859.                                         ; upper range is, as yet, unchecked.
  10860.                                         ; valid range would be $00 - $14.
  10861.                 JP      C,REPORT_C      ; jump back to REPORT_C with anything else
  10862.                                         ; 'Nonsense in Basic'
  10863.                 LD      BC,$04F0        ; prepare priority $04, operation $C0 +
  10864.                                         ; 'not' ($30)
  10865.                 CP      $14             ; is it 'NOT'
  10866.                 JR      Z,S_PUSH_PO     ; forward to S_PUSH_PO if so
  10867.  
  10868.                 JP      NC,REPORT_C     ; to REPORT_C if higher
  10869.                                         ; 'Nonsense in Basic'
  10870.                 LD      B,$10           ; priority $10 for all the rest
  10871.                 ADD     A,$DC           ; make range $DC - $EF
  10872.                                         ; $C0 + 'CODE'($1C) thru 'CHR$' ($2F)
  10873.                 LD      C,A             ; transfer 'function' to C
  10874.                 CP      $DF             ; is it 'SIN' ?
  10875.                 JR      NC,S_NO_TO      ; forward to S_NO_TO  with 'SIN' through
  10876.                                         ; 'CHR$' as operand is numeric.
  10877.  
  10878.                                         ; all the rest 'COS' through 'CHR$' give a numeric result except 'STR$'
  10879.                                         ; and 'CHR$'.
  10880.  
  10881.                 RES     6,C             ; signal string operand for 'CODE', 'VAL' and
  10882.                                         ; 'LEN'.
  10883.  
  10884.                                         ;;;$2707
  10885. S_NO_TO:        CP      $EE             ; compare 'STR$'
  10886.                 JR      C,S_PUSH_PO     ; forward to S_PUSH_PO if lower as result
  10887.                                         ; is numeric.
  10888.                 RES     7,C             ; reset bit 7 of op code for 'STR$', 'CHR$'
  10889.                                         ; as result is string.
  10890.  
  10891.                                         ; >> This is where they were all headed for.
  10892.  
  10893.                                         ;;;$270D
  10894. S_PUSH_PO:      PUSH    BC              ; push the priority and calculator operation code.
  10895.                 RST     20H             ; NEXT_CHAR
  10896.                 JP      S_LOOP_1        ; jump back to S_LOOP_1 to go round the loop
  10897.                                         ; again with the next character.
  10898.  
  10899.                                         ; ===>  there were many branches forward to here
  10900.  
  10901.                                         ;;;$2712
  10902. S_CONT_2:       RST     18H             ; GET_CHAR
  10903.  
  10904.                                         ;;;$2713
  10905. S_CONT_3:       CP      $28             ; is it '(' ?
  10906.                 JR      NZ,S_OPERTR     ; forward to S_OPERTR if not    >
  10907.  
  10908.                 BIT     6,(IY+$01)      ; test FLAGS - numeric or string result ?
  10909.                 JR      NZ,S_LOOP       ; forward to S_LOOP if numeric to evaluate  >
  10910.  
  10911.                                         ; if a string preceded '(' then slice it.
  10912.  
  10913.                 CALL    SLICING         ; routine SLICING
  10914.                 RST     20H             ; NEXT_CHAR
  10915.                 JR      S_CONT_3        ; back to S_CONT_3
  10916.  
  10917.  
  10918.                                         ; the branch was here when possibility of an operator '(' has been excluded.
  10919.  
  10920.                                         ;;;$2723
  10921. S_OPERTR:       LD      B,$00           ; prepare to add
  10922.                 LD      C,A             ; possible operator to C
  10923.                 LD      HL,TBL_OF_OPS   ; Address: TBL_OF_OPS
  10924.                 CALL    INDEXER         ; routine INDEXER
  10925.                 JR      NC,S_LOOP       ; forward to S_LOOP if not in table
  10926.  
  10927.                                         ; but if found in table the priority has to be looked up.
  10928.  
  10929.                 LD      C,(HL)          ; operation code to C ( B is still zero )
  10930.                 LD      HL,TBL_PRIORS-$C3 ; $26ED is base of table
  10931.                 ADD     HL,BC           ; index into table.
  10932.                 LD      B,(HL)          ; priority to B.
  10933.  
  10934. ;-------------------
  10935. ; Scanning main loop
  10936. ;-------------------
  10937. ; the juggling act
  10938.  
  10939.                                         ;;;$2734
  10940. S_LOOP:         POP     DE              ; fetch last priority and operation
  10941.                 LD      A,D             ; priority to A
  10942.                 CP      B               ; compare with this one
  10943.                 JR      C,S_TIGHTER     ; forward to S_TIGHTER to execute the
  10944.                                         ; last operation before this one as it has
  10945.                                         ; higher priority.
  10946.  
  10947.                                         ; the last priority was greater or equal this one.
  10948.  
  10949.                 AND     A               ; if it is zero then so is this
  10950.                 JP      Z,GET_CHAR      ; jump to exit via GET_CHAR pointing at
  10951.                                         ; next character.
  10952.                                         ; This may be the character after the
  10953.                                         ; expression or, if exiting a recursive call,
  10954.                                         ; the next part of the expression to be
  10955.                                         ; evaluated.
  10956.                 PUSH    BC              ; save current priority/operation
  10957.                                         ; as it has lower precedence than the one
  10958.                                         ; now in DE.
  10959.  
  10960.                                         ; the 'USR' function is special in that it is overloaded to give two types
  10961.                                         ; of result.
  10962.  
  10963.                 LD      HL,FLAGS        ; address FLAGS
  10964.                 LD      A,E             ; new operation to A register
  10965.                 CP      $ED             ; is it $C0 + 'USR_NO' ($2D)  ?
  10966.                 JR      NZ,S_STK_LST    ; forward to S_STK_LST if not
  10967.  
  10968.                 BIT     6,(HL)          ; string result expected ?
  10969.                                         ; (from the lower priority operand we've
  10970.                                         ; just pushed on stack )
  10971.                 JR      NZ,S_STK_LST    ; forward to S_STK_LST if numeric
  10972.                                         ; as operand bits match.
  10973.                 LD      E,$99           ; reset bit 6 and substitute $19 'USR-$'
  10974.                                         ; for string operand.
  10975.  
  10976.                                         ;;;$274C
  10977. S_STK_LST:      PUSH    DE              ; now stack this priority/operation
  10978.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  10979.                 JR      Z,S_SYNTEST     ; forward to S_SYNTEST if checking syntax.
  10980.  
  10981.                 LD      A,E             ; fetch the operation code
  10982.                 AND     $3F             ; mask off the result/operand bits to leave a calculator literal.
  10983.                 LD      B,A             ; transfer to B register
  10984.  
  10985.                                         ; now use the calculator to perform the single operation - operand is on
  10986.                                         ; the calculator stack.
  10987.                                         ; Note. although the calculator is performing a single operation most
  10988.                                         ; functions e.g. TAN are written using other functions and literals and
  10989.                                         ; these in turn are written using further strings of calculator literals so
  10990.                                         ; another level of magical recursion joins the juggling act for a while
  10991.                                         ; as the calculator too is calling itself.
  10992.  
  10993.                 RST     28H             ;; FP_CALC
  10994.                 DEFB    $3B             ;;FP_CALC_2
  10995.  
  10996.                                         ;;;$2758
  10997.                 DEFB    $38             ;;END_CALC
  10998.  
  10999.                 JR      S_RUNTEST       ; forward to S_RUNTEST
  11000.  
  11001.                                         ; the branch was here if checking syntax only.
  11002.  
  11003.                                         ;;;$275B
  11004. S_SYNTEST:      LD      A,E             ; fetch the operation code to accumulator
  11005.                 XOR     (IY+$01)        ; compare with bits of FLAGS
  11006.                 AND     $40             ; bit 6 will be zero now if operand
  11007.                                         ; matched expected result.
  11008.  
  11009.                                         ;;;$2761
  11010. S_RPORT_C2:     JP      NZ,REPORT_C     ; to REPORT_C if mismatch
  11011.                                         ; 'Nonsense in Basic'
  11012.                                         ; else continue to set flags for next
  11013.  
  11014.                                         ; the branch is to here in runtime after a successful operation.
  11015.  
  11016.                                         ;;;$2764
  11017. S_RUNTEST:      POP     DE              ; fetch the last operation from stack
  11018.                 LD      HL,FLAGS        ; address FLAGS
  11019.                 SET     6,(HL)          ; set default to numeric result in FLAGS
  11020.                 BIT     7,E             ; test the operational result
  11021.                 JR      NZ,S_LOOPEND    ; forward to S_LOOPEND if numeric
  11022.  
  11023.                 RES     6,(HL)          ; reset bit 6 of FLAGS to show string result.
  11024.  
  11025.                                         ;;;$2770
  11026. S_LOOPEND:      POP     BC              ; fetch the previous priority/operation
  11027.                 JR      S_LOOP          ; back to S_LOOP to perform these
  11028.  
  11029.                                         ; the branch was here when a stacked priority/operator had higher priority
  11030.                                         ; than the current one.
  11031.  
  11032.                                         ;;;$2773
  11033. S_TIGHTER:      PUSH    DE              ; save high priority op on stack again
  11034.                 LD      A,C             ; fetch lower priority operation code
  11035.                 BIT     6,(IY+$01)      ; test FLAGS - Numeric or string result ?
  11036.                 JR      NZ,S_NEXT       ; forward to S_NEXT if numeric result
  11037.  
  11038.                                         ; if this is lower priority yet has string then must be a comparison.
  11039.                                         ; Since these can only be evaluated in context and were defaulted to
  11040.                                         ; numeric in operator look up they must be changed to string equivalents.
  11041.  
  11042.                 AND     $3F             ; mask to give true calculator literal
  11043.                 ADD     A,$08           ; augment numeric literals to string
  11044.                                         ; equivalents.
  11045.                                         ; 'NO_AND_NO' => 'STR_AND_NO'
  11046.                                         ; 'NO_L_EQL'  => 'STR_L_EQL'
  11047.                                         ; 'NO_GR_EQL' => 'STR_GR_EQL'
  11048.                                         ; 'NOS_NEQL'  => 'STRS_NEQL'
  11049.                                         ; 'NO_GRTR'   => 'STR_GRTR'
  11050.                                         ; 'NO_LESS'   => 'STR_LESS'
  11051.                                         ; 'NOS_EQL'   => 'STRS_EQL'
  11052.                                         ; 'ADDITION'  => 'STRS_ADD'
  11053.                 LD      C,A             ; put modified comparison operator back
  11054.                 CP      $10             ; is it now 'STR_AND_NO' ?
  11055.                 JR      NZ,S_NOT_AND    ; forward to S_NOT_AND  if not.
  11056.  
  11057.                 SET     6,C             ; set numeric operand bit
  11058.                 JR      S_NEXT          ; forward to S_NEXT
  11059.  
  11060.                                         ;;;$2788
  11061. S_NOT_AND:      JR      C,S_RPORT_C2    ; back to S_RPORT_C2 if less
  11062.                                         ; 'Nonsense in basic'.
  11063.                                         ; e.g. a$ * b$
  11064.                 CP      $17             ; is it 'STRS_ADD' ?
  11065.                 JR      Z,S_NEXT        ; forward to to S_NEXT if so
  11066.                                         ; (bit 6 and 7 are reset)
  11067.                 SET     7,C             ; set numeric (Boolean) result for all others
  11068.  
  11069.                                         ;;;$2790
  11070. S_NEXT:         PUSH    BC              ; now save this priority/operation on stack
  11071.                 RST     20H             ; NEXT_CHAR
  11072.                 JP      S_LOOP_1        ; jump back to S_LOOP_1
  11073.  
  11074. ;-------------------
  11075. ; Table of operators
  11076. ;-------------------
  11077. ; This table is used to look up the calculator literals associated with
  11078. ; the operator character. The thirteen calculator operations $03 - $0F
  11079. ; have bits 6 and 7 set to signify a numeric result.
  11080. ; Some of these codes and bits may be altered later if the context suggests
  11081. ; a string comparison or operation.
  11082. ; that is '+', '=', '>', '<', '<=', '>=' or '<>'.
  11083.  
  11084.                                         ;;;$2795
  11085. TBL_OF_OPS:     DEFB    '+', $CF        ;       $C0 + 'ADDITION'
  11086.                 DEFB    '-', $C3        ;       $C0 + 'SUBTRACT'
  11087.                 DEFB    '*', $C4        ;       $C0 + 'MULTIPLY'
  11088.                 DEFB    '/', $C5        ;       $C0 + 'DIVISION'
  11089.                 DEFB    '^', $C6        ;       $C0 + 'TO_POWER'
  11090.                 DEFB    '=', $CE        ;       $C0 + 'NOS_EQL'
  11091.                 DEFB    '>', $CC        ;       $C0 + 'NO_GRTR'
  11092.                 DEFB    '<', $CD        ;       $C0 + 'NO_LESS'
  11093.                 DEFB    $C7, $C9        ; '<='  $C0 + 'NO_L_EQL'
  11094.                 DEFB    $C8, $CA        ; '>='  $C0 + 'NO_GR_EQL'
  11095.                 DEFB    $C9, $CB        ; '<>'  $C0 + 'NOS_NEQL'
  11096.                 DEFB    $C5, $C7        ; 'OR'  $C0 + 'OR'
  11097.                 DEFB    $C6, $C8        ; 'AND' $C0 + 'NO_AND_NO'
  11098.  
  11099.                 DEFB    $00             ; zero end-marker.
  11100.  
  11101.  
  11102. ;--------------------
  11103. ; Table of priorities
  11104. ;--------------------
  11105. ; This table is indexed with the operation code obtained from the above
  11106. ; table $C3 - $CF to obtain the priority for the respective operation.
  11107.  
  11108.                                         ;;;$27B0
  11109. TBL_PRIORS:     DEFB    $06             ; '-'   opcode $C3
  11110.                 DEFB    $08             ; '*'   opcode $C4
  11111.                 DEFB    $08             ; '/'   opcode $C5
  11112.                 DEFB    $0A             ; '^'   opcode $C6
  11113.                 DEFB    $02             ; 'OR'  opcode $C7
  11114.                 DEFB    $03             ; 'AND' opcode $C8
  11115.                 DEFB    $05             ; '<='  opcode $C9
  11116.                 DEFB    $05             ; '>='  opcode $CA
  11117.                 DEFB    $05             ; '<>'  opcode $CB
  11118.                 DEFB    $05             ; '>'   opcode $CC
  11119.                 DEFB    $05             ; '<'   opcode $CD
  11120.                 DEFB    $05             ; '='   opcode $CE
  11121.                 DEFB    $06             ; '+'   opcode $CF
  11122.  
  11123. ;-----------------------
  11124. ; Scanning function (FN)
  11125. ;-----------------------
  11126. ; This routine deals with user-defined functions.
  11127. ; The definition can be anywhere in the program area but these are best
  11128. ; placed near the start of the program as we shall see.
  11129. ; The evaluation process is quite complex as the Spectrum has to parse two
  11130. ; statements at the same time. Syntax of both has been checked previously
  11131. ; and hidden locations have been created immediately after each argument
  11132. ; of the DEF FN statement. Each of the arguments of the FN function is
  11133. ; evaluated by SCANNING and placed in the hidden locations. Then the
  11134. ; expression to the right of the DEF FN '=' is evaluated by SCANNING and for
  11135. ; any variables encountered, a search is made in the DEF FN variable list
  11136. ; in the program area before searching in the normal variables area.
  11137. ;
  11138. ; Recursion is not allowed: i.e. the definition of a function should not use
  11139. ; the same function, either directly or indirectly ( through another function).
  11140. ; You'll normally get error 4, ('Out of memory'), although sometimes the sytem
  11141. ; will crash. - Vickers, Pitman 1984.
  11142. ;
  11143. ; As the definition is just an expression, there would seem to be no means
  11144. ; of breaking out of such recursion.
  11145. ; However, by the clever use of string expressions and VAL, such recursion is
  11146. ; possible.
  11147. ; e.g. DEF FN a(n) = VAL "n+FN a(n-1)+0" ((n<1) * 10 + 1 TO )
  11148. ; will evaluate the full 11-character expression for all values where n is
  11149. ; greater than zero but just the 11th character, "0", when n drops to zero
  11150. ; thereby ending the recursion producing the correct result.
  11151. ; Recursive string functions are possible using VAL$ instead of VAL and the
  11152. ; null string as the final addend.
  11153. ; - from a turn of the century newsgroup discussion initiated by Mike Wynne.
  11154.  
  11155.                                         ;;;$27BD
  11156. S_FN_SBRN:      CALL    SYNTAX_Z        ; routine SYNTAX_Z
  11157.                 JR      NZ,SF_RUN       ; forward to SF_RUN in runtime
  11158.  
  11159.                 RST     20H             ; NEXT_CHAR
  11160.                 CALL    ALPHA           ; routine ALPHA check for letters A-Z a-z
  11161.                 JP      NC,REPORT_C     ; jump back to REPORT_C if not
  11162.                                         ; 'Nonsense in Basic'
  11163.                 RST     20H             ; NEXT_CHAR
  11164.                 CP      $24             ; is it '$' ?
  11165.                 PUSH    AF              ; save character and flags
  11166.                 JR      NZ,SF_BRKT_1    ; forward to SF_BRKT_1 with numeric function
  11167.  
  11168.                 RST     20H             ; NEXT_CHAR
  11169.  
  11170.                                         ;;;$27D0
  11171. SF_BRKT_1:      CP      $28             ; is '(' ?
  11172.                 JR      NZ,SF_RPRT_C    ; forward to SF_RPRT_C if not
  11173.                                         ; 'Nonsense in Basic'
  11174.                 RST     20H             ; NEXT_CHAR
  11175.                 CP      $29             ; is it ')' ?
  11176.                 JR      Z,SF_FLAG_6     ; forward to SF_FLAG_6 if no arguments.
  11177.  
  11178.                                         ;;;$27D9
  11179. SF_ARGMTS:      CALL    SCANNING        ; routine SCANNING checks each argument
  11180.                                         ; which may be an expression.
  11181.                 RST     18H             ; GET_CHAR
  11182.                 CP      $2C             ; is it a ',' ?
  11183.                 JR      NZ,SF_BRKT_2    ; forward if not to SF_BRKT_2 to test bracket
  11184.  
  11185.                 RST     20H             ; NEXT_CHAR if a comma was found
  11186.                 JR      SF_ARGMTS       ; back to SF_ARGMTS to parse all arguments.
  11187.  
  11188.                                         ;;;$27E4
  11189. SF_BRKT_2:      CP      $29             ; is character the closing ')' ?
  11190.  
  11191.                                         ;;;$27E6
  11192. SF_RPRT_C:      JP      NZ,REPORT_C     ; jump to REPORT_C
  11193.                                         ; 'Nonsense in Basic'
  11194.  
  11195.                                         ; at this point any optional arguments have had their syntax checked.
  11196.  
  11197.                                         ;;;$27E9
  11198. SF_FLAG_6:      RST     20H             ; NEXT_CHAR
  11199.                 LD      HL,FLAGS        ; address system variable FLAGS
  11200.                 RES     6,(HL)          ; signal string result
  11201.                 POP     AF              ; restore test against '$'.
  11202.                 JR      Z,SF_SYN_EN     ; forward to SF_SYN_EN if string function.
  11203.  
  11204.                 SET     6,(HL)          ; signal numeric result
  11205.  
  11206.                                         ;;;$27F4
  11207. SF_SYN_EN:      JP      S_CONT_2        ; jump back to S_CONT_2 to continue scanning.
  11208.  
  11209.                                         ; the branch was here in runtime.
  11210.  
  11211.                                         ;;;$27F7
  11212. SF_RUN:         RST     20H             ; NEXT_CHAR fetches name
  11213.                 AND     $DF             ; AND 11101111 - reset bit 5 - upper-case.
  11214.                 LD      B,A             ; save in B
  11215.                 RST     20H             ; NEXT_CHAR
  11216.                 SUB     $24             ; subtract '$'
  11217.                 LD      C,A             ; save result in C
  11218.                 JR      NZ,SF_ARGMT1    ; forward if not '$' to SF_ARGMT1
  11219.  
  11220.                 RST     20H             ; NEXT_CHAR advances to bracket
  11221.  
  11222.                                         ;;;$2802
  11223. SF_ARGMT1:      RST     20H             ; NEXT_CHAR advances to start of argument
  11224.                 PUSH    HL              ; save address
  11225.                 LD      HL,(PROG)       ; fetch start of program area from PROG
  11226.                 DEC     HL              ; the search starting point is the previous
  11227.                                         ; location.
  11228.  
  11229.                                         ;;;$2808
  11230. SF_FND_DF:      LD      DE,$00CE        ; search is for token 'DEF FN' in E, statement count in D.
  11231.                 PUSH    BC              ; save C the string test, and B the letter.
  11232.                 CALL    LOOK_PROG       ; routine LOOK_PROG will search for token.
  11233.                 POP     BC              ; restore BC.
  11234.                 JR      NC,SF_CP_DEF    ; forward to SF_CP_DEF if a match was found.
  11235.  
  11236.                                         ;;;$2812
  11237. REPORT_P:       RST     08H             ; ERROR_1
  11238.                 DEFB    $18             ; Error Report: FN without DEF
  11239.  
  11240.                                         ;;;$2814
  11241. SF_CP_DEF:      PUSH    HL              ; save address of DEF FN
  11242.                 CALL    FN_SKPOVR       ; routine FN_SKPOVR skips over white-space etc.
  11243.                                         ; without disturbing CH-ADD.
  11244.                 AND     $DF             ; make fetched character upper-case.
  11245.                 CP      B               ; compare with FN name
  11246.                 JR      NZ,SF_NOT_FD    ; forward to SF_NOT_FD if no match.
  11247.  
  11248.                                         ; the letters match so test the type.
  11249.  
  11250.                 CALL    FN_SKPOVR       ; routine FN_SKPOVR skips white-space
  11251.                 SUB     $24             ; subtract '$' from fetched character
  11252.                 CP      C               ; compare with saved result of same operation on FN name.
  11253.                 JR      Z,SF_VALUES     ; forward to SF_VALUES with a match.
  11254.  
  11255.                                         ; the letters matched but one was string and the other numeric.
  11256.  
  11257.                                         ;;;$2825
  11258. SF_NOT_FD:      POP     HL              ; restore search point.
  11259.                 DEC     HL              ; make location before
  11260.                 LD      DE,$0200        ; the search is to be for the end of the
  11261.                                         ; current definition - 2 statements forward.
  11262.                 PUSH    BC              ; save the letter/type
  11263.                 CALL    EACH_STMT       ; routine EACH_STMT steps past rejected definition.
  11264.                 POP     BC              ; restore letter/type
  11265.                 JR      SF_FND_DF       ; back to SF_FND_DF to continue search
  11266.  
  11267.                                         ; Success!
  11268.                                         ; the branch was here with matching letter and numeric/string type.
  11269.  
  11270.                                         ;;;$2831
  11271. SF_VALUES:      AND     A               ; test A ( will be zero if string '$' - '$' )
  11272.                 CALL    Z,FN_SKPOVR     ; routine FN_SKPOVR advances HL past '$'.
  11273.                 POP     DE              ; discard pointer to 'DEF FN'.
  11274.                 POP     DE              ; restore pointer to first FN argument.
  11275.                 LD      (CH_ADD),DE     ; save in CH_ADD
  11276.                 CALL    FN_SKPOVR       ; routine FN_SKPOVR advances HL past '('
  11277.                 PUSH    HL              ; save start address in DEF FN  ***
  11278.                 CP      $29             ; is character a ')' ?
  11279.                 JR      Z,SF_R_BR_2     ; forward to SF_R_BR_2 if no arguments.
  11280.  
  11281.                                         ;;;$2843
  11282. SF_ARG_LP:      INC     HL              ; point to next character.
  11283.                 LD      A,(HL)          ; fetch it.
  11284.                 CP      $0E             ; is it the number marker
  11285.                 LD      D,$40           ; signal numeric in D.
  11286.                 JR      Z,SF_ARG_VL     ; forward to SF_ARG_VL if numeric.
  11287.  
  11288.                 DEC     HL              ; back to letter
  11289.                 CALL    FN_SKPOVR       ; routine FN_SKPOVR skips any white-space
  11290.                 INC     HL              ; advance past the expected '$' to the 'hidden' marker.
  11291.                 LD      D,$00           ; signal string.
  11292.  
  11293.                                         ;;;$2852
  11294. SF_ARG_VL:      INC     HL              ; now address first of 5-byte location.
  11295.                 PUSH    HL              ; save address in DEF FN statement
  11296.                 PUSH    DE              ; save D - result type
  11297.                 CALL    SCANNING        ; routine SCANNING evaluates expression in
  11298.                                         ; the FN statement setting FLAGS and leaving
  11299.                                         ; result as last value on calculator stack.
  11300.                 POP     AF              ; restore saved result type to A
  11301.                 XOR     (IY+$01)        ; xor with FLAGS
  11302.                 AND     $40             ; and with 01000000 to test bit 6
  11303.                 JR      NZ,REPORT_Q     ; forward to REPORT_Q if type mismatch.
  11304.                                         ; 'Parameter error'
  11305.                 POP     HL              ; pop the start address in DEF FN statement
  11306.                 EX      DE,HL           ; transfer to DE ?? pop straight into de ?
  11307.                 LD      HL,(STKEND)     ; set HL to STKEND location after value
  11308.                 LD      BC,$0005        ; five bytes to move
  11309.                 SBC     HL,BC           ; decrease HL by 5 to point to start.
  11310.                 LD      (STKEND),HL     ; set STKEND 'removing' value from stack.
  11311.                 LDIR                    ; copy value into DEF FN statement
  11312.                 EX      DE,HL           ; set HL to location after value in DEF FN
  11313.                 DEC     HL              ; step back one
  11314.                 CALL    FN_SKPOVR       ; routine FN_SKPOVR gets next valid character
  11315.                 CP      $29             ; is it ')' end of arguments ?
  11316.                 JR      Z,SF_R_BR_2     ; forward to SF_R_BR_2 if so.
  11317.  
  11318.                                         ; a comma separator has been encountered in the DEF FN argument list.
  11319.  
  11320.                 PUSH    HL              ; save position in DEF FN statement
  11321.                 RST     18H             ; GET_CHAR from FN statement
  11322.                 CP      $2C             ; is it ',' ?
  11323.                 JR      NZ,REPORT_Q     ; forward to REPORT_Q if not
  11324.                                         ; 'Parameter error'
  11325.                 RST     20H             ; NEXT_CHAR in FN statement advances to next
  11326.                                         ; argument.
  11327.                 POP     HL              ; restore DEF FN pointer
  11328.                 CALL    FN_SKPOVR       ; routine FN_SKPOVR advances to corresponding
  11329.                                         ; argument.
  11330.                 JR      SF_ARG_LP       ; back to SF_ARG_LP looping until all
  11331.                                         ; arguments are passed into the DEF FN
  11332.                                         ; hidden locations.
  11333.  
  11334.                                         ; the branch was here when all arguments passed.
  11335.  
  11336.                                         ;;;$2885
  11337. SF_R_BR_2:      PUSH    HL              ; save location of ')' in DEF FN
  11338.                 RST     18H             ; GET_CHAR gets next character in FN
  11339.                 CP      $29             ; is it a ')' also ?
  11340.                 JR      Z,SF_VALUE      ; forward to SF_VALUE if so.
  11341.  
  11342.                                         ;;;$288B
  11343. REPORT_Q:       RST     08H             ; ERROR_1
  11344.                 DEFB    $19             ; Error Report: Parameter error
  11345.  
  11346.                                         ;;;$288D
  11347. SF_VALUE:       POP     DE              ; location of ')' in DEF FN to DE.
  11348.                 EX      DE,HL           ; now to HL, FN ')' pointer to DE.
  11349.                 LD      (CH_ADD),HL     ; initialize CH_ADD to this value.
  11350.  
  11351.                                         ; At this point the start of the DEF FN argument list is on the machine stack.
  11352.                                         ; We also have to consider that this defined function may form part of the
  11353.                                         ; definition of another defined function (though not itself).
  11354.                                         ; As this defined function may be part of a hierarchy of defined functions
  11355.                                         ; currently being evaluated by recursive calls to SCANNING, then we have to
  11356.                                         ; preserve the original value of DEFADD and not assume that it is zero.
  11357.  
  11358.                 LD      HL,(DEFADD)     ; get original DEFADD address
  11359.                 EX      (SP),HL         ; swap with DEF FN address on stack ***
  11360.                 LD      (DEFADD),HL     ; set DEFADD to point to this argument list
  11361.                                         ; during scanning.
  11362.                 PUSH    DE              ; save FN ')' pointer.
  11363.                 RST     20H             ; NEXT_CHAR advances past ')' in define
  11364.                 RST     20H             ; NEXT_CHAR advances past '=' to expression
  11365.                 CALL    SCANNING        ; routine SCANNING evaluates but searches
  11366.                                         ; initially for variables at DEFADD
  11367.                 POP     HL              ; pop the FN ')' pointer
  11368.                 LD      (CH_ADD),HL     ; set CH_ADD to this
  11369.                 POP     HL              ; pop the original DEFADD value
  11370.                 LD      (DEFADD),HL     ; and re-insert into DEFADD system variable.
  11371.  
  11372.                 RST     20H             ; NEXT_CHAR advances to character after ')'
  11373.                 JP      S_CONT_2        ; to S_CONT_2 - to continue current
  11374.                                         ; invocation of scanning
  11375.  
  11376. ;---------------------
  11377. ; Used to parse DEF FN
  11378. ;---------------------
  11379. ; e.g. DEF FN     s $ ( x )     =  b     $ (  TO  x  ) : REM exaggerated
  11380. ;
  11381. ; This routine is used 10 times to advance along a DEF FN statement
  11382. ; skipping spaces and colour control codes. It is similar to NEXT-CHAR
  11383. ; which is, at the same time, used to skip along the corresponding FN function
  11384. ; except the latter has to deal with AT and TAB characters in string
  11385. ; expressions. These cannot occur in a program area so this routine is
  11386. ; simpler as both colour controls and their parameters are less than space.
  11387.  
  11388.                                         ;;;$28AB
  11389. FN_SKPOVR:      INC     HL              ; increase pointer
  11390.                 LD      A,(HL)          ; fetch addressed character
  11391.                 CP      $21             ; compare with space + 1
  11392.                 JR      C,FN_SKPOVR     ; back to FN_SKPOVR if less
  11393.  
  11394.                 RET                     ; return pointing to a valid character.
  11395.  
  11396. ;----------
  11397. ; LOOK_VARS
  11398. ;----------
  11399.  
  11400.                                         ;;;$28B2
  11401. LOOK_VARS:      SET     6,(IY+$01)      ; update FLAGS - presume numeric result
  11402.                 RST     18H             ; GET_CHAR
  11403.                 CALL    ALPHA           ; routine ALPHA tests for A-Za-z
  11404.                 JP      NC,REPORT_C     ; jump to REPORT_C if not.
  11405.                                         ; 'Nonsense in basic'
  11406.                 PUSH    HL              ; save pointer to first letter  ^1
  11407.                 AND     $1F             ; mask lower bits, 1 - 26 decimal       000xxxxx
  11408.                 LD      C,A             ; store in C.
  11409.                 RST     20H             ; NEXT_CHAR
  11410.                 PUSH    HL              ; save pointer to second character      ^2
  11411.                 CP      $28             ; is it '(' - an array ?
  11412.                 JR      Z,V_RUN_SYN     ; forward to V_RUN_SYN if so.
  11413.  
  11414.                 SET     6,C             ; set 6 signalling string if solitary   010
  11415.                 CP      $24             ; is character a '$' ?
  11416.                 JR      Z,V_STR_VAR     ; forward to V_STR_VAR
  11417.  
  11418.                 SET     5,C             ; signal numeric                        011
  11419.                 CALL    ALPHANUM        ; routine ALPHANUM sets carry if second
  11420.                                         ; character is alphanumeric.
  11421.                 JR      NC,V_TEST_FN    ; forward to V_TEST_FN if just one character
  11422.  
  11423.  
  11424.                                         ; it is more than one character but re-test current character so that 6 reset
  11425.                                         ; Note. this is a rare lack of elegance. Bit 6 could be reset once before
  11426.                                         ; entering the loop. Another puzzle is that this loop renders the similar
  11427.                                         ; loop at V_PASS redundant.
  11428.  
  11429.                                         ;;;$28D4
  11430. V_CHAR:         CALL    ALPHANUM        ; routine ALPHANUM
  11431.                 JR      NC,V_RUN_SYN    ; to V_RUN_SYN when no more
  11432.  
  11433.                 RES     6,C             ; make long named type                  001
  11434.                 RST     20H             ; NEXT_CHAR
  11435.                 JR      V_CHAR          ; loop back to V_CHAR
  11436.  
  11437.                                         ;;;$28DE
  11438. V_STR_VAR:      RST     20H             ; NEXT_CHAR advances past '$'
  11439.                 RES     6,(IY+$01)      ; update FLAGS - signal string result.
  11440.  
  11441.                                         ;;;$28E3
  11442. V_TEST_FN:      LD      A,($5C0C)       ; load A with DEFADD_hi
  11443.                 AND     A               ; and test for zero.
  11444.                 JR      Z,V_RUN_SYN     ; forward to V_RUN_SYN if a defined function
  11445.                                         ; is not being evaluated.
  11446.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  11447.                 JP      NZ,STK_F_ARG    ; branch to STK_F_ARG in runtime and then
  11448.                                         ; back to this point if no variable found.
  11449.  
  11450.                                         ;;;$28EF
  11451. V_RUN_SYN:      LD      B,C             ; save flags in B
  11452.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  11453.                 JR      NZ,V_RUN        ; to V_RUN to look for the variable in runtime
  11454.  
  11455.                                         ; if checking syntax the letter is not returned
  11456.  
  11457.                 LD      A,C             ; copy letter/flags to A
  11458.                 AND     $E0             ; and with 11100000 to get rid of the letter
  11459.                 SET     7,A             ; use spare bit to signal checking syntax.
  11460.                 LD      C,A             ; and transfer to C.
  11461.                 JR      V_SYNTAX        ; forward to V_SYNTAX
  11462.  
  11463.                                         ; but in runtime search for the variable.
  11464.  
  11465.                                         ;;;$28FD
  11466. V_RUN:          LD      HL,(VARS)       ; set HL to start of variables from VARS
  11467.  
  11468.                                         ;;;$2900
  11469. V_EACH:         LD      A,(HL)          ; get first character
  11470.                 AND     $7F             ; and with 01111111
  11471.                                         ; ignoring bit 7 which distinguishes
  11472.                                         ; arrays or for/next variables.
  11473.                 JR      Z,V_80_BYTE     ; to V_80_BYTE if zero as must be 10000000
  11474.                                         ; the variables end-marker.
  11475.                 CP      C               ; compare with supplied value.
  11476.                 JR      NZ,V_NEXT       ; forward to V_NEXT if no match.
  11477.  
  11478.                 RLA                     ; destructively test
  11479.                 ADD     A,A             ; bits 5 and 6 of A
  11480.                                         ; jumping if bit 5 reset or 6 set
  11481.                 JP      P,V_FOUND_2     ; to V_FOUND_2  strings and arrays
  11482.  
  11483.                 JR      C,V_FOUND_2     ; to V_FOUND_2  simple and for next
  11484.  
  11485.                                         ; leaving long name variables.
  11486.  
  11487.                 POP     DE              ; pop pointer to 2nd. char
  11488.                 PUSH    DE              ; save it again
  11489.                 PUSH    HL              ; save variable first character pointer
  11490.  
  11491.                                         ;;;$2912
  11492. V_MATCHES:      INC     HL              ; address next character in vars area
  11493.  
  11494.                                         ;;;$2913
  11495. V_SPACES:       LD      A,(DE)          ; pick up letter from prog area
  11496.                 INC     DE              ; and advance address
  11497.                 CP      $20             ; is it a space
  11498.                 JR      Z,V_SPACES      ; back to V_SPACES until non-space
  11499.  
  11500.                 OR      $20             ; convert to range 1 - 26.
  11501.                 CP      (HL)            ; compare with addressed variables character
  11502.                 JR      Z,V_MATCHES     ; loop back to V_MATCHES if a match on an
  11503.                                         ; intermediate letter.
  11504.                 OR      $80             ; now set bit 7 as last character of long
  11505.                                         ; names are inverted.
  11506.                 CP      (HL)            ; compare again
  11507.                 JR      NZ,V_GET_PTR    ; forward to V_GET_PTR if no match
  11508.  
  11509.                                         ; but if they match check that this is also last letter in prog area
  11510.  
  11511.                 LD      A,(DE)          ; fetch next character
  11512.                 CALL    ALPHANUM        ; routine ALPHANUM sets carry if not alphanum
  11513.                 JR      NC,V_FOUND_1    ; forward to V_FOUND_1 with a full match.
  11514.  
  11515.                                         ;;;$2929
  11516. V_GET_PTR:      POP     HL              ; pop saved pointer to char 1
  11517.  
  11518.                                         ;;;$292A
  11519. V_NEXT:         PUSH    BC              ; save flags
  11520.                 CALL    NEXT_ONE        ; routine NEXT_ONE gets next variable in DE
  11521.                 EX      DE,HL           ; transfer to HL.
  11522.                 POP     BC              ; restore the flags
  11523.                 JR      V_EACH          ; loop back to V_EACH
  11524.                                         ; to compare each variable
  11525.  
  11526.                                         ;;;$2932
  11527. V_80_BYTE:      SET     7,B             ; will signal not found
  11528.  
  11529.                                         ; the branch was here when checking syntax
  11530.  
  11531.                                         ;;;$2934
  11532. V_SYNTAX:       POP     DE              ; discard the pointer to 2nd. character  v2
  11533.                                         ; in basic line/workspace.
  11534.                 RST     18H             ; GET_CHAR gets character after variable name.
  11535.                 CP      $28             ; is it '(' ?
  11536.                 JR      Z,V_PASS        ; forward to V_PASS
  11537.                                         ; Note. could go straight to V_END ?
  11538.                 SET     5,B             ; signal not an array
  11539.                 JR      V_END           ; forward to V_END
  11540.  
  11541.                                         ; the jump was here when a long name matched and HL pointing to last character
  11542.                                         ; in variables area.
  11543.  
  11544.                                         ;;;$293E
  11545. V_FOUND_1:      POP     DE              ; discard pointer to first var letter
  11546.  
  11547.                                         ; the jump was here with all other matches HL points to first var char.
  11548.  
  11549.                                         ;;;$293F
  11550. V_FOUND_2:      POP     DE              ; discard pointer to 2nd prog char      v2
  11551.                 POP     DE              ; drop pointer to 1st prog char         v1
  11552.                 PUSH    HL              ; save pointer to last char in vars
  11553.                 RST     18H             ; GET_CHAR
  11554.  
  11555.                                         ;;;$2943
  11556. V_PASS:         CALL    ALPHANUM        ; routine ALPHANUM
  11557.                 JR      NC,V_END        ; forward to V_END if not
  11558.  
  11559.                                         ; but it never will be as we advanced past long-named variables earlier.
  11560.  
  11561.                 RST     20H             ; NEXT_CHAR
  11562.                 JR      V_PASS          ; back to V_PASS
  11563.  
  11564.                                         ;;;$294B
  11565. V_END:          POP     HL              ; pop the pointer to first character in basic line/workspace.
  11566.                 RL      B               ; rotate the B register, left bit 7 to carry   
  11567.                 BIT     6,B             ; test the array indicator bit.
  11568.                 RET                     ; return
  11569.  
  11570. ;------------------------
  11571. ; Stack function argument
  11572. ;------------------------
  11573. ; This branch is taken from LOOK_VARS when a defined function is currently
  11574. ; being evaluated.
  11575. ; Scanning is evaluating the expression after the '=' and the variable
  11576. ; found could be in the argument list to the left of the '=' or in the
  11577. ; normal place after the program. Preference will be given to the former.
  11578. ; The variable name to be matched is in C.
  11579.  
  11580.                                         ;;;$2951
  11581. STK_F_ARG:      LD      HL,(DEFADD)     ; set HL to DEFADD
  11582.                 LD      A,(HL)          ; load the first character
  11583.                 CP      $29             ; is it ')' ?
  11584.                 JP      Z,V_RUN_SYN     ; back to V_RUN_SYN, if so, as no arguments.
  11585.  
  11586.                                         ; but proceed to search argument list of defined function first if not empty.
  11587.  
  11588.                                         ;;;$295A
  11589. SFA_LOOP:       LD      A,(HL)          ; fetch character again.
  11590.                 OR      $60             ; or with 01100000 presume a simple variable.
  11591.                 LD      B,A             ; save result in B.
  11592.                 INC     HL              ; address next location.
  11593.                 LD      A,(HL)          ; pick up byte.
  11594.                 CP      $0E             ; is it the number marker ?
  11595.                 JR      Z,SFA_CP_VR     ; forward to SFA_CP_VR if so.
  11596.  
  11597.                                         ; it was a string. White-space may be present but syntax has been checked.
  11598.  
  11599.                 DEC     HL              ; point back to letter.
  11600.                 CALL    FN_SKPOVR       ; routine FN_SKPOVR skips to the '$'
  11601.                 INC     HL              ; now address the hidden marker.
  11602.                 RES     5,B             ; signal a string variable.
  11603.  
  11604.                                         ;;;$296B
  11605. SFA_CP_VR:      LD      A,B             ; transfer found variable letter to A.
  11606.                 CP      C               ; compare with expected.
  11607.                 JR      Z,SFA_MATCH     ; forward to SFA_MATCH with a match.
  11608.  
  11609.                 INC     HL              ; step
  11610.                 INC     HL              ; past
  11611.                 INC     HL              ; the
  11612.                 INC     HL              ; five
  11613.                 INC     HL              ; bytes.
  11614.                 CALL    FN_SKPOVR       ; routine FN_SKPOVR skips to next character
  11615.                 CP      $29             ; is it ')' ?
  11616.                 JP      Z,V_RUN_SYN     ; jump back if so to V_RUN_SYN to look in
  11617.                                         ; normal variables area.
  11618.                 CALL    FN_SKPOVR       ; routine FN_SKPOVR skips past the ','
  11619.                                         ; all syntax has been checked and these
  11620.                                         ; things can be taken as read.
  11621.                 JR      SFA_LOOP        ; back to SFA_LOOP while there are more
  11622.                                         ; arguments.
  11623.  
  11624.                                         ;;;$2981
  11625. SFA_MATCH:      BIT     5,C             ; test if numeric
  11626.                 JR      NZ,SFA_END      ; to SFA_END if so as will be stacked
  11627.                                         ; by scanning
  11628.                 INC     HL              ; point to start of string descriptor
  11629.                 LD      DE,(STKEND)     ; set DE to STKEND
  11630.                 CALL    MOVE_FP         ; routine MOVE_FP puts parameters on stack.
  11631.                 EX      DE,HL           ; new free location to HL.
  11632.                 LD      (STKEND),HL     ; use it to set STKEND system variable.
  11633.  
  11634.                                         ;;;$2991
  11635. SFA_END:        POP     DE              ; discard
  11636.                 POP     DE              ; pointers.
  11637.                 XOR     A               ; clear carry flag.
  11638.                 INC     A               ; and zero flag.
  11639.                 RET                     ; return.
  11640.  
  11641. ;-------------------------
  11642. ; Stack variable component
  11643. ;-------------------------
  11644. ; This is called to evaluate a complex structure that has been found, in
  11645. ; runtime, by LOOK_VARS in the variables area.
  11646. ; In this case HL points to the initial letter, bits 7-5
  11647. ; of which indicate the type of variable.
  11648. ; 010 - simple string, 110 - string array, 100 - array of numbers.
  11649. ;
  11650. ; It is called from CLASS_01 when assigning to a string or array including
  11651. ; a slice.
  11652. ; It is called from SCANNING to isolate the required part of the structure.
  11653. ;
  11654. ; An important part of the runtime process is to check that the number of
  11655. ; dimensions of the variable match the number of subscripts supplied in the
  11656. ; basic line.
  11657. ;
  11658. ; If checking syntax,
  11659. ; the B register, which counts dimensions is set to zero (256) to allow
  11660. ; the loop to continue till all subscripts are checked. While doing this it
  11661. ; is reading dimension sizes from some arbitrary area of memory. Although
  11662. ; these are meaningless it is of no concern as the limit is never checked by
  11663. ; int-exp during syntax checking.
  11664. ;
  11665. ; The routine is also called from the syntax path of DIM command to check the
  11666. ; syntax of both string and numeric arrays definitions except that bit 6 of C
  11667. ; is reset so both are checked as numeric arrays. This ruse avoids a terminal
  11668. ; slice being accepted as part of the DIM command.
  11669. ; All that is being checked is that there are a valid set of comma-separated
  11670. ; expressions before a terminal ')', although, as above, it will still go
  11671. ; through the motions of checking dummy dimension sizes.
  11672.  
  11673.                                         ;;;$2996
  11674. STK_VAR:        XOR     A               ; clear A
  11675.                 LD      B,A             ; and B, the syntax dimension counter (256)
  11676.                 BIT     7,C             ; checking syntax ?
  11677.                 JR      NZ,SV_COUNT     ; forward to SV_COUNT if so.
  11678.  
  11679.                                         ; runtime evaluation.
  11680.  
  11681.                 BIT     7,(HL)          ; will be reset if a simple string.
  11682.                 JR      NZ,SV_ARRAYS    ; forward to SV_ARRAYS otherwise
  11683.  
  11684.                 INC     A               ; set A to 1, simple string.
  11685.  
  11686.                                         ;;;$29A1
  11687. SV_SIMPLE:      INC     HL              ; address length low
  11688.                 LD      C,(HL)          ; place in C
  11689.                 INC     HL              ; address length high
  11690.                 LD      B,(HL)          ; place in B
  11691.                 INC     HL              ; address start of string
  11692.                 EX      DE,HL           ; DE = start now.
  11693.                 CALL    STK_STO_D       ; routine STK_STO_D stacks string parameters
  11694.                                         ; DE start in variables area,
  11695.                                         ; BC length, A=1 simple string
  11696.  
  11697.                                         ; the only thing now is to consider if a slice is required.
  11698.  
  11699.                 RST     18H             ; GET_CHAR puts character at CH_ADD in A
  11700.                 JP      SV_SLICE_EX     ; jump forward to SV_SLICE_EX to test for '('
  11701.  
  11702.                                         ; the branch was here with string and numeric arrays in runtime.
  11703.  
  11704.                                         ;;;$29AE
  11705. SV_ARRAYS:      INC     HL              ; step past
  11706.                 INC     HL              ; the total length
  11707.                 INC     HL              ; to address Number of dimensions.
  11708.                 LD      B,(HL)          ; transfer to B overwriting zero.
  11709.                 BIT     6,C             ; a numeric array ?
  11710.                 JR      Z,SV_PTR        ; forward to SV_PTR with numeric arrays
  11711.  
  11712.                 DEC     B               ; ignore the final element of a string array
  11713.                                         ; the fixed string size.
  11714.                 JR      Z,SV_SIMPLE     ; back to SV_SIMPLE if result is zero as has
  11715.                                         ; been created with DIM a$(10) for instance
  11716.                                         ; and can be treated as a simple string.
  11717.  
  11718.                                         ; proceed with multi-dimensioned string arrays in runtime.
  11719.  
  11720.                 EX      DE,HL           ; save pointer to dimensions in DE
  11721.                 RST     18H             ; GET_CHAR looks at the Basic line
  11722.                 CP      $28             ; is character '(' ?
  11723.                 JR      NZ,REPORT_3     ; to REPORT_3 if not
  11724.                                         ; 'Subscript wrong'
  11725.                 EX      DE,HL           ; dimensions pointer to HL to synchronize
  11726.                                         ; with next instruction.
  11727.  
  11728.                                         ; runtime numeric arrays path rejoins here.
  11729.  
  11730.                                         ;;;$29C0
  11731. SV_PTR:         EX      DE,HL           ; save dimension pointer in DE
  11732.                 JR      SV_COUNT        ; forward to SV_COUNT with true no of dims
  11733.                                         ; in B. As there is no initial comma the
  11734.                                         ; loop is entered at the midpoint.
  11735.  
  11736.                                         ; the dimension counting loop which is entered at mid-point.
  11737.  
  11738.                                         ;;;$29C3
  11739. SV_COMMA:       PUSH    HL              ; save counter
  11740.                 RST     18H             ; GET_CHAR
  11741.                 POP     HL              ; pop counter
  11742.                 CP      $2C             ; is character ',' ?
  11743.                 JR      Z,SV_LOOP       ; forward to SV_LOOP if so
  11744.  
  11745.                                         ; in runtime the variable definition indicates a comma should appear here
  11746.  
  11747.                 BIT     7,C             ; checking syntax ?
  11748.                 JR      Z,REPORT_3      ; forward to REPORT_3 if not
  11749.                                         ; 'Subscript error'
  11750.  
  11751.                                         ; proceed if checking syntax of an array?
  11752.  
  11753.                 BIT     6,C             ; array of strings
  11754.                 JR      NZ,SV_CLOSE     ; forward to SV_CLOSE if so
  11755.  
  11756.                                         ; an array of numbers.
  11757.  
  11758.                 CP      $29             ; is character ')' ?
  11759.                 JR      NZ,SV_RPT_C     ; forward to SV_RPT_C if not
  11760.                                         ; 'Nonsense in basic'
  11761.                 RST     20H             ; NEXT_CHAR moves CH-ADD past the statement
  11762.                 RET                     ; return ->
  11763.  
  11764.                                         ; the branch was here with an array of strings.
  11765.  
  11766.                                         ;;;$29D8
  11767. SV_CLOSE:       CP      $29             ; as above ')' could follow the expression
  11768.                 JR      Z,SV_DIM        ; forward to SV_DIM if so
  11769.  
  11770.                 CP      $CC             ; is it 'TO' ?
  11771.                 JR      NZ,SV_RPT_C     ; to SV_RPT_C with anything else
  11772.                                         ; 'Nonsense in basic'
  11773.  
  11774.                                         ; now backtrack CH_ADD to set up for slicing routine.
  11775.                                         ; Note. in a basic line we can safely backtrack to a colour parameter.
  11776.  
  11777.                                         ;;;$29E0
  11778. SV_CH_ADD:      RST     18H             ; GET_CHAR
  11779.                 DEC     HL              ; backtrack HL
  11780.                 LD      (CH_ADD),HL     ; to set CH_ADD up for slicing routine
  11781.                 JR      SV_SLICE        ; forward to SV_SLICE and make a return
  11782.                                         ; when all slicing complete.
  11783.  
  11784.                                         ; -> the mid-point entry point of the loop
  11785.  
  11786.                                         ;;;$29E7
  11787. SV_COUNT:       LD      HL,$0000        ; initialize data pointer to zero.
  11788.  
  11789.  
  11790.                                         ;;;$29EA
  11791. SV_LOOP:        PUSH    HL              ; save the data pointer.
  11792.                 RST     20H             ; NEXT_CHAR in Basic area points to an expression.
  11793.                 POP     HL              ; restore the data pointer.
  11794.                 LD      A,C             ; transfer name/type to A.
  11795.                 CP      $C0             ; is it 11000000 ?
  11796.                                         ; Note. the letter component is absent if
  11797.                                         ; syntax checking.
  11798.                 JR      NZ,SV_MULT      ; forward to SV_MULT if not an array of
  11799.                                         ; strings.
  11800.  
  11801.                                         ; proceed to check string arrays during syntax.
  11802.  
  11803.                 RST     18H             ; GET_CHAR
  11804.                 CP      $29             ; ')'  end of subscripts ?
  11805.                 JR      Z,SV_DIM                ; forward to SV_DIM to consider further slice
  11806.  
  11807.                 CP      $CC             ; is it 'TO' ?
  11808.                 JR      Z,SV_CH_ADD     ; back to SV_CH_ADD to consider a slice.
  11809.                                         ; (no need to repeat GET_CHAR at SV_CH_ADD)
  11810.  
  11811.                                         ; if neither, then an expression is required so rejoin runtime loop ??
  11812.                                         ; registers HL and DE only point to somewhere meaningful in runtime so
  11813.                                         ; comments apply to that situation.
  11814.  
  11815.                                         ;;;$29FB
  11816. SV_MULT:        PUSH    BC              ; save dimension number.
  11817.                 PUSH    HL              ; push data pointer/rubbish.
  11818.                                         ; DE points to current dimension.
  11819.                 CALL    DE_DE_1         ; routine DE_DE_1 gets next dimension in DE
  11820.                                         ; and HL points to it.
  11821.                 EX      (SP),HL         ; dim pointer to stack, data pointer to HL (*)
  11822.                 EX      DE,HL           ; data pointer to DE, dim size to HL.
  11823.                 CALL    INT_EXP1        ; routine INT_EXP1 checks integer expression
  11824.                                         ; and gets result in BC in runtime.
  11825.                 JR      C,REPORT_3      ; to REPORT_3 if > HL
  11826.                                         ; 'Subscript out of range'
  11827.                 DEC     BC              ; adjust returned result from 1-x to 0-x
  11828.                 CALL    GET_HL_DE       ; routine GET_HL_DE multiplies data pointer by dimension size.
  11829.                 ADD     HL,BC           ; add the integer returned by expression.
  11830.                 POP     DE              ; pop the dimension pointer.                    ***
  11831.                 POP     BC              ; pop dimension counter.
  11832.                 DJNZ    SV_COMMA        ; back to SV_COMMA if more dimensions
  11833.                                         ; Note. during syntax checking, unless there
  11834.                                         ; are more than 256 subscripts, the branch
  11835.                                         ; back to SV_COMMA is always taken.
  11836.                 BIT     7,C             ; are we checking syntax ?
  11837.                                         ; then we've got a joker here.
  11838.  
  11839.                                         ;;;$2A12
  11840. SV_RPT_C:       JR      NZ,SL_RPT_C     ; forward to SL_RPT_C if so
  11841.                                         ; 'Nonsense in Basic'
  11842.                                         ; more than 256 subscripts in Basic line.
  11843.  
  11844.                                         ; but in runtime the number of subscripts are at least the same as dims
  11845.  
  11846.                 PUSH    HL              ; save data pointer.
  11847.                 BIT     6,C             ; is it a string array ?
  11848.                 JR      NZ,SV_ELEM      ; forward to SV_ELEM if so.
  11849.  
  11850.                                         ; a runtime numeric array subscript.
  11851.  
  11852.                 LD      B,D             ; register DE has advanced past all dimensions
  11853.                 LD      C,E             ; and points to start of data in variable.
  11854.                                         ; transfer it to BC.
  11855.                 RST     18H             ; GET_CHAR checks Basic line
  11856.                 CP      $29             ; must be a ')' ?
  11857.                 JR      Z,SV_NUMBER     ; skip to SV_NUMBER if so
  11858.  
  11859.                                         ; else more subscripts in Basic line than the variable definition.
  11860.  
  11861.                                         ;;;$2A20
  11862. REPORT_3:       RST     08H             ; ERROR_1
  11863.                 DEFB    $02             ; Error Report: Subscript wrong
  11864.  
  11865.                                         ; continue if subscripts matched the numeric array.
  11866.  
  11867.                                         ;;;$2A22
  11868. SV_NUMBER:      RST     20H             ; NEXT_CHAR moves CH_ADD to next statement - finished parsing.
  11869.                 POP     HL              ; pop the data pointer.
  11870.                 LD      DE,$0005        ; each numeric element is 5 bytes.
  11871.                 CALL    GET_HL_DE       ; routine GET_HL_DE multiplies.
  11872.                 ADD     HL,BC           ; now add to start of data in the variable.
  11873.                 RET                     ; return with HL pointing at the numeric
  11874.                                         ; array subscript.                      ->
  11875.  
  11876.                                         ; the branch was here for string subscripts when the number of subscripts
  11877.                                         ; in the basic line was one less than in variable definition.
  11878.  
  11879.                                         ;;;$2A2C
  11880. SV_ELEM:        CALL    DE_DE_1         ; routine DE_DE_1 gets final dimension
  11881.                                         ; the length of strings in this array.
  11882.                 EX      (SP),HL         ; start pointer to stack, data pointer to HL.
  11883.                 CALL    GET_HL_DE       ; routine GET_HL_DE multiplies by element size.
  11884.                 POP     BC              ; the start of data pointer is added
  11885.                 ADD     HL,BC           ; in - now points to location before.
  11886.                 INC     HL              ; point to start of required string.
  11887.                 LD      B,D             ; transfer the length (final dimension size)
  11888.                 LD      C,E             ; from DE to BC.
  11889.                 EX      DE,HL           ; put start in DE.
  11890.                 CALL    STK_ST_0        ; routine STK_ST_0 stores the string parameters
  11891.                                         ; with A=0 - a slice or subscript.
  11892.  
  11893.                                         ; now check that there were no more subscripts in the Basic line.
  11894.  
  11895.                 RST     18H             ; GET_CHAR
  11896.                 CP      $29             ; is it ')' ?
  11897.                 JR      Z,SV_DIM        ; forward to SV_DIM to consider a separate
  11898.                                         ; subscript or/and a slice.
  11899.                 CP      $2C             ; a comma is allowed if the final subscript
  11900.                                         ; is to be sliced e.g a$(2,3,4 TO 6).
  11901.                 JR      NZ,REPORT_3     ; to REPORT_3 with anything else
  11902.                                         ; 'Subscript error'
  11903.  
  11904.                                         ;;;$2A45
  11905. SV_SLICE:       CALL    SLICING         ; routine SLICING slices the string.
  11906.                                         ; but a slice of a simple string can itself be sliced.
  11907.  
  11908.                                         ;;;$2A48
  11909. SV_DIM:         RST     20H             ; NEXT_CHAR
  11910.  
  11911.                                         ;;;$2A49
  11912. SV_SLICE_EX:    CP      $28             ; is character '(' ?
  11913.                 JR      Z,SV_SLICE      ; loop back if so to SV_SLICE
  11914.  
  11915.                 RES     6,(IY+$01)      ; update FLAGS  - Signal string result
  11916.                 RET                     ; and return.
  11917.  
  11918. ; The above section deals with the flexible syntax allowed.
  11919. ; DIM a$(3,3,10) can be considered as two dimensional array of ten-character
  11920. ; strings or a 3-dimensional array of characters.
  11921. ; a$(1,1) will return a 10-character string as will a$(1,1,1 TO 10)
  11922. ; a$(1,1,1) will return a single character.
  11923. ; a$(1,1) (1 TO 6) is the same as a$(1,1,1 TO 6)
  11924. ; A slice can itself be sliced ad infinitum
  11925. ; b$ () () () () () () (2 TO 10) (2 TO 9) (3) is the same as b$(5)
  11926.  
  11927.  
  11928. ;--------------------------
  11929. ; Handle slicing of strings
  11930. ;--------------------------
  11931. ; The syntax of string slicing is very natural and it is as well to reflect
  11932. ; on the permutations possible.
  11933. ; a$() and a$( TO ) indicate the entire string although just a$ would do
  11934. ; and would avoid coming here.
  11935. ; h$(16) indicates the single character at position 16.
  11936. ; a$( TO 32) indicates the first 32 characters.
  11937. ; a$(257 TO) indicates all except the first 256 characters.
  11938. ; a$(19000 TO 19999) indicates the thousand characters at position 19000.
  11939. ; Also a$(9 TO 5) returns a null string not an error.
  11940. ; This enables a$(2 TO) to return a null string if the passed string is
  11941. ; of length zero or 1.
  11942. ; A string expression in brackets can be sliced. e.g. (STR$ PI) (3 TO )
  11943. ; We arrived here from SCANNING with CH-ADD pointing to the initial '('
  11944. ; or from above.
  11945.  
  11946.                                         ;;;$2A52
  11947. SLICING:        CALL    SYNTAX_Z        ; routine SYNTAX_Z
  11948.                 CALL    NZ,STK_FETCH    ; routine STK_FETCH fetches parameters of
  11949.                                         ; string at runtime, start in DE, length
  11950.                                         ; in BC. This could be an array subscript.
  11951.                 RST     20H             ; NEXT_CHAR
  11952.                 CP      $29             ; is it ')' ?   e.g. a$()
  11953.                 JR      Z,SL_STORE      ; forward to SL_STORE to store entire string.
  11954.  
  11955.                 PUSH    DE              ; else save start address of string
  11956.                 XOR     A               ; clear accumulator to use as a running flag.
  11957.                 PUSH    AF              ; and save on stack before any branching.
  11958.                 PUSH    BC              ; save length of string to be sliced.
  11959.                 LD      DE,$0001        ; default the start point to position 1.
  11960.                 RST     18H             ; GET_CHAR
  11961.                 POP     HL              ; pop length to HL as default end point
  11962.                                         ; and limit.
  11963.                 CP      $CC             ; is it 'TO' ?  e.g. a$( TO 10000)
  11964.                 JR      Z,SL_SECOND     ; to SL_SECOND to evaluate second parameter.
  11965.  
  11966.                 POP     AF              ; pop the running flag.
  11967.                 CALL    INT_EXP2        ; routine INT_EXP2 fetches first parameter.
  11968.                 PUSH    AF              ; save flag (will be $FF if parameter>limit)
  11969.                 LD      D,B             ; transfer the start
  11970.                 LD      E,C             ; to DE overwriting 0001.
  11971.                 PUSH    HL              ; save original length.
  11972.                 RST     18H             ; GET_CHAR
  11973.                 POP     HL              ; pop the limit length.
  11974.                 CP      $CC             ; is it 'TO' after a start ?
  11975.                 JR      Z,SL_SECOND     ; to SL_SECOND to evaluate second parameter
  11976.  
  11977.                 CP      $29             ; is it ')' ?   e.g. a$(365)
  11978.  
  11979.                                         ;;;$2A7A
  11980. SL_RPT_C:       JP      NZ,REPORT_C     ; jump to REPORT_C with anything else
  11981.                                         ; 'Nonsense in basic'
  11982.                 LD      H,D             ; copy start
  11983.                 LD      L,E             ; to end - just a one character slice.
  11984.                 JR      SL_DEFINE       ; forward to SL_DEFINE.
  11985.  
  11986.                                         ;;;$2A81
  11987. SL_SECOND:      PUSH    HL              ; save limit length.
  11988.                 RST     20H             ; NEXT_CHAR
  11989.                 POP     HL              ; pop the length.
  11990.                 CP      $29             ; is character ')' ?            e.g a$(7 TO )
  11991.                 JR      Z,SL_DEFINE     ; to SL_DEFINE using length as end point.
  11992.  
  11993.                 POP     AF              ; else restore flag.
  11994.                 CALL    INT_EXP2        ; routine INT_EXP2 gets second expression.
  11995.                 PUSH    AF              ; save the running flag.
  11996.                 RST     18H             ; GET_CHAR
  11997.                 LD      H,B             ; transfer second parameter
  11998.                 LD      L,C             ; to HL.                e.g. a$(42 to 99)
  11999.                 CP      $29             ; is character a ')' ?
  12000.                 JR      NZ,SL_RPT_C     ; to SL_RPT_C if not
  12001.                                         ; 'Nonsense in basic'
  12002.  
  12003.                                         ; we now have start in DE and an end in HL.
  12004.  
  12005.                                         ;;;$2A94
  12006. SL_DEFINE:      POP     AF              ; pop the running flag.
  12007.                 EX      (SP),HL         ; put end point on stack, start address to HL
  12008.                 ADD     HL,DE           ; add address of string to the start point.
  12009.                 DEC     HL              ; point to first character of slice.
  12010.                 EX      (SP),HL         ; start address to stack, end point to HL (*)
  12011.                 AND     A               ; prepare to subtract.
  12012.                 SBC     HL,DE           ; subtract start point from end point.
  12013.                 LD      BC,$0000        ; default the length result to zero.
  12014.                 JR      C,SL_OVER       ; forward to SL_OVER if start > end.
  12015.  
  12016.                 INC     HL              ; increment the length for inclusive byte.
  12017.                 AND     A               ; now test the running flag.
  12018.                 JP      M,REPORT_3      ; jump back to REPORT_3 if $FF.
  12019.                                         ; 'Subscript out of range'
  12020.                 LD      B,H             ; transfer the length
  12021.                 LD      C,L             ; to BC.
  12022.  
  12023.                                         ;;;$2AA8
  12024. SL_OVER:        POP     DE              ; restore start address from machine stack ***
  12025.                 RES     6,(IY+$01)      ; update FLAGS - signal string result for
  12026.                                         ; syntax.
  12027.  
  12028.                                         ;;;$2AAD
  12029. SL_STORE:       CALL    SYNTAX_Z        ; routine SYNTAX_Z  (UNSTACK_Z?)
  12030.                 RET     Z               ; return if checking syntax.
  12031.                                         ; but continue to store the string in runtime.
  12032.  
  12033.                                         ; ------------------------------------
  12034.                                         ; other than from above, this routine is called from STK_VAR to stack
  12035.                                         ; a known string array element.
  12036.                                         ; ------------------------------------
  12037.  
  12038.                                         ;;;$2AB1
  12039. STK_ST_0:       XOR     A               ; clear to signal a sliced string or element.
  12040.  
  12041.                                         ; -------------------------
  12042.                                         ; this routine is called from CHR$, scrn$ etc. to store a simple string result.
  12043.                                         ; --------------------------
  12044.  
  12045.                                         ;;;$2AB2
  12046. STK_STO_D:      RES     6,(IY+$01)      ; update FLAGS - signal string result.
  12047.                                         ; and continue to store parameters of string.
  12048.  
  12049. ;----------------------------------------
  12050. ; Pass five registers to calculator stack
  12051. ;----------------------------------------
  12052. ; This subroutine puts five registers on the calculator stack.
  12053.  
  12054.                                         ;;;$2AB6
  12055. STK_STORE:      PUSH    BC              ; save two registers
  12056.                 CALL    TEST_5_SP       ; routine TEST_5_SP checks room and puts 5 in BC.
  12057.                 POP     BC              ; fetch the saved registers.
  12058.                 LD      HL,(STKEND)     ; make HL point to first empty location STKEND
  12059.                 LD      (HL),A          ; place the 5 registers.
  12060.                 INC     HL
  12061.                 LD      (HL),E
  12062.                 INC     HL
  12063.                 LD      (HL),D
  12064.                 INC     HL
  12065.                 LD      (HL),C
  12066.                 INC     HL
  12067.                 LD      (HL),B
  12068.                 INC     HL
  12069.                 LD      (STKEND),HL     ; update system variable STKEND.
  12070.                 RET                     ; and return.
  12071.  
  12072. ;--------------------------------------------
  12073. ; Return result of evaluating next expression
  12074. ;--------------------------------------------
  12075. ; This clever routine is used to check and evaluate an integer expression
  12076. ; which is returned in BC, setting A to $FF, if greater than a limit supplied
  12077. ; in HL. It is used to check array subscripts, parameters of a string slice
  12078. ; and the arguments of the DIM command. In the latter case, the limit check
  12079. ; is not required and H is set to $FF. When checking optional string slice
  12080. ; parameters, it is entered at the second entry point so as not to disturb
  12081. ; the running flag A, which may be $00 or $FF from a previous invocation.
  12082.  
  12083.                                         ;;;$2ACC
  12084. INT_EXP1:       XOR     A               ; set result flag to zero.
  12085.  
  12086.                                         ; -> The entry point is here if A is used as a running flag.
  12087.  
  12088.                                         ;;;$2ACD
  12089. INT_EXP2:       PUSH    DE              ; preserve DE register throughout.
  12090.                 PUSH    HL              ; save the supplied limit.
  12091.                 PUSH    AF              ; save the flag.
  12092.                 CALL    EXPT_1NUM       ; routine EXPT_1NUM evaluates expression
  12093.                                         ; at CH_ADD returning if numeric result,
  12094.                                         ; with value on calculator stack.
  12095.                 POP     AF              ; pop the flag.
  12096.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  12097.                 JR      Z,I_RESTORE     ; forward to I_RESTORE if checking syntax so
  12098.                                         ; avoiding a comparison with supplied limit.
  12099.                 PUSH    AF              ; save the flag.
  12100.                 CALL    FIND_INT2       ; routine FIND_INT2 fetches value from
  12101.                                         ; calculator stack to BC producing an error if too high.
  12102.                 POP     DE              ; pop the flag to D.
  12103.                 LD      A,B             ; test value for zero and reject
  12104.                 OR      C               ; as arrays and strings begin at 1.
  12105.                 SCF                     ; set carry flag.
  12106.                 JR      Z,I_CARRY       ; forward to I_CARRY if zero.
  12107.  
  12108.                 POP     HL              ; restore the limit.
  12109.                 PUSH    HL              ; and save.
  12110.                 AND     A               ; prepare to subtract.
  12111.                 SBC     HL,BC           ; subtract value from limit.
  12112.  
  12113.                                         ;;;$2AE8
  12114. I_CARRY:        LD      A,D             ; move flag to accumulator $00 or $FF.
  12115.                 SBC     A,$00           ; will set to $FF if carry set.
  12116.  
  12117.                                         ;;;$2AEB
  12118. I_RESTORE:      POP     HL              ; restore the limit.
  12119.                 POP     DE              ; and DE register.
  12120.                 RET                     ; return.
  12121.  
  12122.  
  12123. ;------------------------
  12124. ; LD DE,(DE+1) Subroutine
  12125. ;------------------------
  12126. ; This routine just loads the DE register with the contents of the two
  12127. ; locations following the location addressed by DE.
  12128. ; It is used to step along the 16-bit dimension sizes in array definitions.
  12129. ; Note. Such code is made into subroutines to make programs easier to
  12130. ; write and it would use less space to include the five instructions in-line.
  12131. ; However, there are so many exchanges going on at the places this is invoked
  12132. ; that to implement it in-line would make the code hard to follow.
  12133. ; It probably had a zipier label though as the intention is to simplify the
  12134. ; program.
  12135.  
  12136.                                         ;;;$2AEE
  12137. DE_DE_1:        EX      DE,HL
  12138.                 INC     HL
  12139.                 LD      E,(HL)
  12140.                 INC     HL
  12141.                 LD      D,(HL)
  12142.                 RET
  12143.  
  12144. ;--------------------
  12145. ; HL=HL*DE Subroutine
  12146. ;--------------------
  12147. ; This routine calls the mathematical routine to multiply HL by DE in runtime.
  12148. ; It is called from STK_VAR and from DIM. In the latter case syntax is not
  12149. ; being checked so the entry point could have been at the second CALL
  12150. ; instruction to save a few clock-cycles.
  12151.  
  12152.                                         ;;;$2AF4
  12153. GET_HL_DE:      CALL    SYNTAX_Z        ; routine SYNTAX_Z.
  12154.                 RET     Z               ; return if checking syntax.
  12155.  
  12156.                 CALL    HL_HL_DE        ; routine HL_HL_DE.
  12157.                 JP      C,REPORT_4      ; jump back to REPORT_4 if over 65535.
  12158.  
  12159.                 RET                     ; else return with 16-bit result in HL.
  12160.  
  12161. ;-------------------
  12162. ; Handle LET command
  12163. ;-------------------
  12164. ; Sinclair Basic adheres to the ANSI-79 standard and a LET is required in
  12165. ; assignments e.g. LET a = 1  : LET h$ = "hat"
  12166. ; Long names may contain spaces but not colour controls (when assigned).
  12167. ; a substring can appear to the left of the equals sign.
  12168.  
  12169. ; An earlier mathematician Lewis Carroll may have been pleased that
  12170. ; 10 LET Babies cannot manage crocodiles = Babies are illogical AND
  12171. ;       Nobody is despised who can manage a crocodile AND Illogical persons
  12172. ;       are despised
  12173. ; does not give the 'Nonsense..' error if the three variables exist.
  12174. ; I digress.
  12175.  
  12176.                                         ;;;$2AFF
  12177. LET:            LD      HL,(DEST)       ; fetch system variable DEST to HL.
  12178.                 BIT     1,(IY+$37)      ; test FLAGX - handling a new variable ?
  12179.                 JR      Z,L_EXISTS      ; forward to L_EXISTS if not.
  12180.  
  12181.                                         ; continue for a new variable. DEST points to start in Basic line.
  12182.                                         ; from the CLASS routines.
  12183.  
  12184.                 LD      BC,$0005        ; assume numeric and assign an initial 5 bytes
  12185.  
  12186.                                         ;;;$2B0B
  12187. L_EACH_CH:      INC     BC              ; increase byte count for each relevant
  12188.                                         ; character
  12189.  
  12190.                                         ;;;$2B0C
  12191. L_NO_SP:        INC     HL              ; increase pointer.
  12192.                 LD      A,(HL)          ; fetch character.
  12193.                 CP      $20             ; is it a space ?
  12194.                 JR      Z,L_NO_SP       ; back to L_NO_SP is so.
  12195.  
  12196.                 JR      NC,L_TEST_CH    ; forward to L_TEST_CH if higher.
  12197.  
  12198.                 CP      $10             ; is it $00 - $0F ?
  12199.                 JR      C,L_SPACES      ; forward to L_SPACES if so.
  12200.  
  12201.                 CP      $16             ; is it $16 - $1F ?
  12202.                 JR      NC,L_SPACES     ; forward to L_SPACES if so.
  12203.  
  12204.                                         ; it was $10 - $15  so step over a colour code.
  12205.  
  12206.                 INC     HL              ; increase pointer.
  12207.                 JR      L_NO_SP         ; loop back to L_NO_SP.
  12208.  
  12209.                                         ; the branch was here if higher than space
  12210.  
  12211.                                         ;;;$2B1F
  12212. L_TEST_CH:      CALL    ALPHANUM        ; routine ALPHANUM sets carry if alphanumeric
  12213.                 JR      C,L_EACH_CH     ; loop back to L_EACH_CH for more if so.
  12214.  
  12215.                 CP      $24             ; is it '$' ?
  12216.                 JP      Z,L_NEW         ; jump forward if so, to L_NEW
  12217.                                         ; with a new string.
  12218.  
  12219.                                         ;;;$2B29
  12220. L_SPACES:       LD      A,C             ; save length lo in A.
  12221.                 LD      HL,(E_LINE)     ; fetch E_LINE to HL.
  12222.                 DEC     HL              ; point to location before, the variables end-marker.
  12223.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM creates BC spaces
  12224.                                         ; for name and numeric value.
  12225.                 INC     HL              ; advance to first new location.
  12226.                 INC     HL              ; then to second.
  12227.                 EX      DE,HL           ; set DE to second location.
  12228.                 PUSH    DE              ; save this pointer.
  12229.                 LD      HL,(DEST)       ; reload HL with DEST.
  12230.                 DEC     DE              ; point to first.
  12231.                 SUB     $06             ; subtract six from length_lo.
  12232.                 LD      B,A             ; save count in B.
  12233.                 JR      Z,L_SINGLE      ; forward to L_SINGLE if it was just one character.
  12234.  
  12235.                                         ; HL points to start of variable name after 'LET' in Basic line.
  12236.  
  12237.                                         ;;;$2B3E
  12238. L_CHAR:         INC     HL              ; increase pointer.
  12239.                 LD      A,(HL)          ; pick up character.
  12240.                 CP      $21             ; is it space or higher ?
  12241.                 JR      C,L_CHAR        ; back to L_CHAR with space and less.
  12242.  
  12243.                 OR      $20             ; make variable lower-case.
  12244.                 INC     DE              ; increase destination pointer.
  12245.                 LD      (DE),A          ; and load to edit line.
  12246.                 DJNZ    L_CHAR          ; loop back to L_CHAR until B is zero.
  12247.                 OR      $80             ; invert the last character.
  12248.                 LD      (DE),A          ; and overwrite that in edit line.
  12249.  
  12250.                                         ; now consider first character which has bit 6 set
  12251.  
  12252.                 LD      A,$C0           ; set A 11000000 is xor mask for a long name.
  12253.                                         ; %101  is xor/or  result
  12254.  
  12255.                                         ; single character numerics rejoin here with %00000000 in mask.
  12256.                                         ; %011  will be xor/or result
  12257.  
  12258.                                         ;;;$2B4F
  12259. L_SINGLE:       LD      HL,(DEST)       ; fetch DEST - HL addresses first character.
  12260.                 XOR     (HL)            ; apply variable type indicator mask (above).
  12261.                 OR      $20             ; make lowercase - set bit 5.
  12262.                 POP     HL              ; restore pointer to 2nd character.
  12263.                 CALL    L_FIRST         ; routine L_FIRST puts A in first character.
  12264.                                         ; and returns with HL holding
  12265.                                         ; new E_LINE-1  the $80 vars end-marker.
  12266.  
  12267.                                         ;;;$2B59
  12268. L_NUMERIC:      PUSH    HL              ; save the pointer.
  12269.  
  12270.                                         ; the value of variable is deleted but remains after calculator stack.
  12271.  
  12272.                 RST     28H             ;; FP_CALC
  12273.                 DEFB    $02             ;;DELETE        ; delete variable value
  12274.                 DEFB    $38             ;;END_CALC
  12275.  
  12276.                                         ; DE (STKEND) points to start of value.
  12277.  
  12278.                 POP     HL              ; restore the pointer.
  12279.                 LD      BC,$0005        ; start of number is five bytes before.
  12280.                 AND     A               ; prepare for true subtraction.
  12281.                 SBC     HL,BC           ; HL points to start of value.
  12282.                 JR      L_ENTER         ; forward to L_ENTER  ==>
  12283.  
  12284.  
  12285.                                         ; the jump was to here if the variable already existed.
  12286.  
  12287.                                         ;;;$2B66
  12288. L_EXISTS:       BIT     6,(IY+$01)      ; test FLAGS - numeric or string result ?
  12289.                 JR      Z,L_DELETE      ; skip forward to L_DELETE      -*->
  12290.                                         ; if string result.
  12291.  
  12292.                                         ; A numeric variable could be simple or an array element.
  12293.                                         ; They are treated the same and the old value is overwritten.
  12294.  
  12295.                 LD      DE,$0006        ; six bytes forward points to loc past value.
  12296.                 ADD     HL,DE           ; add to start of number.
  12297.                 JR      L_NUMERIC       ; back to L_NUMERIC to overwrite value.
  12298.  
  12299.                                         ; -*-> the branch was here if a string existed.
  12300.  
  12301.                                         ;;;$2B72
  12302. L_DELETE:       LD      HL,(DEST)       ; fetch DEST to HL.
  12303.                                         ; (still set from first instruction)
  12304.                 LD      BC,(STRLEN)     ; fetch STRLEN to BC.
  12305.                 BIT     0,(IY+$37)      ; test FLAGX - handling a complete simple string ?
  12306.                 JR      NZ,L_ADD        ; forward to L_ADD if so.
  12307.  
  12308.                                         ; must be a string array or a slice in workspace.
  12309.                                         ; Note. LET a$(3 TO 6) = h$     will assign "hat " if h$ = "hat"
  12310.                                         ; and   "hats" if h$ = "hatstand".
  12311.  
  12312.                                         ; This is known as Procrustian lengthening and shortening after a
  12313.                                         ; character Procrustes in Greek legend who made travellers sleep in his bed,
  12314.                                         ; cutting off their feet or stretching them so they fitted the bed perfectly.
  12315.                                         ; The bloke was hatstand and slain by Theseus.
  12316.  
  12317.                 LD      A,B             ; test if length
  12318.                 OR      C               ; is zero and
  12319.                 RET     Z               ; return if so.
  12320.  
  12321.                 PUSH    HL              ; save pointer to start.
  12322.                 RST     30H             ; BC_SPACES creates room.
  12323.                 PUSH    DE              ; save pointer to first new location.
  12324.                 PUSH    BC              ; and length            (*)
  12325.                 LD      D,H             ; set DE to point to last location.
  12326.                 LD      E,L
  12327.                 INC     HL              ; set HL to next location.
  12328.                 LD      (HL),$20        ; place a space there.
  12329.                 LDDR                    ; copy bytes filling with spaces.
  12330.                 PUSH    HL              ; save pointer to start.
  12331.                 CALL    STK_FETCH       ; routine STK_FETCH start to DE, length to BC.
  12332.                 POP     HL              ; restore the pointer.
  12333.                 EX      (SP),HL         ; (*) length to HL, pointer to stack.
  12334.                 AND     A               ; prepare for true subtraction.
  12335.                 SBC     HL,BC           ; subtract old length from new.
  12336.                 ADD     HL,BC           ; and add back.
  12337.                 JR      NC,L_LENGTH     ; forward if it fits to L_LENGTH.
  12338.  
  12339.                 LD      B,H             ; otherwise set
  12340.                 LD      C,L             ; length to old length.
  12341.                                         ; "hatstand" becomes "hats"
  12342.  
  12343.                                         ;;;$2B9B
  12344. L_LENGTH:       EX      (SP),HL         ; (*) length to stack, pointer to HL.
  12345.                 EX      DE,HL           ; pointer to DE, start of string to HL.
  12346.                 LD      A,B             ; is the length zero ?
  12347.                 OR      C               ;
  12348.                 JR      Z,L_IN_W_S      ; forward to L_IN_W_S if so
  12349.                                         ; leaving prepared spaces.
  12350.                 LDIR                    ; else copy bytes overwriting some spaces.
  12351.  
  12352.                                         ;;;$2BA3
  12353. L_IN_W_S:       POP     BC              ; pop the new length.  (*)
  12354.                 POP     DE              ; pop pointer to new area.
  12355.                 POP     HL              ; pop pointer to variable in assignment.
  12356.                                         ; and continue copying from workspace
  12357.                                         ; to variables area.
  12358.  
  12359.                                         ; ==> branch here from  L_NUMERIC
  12360.  
  12361.                                         ;;;$2BA6
  12362. L_ENTER:        EX      DE,HL           ; exchange pointers HL=STKEND DE=end of vars.
  12363.                 LD      A,B             ; test the length
  12364.                 OR      C               ; and make a
  12365.                 RET     Z               ; return if zero (strings only).
  12366.  
  12367.                 PUSH    DE              ; save start of destination.
  12368.                 LDIR                    ; copy bytes.
  12369.                 POP     HL              ; address the start.
  12370.                 RET                     ; and return.
  12371.  
  12372.                                         ; the branch was here from L_DELETE if an existing simple string.
  12373.                                         ; register HL addresses start of string in variables area.
  12374.  
  12375.                                         ;;;$2BAF
  12376. L_ADD:          DEC     HL              ; point to high byte of length.
  12377.                 DEC     HL              ; to low byte.
  12378.                 DEC     HL              ; to letter.
  12379.                 LD      A,(HL)          ; fetch masked letter to A.
  12380.                 PUSH    HL              ; save the pointer on stack.
  12381.                 PUSH    BC              ; save new length.
  12382.                 CALL    L_STRING        ; routine L_STRING adds new string at end
  12383.                                         ; of variables area.
  12384.                                         ; if no room we still have old one.
  12385.                 POP     BC              ; restore length.
  12386.                 POP     HL              ; restore start.
  12387.                 INC     BC              ; increase
  12388.                 INC     BC              ; length by three
  12389.                 INC     BC              ; to include character and length bytes.
  12390.                 JP      RECLAIM_2       ; jump to indirect exit via RECLAIM_2
  12391.                                         ; deleting old version and adjusting pointers.
  12392.  
  12393.                                         ; the jump was here with a new string variable.
  12394.  
  12395.                                         ;;;$2BC0
  12396. L_NEW:          LD      A,$DF           ; indicator mask %11011111 for
  12397.                                         ;                %010xxxxx will be result
  12398.                 LD      HL,(DEST)       ; address DEST first character.
  12399.                 AND     (HL)            ; combine mask with character.
  12400.  
  12401.                                         ;;;$2BC6
  12402. L_STRING:       PUSH    AF              ; save first character and mask.
  12403.                 CALL    STK_FETCH       ; routine STK_FETCH fetches parameters of the string.
  12404.                 EX      DE,HL           ; transfer start to HL.
  12405.                 ADD     HL,BC           ; add to length.
  12406.                 PUSH    BC              ; save the length.
  12407.                 DEC     HL              ; point to end of string.
  12408.                 LD      (DEST),HL       ; save pointer in DEST.
  12409.                                         ; (updated by POINTERS if in workspace)
  12410.                 INC     BC              ; extra byte for letter.
  12411.                 INC     BC              ; two bytes
  12412.                 INC     BC              ; for the length of string.
  12413.                 LD      HL,(E_LINE)     ; address E_LINE.
  12414.                 DEC     HL              ; now end of VARS area.
  12415.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM makes room for string.
  12416.                                         ; updating pointers including DEST.
  12417.                 LD      HL,(DEST)       ; pick up pointer to end of string from DEST.
  12418.                 POP     BC              ; restore length from stack.
  12419.                 PUSH    BC              ; and save again on stack.
  12420.                 INC     BC              ; add a byte.
  12421.                 LDDR                    ; copy bytes from end to start.
  12422.                 EX      DE,HL           ; HL addresses length low
  12423.                 INC     HL              ; increase to address high byte
  12424.                 POP     BC              ; restore length to BC
  12425.                 LD      (HL),B          ; insert high byte
  12426.                 DEC     HL              ; address low byte location
  12427.                 LD      (HL),C          ; insert that byte
  12428.                 POP     AF              ; restore character and mask
  12429.  
  12430.                                         ;;;$2BEA
  12431. L_FIRST:        DEC     HL              ; address variable name
  12432.                 LD      (HL),A          ; and insert character.
  12433.                 LD      HL,(E_LINE)     ; load HL with E_LINE.
  12434.                 DEC     HL              ; now end of VARS area.
  12435.                 RET                     ; return
  12436.  
  12437. ;-------------------------------------
  12438. ; Get last value from calculator stack
  12439. ;-------------------------------------
  12440.  
  12441.                                         ;;;$2BF1
  12442. STK_FETCH:      LD      HL,(STKEND)     ; STKEND
  12443.                 DEC     HL
  12444.                 LD      B,(HL)
  12445.                 DEC     HL
  12446.                 LD      C,(HL)
  12447.                 DEC     HL
  12448.                 LD      D,(HL)
  12449.                 DEC     HL
  12450.                 LD      E,(HL)
  12451.                 DEC     HL
  12452.                 LD      A,(HL)
  12453.                 LD      (STKEND),HL     ; STKEND
  12454.                 RET
  12455.  
  12456. ;-------------------
  12457. ; Handle DIM command
  12458. ;-------------------
  12459. ; e.g. DIM a(2,3,4,7): DIM a$(32) : DIM b$(300,2,768) : DIM c$(20000)
  12460. ; the only limit to dimensions is memory so, for example,
  12461. ; DIM a(2,2,2,2,2,2,2,2,2,2,2,2,2) is possible and creates a multi-
  12462. ; dimensional array of zeros. String arrays are initialized to spaces.
  12463. ; It is not possible to erase an array, but it can be re-dimensioned to
  12464. ; a minimal size of 1, after use, to free up memory.
  12465.  
  12466.                                         ;;;$2C02
  12467. DIM:            CALL    LOOK_VARS       ; routine LOOK_VARS
  12468.  
  12469.                                         ;;;$2C05
  12470. D_RPORT_C:      JP      NZ,REPORT_C     ; jump to REPORT_C if a long-name variable.
  12471.                                         ; DIM lottery numbers(49) doesn't work.
  12472.  
  12473.                 CALL    SYNTAX_Z        ; routine SYNTAX_Z
  12474.                 JR      NZ,D_RUN        ; forward to D_RUN in runtime.
  12475.  
  12476.                 RES     6,C             ; signal 'numeric' array even if string as
  12477.                                         ; this simplifies the syntax checking.
  12478.                 CALL    STK_VAR         ; routine STK_VAR checks syntax.
  12479.                 CALL    CHECK_END       ; routine CHECK_END performs early exit ->
  12480.  
  12481.                                         ; the branch was here in runtime.
  12482.  
  12483.                                         ;;;$2C15
  12484. D_RUN:          JR      C,D_LETTER      ; skip to D_LETTER if variable did not exist.
  12485.                                         ; else reclaim the old one.
  12486.                 PUSH    BC              ; save type in C.
  12487.                 CALL    NEXT_ONE        ; routine NEXT_ONE find following variable
  12488.                                         ; or position of $80 end-marker.
  12489.                 CALL    RECLAIM_2       ; routine RECLAIM_2 reclaims the  space between.
  12490.                 POP     BC              ; pop the type.
  12491.  
  12492.                                         ;;;$2C1F
  12493. D_LETTER:       SET     7,C             ; signal array.
  12494.                 LD      B,$00           ; initialize dimensions to zero and
  12495.                 PUSH    BC              ; save with the type.
  12496.                 LD      HL,$0001        ; make elements one character presuming string
  12497.                 BIT     6,C             ; is it a string ?
  12498.                 JR      NZ,D_SIZE       ; forward to D_SIZE if so.
  12499.  
  12500.                 LD      L,$05           ; make elements 5 bytes as is numeric.
  12501.  
  12502.                                         ;;;$2C2D
  12503. D_SIZE:         EX      DE,HL           ; save the element size in DE.
  12504.  
  12505.                                         ; now enter a loop to parse each of the integers in the list.
  12506.  
  12507.                                         ;;;$2C2E
  12508. D_NO_LOOP:      RST     20H             ; NEXT_CHAR
  12509.                 LD      H,$FF           ; disable limit check by setting HL high
  12510.                 CALL    INT_EXP1        ; routine INT_EXP1
  12511.                 JP      C,REPORT_3      ; to REPORT_3 if > 65280 and then some
  12512.                                         ; 'Subscript out of range'
  12513.                 POP     HL              ; pop dimension counter, array type
  12514.                 PUSH    BC              ; save dimension size                   ***
  12515.                 INC     H               ; increment the dimension counter
  12516.                 PUSH    HL              ; save the dimension counter
  12517.                 LD      H,B             ; transfer size
  12518.                 LD      L,C             ; to HL
  12519.                 CALL    GET_HL_DE       ; routine GET_HL_DE multiplies dimension by
  12520.                                         ; running total of size required initially
  12521.                                         ; 1 or 5.
  12522.                 EX      DE,HL           ; save running total in DE
  12523.                 RST     18H             ; GET_CHAR
  12524.                 CP      $2C             ; is it ',' ?
  12525.                 JR      Z,D_NO_LOOP     ; loop back to D_NO_LOOP until all dimensions
  12526.                                         ; have been considered
  12527.  
  12528.                                         ; when loop complete continue.
  12529.  
  12530.                 CP      $29             ; is it ')' ?
  12531.                 JR      NZ,D_RPORT_C    ; to D_RPORT_C with anything else
  12532.                                         ; 'Nonsense in basic'
  12533.  
  12534.  
  12535.                 RST     20H             ; NEXT_CHAR advances to next statement/CR
  12536.                 POP     BC              ; pop dimension counter/type
  12537.                 LD      A,C             ; type to A
  12538.  
  12539.                                         ; now calculate space required for array variable
  12540.  
  12541.                 LD      L,B             ; dimensions to L since these require 16 bits
  12542.                                         ; then this value will be doubled
  12543.                 LD      H,$00           ; set high byte to zero
  12544.  
  12545.                                         ; another four bytes are required for letter(1), total length(2), number of
  12546.                                         ; dimensions(1) but since we have yet to double allow for two
  12547.  
  12548.                 INC     HL              ; increment
  12549.                 INC     HL              ; increment
  12550.                 ADD     HL,HL           ; now double giving 4 + dimensions * 2
  12551.                 ADD     HL,DE           ; add to space required for array contents
  12552.                 JP      C,REPORT_4      ; to REPORT_4 if > 65535
  12553.                                         ; 'Out of memory'
  12554.                 PUSH    DE              ; save data space
  12555.                 PUSH    BC              ; save dimensions/type
  12556.                 PUSH    HL              ; save total space
  12557.                 LD      B,H             ; total space
  12558.                 LD      C,L             ; to BC
  12559.                 LD      HL,(E_LINE)     ; address E_LINE - first location after variables area
  12560.                 DEC     HL              ; point to location before - the $80 end-marker
  12561.                 CALL    MAKE_ROOM       ; routine MAKE_ROOM creates the space if memory is available.
  12562.                 INC     HL              ; point to first new location and
  12563.                 LD      (HL),A          ; store letter/type
  12564.                 POP     BC              ; pop total space
  12565.                 DEC     BC              ; exclude name
  12566.                 DEC     BC              ; exclude the 16-bit
  12567.                 DEC     BC              ; counter itself
  12568.                 INC     HL              ; point to next location the 16-bit counter
  12569.                 LD      (HL),C          ; insert low byte
  12570.                 INC     HL              ; address next
  12571.                 LD      (HL),B          ; insert high byte
  12572.                 POP     BC              ; pop the number of dimensions.
  12573.                 LD      A,B             ; dimensions to A
  12574.                 INC     HL              ; address next
  12575.                 LD      (HL),A          ; and insert "No. of dims"
  12576.                 LD      H,D             ; transfer DE space + 1 from MAKE_ROOM
  12577.                 LD      L,E             ; to HL
  12578.                 DEC     DE              ; set DE to next location down.
  12579.                 LD      (HL),$00        ; presume numeric and insert a zero
  12580.                 BIT     6,C             ; test bit 6 of C. numeric or string ?
  12581.                 JR      Z,DIM_CLEAR     ; skip to DIM_CLEAR if numeric
  12582.  
  12583.                 LD      (HL),$20        ; place a space character in HL
  12584.  
  12585.                                         ;;;$2C7C
  12586. DIM_CLEAR:      POP     BC              ; pop the data length
  12587.                 LDDR                    ; LDDR sets to zeros or spaces
  12588.  
  12589.                                         ; The number of dimensions is still in A.
  12590.                                         ; A loop is now entered to insert the size of each dimension that was pushed
  12591.                                         ; during the D_NO_LOOP working downwards from position before start of data.
  12592.  
  12593.                                         ;;;$2C7F
  12594. DIM_SIZES:      POP     BC              ; pop a dimension size                  ***
  12595.                 LD      (HL),B          ; insert high byte at position
  12596.                 DEC     HL              ; next location down
  12597.                 LD      (HL),C          ; insert low byte
  12598.                 DEC     HL              ; next location down
  12599.                 DEC     A               ; decrement dimension counter
  12600.                 JR      NZ,DIM_SIZES    ; back to DIM_SIZES until all done.
  12601.  
  12602.                 RET                     ; return.
  12603.  
  12604. ;------------------------------
  12605. ; Check whether digit or letter
  12606. ;------------------------------
  12607. ; This routine checks that the character in A is alphanumeric
  12608. ; returning with carry set if so.
  12609.  
  12610.                                         ;;;$2C88
  12611. ALPHANUM:       CALL    NUMERIC         ; routine NUMERIC will reset carry if so.
  12612.                 CCF                     ; Complement Carry Flag
  12613.                 RET     C               ; Return if numeric else continue into next routine.
  12614.  
  12615.                                         ; This routine checks that the character in A is alphabetic
  12616.  
  12617.                                         ;;;$2C8D
  12618. ALPHA:          CP      $41             ; less than 'A' ?
  12619.                 CCF                     ; Complement Carry Flag
  12620.                 RET     NC              ; return if so
  12621.  
  12622.                 CP      $5B             ; less than 'Z'+1 ?
  12623.                 RET     C               ; is within first range
  12624.  
  12625.                 CP      $61             ; less than 'a' ?
  12626.                 CCF                     ; Complement Carry Flag
  12627.                 RET     NC              ; return if so.
  12628.  
  12629.                 CP      $7B             ; less than 'z'+1 ?
  12630.                 RET                     ; carry set if within a-z.
  12631.  
  12632. ;--------------------------
  12633. ; Decimal to floating point
  12634. ;--------------------------
  12635. ; This routine finds the floating point number represented by an expression
  12636. ; beginning with BIN, '.' or a digit.
  12637. ; Note that BIN need not have any '0's or '1's after it.
  12638. ; BIN is really just a notational symbol and not a function.
  12639.  
  12640.                                         ;;;$2C9B
  12641. DEC_TO_FP:      CP      $C4             ; 'BIN' token ?
  12642.                 JR      NZ,NOT_BIN      ; to NOT_BIN if not
  12643.  
  12644.                 LD      DE,$0000        ; initialize 16 bit buffer register.
  12645.  
  12646.                                         ;;;$2CA2
  12647. BIN_DIGIT:      RST     20H             ; NEXT_CHAR
  12648.                 SUB     $31             ; '1'
  12649.                 ADC     A,$00           ; will be zero if '1' or '0'
  12650.                                         ; carry will be set if was '0'
  12651.                 JR      NZ,BIN_END      ; forward to BIN_END if result not zero
  12652.  
  12653.                 EX      DE,HL           ; buffer to HL
  12654.                 CCF                     ; Carry now set if originally '1'
  12655.                 ADC     HL,HL           ; shift the carry into HL
  12656.                 JP      C,REPORT_6      ; to REPORT_6 if overflow - too many digits
  12657.                                         ; after first '1'. There can be an unlimited
  12658.                                         ; number of leading zeros.
  12659.                                         ; 'Number too big' - raise an error
  12660.                 EX      DE,HL           ; save the buffer
  12661.                 JR      BIN_DIGIT       ; back to BIN_DIGIT for more digits
  12662.  
  12663.                                         ;;;$2CB3
  12664. BIN_END:        LD      B,D             ; transfer 16 bit buffer
  12665.                 LD      C,E             ; to BC register pair.
  12666.                 JP      STACK_BC        ; to STACK_BC to put on calculator stack
  12667.  
  12668.                                         ; continue here with .1,  42, 3.14, 5., 2.3 E -4
  12669.  
  12670.                                         ;;;$2CB8
  12671. NOT_BIN:        CP      $2E             ; '.' - leading decimal point ?
  12672.                 JR      Z,DECIMAL       ; skip to DECIMAL if so.
  12673.  
  12674.                 CALL    INT_TO_FP       ; routine INT_TO_FP to evaluate all digits
  12675.                                         ; This number 'x' is placed on stack.
  12676.                 CP      $2E             ; '.' - mid decimal point ?
  12677.                 JR      NZ,E_FORMAT     ; to E_FORMAT if not to consider that format
  12678.  
  12679.                 RST     20H             ; NEXT_CHAR
  12680.                 CALL    NUMERIC         ; routine NUMERIC returns carry reset if 0-9
  12681.                 JR      C,E_FORMAT      ; to E_FORMAT if not a digit e.g. '1.'
  12682.  
  12683.                 JR      DEC_STO_1       ; to DEC_STO_1 to add the decimal part to 'x'
  12684.  
  12685.                                         ; a leading decimal point has been found in a number.
  12686.  
  12687.                                         ;;;$2CCB
  12688. DECIMAL:        RST     20H             ; NEXT_CHAR
  12689.                 CALL    NUMERIC         ; routine NUMERIC will reset carry if digit
  12690.  
  12691.                                         ;;;$2CCF
  12692. DEC_RPT_C:      JP      C,REPORT_C      ; to REPORT_C if just a '.'
  12693.                                         ; raise 'Nonsense in Basic'
  12694.  
  12695.                                         ; since there is no leading zero put one on the calculator stack.
  12696.  
  12697.                 RST     28H             ;; FP_CALC
  12698.                 DEFB    $A0             ;;STK_ZERO      ; 0.
  12699.                 DEFB    $38             ;;END_CALC
  12700.  
  12701.                                         ; If rejoining from earlier there will be a value 'x' on stack.
  12702.                                         ; If continuing from above the value zero.
  12703.                                         ; Now store 1 in mem-0.
  12704.                                         ; Note. At each pass of the digit loop this will be divided by ten.
  12705.  
  12706.                                         ;;;$2CD5
  12707. DEC_STO_1:      RST     28H             ;; FP_CALC
  12708.                 DEFB    $A1             ;;STK_ONE       ;x or 0,1.
  12709.                 DEFB    $C0             ;;st-mem-0      ;x or 0,1.
  12710.                 DEFB    $02             ;;DELETE        ;x or 0.
  12711.                 DEFB    $38             ;;END_CALC
  12712.  
  12713.                                         ;;;$2CDA
  12714. NXT_DGT_1:      RST     18H             ; GET_CHAR
  12715.                 CALL    STK_DIGIT       ; routine STK_DIGIT stacks single digit 'd'
  12716.                 JR      C,E_FORMAT      ; exit to E_FORMAT when digits exhausted  >
  12717.  
  12718.                 RST     28H             ;; FP_CALC      ;x or 0,d.      first pass.
  12719.                 DEFB    $E0             ;;get-mem-0     ;x or 0,d,1.
  12720.                 DEFB    $A4             ;;STK_TEN       ;x or 0,d,1,10.
  12721.                 DEFB    $05             ;;DIVISION      ;x or 0,d,1/10.
  12722.                 DEFB    $C0             ;;st-mem-0      ;x or 0,d,1/10.
  12723.                 DEFB    $04             ;;MULTIPLY      ;x or 0,d/10.
  12724.                 DEFB    $0F             ;;ADDITION      ;x or 0 + d/10.
  12725.                 DEFB    $38             ;;END_CALC      last value.
  12726.  
  12727.                 RST     20H             ; NEXT_CHAR  moves to next character
  12728.                 JR      NXT_DGT_1       ; back to NXT_DGT_1
  12729.  
  12730.                                         ; although only the first pass is shown it can be seen that at each pass
  12731.                                         ; the new less significant digit is multiplied by an increasingly smaller
  12732.                                         ; factor (1/100, 1/1000, 1/10000 ... ) before being added to the previous
  12733.                                         ; last value to form a new last value.
  12734.  
  12735.                                         ; Finally see if an exponent has been input.
  12736.  
  12737.                                         ;;;$2CEB
  12738. E_FORMAT:       CP      $45             ; is character 'E' ?
  12739.                 JR      Z,SIGN_FLAG     ; to SIGN_FLAG if so
  12740.  
  12741.                 CP      $65             ; 'e' is acceptable as well.
  12742.                 RET     NZ              ; return as no exponent.
  12743.  
  12744.                                         ;;;$2CF2
  12745. SIGN_FLAG:      LD      B,$FF           ; initialize temporary sign byte to $FF
  12746.                 RST     20H             ; NEXT_CHAR
  12747.                 CP      $2B             ; is character '+' ?
  12748.                 JR      Z,SIGN_DONE     ; to SIGN_DONE
  12749.  
  12750.                 CP      $2D             ; is character '-' ?
  12751.                 JR      NZ,ST_E_PART    ; to ST_E_PART as no sign
  12752.  
  12753.                 INC     B               ; set sign to zero
  12754.  
  12755.                                         ; now consider digits of exponent.
  12756.                                         ; Note. incidentally this is the only occasion in Spectrum Basic when an
  12757.                                         ; expression may not be used when a number is expected.
  12758.  
  12759.                                         ;;;$2CFE
  12760. SIGN_DONE:      RST     20H             ; NEXT_CHAR
  12761.  
  12762.                                         ;;;$2CFF
  12763. ST_E_PART:      CALL    NUMERIC         ; routine NUMERIC
  12764.                 JR      C,DEC_RPT_C     ; to DEC_RPT_C if not
  12765.                                         ; raise 'Nonsense in Basic'.
  12766.                 PUSH    BC              ; save sign (in B)
  12767.                 CALL    INT_TO_FP       ; routine INT_TO_FP places exponent on stack
  12768.                 CALL    FP_TO_A         ; routine FP_TO_A  transfers it to A
  12769.                 POP     BC              ; restore sign
  12770.                 JP      C,REPORT_6      ; to REPORT_6 if overflow (over 255)
  12771.                                         ; raise 'Number too big'.
  12772.                 AND     A               ; set flags
  12773.                 JP      M,REPORT_6      ; to REPORT_6 if over '127'.
  12774.                                         ; raise 'Number too big'.
  12775.                                         ; 127 is still way too high and it is
  12776.                                         ; impossible to enter an exponent greater
  12777.                                         ; than 39 from the keyboard. The error gets
  12778.                                         ; raised later in E_TO_FP so two different
  12779.                                         ; error messages depending how high A is.
  12780.                 INC     B               ; $FF to $00 or $00 to $01 - expendable now.
  12781.                 JR      Z,E_FP_JUMP     ; forward to E_FP_JUMP if exponent positive
  12782.  
  12783.                 NEG                     ; Negate the exponent.
  12784.  
  12785.                                         ;;;$2D18
  12786. E_FP_JUMP:      JP      E_TO_FP         ; jump forward to E_TO_FP to assign to
  12787.                                         ; last value x on stack x * 10 to power A
  12788.                                         ; a relative jump would have done.
  12789.  
  12790. ;----------------------
  12791. ; Check for valid digit
  12792. ;----------------------
  12793. ; This routine checks that the ascii character in A is numeric
  12794. ; returning with carry reset if so.
  12795.  
  12796.                                         ;;;$2D1B
  12797. NUMERIC:        CP      $30             ; '0'
  12798.                 RET     C               ; return if less than zero character.
  12799.  
  12800.                 CP      $3A             ; The upper test is '9'
  12801.                 CCF                     ; Complement Carry Flag
  12802.                 RET                     ; Return - carry clear if character '0' - '9'
  12803.  
  12804. ;------------
  12805. ; Stack Digit
  12806. ;------------
  12807. ; This subroutine is called from INT_TO_FP and DEC_TO_FP to stack a digit
  12808. ; on the calculator stack.
  12809.  
  12810.                                         ;;;$2D22
  12811. STK_DIGIT:      CALL    NUMERIC         ; routine NUMERIC
  12812.                 RET     C               ; return if not numeric character
  12813.  
  12814.                 SUB     $30             ; convert from ascii to digit
  12815.  
  12816. ;------------------
  12817. ; Stack accumulator
  12818. ;------------------
  12819.  
  12820.                                         ;;;$2D28
  12821. STACK_A:        LD      C,A             ; transfer to C
  12822.                 LD      B,$00           ; and make B zero
  12823.  
  12824. ;-----------------------
  12825. ; Stack BC register pair
  12826. ;-----------------------
  12827.  
  12828.                                         ;;;$2D2B
  12829. STACK_BC:       LD      IY,ERR_NR       ; re-initialize ERR_NR
  12830.                 XOR     A               ; clear to signal small integer
  12831.                 LD      E,A             ; place in E for sign
  12832.                 LD      D,C             ; LSB to D
  12833.                 LD      C,B             ; MSB to C
  12834.                 LD      B,A             ; last byte not used
  12835.                 CALL    STK_STORE       ; routine STK_STORE
  12836.                 RST     28H             ;; FP_CALC
  12837.                 DEFB    $38             ;;END_CALC  make HL = STKEND-5
  12838.  
  12839.                 AND     A               ; clear carry
  12840.                 RET                     ; before returning
  12841.  
  12842. ;--------------------------
  12843. ; Integer to floating point
  12844. ;--------------------------
  12845. ; This routine places one or more digits found in a basic line
  12846. ; on the calculator stack multiplying the previous value by ten each time
  12847. ; before adding in the new digit to form a last value on calculator stack.
  12848.  
  12849.                                         ;;;$2D3B
  12850. INT_TO_FP:      PUSH    AF              ; save first character
  12851.                 RST     28H             ;; FP_CALC
  12852.                 DEFB    $A0             ;;STK_ZERO      ; v=0. initial value
  12853.                 DEFB    $38             ;;END_CALC
  12854.  
  12855.                 POP     AF              ; fetch first character back.
  12856.  
  12857.                                         ;;;$2D40
  12858. NXT_DGT_2:      CALL    STK_DIGIT       ; routine STK_DIGIT puts 0-9 on stack
  12859.                 RET     C               ; will return when character is not numeric >
  12860.  
  12861.                 RST     28H             ;; FP_CALC      ; v, d.
  12862.                 DEFB    $01             ;;EXCHANGE      ; d, v.
  12863.                 DEFB    $A4             ;;STK_TEN       ; d, v, 10.
  12864.                 DEFB    $04             ;;MULTIPLY      ; d, v*10.
  12865.                 DEFB    $0F             ;;ADDITION      ; d + v*10 = newvalue
  12866.                 DEFB    $38             ;;END_CALC      ; v.
  12867.  
  12868.                 CALL    CH_ADD_1        ; routine CH_ADD_1 get next character
  12869.                 JR      NXT_DGT_2       ; back to NXT_DGT_2 to process as a digit
  12870.  
  12871.  
  12872. ;*********************************
  12873. ;** Part 9. ARITHMETIC ROUTINES **
  12874. ;*********************************
  12875.  
  12876. ;---------------------------
  12877. ; E-format to floating point
  12878. ;---------------------------
  12879. ; This subroutine is used by the PRINT_FP routine and the decimal to FP
  12880. ; routines to stack a number expressed in exponent format.
  12881. ; Note. Though not used by the ROM as such, it has also been set up as
  12882. ; a unary calculator literal but this will not work as the accumulator
  12883. ; is not available from within the calculator.
  12884.  
  12885. ; on entry there is a value x on the calculator stack and an exponent of ten
  12886. ; in A. The required value is x + 10 ^ A
  12887.  
  12888.                                         ;;;$2D4F
  12889. E_TO_FP:        RLCA                    ; this will set the             x.
  12890.                 RRCA                    ; carry if bit 7 is set
  12891.                 JR      NC,E_SAVE       ; to E_SAVE  if positive.
  12892.  
  12893.                 CPL                     ; make negative positive
  12894.                 INC     A               ; without altering carry.
  12895.  
  12896.                                         ;;;$2D55
  12897. E_SAVE:         PUSH    AF              ; save positive exp and sign in carry
  12898.                 LD      HL,MEM_0        ; address MEM_0
  12899.                 CALL    FP_0_1          ; routine FP_0_1
  12900.                                         ; places an integer zero, if no carry,
  12901.                                         ; else a one in mem-0 as a sign flag
  12902.                 RST     28H             ;; FP_CALC
  12903.                 DEFB    $A4             ;;STK_TEN               x, 10.
  12904.                 DEFB    $38             ;;END_CALC
  12905.  
  12906.                 POP     AF              ; pop the exponent.
  12907.  
  12908.                                         ; now enter a loop
  12909.  
  12910.                                         ;;;$2D60
  12911. E_LOOP:         SRL     A               ; 0>76543210>C
  12912.                 JR      NC,E_TST_END    ; forward to E_TST_END if no bit
  12913.  
  12914.                 PUSH    AF              ; save shifted exponent.
  12915.                 RST     28H             ;; FP_CALC
  12916.                 DEFB    $C1             ;;st-mem-1              x, 10.
  12917.                 DEFB    $E0             ;;get-mem-0             x, 10, (0/1).
  12918.                 DEFB    $00             ;;JUMP_TRUE
  12919.  
  12920.                 DEFB    $04             ;;to E_DIVSN
  12921.  
  12922.                 DEFB    $04             ;;MULTIPLY              x*10.
  12923.                 DEFB    $33             ;;jump
  12924.  
  12925.                 DEFB    $02             ;;to E_FETCH
  12926.  
  12927.                                         ;;;$2D6D
  12928. E_DIVSN:        DEFB    $05             ;;DIVISION              x/10.
  12929.  
  12930.                                         ;;;$2D6E
  12931. E_FETCH:        DEFB    $E1             ;;get-mem-1             x/10 or x*10, 10.
  12932.                 DEFB    $38             ;;END_CALC              new x, 10.
  12933.  
  12934.                 POP     AF              ; restore shifted exponent
  12935.  
  12936.                                         ; the loop branched to here with no carry
  12937.  
  12938.                                         ;;;$2D71
  12939. E_TST_END:      JR      Z,E_END         ; forward to E_END  if A emptied of bits
  12940.                 PUSH    AF              ; re-save shifted exponent
  12941.                 RST     28H             ;; FP_CALC
  12942.                 DEFB    $31             ;;DUPLICATE             new x, 10, 10.
  12943.                 DEFB    $04             ;;MULTIPLY              new x, 100.
  12944.                 DEFB    $38             ;;END_CALC
  12945.  
  12946.                 POP     AF              ; restore shifted exponent
  12947.                 JR      E_LOOP          ; back to E_LOOP  until all bits done.
  12948.  
  12949.                                         ; although only the first pass is shown it can be seen that for each set bit
  12950.                                         ; representing a power of two, x is multiplied or divided by the
  12951.                                         ; corresponding power of ten.
  12952.  
  12953.                                         ;;;$2D7B
  12954. E_END:          RST     28H             ;; FP_CALC              final x, factor.
  12955.                 DEFB    $02             ;;DELETE                final x.
  12956.                 DEFB    $38             ;;END_CALC              x.
  12957.  
  12958.                 RET                     ; return
  12959.  
  12960. ;--------------
  12961. ; Fetch integer
  12962. ;--------------
  12963. ; This routine is called by the mathematical routines - FP_TO_BC, PRINT_FP,
  12964. ; MULTIPLY, RE_STACK and NEGATE to fetch an integer from address HL.
  12965. ; HL points to the stack or a location in MEM and no deletion occurs.
  12966. ; If the number is negative then a similar process to that used in INT_STORE
  12967. ; is used to restore the twos complement number to normal in DE and a sign
  12968. ; in C.
  12969.  
  12970.                                         ;;;$2D7F
  12971. INT_FETCH:      INC     HL              ; skip zero indicator.
  12972.                 LD      C,(HL)          ; fetch sign to C
  12973.                 INC     HL              ; address low byte
  12974.                 LD      A,(HL)          ; fetch to A
  12975.                 XOR     C               ; two's complement
  12976.                 SUB     C
  12977.                 LD      E,A             ; place in E
  12978.                 INC     HL              ; address high byte
  12979.                 LD      A,(HL)          ; fetch to A
  12980.                 ADC     A,C             ; two's complement
  12981.                 XOR     C
  12982.                 LD      D,A             ; place in D
  12983.                 RET                     ; return
  12984.  
  12985. ;-------------------------
  12986. ; Store a positive integer
  12987. ;-------------------------
  12988. ; This entry point is not used in this ROM but would
  12989. ; store any integer as positive.
  12990.  
  12991.                                         ;;;$2D8C
  12992. P_INT_STO:      LD      C,$00           ; make sign byte positive and continue
  12993.  
  12994. ;--------------
  12995. ; Store integer
  12996. ;--------------
  12997. ; this routine stores an integer in DE at address HL.
  12998. ; It is called from MULTIPLY, TRUNCATE, NEGATE and SGN.
  12999. ; The sign byte $00 +ve or $FF -ve is in C.
  13000. ; If negative, the number is stored in 2's complement form so that it is
  13001. ; ready to be added.
  13002.  
  13003.                                         ;;;$2D8E
  13004. INT_STORE:      PUSH    HL              ; preserve HL
  13005.                 LD      (HL),$00        ; first byte zero shows integer not exponent
  13006.                 INC     HL
  13007.                 LD      (HL),C          ; then store the sign byte
  13008.                 INC     HL
  13009.                                         ; e.g.             +1             -1
  13010.                 LD      A,E             ; fetch low byte   00000001       00000001
  13011.                 XOR     C               ; xor sign         00000000   or  11111111
  13012.                                         ; gives            00000001   or  11111110
  13013.                 SUB     C               ; sub sign         00000000   or  11111111
  13014.                                         ; gives            00000001>0 or  11111111>C
  13015.                 LD      (HL),A          ; store 2's complement.
  13016.                 INC     HL
  13017.                 LD      A,D             ; high byte        00000000       00000000
  13018.                 ADC     A,C             ; sign             00000000<0     11111111<C
  13019.                                         ; gives            00000000   or  00000000
  13020.                 XOR     C               ; xor sign         00000000       11111111
  13021.                 LD      (HL),A          ; store 2's complement.
  13022.                 INC     HL
  13023.                 LD      (HL),$00        ; last byte always zero for integers.
  13024.                                         ; is not used and need not be looked at when
  13025.                                         ; testing for zero but comes into play should
  13026.                                         ; an integer be converted to fp.
  13027.                 POP     HL              ; restore HL
  13028.                 RET                     ; return.
  13029.  
  13030.  
  13031. ;------------------------------
  13032. ; Floating point to BC register
  13033. ;------------------------------
  13034. ; This routine gets a floating point number e.g. 127.4 from the calculator
  13035. ; stack to the BC register.
  13036.  
  13037.                                         ;;;$2DA2
  13038. FP_TO_BC:       RST     28H             ;; FP_CALC              set HL to
  13039.                 DEFB    $38             ;;END_CALC              point to last value.
  13040.  
  13041.                 LD      A,(HL)          ; get first of 5 bytes
  13042.                 AND     A               ; and test
  13043.                 JR      Z,FP_DELETE     ; forward to FP_DELETE if an integer
  13044.  
  13045.                                         ; The value is first rounded up and then converted to integer.
  13046.  
  13047.                 RST     28H             ;; FP_CAL               x.
  13048.                 DEFB    $A2             ;;STK_HALF              x. 1/2.
  13049.                 DEFB    $0F             ;;ADDITION              x + 1/2.
  13050.                 DEFB    $27             ;;INT                   int(x + .5)
  13051.                 DEFB    $38             ;;END_CALC
  13052.  
  13053.                                         ; now delete but leave HL pointing at integer
  13054.  
  13055.                                         ;;;$2DAD
  13056. FP_DELETE:      RST     28H             ;; FP_CALC
  13057.                 DEFB    $02             ;;DELETE
  13058.                 DEFB    $38             ;;END_CALC
  13059.  
  13060.                 PUSH    HL              ; save pointer.
  13061.                 PUSH    DE              ; and STKEND.
  13062.                 EX      DE,HL           ; make HL point to exponent/zero indicator
  13063.                 LD      B,(HL)          ; indicator to B
  13064.                 CALL    INT_FETCH       ; routine INT_FETCH
  13065.                                         ; gets int in DE sign byte to C
  13066.                                         ; but meaningless values if a large integer
  13067.                 XOR     A               ; clear A
  13068.                 SUB     B               ; subtract indicator byte setting carry
  13069.                                         ; if not a small integer.
  13070.                 BIT     7,C             ; test a bit of the sign byte setting zero
  13071.                                         ; if positive.
  13072.                 LD      B,D             ; transfer int
  13073.                 LD      C,E             ; to BC
  13074.                 LD      A,E             ; low byte to A as a useful return value.
  13075.                 POP     DE              ; pop STKEND
  13076.                 POP     HL              ; and pointer to last value
  13077.                 RET                     ; return
  13078.                                         ; if carry is set then the number was too big.
  13079.  
  13080. ;-------------
  13081. ; LOG(2&A)
  13082. ;-------------
  13083. ; This routine is used when printing floating point numbers to
  13084.  
  13085.                                         ;;;$2DC1
  13086. LOG_2_A:        LD      D,A
  13087.                 RLA
  13088.                 SBC     A,A
  13089.                 LD      E,A
  13090.                 LD      C,A
  13091.                 XOR     A
  13092.                 LD      B,A
  13093.                 CALL    STK_STORE       ; routine STK_STORE
  13094.                 RST     28H             ;; FP_CALC
  13095.                 DEFB    $34             ;;STK_DATA
  13096.                 DEFB    $EF             ;;Exponent: $7F, Bytes: 4
  13097.                 DEFB    $1A,$20,$9A,$85
  13098.                 DEFB    $04             ;;MULTIPLY
  13099.                 DEFB    $27             ;;INT
  13100.                 DEFB    $38             ;;END_CALC
  13101.  
  13102. ;--------------------
  13103. ; Floating point to A
  13104. ;--------------------
  13105. ; this routine collects a floating point number from the stack into the
  13106. ; accumulator returning carry set if not in range 0 - 255.
  13107. ; Not all the calling routines raise an error with overflow so no attempt
  13108. ; is made to produce an error report here.
  13109.  
  13110.                                         ;;;$2DD5
  13111. FP_TO_A:        CALL    FP_TO_BC        ; routine FP_TO_BC returns with C in A also.
  13112.                 RET     C               ; return with carry set if > 65535, overflow
  13113.  
  13114.                 PUSH    AF              ; save the value and flags
  13115.                 DEC     B               ; and test that
  13116.                 INC     B               ; the high byte is zero.
  13117.                 JR      Z,FP_A_END      ; forward  FP_A_END if zero
  13118.  
  13119.                                         ; else there has been 8-bit overflow
  13120.  
  13121.                 POP     AF              ; retrieve the value
  13122.                 SCF                     ; set carry flag to show overflow
  13123.                 RET                     ; and return.
  13124.  
  13125.                                         ;;;$2DE1
  13126. FP_A_END:       POP     AF              ; restore value and success flag and
  13127.                 RET                     ; return.
  13128.  
  13129.  
  13130. ;------------------------------
  13131. ; Print a floating point number
  13132. ;------------------------------
  13133. ; Not a trivial task.
  13134. ; Begin by considering whether to print a leading sign for negative numbers.
  13135.  
  13136.                                         ;;;$2DE3
  13137. PRINT_FP:       RST     28H             ;; FP_CALC
  13138.                 DEFB    $31             ;;DUPLICATE
  13139.                 DEFB    $36             ;;LESS_0
  13140.                 DEFB    $00             ;;JUMP_TRUE
  13141.  
  13142.                 DEFB    $0B             ;;to PF_NEGTVE
  13143.  
  13144.                 DEFB    $31             ;;DUPLICATE
  13145.                 DEFB    $37             ;;GREATER_0
  13146.                 DEFB    $00             ;;JUMP_TRUE
  13147.  
  13148.                 DEFB    $0D             ;;to PF_POSTVE
  13149.  
  13150.                                         ; must be zero itself
  13151.  
  13152.                 DEFB    $02             ;;DELETE
  13153.                 DEFB    $38             ;;END_CALC
  13154.  
  13155.                 LD      A,$30           ; prepare the character '0'
  13156.                 RST     10H             ; PRINT_A
  13157.                 RET                     ; return.               ->
  13158.  
  13159.                                         ;;;$2DF2
  13160. PF_NEGTVE:      DEFB    $2A             ;;ABS
  13161.                 DEFB    $38             ;;END_CALC
  13162.  
  13163.                 LD      A,$2D           ; the character '-'
  13164.                 RST     10H             ; PRINT_A
  13165.  
  13166.                                         ; and continue to print the now positive number.
  13167.  
  13168.                 RST     28H             ;; FP_CALC
  13169.  
  13170.                                         ;;;$2DF8
  13171. PF_POSTVE:      DEFB    $A0             ;;STK_ZERO      x,0.    begin by
  13172.                 DEFB    $C3             ;;st-mem-3      x,0.    clearing a temporary
  13173.                 DEFB    $C4             ;;st-mem-4      x,0.    output buffer to
  13174.                 DEFB    $C5             ;;st-mem-5      x,0.    fifteen zeros.
  13175.                 DEFB    $02             ;;DELETE        x.
  13176.                 DEFB    $38             ;;END_CALC      x.
  13177.  
  13178.                 EXX                     ; in case called from 'STR$' then save the
  13179.                 PUSH    HL              ; pointer to whatever comes after
  13180.                 EXX                     ; STR$ as H'L' will be used.
  13181.  
  13182.                                         ; now enter a loop?
  13183.  
  13184.                                         ;;;$2E01
  13185. PF_LOOP:        RST     28H             ;; FP_CALC
  13186.                 DEFB    $31             ;;DUPLICATE     x,x.
  13187.                 DEFB    $27             ;;INT           x,int x.
  13188.                 DEFB    $C2             ;;st-mem-2      x,int x.
  13189.                 DEFB    $03             ;;SUBTRACT      x-int x.        fractional part.
  13190.                 DEFB    $E2             ;;get-mem-2     x-int x, int x.
  13191.                 DEFB    $01             ;;EXCHANGE      int x, x-int x.
  13192.                 DEFB    $C2             ;;st-mem-2      int x, x-int x.
  13193.                 DEFB    $02             ;;DELETE        int x.
  13194.                 DEFB    $38             ;;END_CALC      int x.
  13195.                                         ;
  13196.                                         ; mem-2 holds the fractional part.
  13197.  
  13198.                                         ; HL points to last value int x
  13199.  
  13200.                 LD      A,(HL)          ; fetch exponent of int x.
  13201.                 AND     A               ; test
  13202.                 JR      NZ,PF_LARGE     ; forward to PF_LARGE if a large integer
  13203.                                         ; > 65535
  13204.  
  13205.                                         ; continue with small positive integer components in range 0 - 65535
  13206.                                         ; if original number was say .999 then this integer component is zero.
  13207.  
  13208.                 CALL    INT_FETCH       ; routine INT_FETCH gets x in DE
  13209.                                         ; (but x is not deleted)
  13210.                 LD      B,$10           ; set B, bit counter, to 16d
  13211.                 LD      A,D             ; test if
  13212.                 AND     A               ; high byte is zero
  13213.                 JR      NZ,PF_SAVE      ; forward to PF_SAVE if 16-bit integer.
  13214.  
  13215.                                         ; and continue with integer in range 0 - 255.
  13216.  
  13217.                 OR      E               ; test the low byte for zero
  13218.                                         ; i.e. originally just point something or other.
  13219.                 JR      Z,PF_SMALL      ; forward if so to PF_SMALL  
  13220.  
  13221.                 LD      D,E             ; transfer E to D
  13222.                 LD      B,$08           ; and reduce the bit counter to 8.
  13223.  
  13224.                                         ;;;$2E1E
  13225. PF_SAVE:        PUSH    DE              ; save the part before decimal point.
  13226.                 EXX
  13227.                 POP     DE              ; and pop in into D'E'
  13228.                 EXX
  13229.                 JR      PF_BITS         ; forward to PF_BITS
  13230.  
  13231.                                         ; the branch was here when 'int x' was found to be zero as in say 0.5.
  13232.                                         ; The zero has been fetched from the calculator stack but not deleted and
  13233.                                         ; this should occur now. This omission leaves the stack unbalanced and while
  13234.                                         ; that causes no problems with a simple PRINT statement, it will if STR$ is
  13235.                                         ; being used in an expression e.g. "2" + STR$ 0.5 gives the result "0.5"
  13236.                                         ; instead of the expected result "20.5".
  13237.                                         ; credit Tony Stratton, 1982.
  13238.                                         ; A DEFB 02 delete is required immediately on using the calculator.
  13239.  
  13240.                                         ;;;$2E24
  13241. PF_SMALL:       RST     28H             ;; FP_CALC      int x = 0.
  13242. L2E25:          DEFB    $E2             ;;get-mem-2     int x = 0, x-int x.
  13243.                 DEFB    $38             ;;END_CALC
  13244.  
  13245.                 LD      A,(HL)          ; fetch exponent of positive fractional number
  13246.                 SUB     $7E             ; subtract
  13247.                 CALL    LOG_2_A         ; routine LOG_2_A calculates leading digits.
  13248.                 LD      D,A             ; transfer count to D
  13249.                 LD      A,(MEM_5_1)     ; fetch total digits - MEM_5 2nd byte
  13250.                 SUB     D
  13251.                 LD      (MEM_5_1),A     ; store MEM_5 2nd byte
  13252.                 LD      A,D
  13253.                 CALL    E_TO_FP         ; routine E_TO_FP
  13254.                 RST     28H             ;; FP_CALC
  13255.                 DEFB    $31             ;;DUPLICATE
  13256.                 DEFB    $27             ;;INT
  13257.                 DEFB    $C1             ;;st-mem-1
  13258.                 DEFB    $03             ;;SUBTRACT
  13259.                 DEFB    $E1             ;;get-mem-1
  13260.                 DEFB    $38             ;;END_CALC
  13261.  
  13262.                 CALL    FP_TO_A         ; routine FP_TO_A
  13263.                 PUSH    HL              ; save HL
  13264.                 LD      (MEM_3),A       ; MEM_3 1st byte
  13265.                 DEC     A
  13266.                 RLA
  13267.                 SBC     A,A
  13268.                 INC     A
  13269.                 LD      HL,MEM_5_0      ; address MEM_5 leading digit counter
  13270.                 LD      (HL),A          ; store counter
  13271.                 INC     HL              ; address MEM_5 2nd byte - total digits
  13272.                 ADD     A,(HL)          ; add counter to contents
  13273.                 LD      (HL),A          ; and store updated value
  13274.                 POP     HL              ; restore HL
  13275.                 JP      PF_FRACTN       ; jump forward to PF_FRACTN
  13276.  
  13277.                                         ; Note. while it would be pedantic to comment on every occasion a JP
  13278.                                         ; instruction could be replaced with a JR instruction, this applies to the
  13279.                                         ; above, which is useful if you wish to correct the unbalanced stack error
  13280.                                         ; by inserting a 'DEFB 02 delete' at L2E25, and maintain main addresses.
  13281.  
  13282.                                         ; the branch was here with a large positive integer > 65535 e.g. 123456789
  13283.                                         ; the accumulator holds the exponent.
  13284.  
  13285.                                         ;;;$2E56
  13286. PF_LARGE:       SUB     $80             ; make exponent positive
  13287.                 CP      $1C             ; compare to 28
  13288.                 JR      C,PF_MEDIUM     ; to PF_MEDIUM if integer <= 2^27
  13289.  
  13290.                 CALL    LOG_2_A         ; routine LOG_2_A
  13291.                 SUB     $07
  13292.                 LD      B,A
  13293.                 LD      HL,MEM_5_1      ; address MEM_5_1 the leading digits counter.
  13294.                 ADD     A,(HL)          ; add A to contents
  13295.                 LD      (HL),A          ; store updated value.
  13296.                 LD      A,B
  13297.                 NEG                     ; negate
  13298.                 CALL    E_TO_FP         ; routine E_TO_FP
  13299.                 JR      PF_LOOP         ; back to PF_LOOP
  13300.  
  13301.                                         ;;;$2E6F
  13302. PF_MEDIUM:      EX      DE,HL
  13303.                 CALL    FETCH_TWO       ; routine FETCH_TWO
  13304.                 EXX
  13305.                 SET     7,D
  13306.                 LD      A,L
  13307.                 EXX
  13308.                 SUB     $80
  13309.                 LD      B,A
  13310.  
  13311.                                         ; the branch was here to handle bits in DE with 8 or 16 in B  if small int
  13312.                                         ; and integer in D'E', 6 nibbles will accommodate 065535 but routine does
  13313.                                         ; 32-bit numbers as well from above
  13314.  
  13315.                                         ;;;$2E7B
  13316. PF_BITS:        SLA     E               ;  C<xxxxxxxx<0
  13317.                 RL      D               ;  C<xxxxxxxx<C
  13318.                 EXX
  13319.                 RL      E               ;  C<xxxxxxxx<C
  13320.                 RL      D               ;  C<xxxxxxxx<C
  13321.                 EXX
  13322.                 LD      HL,MEM_4_4      ; set HL to MEM_4 5th last byte of buffer
  13323.                 LD      C,$05           ; set byte count to 5 - 10 nibbles
  13324.  
  13325.                                         ;;;$2E8A
  13326. PF_BYTES:       LD      A,(HL)          ; fetch 0 or prev value
  13327.                 ADC     A,A             ; shift left add in carry       C<xxxxxxxx<C
  13328.                 DAA                     ; Decimal Adjust Accumulator.
  13329.                                         ; if greater than 9 then the left hand
  13330.                                         ; nibble is incremented. If greater than
  13331.                                         ; 99 then adjusted and carry set.
  13332.                                         ; so if we'd built up 7 and a carry came in
  13333.                                         ;       0000 0111 < C
  13334.                                         ;       0000 1111
  13335.                                         ; daa   1 0101  which is 15 in BCD
  13336.                 LD      (HL),A          ; put back
  13337.                 DEC     HL              ; work down thru mem 4
  13338.                 DEC     C               ; decrease the 5 counter.
  13339.                 JR      NZ,PF_BYTES     ; back to PF_BYTES until the ten nibbles rolled
  13340.  
  13341.                 DJNZ    PF_BITS         ; back to PF_BITS until 8 or 16 (or 32) done
  13342.  
  13343.                                         ; at most 9 digits for 32-bit number will have been loaded with digits
  13344.                                         ; each of the 9 nibbles in mem 4 is placed into ten bytes in mem-3 and mem 4
  13345.                                         ; unless the nibble is zero as the buffer is already zero.
  13346.                                         ; ( or in the case of mem-5 will become zero as a result of RLD instruction )
  13347.  
  13348.                 XOR     A               ; clear to accept
  13349.                 LD      HL,MEM_4        ; address MEM_4 byte destination.
  13350.                 LD      DE,MEM_3        ; address MEM_3 nibble source.
  13351.                 LD      B,$09           ; the count is 9 (not ten) as the first
  13352.                                         ; nibble is known to be blank.
  13353.                 RLD                     ; shift RH nibble to left in (HL)
  13354.                                         ;       A               (HL)
  13355.                                         ; 0000 0000 < 0000 3210
  13356.                                         ; 0000 0000     3210 0000
  13357.                                         ; A picks up the blank nibble
  13358.                 LD      C,$FF           ; set a flag to indicate when a significant
  13359.                                         ; digit has been encountered.
  13360.  
  13361.                                         ;;;$2EA1
  13362. PF_DIGITS:      RLD                     ; pick up leftmost nibble from (HL)
  13363.                                         ;    A           (HL)
  13364.                                         ; 0000 0000 < 7654 3210
  13365.                                         ; 0000 7654   3210 0000
  13366.                 JR      NZ,PF_INSERT    ; to PF_INSERT if non-zero value picked up.
  13367.  
  13368.                 DEC     C               ; test
  13369.                 INC     C               ; flag
  13370.                 JR      NZ,PF_TEST_2    ; skip forward to PF_TEST_2 if flag still $FF
  13371.                                         ; indicating this is a leading zero.
  13372.  
  13373.                                         ; but if the zero is a significant digit e.g. 10 then include in digit totals.
  13374.                                         ; the path for non-zero digits rejoins here.
  13375.  
  13376.                                         ;;;$2EA9
  13377. PF_INSERT:      LD      (DE),A          ; insert digit at destination
  13378.                 INC     DE              ; increase the destination pointer
  13379.                 INC     (IY+$71)        ; increment MEM_5 1st  digit counter
  13380.                 INC     (IY+$72)        ; increment MEM_5 2nd  leading digit counter
  13381.                 LD      C,$00           ; set flag to zero indicating that any
  13382.                                         ; subsequent zeros are significant and not leading.
  13383.  
  13384.                                         ;;;$L2EB3
  13385. PF_TEST_2:      BIT     0,B             ; test if the nibble count is even
  13386.                 JR      Z,PF_ALL_9      ; skip to PF_ALL_9 if so to deal with the other nibble in the same byte
  13387.  
  13388.                 INC     HL              ; point to next source byte if not
  13389.  
  13390.                                         ;;;$2EB8
  13391. PF_ALL_9:       DJNZ    PF_DIGITS       ; decrement the nibble count, back to PF_DIGITS
  13392.                                         ; if all nine not done.
  13393.  
  13394.                                         ; For 8-bit integers there will be at most 3 digits.
  13395.                                         ; For 16-bit integers there will be at most 5 digits.
  13396.                                         ; but for larger integers there could be nine leading digits.
  13397.                                         ; if nine digits complete then the last one is rounded up as the number will
  13398.                                         ; be printed using E-format notation
  13399.                 LD      A,(MEM_5_0)     ; fetch digit count from MEM_5 1st
  13400.                 SUB     $09             ; subtract 9 - max possible
  13401.                 JR      C,PF_MORE       ; forward if less to PF_MORE
  13402.  
  13403.                 DEC     (IY+$71)        ; decrement digit counter MEM_5 1st to 8
  13404.                 LD      A,$04           ; load A with the value 4.
  13405.                 CP      (IY+$6F)        ; compare with MEM_4 4th - the ninth digit
  13406.                 JR      PF_ROUND        ; forward to PF_ROUND
  13407.                                         ; to consider rounding.
  13408.  
  13409.                                         ; now delete int x from calculator stack and fetch fractional part.
  13410.  
  13411.                                         ;;;$2ECB
  13412. PF_MORE:        RST     28H             ;; FP_CALC      int x.
  13413.                 DEFB    $02             ;;DELETE        .
  13414.                 DEFB    $E2             ;;get-mem-2     x - int x = f.
  13415.                 DEFB    $38             ;;end-calca     f.
  13416.  
  13417.                                         ;;;$2ECF
  13418. PF_FRACTN:      EX      DE,HL
  13419.                 CALL    FETCH_TWO       ; routine FETCH_TWO
  13420.                 EXX
  13421.                 LD      A,$80
  13422.                 SUB     L
  13423.                 LD      L,$00
  13424.                 SET     7,D
  13425.                 EXX
  13426.                 CALL    SHIFT_FP        ; routine SHIFT_FP
  13427.  
  13428.                                         ;;;$2EDF
  13429. PF_FRN_LP:      LD      A,(IY+$71)      ; MEM_5 1st
  13430.                 CP      $08
  13431.                 JR      C,PF_FR_DGT     ; to PF_FR_DGT
  13432.  
  13433.                 EXX
  13434.                 RL      D
  13435.                 EXX
  13436.                 JR      PF_ROUND        ; to PF_ROUND
  13437.  
  13438.                                         ;;;$2EEC
  13439. PF_FR_DGT:      LD      BC,$0200
  13440.  
  13441.                                         ;;;$2EEF
  13442. PF_FR_EXX:      LD      A,E
  13443.                 CALL    CA_10_A_C       ; routine CA_10_A_C
  13444.                 LD      E,A
  13445.                 LD      A,D
  13446.                 CALL    CA_10_A_C       ; routine CA_10_A_C
  13447.                 LD      D,A
  13448.                 PUSH    BC
  13449.                 EXX
  13450.                 POP     BC
  13451.                 DJNZ    PF_FR_EXX       ; to PF_FR_EXX
  13452.                 LD      HL,MEM_3        ; MEM-3
  13453.                 LD      A,C
  13454.                 LD      C,(IY+$71)      ; MEM_5 1st
  13455.                 ADD     HL,BC
  13456.                 LD      (HL),A
  13457.                 INC     (IY+$71)        ; MEM_5 1st
  13458.                 JR      PF_FRN_LP       ; to PF_FRN_LP
  13459.  
  13460.  
  13461.                                         ; 1) with 9 digits but 8 in MEM_5_1 and A holding 4, carry set if rounding up.
  13462.                                         ; e.g.
  13463.                                         ;       999999999 is printed as 1E+9
  13464.                                         ;       100000001 is printed as 1E+8
  13465.                                         ;       100000009 is printed as 1.0000001E+8
  13466.  
  13467.                                         ;;;$2F0C
  13468. PF_ROUND:       PUSH    AF              ; save A and flags
  13469.                 LD      HL,MEM_3        ; address MEM_3 start of digits
  13470.                 LD      C,(IY+$71)      ; MEM_5 1st No. of digits to C
  13471.                 LD      B,$00           ; prepare to add
  13472.                 ADD     HL,BC           ; address last digit + 1
  13473.                 LD      B,C             ; No. of digits to B counter
  13474.                 POP     AF              ; restore A and carry flag from comparison.
  13475.  
  13476.                                         ;;;$2F18
  13477. PF_RND_LP:      DEC     HL              ; address digit at rounding position.
  13478.                 LD      A,(HL)          ; fetch it
  13479.                 ADC     A,$00           ; add carry from the comparison
  13480.                 LD      (HL),A          ; put back result even if $0A.
  13481.                 AND     A               ; test A
  13482.                 JR      Z,PF_R_BACK     ; skip to PF_R_BACK if ZERO?
  13483.  
  13484.                 CP      $0A             ; compare to 'ten' - overflow
  13485.                 CCF                     ; complement carry flag so that set if ten.
  13486.                 JR      NC,PF_COUNT     ; forward to PF_COUNT with 1 - 9.
  13487.  
  13488.                                         ;;;$2F25
  13489. PF_R_BACK:      DJNZ    PF_RND_LP       ; loop back to PF_RND_LP
  13490.  
  13491.                                         ; if B counts down to zero then we've rounded right back as in 999999995.
  13492.                                         ; and the first 8 locations all hold $0A.
  13493.  
  13494.  
  13495.                 LD      (HL),$01        ; load first location with digit 1.
  13496.                 INC     B               ; make B hold 1 also.
  13497.                                         ; could save an instruction byte here.
  13498.                 INC     (IY+$72)        ; make MEM-5-2nd hold 1.
  13499.                                         ; and proceed to initialize total digits to 1.
  13500.  
  13501.                                         ;;;$2F2D
  13502. PF_COUNT:       LD      (IY+$71),B      ; MEM_5 1st
  13503.  
  13504.                                         ; now balance the calculator stack by deleting  it
  13505.  
  13506.                 RST     28H             ;; FP_CALC
  13507.                 DEFB    $02             ;;DELETE
  13508.                 DEFB    $38             ;;END_CALC
  13509.  
  13510.                                         ; note if used from STR$ then other values may be on the calculator stack.
  13511.                                         ; we can also restore the next literal pointer from it's position on the
  13512.                                         ; machine stack.
  13513.  
  13514.                 EXX
  13515.                 POP     HL              ; restore next literal pointer.
  13516.                 EXX
  13517.                 LD      BC,(MEM_5_0)    ; set C to MEM_5 1st digit counter.
  13518.                                         ; set B to MEM_5 2nd leading digit counter.
  13519.                 LD      HL,MEM_3        ; set HL to start of digits at MEM_3
  13520.                 LD      A,B
  13521.                 CP      $09
  13522.                 JR      C,PF_NOT_E      ; to PF_NOT_E
  13523.  
  13524.                 CP      $FC             ;
  13525.                 JR      C,PF_E_FRMT     ; to PF_E_FRMT
  13526.  
  13527.                                         ;;;$2F46
  13528. PF_NOT_E:       AND     A               ; test for zero leading digits as in .123
  13529.                 CALL    Z,OUT_CODE      ; routine OUT_CODE prints a zero e.g. 0.123
  13530.  
  13531.                                         ;;;$2F4A
  13532. PF_E_SBRN:      XOR     A
  13533.                 SUB     B
  13534.                 JP      M,PF_OUT_LP     ; skip forward to PF_OUT_LP if originally +ve
  13535.  
  13536.                 LD      B,A             ; else negative count now +ve
  13537.                 JR      PF_DC_OUT       ; forward to PF_DC_OUT  ->
  13538.  
  13539.                                         ;;;$2F52
  13540. PF_OUT_LP:      LD      A,C             ; fetch total digit count
  13541.                 AND     A               ; test for zero
  13542.                 JR      Z,PF_OUT_DT     ; forward to PF_OUT_DT if so
  13543.  
  13544.                 LD      A,(HL)          ; fetch digit
  13545.                 INC     HL              ; address next digit
  13546.                 DEC     C               ; decrease total digit counter
  13547.  
  13548.                                         ;;;$2F59
  13549. PF_OUT_DT:      CALL    OUT_CODE        ; routine OUT_CODE outputs it.
  13550.                 DJNZ    PF_OUT_LP       ; loop back to PF_OUT_LP until B leading digits output.
  13551.  
  13552.                                         ;;;$2F5E
  13553. PF_DC_OUT:      LD      A,C             ; fetch total digits and
  13554.                 AND     A               ; test if also zero
  13555.                 RET     Z               ; return if so                  -->
  13556.  
  13557.                 INC     B               ; increment B
  13558.                 LD      A,$2E           ; prepare the character '.'
  13559.  
  13560.                                         ;;;$L2F64
  13561. PF_DEC_0:       RST     10H             ; PRINT_A outputs the character '.' or '0'
  13562.                 LD      A,$30           ; prepare the character '0'
  13563.                                         ; (for cases like .000012345678)
  13564.                 DJNZ    PF_DEC_0        ; loop back to PF_DEC_0 for B times.
  13565.                 LD      B,C             ; load B with now trailing digit counter.
  13566.                 JR      PF_OUT_LP       ; back to PF_OUT_LP
  13567.  
  13568.                                         ; the branch was here for E-format printing e.g 123456789 => 1.2345679e+8
  13569.  
  13570.                                         ;;;$2F6C
  13571. PF_E_FRMT:      LD      D,B             ; counter to D
  13572.                 DEC     D               ; decrement
  13573.                 LD      B,$01           ; load B with 1.
  13574.                 CALL    PF_E_SBRN       ; routine PF_E_SBRN above
  13575.                 LD      A,$45           ; prepare character 'e'
  13576.                 RST     10H             ; PRINT_A
  13577.                 LD      C,D             ; exponent to C
  13578.                 LD      A,C             ; and to A
  13579.                 AND     A               ; test exponent
  13580.                 JP      P,PF_E_POS      ; to PF_E_POS if positive
  13581.  
  13582.                 NEG                     ; negate
  13583.                 LD      C,A             ; positive exponent to C
  13584.                 LD      A,$2D           ; prepare character '-'
  13585.                 JR      PF_E_SIGN       ; skip to PF_E_SIGN
  13586.  
  13587.                                         ;;;$2F83
  13588. PF_E_POS:       LD      A,$2B           ; prepare character '+'
  13589.  
  13590.                                         ;;;$2F85
  13591. PF_E_SIGN:      RST     10H             ; PRINT_A outputs the sign
  13592.                 LD      B,$00           ; make the high byte zero.
  13593.                 JP      OUT_NUM_1       ; exit via OUT_NUM_1 to print exponent in BC
  13594.  
  13595. ;-------------------------------
  13596. ; Handle printing floating point
  13597. ;-------------------------------
  13598. ; This subroutine is called twice from above when printing floating-point
  13599. ; numbers. It returns 10*A +C in registers C and A
  13600.  
  13601.                                         ;;;$2F8B
  13602.                                         ; CA-10*A+C
  13603. CA_10_A_C:      PUSH    DE              ; preserve DE.
  13604.                 LD      L,A             ; transfer A to L
  13605.                 LD      H,$00           ; zero high byte.
  13606.                 LD      E,L             ; copy HL
  13607.                 LD      D,H             ; to DE.
  13608.                 ADD     HL,HL           ; double (*2)
  13609.                 ADD     HL,HL           ; double (*4)
  13610.                 ADD     HL,DE           ; add DE (*5)
  13611.                 ADD     HL,HL           ; double (*10)
  13612.                 LD      E,C             ; copy C to E   (D is 0)
  13613.                 ADD     HL,DE           ; and add to give required result.
  13614.                 LD      C,H             ; transfer to
  13615.                 LD      A,L             ; destination registers.
  13616.                 POP     DE              ; restore DE
  13617.                 RET                     ; return with result.
  13618.  
  13619. ;---------------
  13620. ; Prepare to add
  13621. ;---------------
  13622. ; This routine is called twice by addition to prepare the two numbers. The
  13623. ; exponent is picked up in A and the location made zero. Then the sign bit
  13624. ; is tested before being set to the implied state. Negative numbers are twos
  13625. ; complemented.
  13626.  
  13627.                                         ;;;$2F9B
  13628. PREP_ADD:       LD      A,(HL)          ; pick up exponent
  13629.                 LD      (HL),$00        ; make location zero
  13630.                 AND     A               ; test if number is zero
  13631.                 RET     Z               ; return if so
  13632.  
  13633.                 INC     HL              ; address mantissa
  13634.                 BIT     7,(HL)          ; test the sign bit
  13635.                 SET     7,(HL)          ; set it to implied state
  13636.                 DEC     HL              ; point to exponent
  13637.                 RET     Z               ; return if positive number.
  13638.  
  13639.                 PUSH    BC              ; preserve BC
  13640.                 LD      BC,$0005        ; length of number
  13641.                 ADD     HL,BC           ; point HL past end
  13642.                 LD      B,C             ; set B to 5 counter
  13643.                 LD      C,A             ; store exponent in C
  13644.                 SCF                     ; set carry flag
  13645.  
  13646.                                         ;;;$2FAF
  13647. NEG_BYTE:       DEC     HL              ; work from LSB to MSB
  13648.                 LD      A,(HL)          ; fetch byte
  13649.                 CPL                     ; complement
  13650.                 ADC     A,$00           ; add in initial carry or from prev operation
  13651.                 LD      (HL),A          ; put back
  13652.                 DJNZ    NEG_BYTE        ; loop to NEG_BYTE till all 5 done
  13653.                 LD      A,C             ; stored exponent to A
  13654.                 POP     BC              ; restore original BC
  13655.                 RET                     ; return
  13656.  
  13657. ;------------------
  13658. ; Fetch two numbers
  13659. ;------------------
  13660. ; This routine is called twice when printing floating point numbers and also
  13661. ; to fetch two numbers by the addition, multiply and division routines.
  13662. ; HL addresses the first number, DE addresses the second number.
  13663. ; For arithmetic only, A holds the sign of the result which is stored in
  13664. ; the second location.
  13665.  
  13666.                                         ;;;$2FBA
  13667. FETCH_TWO:      PUSH    HL              ; save pointer to first number, result if math.
  13668.                 PUSH    AF              ; save result sign.
  13669.                 LD      C,(HL)
  13670.                 INC     HL
  13671.                 LD      B,(HL)
  13672.                 LD      (HL),A          ; store the sign at correct location in
  13673.                                         ; destination 5 bytes for arithmetic only.
  13674.                 INC     HL
  13675.                 LD      A,C
  13676.                 LD      C,(HL)
  13677.                 PUSH    BC
  13678.                 INC     HL
  13679.                 LD      C,(HL)
  13680.                 INC     HL
  13681.                 LD      B,(HL)
  13682.                 EX      DE,HL
  13683.                 LD      D,A
  13684.                 LD      E,(HL)
  13685.                 PUSH    DE
  13686.                 INC     HL
  13687.                 LD      D,(HL)
  13688.                 INC     HL
  13689.                 LD      E,(HL)
  13690.                 PUSH    DE
  13691.                 EXX
  13692.                 POP     DE
  13693.                 POP     HL
  13694.                 POP     BC
  13695.                 EXX
  13696.                 INC     HL
  13697.                 LD      D,(HL)
  13698.                 INC     HL
  13699.                 LD      E,(HL)
  13700.                 POP     AF              ; restore possible result sign.
  13701.                 POP     HL              ; and pointer to possible result.
  13702.                 RET                     ; return.
  13703.  
  13704. ;----------------------------------
  13705. ; Shift floating point number right
  13706. ;----------------------------------
  13707.  
  13708.                                         ;;;$2FDD
  13709. SHIFT_FP:       AND     A
  13710.                 RET     Z
  13711.  
  13712.                 CP      $21
  13713.                 JR      NC,ADDEND_0     ; to ADDEND_0
  13714.  
  13715.                 PUSH    BC
  13716.                 LD      B,A
  13717.  
  13718.                                         ;;;$2FE5
  13719. ONE_SHIFT:      EXX
  13720.                 SRA     L
  13721.                 RR      D
  13722.                 RR      E
  13723.                 EXX
  13724.                 RR      D
  13725.                 RR      E
  13726.                 DJNZ    ONE_SHIFT       ; to ONE_SHIFT
  13727.                 POP     BC
  13728.                 RET     NC
  13729.  
  13730.                 CALL    ADD_BACK        ; routine ADD_BACK
  13731.                 RET     NZ
  13732.  
  13733.                                         ;;;$2FF9
  13734. ADDEND_0:       EXX
  13735.                 XOR     A
  13736.  
  13737.                                         ;;;$2FFB
  13738. ZEROS_4_5:      LD      L,$00
  13739.                 LD      D,A
  13740.                 LD      E,L
  13741.                 EXX
  13742.                 LD      DE,$0000
  13743.                 RET
  13744.  
  13745. ;-------------------
  13746. ; Add back any carry
  13747. ;-------------------
  13748.  
  13749.                                         ;;;$3004
  13750. ADD_BACK:       INC     E
  13751.                 RET     NZ
  13752.  
  13753.                 INC     D
  13754.                 RET     NZ
  13755.  
  13756.                 EXX
  13757.                 INC     E
  13758.                 JR      NZ,ALL_ADDED    ; to ALL_ADDED
  13759.  
  13760.                 INC     D
  13761.  
  13762.                                         ;;;$300D
  13763. ALL_ADDED:      EXX
  13764.                 RET
  13765.  
  13766. ;-------------------------
  13767. ; Handle subtraction ($03)
  13768. ;-------------------------
  13769. ; Subtraction is done by switching the sign byte/bit of the second number
  13770. ; which may be integer of floating point and continuing into addition.
  13771.  
  13772.                                         ;;;$300F
  13773. SUBTRACT:       EX      DE,HL           ; address second number with HL
  13774.                 CALL    NEGATE          ; routine NEGATE switches sign
  13775.                 EX      DE,HL           ; address first number again
  13776.                                         ; and continue.
  13777.  
  13778. ;----------------------
  13779. ; Handle addition ($0F)
  13780. ;----------------------
  13781. ; HL points to first number, DE to second.
  13782. ; If they are both integers, then go for the easy route.
  13783.  
  13784.                                         ;; ADDITION
  13785. ADDITION:       LD      A,(DE)          ; fetch first byte of second
  13786.                 OR      (HL)            ; combine with first byte of first
  13787.                 JR      NZ,FULL_ADDN    ; forward to FULL_ADDN if at least one was
  13788.                                         ; in floating point form.
  13789.  
  13790.                                         ; continue if both were small integers.
  13791.  
  13792.                 PUSH    DE              ; save pointer to lowest number for result.
  13793.                 INC     HL              ; address sign byte and
  13794.                 PUSH    HL              ; push the pointer.
  13795.                 INC     HL              ; address low byte
  13796.                 LD      E,(HL)          ; to E
  13797.                 INC     HL              ; address high byte
  13798.                 LD      D,(HL)          ; to D
  13799.                 INC     HL              ; address unused byte
  13800.                 INC     HL              ; address known zero indicator of 1st number
  13801.                 INC     HL              ; address sign byte
  13802.                 LD      A,(HL)          ; sign to A, $00 or $FF
  13803.                 INC     HL              ; address low byte
  13804.                 LD      C,(HL)          ; to C
  13805.                 INC     HL              ; address high byte
  13806.                 LD      B,(HL)          ; to B
  13807.                 POP     HL              ; pop result sign pointer
  13808.                 EX      DE,HL           ; integer to HL
  13809.                 ADD     HL,BC           ; add to the other one in BC
  13810.                                         ; setting carry if overflow.
  13811.                 EX      DE,HL           ; save result in DE bringing back sign pointer
  13812.                 ADC     A,(HL)          ; if pos/pos A=01 with overflow else 00
  13813.                                         ; if neg/neg A=FF with overflow else FE
  13814.                                         ; if mixture A=00 with overflow else FF
  13815.                 RRCA                    ; bit 0 to (C)
  13816.                 ADC     A,$00           ; both acceptable signs now zero
  13817.                 JR      NZ,ADDN_OFLW    ; forward to ADDN_OFLW if not
  13818.  
  13819.                 SBC     A,A             ; restore a negative result sign
  13820.                 LD      (HL),A
  13821.                 INC     HL
  13822.                 LD      (HL),E
  13823.                 INC     HL
  13824.                 LD      (HL),D
  13825.                 DEC     HL
  13826.                 DEC     HL
  13827.                 DEC     HL
  13828.                 POP     DE              ; STKEND
  13829.                 RET
  13830.  
  13831.                                         ;;;$303C
  13832. ADDN_OFLW:      DEC     HL
  13833.                 POP     DE
  13834.  
  13835.                                         ;;;$303E
  13836. FULL_ADDN:      CALL    RE_ST_TWO       ; routine RE_ST_TWO
  13837.                 EXX
  13838.                 PUSH    HL
  13839.                 EXX
  13840.                 PUSH    DE
  13841.                 PUSH    HL
  13842.                 CALL    PREP_ADD        ; routine PREP_ADD
  13843.                 LD      B,A
  13844.                 EX      DE,HL
  13845.                 CALL    PREP_ADD        ; routine PREP_ADD
  13846.                 LD      C,A
  13847.                 CP      B
  13848.                 JR      NC,SHIFT_LEN    ; to SHIFT_LEN
  13849.  
  13850.                 LD      A,B
  13851.                 LD      B,C
  13852.                 EX      DE,HL
  13853.  
  13854.                                         ;;;$3055
  13855. SHIFT_LEN:      PUSH    AF
  13856.                 SUB     B
  13857.                 CALL    FETCH_TWO       ; routine FETCH_TWO
  13858.                 CALL    SHIFT_FP        ; routine SHIFT_FP
  13859.                 POP     AF
  13860.                 POP     HL
  13861.                 LD      (HL),A
  13862.                 PUSH    HL
  13863.                 LD      L,B
  13864.                 LD      H,C
  13865.                 ADD     HL,DE
  13866.                 EXX
  13867.                 EX      DE,HL
  13868.                 ADC     HL,BC
  13869.                 EX      DE,HL
  13870.                 LD      A,H
  13871.                 ADC     A,L
  13872.                 LD      L,A
  13873.                 RRA
  13874.                 XOR     L
  13875.                 EXX
  13876.                 EX      DE,HL
  13877.                 POP     HL
  13878.                 RRA
  13879.                 JR      NC,TEST_NEG     ; to TEST_NEG
  13880.  
  13881.                 LD      A,$01
  13882.                 CALL    SHIFT_FP        ; routine SHIFT_FP
  13883.                 INC     (HL)
  13884.                 JR      Z,ADD_REP_6     ; to ADD_REP_6
  13885.  
  13886.                                         ;;;$307C
  13887. TEST_NEG:       EXX
  13888.                 LD      A,L
  13889.                 AND     $80
  13890.                 EXX
  13891.                 INC     HL
  13892.                 LD      (HL),A
  13893.                 DEC     HL
  13894.                 JR      Z,GO_NC_MLT     ; to GO_NC_MLT
  13895.  
  13896.                 LD      A,E
  13897.                 NEG                     ; Negate
  13898.                 CCF                     ; Complement Carry Flag
  13899.                 LD      E,A
  13900.                 LD      A,D
  13901.                 CPL
  13902.                 ADC     A,$00
  13903.                 LD      D,A
  13904.                 EXX
  13905.                 LD      A,E
  13906.                 CPL
  13907.                 ADC     A,$00
  13908.                 LD      E,A
  13909.                 LD      A,D
  13910.                 CPL
  13911.                 ADC     A,$00
  13912.                 JR      NC,END_COMPL    ; to END_COMPL
  13913.  
  13914.                 RRA
  13915.                 EXX
  13916.                 INC     (HL)
  13917.  
  13918.                                         ;;;$309F
  13919. ADD_REP_6:      JP      Z,REPORT_6      ; to REPORT_6
  13920.  
  13921.                 EXX
  13922.  
  13923.                                         ;;;$30A3
  13924. END_COMPL:      LD      D,A
  13925.                 EXX
  13926.  
  13927.                                         ;;;$30A5
  13928. GO_NC_MLT:      XOR     A
  13929.                 JP      TEST_NORM       ; to TEST_NORM
  13930.  
  13931. ;------------------------------
  13932. ; Used in 16 bit multiplication
  13933. ;------------------------------
  13934. ; This routine is used, in the first instance, by the multiply calculator
  13935. ; literal to perform an integer multiplication in preference to
  13936. ; 32-bit multiplication to which it will resort if this overflows.
  13937. ;
  13938. ; It is also used by STK_VAR to calculate array subscripts and by DIM to
  13939. ; calculate the space required for multi-dimensional arrays.
  13940.  
  13941.                                         ;;;$30A9
  13942.                                         ;; HL-HL*DE
  13943. HL_HL_DE:       PUSH    BC              ; preserve BC throughout
  13944.                 LD      B,$10           ; set B to 16
  13945.                 LD      A,H             ; save H in A high byte
  13946.                 LD      C,L             ; save L in C low byte
  13947.                 LD      HL,$0000        ; initialize result to zero
  13948.  
  13949.                                         ; now enter a loop.
  13950.  
  13951.                                         ;;;$30B1
  13952. HL_LOOP:        ADD     HL,HL           ; double result
  13953.                 JR      C,HL_END        ; to HL_END if overflow
  13954.  
  13955.                 RL      C               ; shift AC left into carry
  13956.                 RLA                     ;
  13957.                 JR      NC,HL_AGAIN     ; to HL_AGAIN to skip addition if no carry
  13958.  
  13959.                 ADD     HL,DE           ; add in DE
  13960.                 JR      C,HL_END        ; to HL_END if overflow
  13961.  
  13962.                                         ;;;$30BC
  13963. HL_AGAIN:       DJNZ    HL_LOOP         ; back to HL_LOOP for all 16 bits
  13964.  
  13965.                                         ;;;$30BE
  13966. HL_END:         POP     BC              ; restore preserved BC
  13967.                 RET                     ; return with carry reset if successful
  13968.                                         ; and result in HL.
  13969.  
  13970. ;------------------------------
  13971. ; Prepare to multiply or divide
  13972. ;------------------------------
  13973. ; This routine is called in succession from multiply and divide to prepare
  13974. ; two mantissas by setting the leftmost bit that is used for the sign.
  13975. ; On the first call A holds zero and picks up the sign bit. On the second
  13976. ; call the two bits are XORed to form the result sign - minus * minus giving
  13977. ; plus etc. If either number is zero then this is flagged.
  13978. ; HL addresses the exponent.
  13979.  
  13980.                                         ;;;$30C0
  13981. PREP_M_D:       CALL    TEST_ZERO       ; routine TEST_ZERO  preserves accumulator.
  13982.                 RET     C               ; return carry set if zero
  13983.  
  13984.                 INC     HL              ; address first byte of mantissa
  13985.                 XOR     (HL)            ; pick up the first or xor with first.
  13986.                 SET     7,(HL)          ; now set to give true 32-bit mantissa
  13987.                 DEC     HL              ; point to exponent
  13988.                 RET                     ; return with carry reset
  13989.  
  13990. ;----------------------------
  13991. ; Handle multiplication ($04)
  13992. ;----------------------------
  13993.  
  13994.                                         ;;;$30CA
  13995. MULTIPLY:       LD      A,(DE)
  13996.                 OR      (HL)
  13997.                 JR      NZ,MULT_LONG    ; to MULT_LONG
  13998.  
  13999.                 PUSH    DE
  14000.                 PUSH    HL
  14001.                 PUSH    DE
  14002.                 CALL    INT_FETCH       ; routine INT_FETCH
  14003.                 EX      DE,HL
  14004.                 EX      (SP),HL
  14005.                 LD      B,C
  14006.                 CALL    INT_FETCH       ; routine INT_FETCH
  14007.                 LD      A,B
  14008.                 XOR     C
  14009.                 LD      C,A
  14010.                 POP     HL
  14011.                 CALL    HL_HL_DE        ; routine HL_HL_DE
  14012.                 EX      DE,HL
  14013.                 POP     HL
  14014.                 JR      C,MULT_OFLW     ; to MULT_OFLW
  14015.  
  14016.                 LD      A,D
  14017.                 OR      E
  14018.                 JR      NZ,MULT_RSLT    ; to MULT_RSLT
  14019.  
  14020.                 LD      C,A
  14021.  
  14022.                                         ;;;$30EA
  14023. MULT_RSLT:      CALL    INT_STORE       ; routine INT_STORE
  14024.                 POP     DE
  14025.                 RET
  14026.  
  14027.                                         ;;;$30EF
  14028. MULT_OFLW:      POP     DE
  14029.  
  14030.                                         ;;;$30F0
  14031. MULT_LONG:      CALL    RE_ST_TWO       ; routine RE_ST_TWO
  14032.                 XOR     A
  14033.                 CALL    PREP_M_D        ; routine PREP_M_D
  14034.                 RET     C
  14035.  
  14036.                 EXX
  14037.                 PUSH    HL
  14038.                 EXX
  14039.                 PUSH    DE
  14040.                 EX      DE,HL
  14041.                 CALL    PREP_M_D        ; routine PREP_M_D
  14042.                 EX      DE,HL
  14043.                 JR      C,ZERO_RSLT     ; to ZERO_RSLT
  14044.  
  14045.                 PUSH    HL
  14046.                 CALL    FETCH_TWO       ; routine FETCH_TWO
  14047.                 LD      A,B
  14048.                 AND     A
  14049.                 SBC     HL,HL
  14050.                 EXX
  14051.                 PUSH    HL
  14052.                 SBC     HL,HL
  14053.                 EXX
  14054.                 LD      B,$21
  14055.                 JR      STRT_MLT        ; to STRT_MLT
  14056.  
  14057.                                         ;;;$3114
  14058. MLT_LOOP:       JR      NC,NO_ADD       ; to NO_ADD
  14059.  
  14060.                 ADD     HL,DE
  14061.                 EXX
  14062.                 ADC     HL,DE
  14063.                 EXX
  14064.  
  14065.                                         ;;;$311B
  14066. NO_ADD:         EXX
  14067.                 RR      H
  14068.                 RR      L
  14069.                 EXX
  14070.                 RR      H
  14071.                 RR      L
  14072.  
  14073.                                         ;;;$3125
  14074. STRT_MLT:       EXX
  14075.                 RR      B
  14076.                 RR      C
  14077.                 EXX
  14078.                 RR      C
  14079.                 RRA
  14080.                 DJNZ    MLT_LOOP        ; to MLT_LOOP
  14081.                 EX      DE,HL
  14082.                 EXX
  14083.                 EX      DE,HL
  14084.                 EXX
  14085.                 POP     BC
  14086.                 POP     HL
  14087.                 LD      A,B
  14088.                 ADD     A,C
  14089.                 JR      NZ,MAKE_EXPT    ; to MAKE_EXPT
  14090.  
  14091.                 AND     A
  14092.  
  14093.                                         ;;;$313B
  14094. MAKE_EXPT:      DEC     A
  14095.                 CCF                     ; Complement Carry Flag
  14096.  
  14097.                                         ;;;$313D
  14098. DIVN_EXPT:      RLA
  14099.                 CCF                     ; Complement Carry Flag
  14100.                 RRA
  14101.                 JP      P,OFLW1_CLR     ; to OFLW1_CLR
  14102.  
  14103.                 JR      NC,REPORT_6     ; to REPORT_6
  14104.  
  14105.                 AND     A
  14106.  
  14107.                                         ;;;$3146
  14108. OFLW1_CLR:      INC     A               ;
  14109.                 JR      NZ,OFLW2_CLR    ; to OFLW2_CLR
  14110.  
  14111.                 JR      C,OFLW2_CLR     ; to OFLW2_CLR
  14112.  
  14113.                 EXX
  14114.                 BIT     7,D
  14115.                 EXX
  14116.                 JR      NZ,REPORT_6     ; to REPORT_6
  14117.  
  14118.                                         ;;;$3151
  14119. OFLW2_CLR:      LD      (HL),A
  14120.                 EXX
  14121.                 LD      A,B
  14122.                 EXX
  14123.  
  14124.                                         ;;;$3155
  14125. TEST_NORM:      JR      NC,NORMALISE    ; to NORMALISE
  14126.  
  14127.                 LD      A,(HL)
  14128.                 AND     A
  14129.  
  14130.                                         ;;;$3159
  14131. NEAR_ZERO:      LD      A,$80
  14132.                 JR      Z,SKIP_ZERO     ; to SKIP_ZERO
  14133.  
  14134.                                         ;;;$315D
  14135. ZERO_RSLT:      XOR     A
  14136.  
  14137.                                         ;;;$315E
  14138. SKIP_ZERO:      EXX
  14139.                 AND     D
  14140.                 CALL    ZEROS_4_5       ; routine ZEROS_4_5
  14141.                 RLCA
  14142.                 LD      (HL),A
  14143.                 JR      C,OFLOW_CLR     ; to OFLOW_CLR
  14144.  
  14145.                 INC     HL
  14146.                 LD      (HL),A
  14147.                 DEC     HL
  14148.                 JR      OFLOW_CLR       ; to OFLOW_CLR
  14149.  
  14150.                                         ;;;$316C
  14151. NORMALISE:      LD      B,$20
  14152.  
  14153.                                         ;;;$316E
  14154. SHIFT_ONE:      EXX
  14155.                 BIT     7,D
  14156.                 EXX
  14157.                 JR      NZ,NORML_NOW    ; to NORML_NOW
  14158.  
  14159.                 RLCA
  14160.                 RL      E
  14161.                 RL      D
  14162.                 EXX
  14163.                 RL      E
  14164.                 RL      D
  14165.                 EXX
  14166.                 DEC     (HL)
  14167.                 JR      Z,NEAR_ZERO     ; to NEAR_ZERO
  14168.  
  14169.                 DJNZ    SHIFT_ONE       ; to SHIFT_ONE
  14170.                 JR      ZERO_RSLT       ; to ZERO_RSLT
  14171.  
  14172.                                         ;;;$3186
  14173. NORML_NOW:      RLA
  14174.                 JR      NC,OFLOW_CLR    ; to OFLOW_CLR
  14175.  
  14176.                 CALL    ADD_BACK        ; routine ADD_BACK
  14177.                 JR      NZ,OFLOW_CLR    ; to OFLOW_CLR
  14178.  
  14179.                 EXX
  14180.                 LD      D,$80
  14181.                 EXX
  14182.                 INC     (HL)
  14183.                 JR      Z,REPORT_6      ; to REPORT_6
  14184.  
  14185.                                         ;;;$3195
  14186. OFLOW_CLR:      PUSH    HL
  14187.                 INC     HL
  14188.                 EXX
  14189.                 PUSH    DE
  14190.                 EXX
  14191.                 POP     BC
  14192.                 LD      A,B
  14193.                 RLA
  14194.                 RL      (HL)
  14195.                 RRA
  14196.                 LD      (HL),A
  14197.                 INC     HL
  14198.                 LD      (HL),C
  14199.                 INC     HL
  14200.                 LD      (HL),D
  14201.                 INC     HL
  14202.                 LD      (HL),E
  14203.                 POP     HL
  14204.                 POP     DE
  14205.                 EXX
  14206.                 POP     HL
  14207.                 EXX
  14208.                 RET
  14209.  
  14210.                                         ;;;$31AD
  14211. REPORT_6:       RST     08H             ; ERROR_1
  14212.                 DEFB    $05             ; Error Report: Number too big
  14213.  
  14214. ;----------------------
  14215. ; Handle division ($05)
  14216. ;----------------------
  14217.  
  14218.                                         ;;;$31AF
  14219. DIVISION:       CALL    RE_ST_TWO       ; routine RE_ST_TWO
  14220.                 EX      DE,HL
  14221.                 XOR     A
  14222.                 CALL    PREP_M_D        ; routine PREP_M_D
  14223.                 JR      C,REPORT_6      ; to REPORT_6
  14224.  
  14225.                 EX      DE,HL
  14226.                 CALL    PREP_M_D        ; routine PREP_M_D
  14227.                 RET     C
  14228.  
  14229.                 EXX
  14230.                 PUSH    HL
  14231.                 EXX
  14232.                 PUSH    DE
  14233.                 PUSH    HL
  14234.                 CALL    FETCH_TWO       ; routine FETCH_TWO
  14235.                 EXX
  14236.                 PUSH    HL
  14237.                 LD      H,B
  14238.                 LD      L,C
  14239.                 EXX
  14240.                 LD      H,C
  14241.                 LD      L,B
  14242.                 XOR     A
  14243.                 LD      B,$DF
  14244.                 JR      DIV_START       ; to DIV_START
  14245.  
  14246.                                         ;;;$31D2
  14247. DIV_LOOP:       RLA
  14248.                 RL      C
  14249.                 EXX
  14250.                 RL      C
  14251.                 RL      B
  14252.                 EXX
  14253.  
  14254.                                         ;;;$31DB
  14255. DIV_34TH:       ADD     HL,HL
  14256.                 EXX
  14257.                 ADC     HL,HL
  14258.                 EXX
  14259.                 JR      C,SUBN_ONLY     ; to SUBN_ONLY
  14260.  
  14261.                                         ;;;$31E2
  14262. DIV_START:      SBC     HL,DE
  14263.                 EXX
  14264.                 SBC     HL,DE
  14265.                 EXX
  14266.                 JR      NC,NO_RSTORE    ; to NO_RSTORE
  14267.  
  14268.                 ADD     HL,DE
  14269.                 EXX
  14270.                 ADC     HL,DE
  14271.                 EXX
  14272.                 AND     A
  14273.                 JR      COUNT_ONE       ; to COUNT_ONE
  14274.  
  14275.                                         ;;;$31F2
  14276. SUBN_ONLY:      AND     A
  14277.                 SBC     HL,DE
  14278.                 EXX
  14279.                 SBC     HL,DE
  14280.                 EXX
  14281.  
  14282.                                         ;;;$31F9
  14283. NO_RSTORE:      SCF                     ; Set Carry Flag
  14284.  
  14285.                                         ;;;$31FA
  14286. COUNT_ONE:      INC     B
  14287.                 JP      M,DIV_LOOP      ; to DIV_LOOP
  14288.  
  14289.                 PUSH    AF
  14290.                 JR      Z,DIV_START     ; to DIV_START
  14291.  
  14292.                 LD      E,A
  14293.                 LD      D,C
  14294.                 EXX
  14295.                 LD      E,C
  14296.                 LD      D,B
  14297.                 POP     AF
  14298.                 RR      B
  14299.                 POP     AF
  14300.                 RR      B
  14301.                 EXX
  14302.                 POP     BC
  14303.                 POP     HL
  14304.                 LD      A,B
  14305.                 SUB     C
  14306.                 JP      DIVN_EXPT               ; to DIVN_EXPT
  14307.  
  14308. ;--------------------------------------
  14309. ; Integer truncation towards zero ($3A)
  14310. ;--------------------------------------
  14311.  
  14312.                                         ;;;$3214
  14313. TRUNCATE:       LD      A,(HL) 
  14314.                 AND     A
  14315.                 RET     Z
  14316.  
  14317.                 CP      $81
  14318.                 JR      NC,T_GR_ZERO    ; to T_GR_ZERO
  14319.  
  14320.                 LD      (HL),$00
  14321.                 LD      A,$20
  14322.                 JR      NIL_BYTES       ; to NIL_BYTES
  14323.  
  14324.                                         ;;;$3221
  14325. T_GR_ZERO:      CP      $91
  14326.                 JR      NZ,T_SMALL      ; to T_SMALL
  14327.  
  14328.                 INC     HL
  14329.                 INC     HL
  14330.                 INC     HL
  14331.                 LD      A,$80
  14332.                 AND     (HL)
  14333.                 DEC     HL
  14334.                 OR      (HL)
  14335.                 DEC     HL
  14336.                 JR      NZ,T_FIRST      ; to T_FIRST
  14337.  
  14338.                 LD      A,$80
  14339.                 XOR     (HL)
  14340.  
  14341.                                         ;;;$3233
  14342. T_FIRST:        DEC     HL
  14343.                 JR      NZ,T_EXPNENT    ; to T_EXPNENT
  14344.  
  14345.                 LD      (HL),A
  14346.                 INC     HL
  14347.                 LD      (HL),$FF
  14348.                 DEC     HL
  14349.                 LD      A,$18
  14350.                 JR      NIL_BYTES       ; to NIL_BYTES
  14351.  
  14352.                                         ;;;$323F
  14353. T_SMALL:        JR      NC,X_LARGE      ; to X_LARGE
  14354.  
  14355.                 PUSH    DE
  14356.                 CPL
  14357.                 ADD     A,$91
  14358.                 INC     HL
  14359.                 LD      D,(HL)
  14360.                 INC     HL
  14361.                 LD      E,(HL)
  14362.                 DEC     HL
  14363.                 DEC     HL
  14364.                 LD      C,$00
  14365.                 BIT     7,D
  14366.                 JR      Z,T_NUMERIC     ; to T_NUMERIC
  14367.  
  14368.                 DEC     C
  14369.  
  14370.                                         ;;;$3252
  14371. T_NUMERIC:      SET     7,D
  14372.                 LD      B,$08
  14373.                 SUB     B
  14374.                 ADD     A,B
  14375.                 JR      C,T_TEST        ; to T_TEST
  14376.  
  14377.                 LD      E,D
  14378.                 LD      D,$00
  14379.                 SUB     B
  14380.  
  14381.                                         ;;;$325E
  14382. T_TEST:         JR      Z,T_STORE       ; to T_STORE
  14383.  
  14384.                 LD      B,A
  14385.  
  14386.                                         ;;;$3261
  14387. T_SHIFT:        SRL     D
  14388.                 RR      E
  14389.                 DJNZ    T_SHIFT         ; to T_SHIFT
  14390.  
  14391.                                         ;;;$3267
  14392. T_STORE:        CALL    INT_STORE       ; routine INT_STORE
  14393.                 POP     DE
  14394.                 RET
  14395.  
  14396.                                         ;;;$326C
  14397. T_EXPNENT:      LD      A,(HL)
  14398.  
  14399.                                         ;;;$326D
  14400. X_LARGE:        SUB     $A0
  14401.                 RET     P
  14402.  
  14403.                 NEG                     ; Negate
  14404.  
  14405.                                         ;;;$3272
  14406. NIL_BYTES:      PUSH    DE
  14407.                 EX      DE,HL
  14408.                 DEC     HL
  14409.                 LD      B,A
  14410.                 SRL     B
  14411.                 SRL     B
  14412.                 SRL     B
  14413.                 JR      Z,BITS_ZERO     ; to BITS_ZERO
  14414.  
  14415.                                         ;;;$327E
  14416. BYTE_ZERO:      LD      (HL),$00
  14417.                 DEC     HL
  14418.                 DJNZ    BYTE_ZERO       ; to BYTE_ZERO
  14419.  
  14420.                                         ;; BITS_ZERO
  14421. BITS_ZERO:      AND     $07
  14422.                 JR      Z,IX_END        ; to IX_END
  14423.  
  14424.                 LD      B,A
  14425.                 LD      A,$FF
  14426.  
  14427.                                         ;;;$328A
  14428. LESS_MASK:      SLA     A
  14429.                 DJNZ    LESS_MASK       ; to LESS_MASK
  14430.                 AND     (HL)
  14431.                 LD      (HL),A
  14432.  
  14433.                                         ;;;$3290
  14434. IX_END:         EX      DE,HL
  14435.                 POP     DE
  14436.                 RET
  14437.  
  14438. ; ----------------------------------
  14439. ; Storage of numbers in 5 byte form.
  14440. ; ==================================
  14441. ; Both integers and floating-point numbers can be stored in five bytes.
  14442. ; Zero is a special case stored as 5 zeros.
  14443. ; For integers the form is
  14444. ; Byte 1 - zero,
  14445. ; Byte 2 - sign byte, $00 +ve, $FF -ve.
  14446. ; Byte 3 - Low byte of integer.
  14447. ; Byte 4 - High byte
  14448. ; Byte 5 - unused but always zero.
  14449. ;
  14450. ; it seems unusual to store the low byte first but it is just as easy either
  14451. ; way. Statistically it just increases the chances of trailing zeros which
  14452. ; is an advantage elsewhere in saving ROM code.
  14453. ;
  14454. ;             zero     sign     low      high    unused
  14455. ; So +1 is  00000000 00000000 00000001 00000000 00000000
  14456. ;
  14457. ; and -1 is 00000000 11111111 11111111 11111111 00000000
  14458. ;
  14459. ; much of the arithmetic found in basic lines can be done using numbers
  14460. ; in this form using the Z80's 16 bit register operation ADD.
  14461. ; (multiplication is done by a sequence of additions).
  14462. ;
  14463. ; Storing -ve integers in two's complement form, means that they are ready for
  14464. ; addition and you might like to add the numbers above to prove that the
  14465. ; answer is zero. If, as in this case, the carry is set then that denotes that
  14466. ; the result is positive. This only applies when the signs don't match.
  14467. ; With positive numbers a carry denotes the result is out of integer range.
  14468. ; With negative numbers a carry denotes the result is within range.
  14469. ; The exception to the last rule is when the result is -65536
  14470. ;
  14471. ; Floating point form is an alternative method of storing numbers which can
  14472. ; be used for integers and larger (or fractional) numbers.
  14473. ;
  14474. ; In this form 1 is stored as
  14475. ;           10000001 00000000 00000000 00000000 00000000
  14476. ;
  14477. ; When a small integer is converted to a floating point number the last two
  14478. ; bytes are always blank so they are omitted in the following steps
  14479. ;
  14480. ; first make exponent +1 +16d  (bit 7 of the exponent is set if positive)
  14481.  
  14482. ; 10010001 00000000 00000001
  14483. ; 10010000 00000000 00000010 <-  now shift left and decrement exponent
  14484. ; ...
  14485. ; 10000010 01000000 00000000 <-  until a 1 abuts the imaginary point
  14486. ; 10000001 10000000 00000000     to the left of the mantissa.
  14487. ;
  14488. ; however since the leftmost bit of the mantissa is always set then it can
  14489. ; be used to denote the sign of the mantissa and put back when needed by the
  14490. ; PREP routines which gives
  14491. ;
  14492. ; 10000001 00000000 00000000
  14493.  
  14494. ;------------------------------
  14495. ; Re-stack two `small' integers
  14496. ;------------------------------
  14497. ; This routine is called to re-stack two numbers in full floating point form
  14498. ; e.g. from MULTIPLY when integer multiplication has overflowed.
  14499.  
  14500.                                         ;;;$3293
  14501. RE_ST_TWO:      CALL    RESTK_SUB       ; routine RESTK_SUB  below and continue
  14502.                                         ; into the routine to do the other one.
  14503.  
  14504.                                         ;;;$3296
  14505. RESTK_SUB:      EX      DE,HL           ; swap pointers
  14506.  
  14507. ;---------------------------------
  14508. ; Re-stack one number in full form
  14509. ;---------------------------------
  14510. ; This routine re-stacks an integer usually on the calculator stack
  14511. ; in full floating point form.
  14512. ; HL points to first byte.
  14513.  
  14514.                                         ;;;$3297
  14515. RE_STACK:       LD      A,(HL)          ; Fetch Exponent byte to A
  14516.                 AND     A               ; test it
  14517.                 RET     NZ              ; return if not zero as already in full
  14518.                                         ; floating-point form.
  14519.                 PUSH    DE              ; preserve DE.
  14520.                 CALL    INT_FETCH       ; routine INT_FETCH
  14521.                                         ; integer to DE, sign to C.
  14522.  
  14523.                                         ; HL points to 4th byte.
  14524.  
  14525.                 XOR     A               ; clear accumulator.
  14526.                 INC     HL              ; point to 5th.
  14527.                 LD      (HL),A          ; and blank.
  14528.                 DEC     HL              ; point to 4th.
  14529.                 LD      (HL),A          ; and blank.
  14530.                 LD      B,$91           ; set exponent byte +ve $81
  14531.                                         ; and imaginary dec point 16 bits to right
  14532.                                         ; of first bit.
  14533.  
  14534.                                         ; we could skip to normalize now but it's quicker to avoid
  14535.                                         ; normalizing through an empty D.
  14536.  
  14537.                 LD      A,D             ; fetch the high byte D
  14538.                 AND     A               ; is it zero ?
  14539.                 JR      NZ,RS_NRMLSE    ; skip to RS_NRMLSE if not.
  14540.  
  14541.                 OR      E               ; low byte E to A and test for zero
  14542.                 LD      B,D             ; set B exponent to 0
  14543.                 JR      Z,RS_STORE      ; forward to RS_STORE if value is zero.
  14544.  
  14545.                 LD      D,E             ; transfer E to D
  14546.                 LD      E,B             ; set E to 0
  14547.                 LD      B,$89           ; reduce the initial exponent by eight.
  14548.  
  14549.  
  14550.                                         ;;;$32B1
  14551. RS_NRMLSE:      EX      DE,HL           ; integer to HL, addr of 4th byte to DE.
  14552.  
  14553.                                         ;;;$32B2
  14554. RSTK_LOOP:      DEC     B               ; decrease exponent
  14555.                 ADD     HL,HL           ; shift DE left
  14556.                 JR      NC,RSTK_LOOP    ; loop back to RSTK_LOOP
  14557.                                         ; until a set bit pops into carry
  14558.                 RRC     C               ; now rotate the sign byte $00 or $FF
  14559.                                         ; into carry to give a sign bit
  14560.                 RR      H               ; rotate the sign bit to left of H
  14561.                 RR      L               ; rotate any carry into L
  14562.                 EX      DE,HL           ; address 4th byte, normalized int to DE
  14563.  
  14564.                                         ;;;$32BD
  14565. RS_STORE:       DEC     HL              ; address 3rd byte
  14566.                 LD      (HL),E          ; place E
  14567.                 DEC     HL              ; address 2nd byte
  14568.                 LD      (HL),D          ; place D
  14569.                 DEC     HL              ; address 1st byte
  14570.                 LD      (HL),B          ; store the exponent
  14571.  
  14572.                 POP     DE              ; restore initial DE.
  14573.                 RET                     ; return.
  14574.  
  14575. ;****************************************
  14576. ;** Part 10. FLOATING-POINT CALCULATOR **
  14577. ;****************************************
  14578.  
  14579. ; As a general rule the calculator avoids using the IY register.
  14580. ; exceptions are VAL, VAL$ and STR$.
  14581. ; So an assembly language programmer who has disabled interrupts to use
  14582. ; IY for other purposes can still use the calculator for mathematical
  14583. ; purposes.
  14584.  
  14585.  
  14586. ;-------------------
  14587. ; Table of constants
  14588. ;-------------------
  14589.  
  14590. ; used 11 times
  14591.                                         ;;;$32C5                        00 00 00 00 00
  14592. STK_ZERO:       DEFB    $00             ;;Bytes: 1
  14593.                 DEFB    $B0             ;;Exponent $00
  14594.                 DEFB    $00             ;;(+00,+00,+00)
  14595.  
  14596. ; used 19 times
  14597.                                         ;;;$32C8                        00 00 01 00 00
  14598. STK_ONE:        DEFB    $40             ;;Bytes: 2
  14599.                 DEFB    $B0             ;;Exponent $00
  14600.                 DEFB    $00,$01         ;;(+00,+00)
  14601.  
  14602. ; used 9 times
  14603.                                         ;;;$32CC                        80 00 00 00 00
  14604. STK_HALF:       DEFB    $30             ;;Exponent: $80, Bytes: 1
  14605.                 DEFB    $00             ;;(+00,+00,+00)
  14606.  
  14607. ; used 4 times
  14608.                                         ;;;$32CE
  14609.                                         ;; stk-pi/2                     81 49 0F DA A2
  14610. STK_PI_2:       DEFB    $F1             ;;Exponent: $81, Bytes: 4
  14611.                 DEFB    $49,$0F,$DA,$A2
  14612.  
  14613. ; used 3 times
  14614.                                         ;;;$32D3                        00 00 0A 00 00
  14615. STK_TEN:        DEFB    $40             ;;Bytes: 2
  14616.                 DEFB    $B0             ;;Exponent $00
  14617.                 DEFB    $00,$0A         ;;(+00,+00)
  14618.  
  14619.  
  14620. ;-------------------
  14621. ; Table of addresses
  14622. ;-------------------
  14623. ;
  14624. ; starts with binary operations which have two operands and one result.
  14625. ; three pseudo binary operations first.
  14626.  
  14627.                                         ;;;$32D7
  14628. TBL_ADDRS:      DEFW    JUMP_TRUE       ; $00 Address: $368F - JUMP_TRUE
  14629.                 DEFW    EXCHANGE        ; $01 Address: $343C - EXCHANGE
  14630.                 DEFW    DELETE          ; $02 Address: $33A1 - DELETE
  14631.  
  14632.                                         ; true binary operations.
  14633.  
  14634.                 DEFW    SUBTRACT        ; $03 Address: $300F - SUBTRACT
  14635.                 DEFW    MULTIPLY        ; $04 Address: $30CA - MULTIPLY
  14636.                 DEFW    DIVISION        ; $05 Address: $31AF - DIVISION
  14637.                 DEFW    TO_POWER        ; $06 Address: $3851 - TO_POWER
  14638.                 DEFW    OR_             ; $07 Address: $351B - OR
  14639.  
  14640.                 DEFW    NO_AND_NO       ; $08 Address: $3524 - NO_AND_NO
  14641.                 DEFW    NO_L_EQL        ; $09 Address: $353B - NO_L_EQL
  14642.                 DEFW    NO_GR_EQL       ; $0A Address: $353B - NO_GR_EQL
  14643.                 DEFW    NOS_NEQL        ; $0B Address: $353B - NOS_NEQL
  14644.                 DEFW    NO_GRTR         ; $0C Address: $353B - NO_GRTR
  14645.                 DEFW    NO_LESS         ; $0D Address: $353B - NO_LESS
  14646.                 DEFW    NOS_EQL         ; $0E Address: $353B - NOS_EQL
  14647.                 DEFW    ADDITION        ; $0F Address: $3014 - ADDITION
  14648.  
  14649.                 DEFW    STR_AND_NO      ; $10 Address: $352D - STR_AND_NO
  14650.                 DEFW    STR_L_EQL       ; $11 Address: $353B - STR_L_EQL
  14651.                 DEFW    STR_GR_EQL      ; $12 Address: $353B - STR_GR_EQL
  14652.                 DEFW    STRS_NEQL       ; $13 Address: $353B - STRS_NEQL
  14653.                 DEFW    STR_GRTR        ; $14 Address: $353B - STR_GRTR
  14654.                 DEFW    STR_LESS        ; $15 Address: $353B - STR_LESS
  14655.                 DEFW    STRS_EQL        ; $16 Address: $353B - STRS_EQL
  14656.                 DEFW    STRS_ADD        ; $17 Address: $359C - STRS_ADD
  14657.  
  14658.                                         ; unary follow
  14659.  
  14660.                 DEFW    VALS            ; $18 Address: $35DE - VAL$
  14661.                 DEFW    USR_            ; $19 Address: $34BC - USR-$
  14662.                 DEFW    READ_IN         ; $1A Address: $3645 - READ_IN
  14663.                 DEFW    NEGATE          ; $1B Address: $346E - NEGATE
  14664.  
  14665.                 DEFW    CODE            ; $1C Address: $3669 - CODE
  14666.                 DEFW    VAL             ; $1D Address: $35DE - VAL
  14667.                 DEFW    LEN             ; $1E Address: $3674 - LEN
  14668.                 DEFW    SIN_            ; $1F Address: $37B5 - SIN
  14669.                 DEFW    COS_            ; $20 Address: $37AA - COS
  14670.                 DEFW    TAN             ; $21 Address: $37DA - TAN
  14671.                 DEFW    ASN             ; $22 Address: $3833 - ASN
  14672.                 DEFW    ACS             ; $23 Address: $3843 - ACS
  14673.                 DEFW    ATN             ; $24 Address: $37E2 - ATN
  14674.                 DEFW    LN              ; $25 Address: $3713 - LN
  14675.                 DEFW    EXP             ; $26 Address: $36C4 - EXP
  14676.                 DEFW    INT             ; $27 Address: $36AF - INT
  14677.                 DEFW    SQR             ; $28 Address: $384A - SQR
  14678.                 DEFW    SGN             ; $29 Address: $3492 - SGN
  14679.                 DEFW    @ABS            ; $2A Address: $346A - ABS
  14680.                 DEFW    PEEK            ; $2B Address: $34AC - PEEK
  14681.                 DEFW    IN_             ; $2C Address: $34A5 - IN
  14682.                 DEFW    USR_NO          ; $2D Address: $34B3 - USR_NO
  14683.                 DEFW    STRS            ; $2E Address: $361F - STR$
  14684.                 DEFW    CHRS            ; $2F Address: $35C9 - CHR$
  14685.                 DEFW    NOT_            ; $30 Address: $3501 - NOT
  14686.  
  14687.                                         ; end of true unary
  14688.  
  14689.                 DEFW    DUPLICATE       ; $31 Address: $33C0 - DUPLICATE
  14690.                 DEFW    N_MOD_M         ; $32 Address: $36A0 - N_MOD_M
  14691.                 DEFW    JUMP            ; $33 Address: $3686 - JUMP
  14692.                 DEFW    STK_DATA        ; $34 Address: $33C6 - STK_DATA
  14693.                 DEFW    DEC_JR_NZ       ; $35 Address: $367A - DEC_JR_NZ
  14694.                 DEFW    LESS_0          ; $36 Address: $3506 - LESS_0
  14695.                 DEFW    GREATER_0       ; $37 Address: $34F9 - GREATER_0
  14696.                 DEFW    END_CALC        ; $38 Address: $369B - END_CALC
  14697.                 DEFW    GET_ARGT        ; $39 Address: $3783 - GET_ARGT
  14698.                 DEFW    TRUNCATE        ; $3A Address: $3214 - TRUNCATE
  14699.                 DEFW    FP_CALC_2       ; $3B Address: $33A2 - FP_CALC_2
  14700.                 DEFW    E_TO_FP         ; $3C Address: $2D4F - E_TO_FP
  14701.                 DEFW    RE_STACK        ; $3D Address: $3297 - RE_STACK
  14702.  
  14703.                                         ; the following are just the next available slots for the 128 compound literals
  14704.                                         ; which are in range $80 - $FF.
  14705.  
  14706.                 DEFW    SERIES_XX       ; $3E Address: $3449 - SERIES_XX    $80 - $9F.
  14707.                 DEFW    STK_CONST_XX    ; $3F Address: $341B - STK_CONST_XX $A0 - $BF.
  14708.                 DEFW    ST_MEM_XX       ; $40 Address: $342D - ST_MEM_XX    $C0 - $DF.
  14709.                 DEFW    GET_MEM_XX      ; $41 Address: $340F - GET_MEM_XX   $E0 - $FF.
  14710.  
  14711.                                         ; Aside: $3E - $7F are therefore unused calculator literals.
  14712.                                         ;        $3E - $7B would be available for expansion.
  14713.  
  14714. ;---------------
  14715. ; The Calculator
  14716. ;---------------
  14717.  
  14718.                                         ;;;$335B
  14719. CALCULATE:      CALL    STK_PNTRS       ; routine STK_PNTRS is called to set up the
  14720.                                         ; calculator stack pointers for a default
  14721.                                         ; unary operation. HL = last value on stack.
  14722.                                         ; DE = STKEND first location after stack.
  14723.  
  14724.                                         ; the calculate routine is called at this point by the series generator...
  14725.  
  14726.                                         ;;;$335E
  14727. GEN_ENT_1:      LD      A,B             ; fetch the Z80 B register to A
  14728.                 LD      (BREG),A        ; and store value in system variable BREG.
  14729.                                         ; this will be the counter for DEC_JR_NZ
  14730.                                         ; or if used from FP_CALC2 the calculator
  14731.                                         ; instruction.
  14732.  
  14733.                                         ; ... and again later at this point
  14734.  
  14735.                                         ;;;$3362
  14736. GEN_ENT_2:      EXX                     ; switch sets
  14737.                 EX      (SP),HL         ; and store the address of next instruction,
  14738.                                         ; the return address, in H'L'.
  14739.                                         ; If this is a recursive call the the H'L'
  14740.                                         ; of the previous invocation goes on stack.
  14741.                                         ; c.f. END_CALC.
  14742.                 EXX                     ; switch back to main set
  14743.  
  14744.                                         ; this is the re-entry looping point when handling a string of literals.
  14745.  
  14746.                                         ;;;$3365
  14747. RE_ENTRY:       LD      (STKEND),DE     ; save end of stack in system variable STKEND
  14748.                 EXX                     ; switch to alt
  14749.                 LD      A,(HL)          ; get next literal
  14750.                 INC     HL              ; increase pointer'
  14751.  
  14752.                                         ; single operation jumps back to here
  14753.  
  14754.                                         ;;;$336C
  14755. SCAN_ENT:       PUSH    HL              ; save pointer on stack
  14756.                 AND     A               ; now test the literal
  14757.                 JP      P,FIRST_3D      ; forward to FIRST_3D if in range $00 - $3D
  14758.                                         ; anything with bit 7 set will be one of
  14759.                                         ; 128 compound literals.
  14760.  
  14761.                                         ; compound literals have the following format.
  14762.                                         ; bit 7 set indicates compound.
  14763.                                         ; bits 6-5 the subgroup 0-3.
  14764.                                         ; bits 4-0 the embedded parameter $00 - $1F.
  14765.                                         ; The subgroup 0-3 needs to be manipulated to form the next available four
  14766.                                         ; address places after the simple literals in the address table.
  14767.  
  14768.                 LD      D,A             ; save literal in D
  14769.                 AND     $60             ; and with 01100000 to isolate subgroup
  14770.                 RRCA                    ; rotate bits
  14771.                 RRCA                    ; 4 places to right
  14772.                 RRCA                    ; not five as we need offset * 2
  14773.                 RRCA                    ; 00000xx0
  14774.                 ADD     A,$7C           ; add ($3E * 2) to give correct offset.
  14775.                                         ; alter above if you add more literals.
  14776.                 LD      L,A             ; store in L for later indexing.
  14777.                 LD      A,D             ; bring back compound literal
  14778.                 AND     $1F             ; use mask to isolate parameter bits
  14779.                 JR      ENT_TABLE       ; forward to ENT_TABLE
  14780.  
  14781.                                         ; the branch was here with simple literals.
  14782.  
  14783.                                         ;;;$3380
  14784. FIRST_3D:       CP      $18             ; compare with first unary operations.
  14785.                 JR      NC,DOUBLE_A     ; to DOUBLE_A with unary operations
  14786.  
  14787.                                         ; it is binary so adjust pointers.
  14788.  
  14789.                 EXX
  14790.                 LD      BC,$FFFB        ; the value -5
  14791.                 LD      D,H             ; transfer HL, the last value, to DE.
  14792.                 LD      E,L
  14793.                 ADD     HL,BC           ; subtract 5 making HL point to second  value.
  14794.                 EXX
  14795.  
  14796.                                         ;;;$338C
  14797. DOUBLE_A:       RLCA                    ; double the literal
  14798.                 LD      L,A             ; and store in L for indexing
  14799.  
  14800.                                         ;;;$338E
  14801. ENT_TABLE:      LD      DE,TBL_ADDRS    ; Address: TBL_ADDRS
  14802.                 LD      H,$00           ; prepare to index
  14803.                 ADD     HL,DE           ; add to get address of routine
  14804.                 LD      E,(HL)          ; low byte to E
  14805.                 INC     HL
  14806.                 LD      D,(HL)          ; high byte to D
  14807.                 LD      HL,RE_ENTRY     ; Address: RE_ENTRY
  14808.                 EX      (SP),HL         ; goes to stack
  14809.                 PUSH    DE              ; now address of routine
  14810.                 EXX                     ; main set
  14811.                                         ; avoid using IY register.
  14812.                 LD      BC,(STKEND_HI)  ; STKEND_hi
  14813.                                         ; nothing much goes to C but BREG to B
  14814.                                         ; and continue into next ret instruction
  14815.                                         ; which has a dual identity
  14816.  
  14817.  
  14818. ;--------------------
  14819. ; Handle delete ($02)
  14820. ;--------------------
  14821. ; A simple return but when used as a calculator literal this
  14822. ; deletes the last value from the calculator stack.
  14823. ; On entry, as always with binary operations,
  14824. ; HL=first number, DE=second number
  14825. ; On exit, HL=result, DE=stkend.
  14826. ; So nothing to do
  14827.  
  14828.                                         ;;;$33A1
  14829. DELETE:         RET                     ; return - indirect jump if from above.
  14830.  
  14831. ;-----------------------
  14832. ; Single operation ($3B)
  14833. ;-----------------------
  14834. ; this single operation is used, in the first instance, to evaluate most
  14835. ; of the mathematical and string functions found in Basic expressions.
  14836.  
  14837.                                         ;;;$33A2
  14838. FP_CALC_2:      POP     AF              ; drop return address.
  14839.                 LD      A,(BREG)        ; load accumulator from system variable BREG
  14840.                                         ; value will be literal eg. 'TAN'
  14841.                 EXX                     ; switch to alt
  14842.                 JR      SCAN_ENT        ; back to SCAN_ENT
  14843.                                         ; next literal will be END_CALC at $2758
  14844.  
  14845. ;-----------------
  14846. ; Test five-spaces
  14847. ;-----------------
  14848. ; This routine is called from MOVE_FP, STK_CONST and STK_STORE to
  14849. ; test that there is enough space between the calculator stack and the
  14850. ; machine stack for another five-byte value. It returns with BC holding
  14851. ; the value 5 ready for any subsequent LDIR.
  14852.  
  14853.                                         ;;;$33A9
  14854. TEST_5_SP:      PUSH    DE              ; save
  14855.                 PUSH    HL              ; registers
  14856.                 LD      BC,$0005        ; an overhead of five bytes
  14857.                 CALL    TEST_ROOM       ; routine TEST_ROOM tests free RAM raising an error if not.
  14858.                 POP     HL              ; else restore
  14859.                 POP     DE              ; registers.
  14860.                 RET                     ; return with BC set at 5.
  14861.  
  14862. ;-------------
  14863. ; Stack number
  14864. ;-------------
  14865. ; This routine is called to stack a hidden floating point number found in
  14866. ; a Basic line. It is also called to stack a numeric variable value, and
  14867. ; from BEEP, to stack an entry in the semi-tone table. It is not part of the
  14868. ; calculator suite of routines.
  14869. ; On entry HL points to the number to be stacked.
  14870.  
  14871.                                         ;;;$33B4
  14872. STACK_NUM:      LD      DE,(STKEND)     ; load destination from STKEND system variable.
  14873.                 CALL    MOVE_FP         ; routine MOVE_FP puts on calculator stack with a memory check.
  14874.                 LD      (STKEND),DE     ; set STKEND to next free location.
  14875.                 RET                     ; return.
  14876.  
  14877. ;-----------------------------------
  14878. ; Move a floating point number ($31)
  14879. ;-----------------------------------
  14880. ; This simple routine is a 5-byte LDIR instruction
  14881. ; that incorporates a memory check.
  14882. ; When used as a calculator literal it duplicates the last value on the
  14883. ; calculator stack.
  14884. ; Unary so on entry HL points to last value, DE to stkend
  14885.  
  14886.                                         ;;;$33C0
  14887. DUPLICATE:
  14888. MOVE_FP:        CALL    TEST_5_SP       ; routine TEST_5_SP test free memory and sets BC to 5.
  14889.                 LDIR                    ; copy the five bytes.
  14890.                 RET                     ; return with DE addressing new STKEND
  14891.                                         ; and HL addressing new last value.
  14892.  
  14893. ;---------------------
  14894. ; Stack literals ($34)
  14895. ;---------------------
  14896. ; When a calculator subroutine needs to put a value on the calculator
  14897. ; stack that is not a regular constant this routine is called with a
  14898. ; variable number of following data bytes that convey to the routine
  14899. ; the integer or floating point form as succinctly as is possible.
  14900.  
  14901.                                         ;;;$33C6
  14902. STK_DATA:       LD      H,D             ; transfer STKEND
  14903.                 LD      L,E             ; to HL for result.
  14904.  
  14905.                                         ;;;$33C8
  14906. STK_CONST:      CALL    TEST_5_SP       ; routine TEST_5_SP tests that room exists
  14907.                                         ; and sets BC to $05.
  14908.                 EXX                     ; switch to alternate set
  14909.                 PUSH    HL              ; save the pointer to next literal on stack
  14910.                 EXX                     ; switch back to main set
  14911.                 EX      (SP),HL         ; pointer to HL, destination to stack.
  14912.                 PUSH    BC              ; save BC - value 5 from test room ??.
  14913.                 LD      A,(HL)          ; fetch the byte following 'STK_DATA'
  14914.                 AND     $C0             ; isolate bits 7 and 6
  14915.                 RLCA                    ; rotate
  14916.                 RLCA                    ; to bits 1 and 0  range $00 - $03.
  14917.                 LD      C,A             ; transfer to C
  14918.                 INC     C               ; and increment to give number of bytes
  14919.                                         ; to read. $01 - $04
  14920.                 LD      A,(HL)          ; reload the first byte
  14921.                 AND     $3F             ; mask off to give possible exponent.
  14922.                 JR      NZ,FORM_EXP     ; forward to FORM_EXP if it was possible to
  14923.                                         ; include the exponent.
  14924.  
  14925.                                         ; else byte is just a byte count and exponent comes next.
  14926.  
  14927.                 INC     HL              ; address next byte and
  14928.                 LD      A,(HL)          ; pick up the exponent ( - $50).
  14929.  
  14930.                                         ;;;$33DE
  14931. FORM_EXP:       ADD     A,$50           ; now add $50 to form actual exponent
  14932.                 LD      (DE),A          ; and load into first destination byte.
  14933.                 LD      A,$05           ; load accumulator with $05 and
  14934.                 SUB     C               ; subtract C to give count of trailing zeros plus one.
  14935.                 INC     HL              ; increment source
  14936.                 INC     DE              ; increment destination
  14937.                 LD      B,$00           ; prepare to copy
  14938.                 LDIR                    ; copy C bytes
  14939.                 POP     BC              ; restore 5 counter to BC ??.
  14940.                 EX      (SP),HL         ; put HL on stack as next literal pointer
  14941.                                         ; and the stack value - result pointer - to HL.
  14942.                 EXX                     ; switch to alternate set.
  14943.                 POP     HL              ; restore next literal pointer from stack to H'L'.
  14944.                 EXX                     ; switch back to main set.
  14945.                 LD      B,A             ; zero count to B
  14946.                 XOR     A               ; clear accumulator
  14947.  
  14948.                                         ;;;$33F1
  14949. STK_ZEROS:      DEC     B               ; decrement B counter
  14950.                 RET     Z               ; return if zero.               >>
  14951.                                         ; DE points to new STKEND
  14952.                                         ; HL to new number.
  14953.  
  14954.                 LD      (DE),A          ; else load zero to destination
  14955.                 INC     DE              ; increase destination
  14956.                 JR      STK_ZEROS       ; loop back to STK_ZEROS until done.
  14957.  
  14958. ;---------------
  14959. ; Skip constants
  14960. ;---------------
  14961. ; This routine traverses variable-length entries in the table of constants,
  14962. ; stacking intermediate, unwanted constants onto a dummy calculator stack,
  14963. ; in the first five bytes of ROM.
  14964.  
  14965.                                         ;;;$33F7
  14966. SKIP_CONS:      AND     A               ; test if initially zero.
  14967.  
  14968.                                         ;;;$33F8
  14969. SKIP_NEXT:      RET     Z               ; return if zero.               >>
  14970.  
  14971.                 PUSH    AF              ; save count.
  14972.                 PUSH    DE              ; and normal STKEND
  14973.                 LD      DE,$0000        ; dummy value for STKEND at start of ROM
  14974.                                         ; Note. not a fault but this has to be
  14975.                                         ; moved elsewhere when running in RAM.
  14976.                                         ; e.g. with Expandor Systems 'Soft Rom'.
  14977.                 CALL    STK_CONST       ; routine STK_CONST works through variable length records.
  14978.                 POP     DE              ; restore real STKEND
  14979.                 POP     AF              ; restore count
  14980.                 DEC     A               ; decrease
  14981.                 JR      SKIP_NEXT       ; loop back to SKIP_NEXT
  14982.  
  14983. ;----------------
  14984. ; Memory location
  14985. ;----------------
  14986. ; This routine, when supplied with a base address in HL and an index in A
  14987. ; will calculate the address of the A'th entry, where each entry occupies
  14988. ; five bytes. It is used for reading the semi-tone table and addressing
  14989. ; floating-point numbers in the calculator's memory area.
  14990.  
  14991.                                         ;;;$3406
  14992. LOC_MEM:        LD      C,A             ; store the original number $00-$1F.
  14993.                 RLCA                    ; double.
  14994.                 RLCA                    ; quadruple.
  14995.                 ADD     A,C             ; now add original to multiply by five.
  14996.                 LD      C,A             ; place the result in C.
  14997.                 LD      B,$00           ; set B to 0.
  14998.                 ADD     HL,BC           ; add to form address of start of number in HL.
  14999.                 RET                     ; return.
  15000.  
  15001. ;--------------------------------
  15002. ; Get from memory area ($E0 etc.)
  15003. ;--------------------------------
  15004. ; Literals $E0 to $FF
  15005. ; A holds $00-$1F offset.
  15006. ; The calculator stack increases by 5 bytes.
  15007.  
  15008.                                         ;;;$340F
  15009. GET_MEM_XX:     PUSH    DE              ; save STKEND
  15010.                 LD      HL,(MEM)        ; MEM is base address of the memory cells.
  15011.                 CALL    LOC_MEM         ; routine LOC_MEM so that HL = first byte
  15012.                 CALL    MOVE_FP         ; routine MOVE_FP moves 5 bytes with memory check.
  15013.                                         ; DE now points to new STKEND.
  15014.                 POP     HL              ; original STKEND is now RESULT pointer.
  15015.                 RET                     ; return.
  15016.  
  15017. ;----------------------------
  15018. ; Stack a constant ($A0 etc.)
  15019. ;----------------------------
  15020. ; This routine allows a one-byte instruction to stack up to 32 constants
  15021. ; held in short form in a table of constants. In fact only 5 constants are
  15022. ; required. On entry the A register holds the literal ANDed with 1F.
  15023. ; It isn't very efficient and it would have been better to hold the
  15024. ; numbers in full, five byte form and stack them in a similar manner
  15025. ; to that used for semi-tone table values.
  15026.  
  15027.                                         ;;;$341B
  15028. STK_CONST_XX:   LD      H,D             ; save STKEND - required for result
  15029.                 LD      L,E
  15030.                 EXX                     ; swap
  15031.                 PUSH    HL              ; save pointer to next literal
  15032.                 LD      HL,STK_ZERO     ; Address: STK_ZERO - start of table of constants
  15033.                 EXX
  15034.                 CALL    SKIP_CONS       ; routine SKIP_CONS
  15035.                 CALL    STK_CONST       ; routine STK_CONST
  15036.                 EXX
  15037.                 POP     HL              ; restore pointer to next literal.
  15038.                 EXX
  15039.                 RET                     ; return.
  15040.  
  15041. ;----------------------------------
  15042. ; Store in a memory area ($C0 etc.)
  15043. ;----------------------------------
  15044. ; Offsets $C0 to $DF
  15045. ; Although 32 memory storage locations can be addressed, only six
  15046. ; $C0 to $C5 are required by the ROM and only the thirty bytes (6*5)
  15047. ; required for these are allocated. Spectrum programmers who wish to
  15048. ; use the floating point routines from assembly language may wish to
  15049. ; alter the system variable MEM to point to 160 bytes of RAM to have
  15050. ; use the full range available.
  15051. ; A holds derived offset $00-$1F.
  15052. ; Unary so on entry HL points to last value, DE to STKEND.
  15053.  
  15054.                                         ;;;$342D
  15055. ST_MEM_XX:      PUSH    HL              ; save the result pointer.
  15056.                 EX      DE,HL           ; transfer to DE.
  15057.                 LD      HL,(MEM)        ; fetch MEM the base of memory area.
  15058.                 CALL    LOC_MEM         ; routine LOC_MEM sets HL to the destination.
  15059.                 EX      DE,HL           ; swap - HL is start, DE is destination.
  15060.                 CALL    MOVE_FP         ; routine MOVE_FP.
  15061.                                         ; note. a short ld bc,5; ldir
  15062.                                         ; the embedded memory check is not required
  15063.                                         ; so these instructions would be faster.
  15064.                 EX      DE,HL           ; DE = STKEND
  15065.                 POP     HL              ; restore original result pointer
  15066.                 RET                     ; return.
  15067.  
  15068. ;-------------------------------------
  15069. ; Swap first number with second number
  15070. ;-------------------------------------
  15071. ; This routine exchanges the last two values on the calculator stack
  15072. ; On entry, as always with binary operations,
  15073. ; HL=first number, DE=second number
  15074. ; On exit, HL=result, DE=stkend.
  15075.  
  15076.                                         ;;;$343C
  15077. EXCHANGE:       LD      B,$05           ; there are five bytes to be swapped
  15078.  
  15079.                                         ; start of loop.
  15080.  
  15081.                                         ;;;$343E
  15082. SWAP_BYTE:      LD      A,(DE)          ; each byte of second
  15083.                 LD      C,(HL)          ; each byte of first
  15084.                 EX      DE,HL           ; swap pointers
  15085.                 LD      (DE),A          ; store each byte of first
  15086.                 LD      (HL),C          ; store each byte of second
  15087.                 INC     HL              ; advance both
  15088.                 INC     DE              ; pointers.
  15089.                 DJNZ    SWAP_BYTE       ; loop back to SWAP_BYTE until all 5 done.
  15090.                 EX      DE,HL           ; even up the exchanges
  15091.                                         ; so that DE addresses STKEND.
  15092.                 RET                     ; return.
  15093.  
  15094. ;----------------------------
  15095. ; Series generator ($86 etc.)
  15096. ;----------------------------
  15097. ; The Spectrum uses Chebyshev polynomials to generate approximations for
  15098. ; SIN, ATN, LN and EXP. These are named after the Russian mathematician
  15099. ; Pafnuty Chebyshev, born in 1821, who did much pioneering work on numerical
  15100. ; series. As far as calculators are concerned, Chebyshev polynomials have an
  15101. ; advantage over other series, for example the Taylor series, as they can
  15102. ; reach an approximation in just six iterations for SIN, eight for EXP and
  15103. ; twelve for LN and ATN. The mechanics of the routine are interesting but
  15104. ; for full treatment of how these are generated with demonstrations in
  15105. ; Sinclair Basic see "The Complete Spectrum ROM Disassembly" by Dr Ian Logan
  15106. ; and Dr Frank O'Hara, published 1983 by Melbourne House.
  15107.  
  15108.                                         ;;;$3449
  15109. SERIES_XX:      LD      B,A             ; parameter $00 - $1F to B counter
  15110.                 CALL    GEN_ENT_1       ; routine GEN_ENT_1 is called.
  15111.                                         ; A recursive call to a special entry point
  15112.                                         ; in the calculator that puts the B register
  15113.                                         ; in the system variable BREG. The return
  15114.                                         ; address is the next location and where
  15115.                                         ; the calculator will expect it's first
  15116.                                         ; instruction - now pointed to by HL'.
  15117.                                         ; The previous pointer to the series of
  15118.                                         ; five-byte numbers goes on the machine stack.
  15119.  
  15120.                                         ; The initialization phase.
  15121.  
  15122.                 DEFB    $31             ;;DUPLICATE     x,x
  15123.                 DEFB    $0F             ;;ADDITION      x+x
  15124.                 DEFB    $C0             ;;st-mem-0      x+x
  15125.                 DEFB    $02             ;;DELETE        .
  15126.                 DEFB    $A0             ;;STK_ZERO      0
  15127.                 DEFB    $C2             ;;st-mem-2      0
  15128.  
  15129.                                         ; a loop is now entered to perform the algebraic calculation for each of
  15130.                                         ; the numbers in the series
  15131.  
  15132.                                         ;; G_LOOP
  15133. G_LOOP:         DEFB    $31             ;;DUPLICATE     v,v.
  15134.                 DEFB    $E0             ;;get-mem-0     v,v,x+2
  15135.                 DEFB    $04             ;;MULTIPLY      v,v*x+2
  15136.                 DEFB    $E2             ;;get-mem-2     v,v*x+2,v
  15137.                 DEFB    $C1             ;;st-mem-1
  15138.                 DEFB    $03             ;;SUBTRACT
  15139.                 DEFB    $38             ;;END_CALC
  15140.  
  15141.                                         ; the previous pointer is fetched from the machine stack to H'L' where it
  15142.                                         ; addresses one of the numbers of the series following the series literal.
  15143.  
  15144.                 CALL    STK_DATA        ; routine STK_DATA is called directly to
  15145.                                         ; push a value and advance H'L'.
  15146.                 CALL    GEN_ENT_2       ; routine GEN_ENT_2 recursively re-enters
  15147.                                         ; the calculator without disturbing
  15148.                                         ; system variable BREG
  15149.                                         ; H'L' value goes on the machine stack and is
  15150.                                         ; then loaded as usual with the next address.
  15151.  
  15152.                 DEFB    $0F             ;;ADDITION
  15153.                 DEFB    $01             ;;EXCHANGE
  15154.                 DEFB    $C2             ;;st-mem-2
  15155.                 DEFB    $02             ;;DELETE
  15156.  
  15157.                 DEFB    $35             ;;DEC_JR_NZ
  15158.                 DEFB    $EE             ;;back to G_LOOP
  15159.  
  15160.                                         ; when the counted loop is complete the final subtraction yields the result
  15161.                                         ; for example SIN X.
  15162.  
  15163.                 DEFB    $E1             ;;get-mem-1
  15164.                 DEFB    $03             ;;SUBTRACT
  15165.                 DEFB    $38             ;;END_CALC
  15166.  
  15167.                 RET                     ; return with H'L' pointing to location
  15168.                                         ; after last number in series.
  15169.  
  15170. ;-------------------------
  15171. ; Absolute magnitude ($2A)
  15172. ;-------------------------
  15173. ; This calculator literal finds the absolute value of the last value,
  15174. ; integer or floating point, on calculator stack.
  15175.  
  15176.                                         ;;;$346A
  15177. ABS:            LD      B,$FF           ; signal abs
  15178.                 JR      NEG_TEST        ; forward to NEG_TEST
  15179.  
  15180. ;-------------------------
  15181. ; Handle unary minus ($1B)
  15182. ;-------------------------
  15183. ; Unary so on entry HL points to last value, DE to STKEND.
  15184.  
  15185.                                         ;;;$346E
  15186. NEGATE:         CALL    TEST_ZERO       ; call routine TEST_ZERO and
  15187.                 RET     C               ; return if so leaving zero unchanged.
  15188.  
  15189.                 LD      B,$00           ; signal negate required before joining
  15190.                                         ; common code.
  15191.  
  15192.                                         ;;;$3474
  15193. NEG_TEST:       LD      A,(HL)          ; load first byte and
  15194.                 AND     A               ; test for zero
  15195.                 JR      Z,INT_CASE      ; forward to INT_CASE if a small integer
  15196.  
  15197.                                         ; for floating point numbers a single bit denotes the sign.
  15198.  
  15199.                 INC     HL              ; address the first byte of mantissa.
  15200.                 LD      A,B             ; action flag $FF=abs, $00=neg.
  15201.                 AND     $80             ; now           $80     $00
  15202.                 OR      (HL)            ; sets bit 7 for abs
  15203.                 RLA                     ; sets carry for abs and if number negative
  15204.                 CCF                     ; complement carry flag
  15205.                 RRA                     ; and rotate back in altering sign
  15206.                 LD      (HL),A          ; put the altered adjusted number back
  15207.                 DEC     HL              ; HL points to result
  15208.                 RET                     ; return with DE unchanged
  15209.  
  15210.                                         ; for integer numbers an entire byte denotes the sign.
  15211.  
  15212.                                         ;;;$3483
  15213. INT_CASE:       PUSH    DE              ; save STKEND.
  15214.                 PUSH    HL              ; save pointer to the last value/result.
  15215.                 CALL    INT_FETCH       ; routine INT_FETCH puts integer in DE and the sign in C.
  15216.                 POP     HL              ; restore the result pointer.
  15217.                 LD      A,B             ; $FF=abs, $00=neg
  15218.                 OR      C               ; $FF for abs, no change neg
  15219.                 CPL                     ; $00 for abs, switched for neg
  15220.                 LD      C,A             ; transfer result to sign byte.
  15221.                 CALL    INT_STORE       ; routine INT_STORE to re-write the integer.
  15222.                 POP     DE              ; restore STKEND.
  15223.                 RET                     ; return.
  15224.  
  15225. ;-------------
  15226. ; Signum ($29)
  15227. ;-------------
  15228. ; This routine replaces the last value on the calculator stack,
  15229. ; which may be in floating point or integer form, with the integer values
  15230. ; zero if zero, with one if positive and  with -minus one if negative.
  15231.  
  15232.                                         ;;;$3492
  15233. SGN:            CALL    TEST_ZERO       ; call routine TEST_ZERO and
  15234.                 RET     C               ; exit if so as no change is required.
  15235.                 PUSH    DE              ; save pointer to STKEND.
  15236.                 LD      DE,$0001        ; the result will be 1.
  15237.                 INC     HL              ; skip over the exponent.
  15238.                 RL      (HL)            ; rotate the sign bit into the carry flag.
  15239.                 DEC     HL              ; step back to point to the result.
  15240.                 SBC     A,A             ; byte will be $FF if negative, $00 if positive.
  15241.                 LD      C,A             ; store the sign byte in the C register.
  15242.                 CALL    INT_STORE       ; routine INT_STORE to overwrite the last value with 0001 and sign.
  15243.                 POP     DE              ; restore STKEND.
  15244.                 RET                     ; return.
  15245.  
  15246. ;-------------------------
  15247. ; Handle IN function ($2C)
  15248. ;-------------------------
  15249. ; This function reads a byte from an input port.
  15250.  
  15251.                                         ;;;$34A5
  15252. IN_:            CALL    FIND_INT2       ; routine FIND_INT2 puts port address in BC.
  15253.                                         ; all 16 bits are put on the address line.
  15254.                 IN      A,(C)           ; read the port.
  15255.                 JR      IN_PK_STK       ; exit to STACK_A (via IN_PK_STK to save a byte
  15256.                                         ; of instruction code).
  15257.  
  15258. ;--------------------------
  15259. ; Handle PEEK function ($2B)
  15260. ;--------------------------
  15261. ; This function returns the contents of a memory address.
  15262. ; The entire address space can be peeked including the ROM.
  15263.  
  15264.                                         ;;;$34AC
  15265. PEEK:           CALL    FIND_INT2       ; routine FIND_INT2 puts address in BC.
  15266.                 LD      A,(BC)          ; load contents into A register.
  15267.  
  15268.                                         ;;;$34B0
  15269. IN_PK_STK:      JP      STACK_A         ; exit via STACK_A to put value on the
  15270.                                         ; calculator stack.
  15271.  
  15272. ;-----------------
  15273. ; USR number ($2D)
  15274. ;-----------------
  15275. ; The USR function followed by a number 0-65535 is the method by which
  15276. ; the Spectrum invokes machine code programs. This function returns the
  15277. ; contents of the BC register pair.
  15278. ; Note. that STACK_BC re-initializes the IY register if a user-written
  15279. ; program has altered it.
  15280.  
  15281.                                         ;; USR_NO
  15282. USR_NO:         CALL    FIND_INT2       ; routine FIND_INT2 to fetch the supplied address into BC.
  15283.                 LD      HL,STACK_BC     ; address: STACK_BC is
  15284.                 PUSH    HL              ; pushed onto the machine stack.
  15285.                 PUSH    BC              ; then the address of the machine code routine.
  15286.                 RET                     ; make an indirect jump to the routine
  15287.                                         ; and, hopefully, to STACK_BC also.
  15288.  
  15289. ;-----------------
  15290. ; USR string ($19)
  15291. ;-----------------
  15292. ; The user function with a one-character string argument, calculates the
  15293. ; address of the User Defined Graphic character that is in the string.
  15294. ; As an alternative, the ascii equivalent, upper or lower case,
  15295. ; may be supplied. This provides a user-friendly method of redefining
  15296. ; the 21 User Definable Graphics e.g.
  15297. ; POKE USR "a", BIN 10000000 will put a dot in the top left corner of the
  15298. ; character 144.
  15299. ; Note. the curious double check on the range. With 26 UDGs the first check
  15300. ; only is necessary. With anything less the second check only is required.
  15301. ; It is highly likely that the first check was written by Steven Vickers.
  15302.  
  15303.                                         ;;;$34BC
  15304. USR_:           CALL    STK_FETCH       ; routine STK_FETCH fetches the string parameters.
  15305.                 DEC     BC              ; decrease BC by
  15306.                 LD      A,B             ; one to test
  15307.                 OR      C               ; the length.
  15308.                 JR      NZ,REPORT_A     ; to REPORT_A if not a single character.
  15309.  
  15310.                 LD      A,(DE)          ; fetch the character
  15311.                 CALL    ALPHA           ; routine ALPHA sets carry if 'A-Z' or 'a-z'.
  15312.                 JR      C,USR_RANGE     ; forward to USR_RANGE if ascii.
  15313.  
  15314.                 SUB     $90             ; make udgs range 0-20d
  15315.                 JR      C,REPORT_A      ; to REPORT_A if too low. e.g. usr " ".
  15316.  
  15317.                 CP      $15             ; Note. this test is not necessary.
  15318.                 JR      NC,REPORT_A     ; to REPORT_A if higher than 20.
  15319.  
  15320.                 INC     A               ; make range 1-21d to match LSBs of ascii
  15321.  
  15322.                                         ;;;$34D3
  15323. USR_RANGE:      DEC     A               ; make range of bits 0-4 start at zero
  15324.                 ADD     A,A             ; multiply by eight
  15325.                 ADD     A,A             ; and lose any set bits
  15326.                 ADD     A,A             ; range now 0 - 25*8
  15327.                 CP      $A8             ; compare to 21*8
  15328.                 JR      NC,REPORT_A     ; to REPORT_A if originally higher
  15329.                                         ; than 'U','u' or graphics U.
  15330.                 LD      BC,(UDG)        ; fetch the UDG system variable value.
  15331.                 ADD     A,C             ; add the offset to character
  15332.                 LD      C,A             ; and store back in register C.
  15333.                 JR      NC,USR_STACK    ; forward to USR_STACK if no overflow.
  15334.  
  15335.                 INC     B               ; increment high byte.
  15336.  
  15337.                                         ;;;$34E4
  15338. USR_STACK:      JP      STACK_BC        ; jump back and exit via STACK_BC to store
  15339.  
  15340.                                         ;;;$34E7
  15341. REPORT_A:       RST     08H             ; ERROR_1
  15342.                 DEFB    $09             ; Error Report: Invalid argument
  15343.  
  15344. ;--------------
  15345. ; Test for zero
  15346. ;--------------
  15347. ; Test if top value on calculator stack is zero.
  15348. ; The carry flag is set if the last value is zero but no registers are altered.
  15349. ; All five bytes will be zero but first four only need be tested.
  15350. ; On entry HL points to the exponent the first byte of the value.
  15351.  
  15352.                                         ;;;$34E9
  15353. TEST_ZERO:      PUSH    HL              ; preserve HL which is used to address.
  15354.                 PUSH    BC              ; preserve BC which is used as a store.
  15355.                 LD      B,A             ; preserve A in B.
  15356.                 LD      A,(HL)          ; load first byte to accumulator
  15357.                 INC     HL              ; advance.
  15358.                 OR      (HL)            ; OR with second byte and clear carry.
  15359.                 INC     HL              ; advance.
  15360.                 OR      (HL)            ; OR with third byte.
  15361.                 INC     HL              ; advance.
  15362.                 OR      (HL)            ; OR with fourth byte.
  15363.                 LD      A,B             ; restore A without affecting flags.
  15364.                 POP     BC              ; restore the saved
  15365.                 POP     HL              ; registers.
  15366.                 RET     NZ              ; return if not zero and with carry reset.
  15367.  
  15368.                 SCF                     ; set the carry flag.
  15369.                 RET                     ; return with carry set if zero.
  15370.  
  15371. ;------------------------
  15372. ; Greater than zero ($37)
  15373. ;------------------------
  15374. ; Test if the last value on the calculator stack is greater than zero.
  15375. ; This routine is also called directly from the end-tests of the comparison
  15376. ; routine.
  15377.  
  15378.                                         ;;;$34F9
  15379. GREATER_0:      CALL    TEST_ZERO       ; routine TEST_ZERO
  15380.                 RET     C               ; return if was zero as this
  15381.                                         ; is also the Boolean 'false' value.
  15382.                 LD      A,$FF           ; prepare XOR mask for sign bit
  15383.                 JR      SIGN_TO_C       ; forward to SIGN_TO_C
  15384.                                         ; to put sign in carry
  15385.                                         ; (carry will become set if sign is positive)
  15386.                                         ; and then overwrite location with 1 or 0
  15387.                                         ; as appropriate.
  15388.  
  15389. ;--------------------------
  15390. ; Handle NOT operator ($30)
  15391. ;--------------------------
  15392. ; This overwrites the last value with 1 if it was zero else with zero
  15393. ; if it was any other value.
  15394. ;
  15395. ; e.g NOT 0 returns 1, NOT 1 returns 0, NOT -3 returns 0.
  15396. ;
  15397. ; The subroutine is also called directly from the end-tests of the comparison
  15398. ; operator.
  15399.  
  15400.                                         ;;;$3501
  15401. NOT_:           CALL    TEST_ZERO       ; routine TEST_ZERO sets carry if zero
  15402.                 JR      FP_0_1          ; to FP_0_1 to overwrite operand with
  15403.                                         ; 1 if carry is set else to overwrite with zero.
  15404.  
  15405. ;---------------------
  15406. ; Less than zero ($36)
  15407. ;---------------------
  15408. ; Destructively test if last value on calculator stack is less than zero.
  15409. ; Bit 7 of second byte will be set if so.
  15410.  
  15411.                                         ;;;$3506
  15412. LESS_0:         XOR     A               ; set xor mask to zero
  15413.                                         ; (carry will become set if sign is negative).
  15414.  
  15415.                                         ; transfer sign of mantissa to Carry Flag.
  15416.  
  15417.                                         ;;;$3507
  15418. SIGN_TO_C:      INC     HL              ; address 2nd byte.
  15419.                 XOR     (HL)            ; bit 7 of HL will be set if number is negative.
  15420.                 DEC     HL              ; address 1st byte again.
  15421.                 RLCA                    ; rotate bit 7 of A to carry.
  15422.  
  15423. ;------------
  15424. ; Zero or one
  15425. ;------------
  15426. ; This routine places an integer value zero or one at the addressed location
  15427. ; of calculator stack or MEM area. The value one is written if carry is set on
  15428. ; entry else zero.
  15429.  
  15430.                                         ;;;$350B
  15431.                                         ;; FP-0/1
  15432. FP_0_1:         PUSH    HL              ; save pointer to the first byte
  15433.                 LD      A,$00           ; load accumulator with zero - without disturbing flags.
  15434.                 LD      (HL),A          ; zero to first byte
  15435.                 INC     HL              ; address next
  15436.                 LD      (HL),A          ; zero to 2nd byte
  15437.                 INC     HL              ; address low byte of integer
  15438.                 RLA                     ; carry to bit 0 of A
  15439.                 LD      (HL),A          ; load one or zero to low byte.
  15440.                 RRA                     ; restore zero to accumulator.
  15441.                 INC     HL              ; address high byte of integer.
  15442.                 LD      (HL),A          ; put a zero there.
  15443.                 INC     HL              ; address fifth byte.
  15444.                 LD      (HL),A          ; put a zero there.
  15445.                 POP     HL              ; restore pointer to the first byte.
  15446.                 RET                     ; return.
  15447.  
  15448. ;-------------------------
  15449. ; Handle OR operator ($07)
  15450. ;-------------------------
  15451. ; The Boolean OR operator. eg. X OR Y
  15452. ; The result is zero if both values are zero else a non-zero value.
  15453. ;
  15454. ; e.g.   0 OR 0  returns 0.
  15455. ;       -3 OR 0  returns -3.
  15456. ;        0 OR -3 returns 1.
  15457. ;       -3 OR 2  returns 1.
  15458. ;
  15459. ; A binary operation.
  15460. ; On entry HL points to first operand (X) and DE to second operand (Y).
  15461.  
  15462.                                         ;;;$351B
  15463. OR_:            EX      DE,HL           ; make HL point to second number
  15464.                 CALL    TEST_ZERO       ; routine TEST_ZERO
  15465.                 EX      DE,HL           ; restore pointers
  15466.                 RET     C               ; return if result was zero - first operand,
  15467.                                         ; now the last value, is the result.
  15468.                 SCF                     ; set carry flag
  15469.                 JR      FP_0_1          ; back to FP_0_1 to overwrite the first operand
  15470.                                         ; with the value 1.
  15471.  
  15472.  
  15473. ;-------------------------------
  15474. ; Handle number AND number ($08)
  15475. ;-------------------------------
  15476. ; The Boolean AND operator.
  15477. ;
  15478. ; e.g.  -3 AND 2  returns -3.
  15479. ;       -3 AND 0  returns 0.
  15480. ;        0 AND -2 returns 0.
  15481. ;        0 AND 0  returns 0.
  15482. ;
  15483. ; Compare with OR routine above.
  15484.  
  15485.                                         ;;;$3524
  15486. NO_AND_NO:      EX      DE,HL           ; make HL address second operand.
  15487.                 CALL    TEST_ZERO       ; routine TEST_ZERO sets carry if zero.
  15488.                 EX      DE,HL           ; restore pointers.
  15489.                 RET     NC              ; return if second non-zero, first is result.
  15490.  
  15491.                 AND     A               ; else clear carry.
  15492.                 JR      FP_0_1          ; back to FP_0_1 to overwrite first operand
  15493.                                         ; with zero for return value.
  15494.  
  15495. ;-------------------------------
  15496. ; Handle string AND number ($10)
  15497. ;-------------------------------
  15498. ; e.g. "You Win" AND score>99 will return the string if condition is true
  15499. ; or the null string if false.
  15500.  
  15501.                                         ;;;$352D
  15502. STR_AND_NO:     EX      DE,HL           ; make HL point to the number.
  15503.                 CALL    TEST_ZERO       ; routine TEST_ZERO.
  15504.                 EX      DE,HL           ; restore pointers.
  15505.                 RET     NC              ; return if number was not zero - the string is the result.
  15506.  
  15507.                                         ; if the number was zero (false) then the null string must be returned by
  15508.                                         ; altering the length of the string on the calculator stack to zero.
  15509.  
  15510.                 PUSH    DE              ; save pointer to the now obsolete number
  15511.                                         ; (which will become the new STKEND)
  15512.                 DEC     DE              ; point to the 5th byte of string descriptor.
  15513.                 XOR     A               ; clear the accumulator.
  15514.                 LD      (DE),A          ; place zero in high byte of length.
  15515.                 DEC     DE              ; address low byte of length.
  15516.                 LD      (DE),A          ; place zero there - now the null string.
  15517.                 POP     DE              ; restore pointer - new STKEND.
  15518.                 RET                     ; return.
  15519.  
  15520. ;------------------------------------
  15521. ; Perform comparison ($09-$0E, $11-$16)
  15522. ;------------------------------------
  15523. ; True binary operations.
  15524. ;
  15525. ; A single entry point is used to evaluate six numeric and six string
  15526. ; comparisons. On entry, the calculator literal is in the B register and
  15527. ; the two numeric values, or the two string parameters, are on the
  15528. ; calculator stack.
  15529. ; The individual bits of the literal are manipulated to group similar
  15530. ; operations although the SUB 8 instruction does nothing useful and merely
  15531. ; alters the string test bit.
  15532. ; Numbers are compared by subtracting one from the other, strings are
  15533. ; compared by comparing every character until a mismatch, or the end of one
  15534. ; or both, is reached.
  15535. ;
  15536. ; Numeric Comparisons.
  15537. ; --------------------
  15538. ; The 'x>y' example is the easiest as it employs straight-thru logic.
  15539. ; Number y is subtracted from x and the result tested for GREATER_0 yielding
  15540. ; a final value 1 (true) or 0 (false).
  15541. ; For 'x<y' the same logic is used but the two values are first swapped on the
  15542. ; calculator stack.
  15543. ; For 'x=y' NOT is applied to the subtraction result yielding true if the
  15544. ; difference was zero and false with anything else.
  15545. ; The first three numeric comparisons are just the opposite of the last three
  15546. ; so the same processing steps are used and then a final NOT is applied.
  15547. ;
  15548. ; literal    Test   No  sub 8       ExOrNot  1st RRCA  exch sub  ?   End-Tests
  15549. ; =========  ====   == ======== === ======== ========  ==== ===  =  === === ===
  15550. ; NO_L_EQL   x<=y   09 00000001 dec 00000000 00000000  ---- x-y  ?  --- >0? NOT
  15551. ; NO_GR_EQL  x>=y   0A 00000010 dec 00000001 10000000c swap y-x  ?  --- >0? NOT
  15552. ; NOS_NEQL   x<>y   0B 00000011 dec 00000010 00000001  ---- x-y  ?  NOT --- NOT
  15553. ; NO_GRTR    x>y    0C 00000100  -  00000100 00000010  ---- x-y  ?  --- >0? ---
  15554. ; NO_LESS    x<y    0D 00000101  -  00000101 10000010c swap y-x  ?  --- >0? ---
  15555. ; NOS_EQL    x=y    0E 00000110  -  00000110 00000011  ---- x-y  ?  NOT --- ---
  15556. ;
  15557. ;                                                           comp -> C/F
  15558. ;                                                           ====    ===
  15559. ; STR_L_EQL  x$<=y$ 11 00001001 dec 00001000 00000100  ---- x$y$ 0  !or >0? NOT
  15560. ; STR_GR_EQL x$>=y$ 12 00001010 dec 00001001 10000100c swap y$x$ 0  !or >0? NOT
  15561. ; STRS_NEQL  x$<>y$ 13 00001011 dec 00001010 00000101  ---- x$y$ 0  !or >0? NOT
  15562. ; STR_GRTR   x$>y$  14 00001100  -  00001100 00000110  ---- x$y$ 0  !or >0? ---
  15563. ; STR_LESS   x$<y$  15 00001101  -  00001101 10000110c swap y$x$ 0  !or >0? ---
  15564. ; STRS_EQL   x$=y$  16 00001110  -  00001110 00000111  ---- x$y$ 0  !or >0? ---
  15565. ;
  15566. ; String comparisons are a little different in that the eql/neql carry flag
  15567. ; from the 2nd RRCA is, as before, fed into the first of the end tests but
  15568. ; along the way it gets modified by the comparison process. The result on the
  15569. ; stack always starts off as zero and the carry fed in determines if NOT is
  15570. ; applied to it. So the only time the GREATER_0 test is applied is if the
  15571. ; stack holds zero which is not very efficient as the test will always yield
  15572. ; zero. The most likely explanation is that there were once separate end tests
  15573. ; for numbers and strings.
  15574.  
  15575.                                         ;;;$353B
  15576. NO_L_EQL:
  15577. NO_GR_EQL:
  15578. NOS_NEQL:
  15579. NO_GRTR:
  15580. NO_LESS:
  15581. NOS_EQL:
  15582.  
  15583. STR_L_EQL:
  15584. STR_GR_EQL:
  15585. STRS_NEQL:
  15586. STR_GRTR:
  15587. STR_LESS:
  15588. STRS_EQL:
  15589.  
  15590.                 LD      A,B             ; transfer literal to accumulator.
  15591.                 SUB     $08             ; subtract eight - which is not useful.
  15592.                 BIT     2,A             ; isolate '>', '<', '='.
  15593.                 JR      NZ,EX_OR_NOT    ; skip to EX_OR_NOT with these.
  15594.  
  15595.                 DEC     A               ; else make $00-$02, $08-$0A to match bits 0-2.
  15596.  
  15597.                                         ;;;$3543
  15598. EX_OR_NOT:      RRCA                    ; the first RRCA sets carry for a swap.
  15599.                 JR      NC,NU_OR_STR    ; forward to NU_OR_STR with other 8 cases
  15600.  
  15601.                                         ; for the other 4 cases the two values on the calculator stack are exchanged.
  15602.  
  15603.                 PUSH    AF              ; save A and carry.
  15604.                 PUSH    HL              ; save HL - pointer to first operand.
  15605.                                         ; (DE points to second operand).
  15606.                 CALL    EXCHANGE        ; routine EXCHANGE swaps the two values.
  15607.                                         ; (HL = second operand, DE = STKEND)
  15608.                 POP     DE              ; DE = first operand
  15609.                 EX      DE,HL           ; as we were.
  15610.                 POP     AF              ; restore A and carry.
  15611.  
  15612.                                         ; Note. it would be better if the 2nd RRCA preceded the string test.
  15613.                                         ; It would save two duplicate bytes and if we also got rid of that sub 8
  15614.                                         ; at the beginning we wouldn't have to alter which bit we test.
  15615.  
  15616.                                         ;;;$354E
  15617. NU_OR_STR:      BIT     2,A             ; test if a string comparison.
  15618.                 JR      NZ,STRINGS      ; forward to STRINGS if so.
  15619.  
  15620.                                         ; continue with numeric comparisons.
  15621.  
  15622.                 RRCA                    ; 2nd RRCA causes eql/neql to set carry.
  15623.                 PUSH    AF              ; save A and carry
  15624.                 CALL    SUBTRACT        ; routine SUBTRACT leaves result on stack.
  15625.                 JR      END_TESTS       ; forward to END_TESTS
  15626.  
  15627.                                         ;;;$3559
  15628. STRINGS:        RRCA                    ; 2nd RRCA causes eql/neql to set carry.
  15629.                 PUSH    AF              ; save A and carry.
  15630.                 CALL    STK_FETCH       ; routine STK_FETCH gets 2nd string params
  15631.                 PUSH    DE              ; save start2 *.
  15632.                 PUSH    BC              ; and the length.
  15633.                 CALL    STK_FETCH       ; routine STK_FETCH gets 1st string
  15634.                                         ; parameters - start in DE, length in BC.
  15635.                 POP     HL              ; restore length of second to HL.
  15636.  
  15637.                                         ; A loop is now entered to compare, by subtraction, each corresponding character
  15638.                                         ; of the strings. For each successful match, the pointers are incremented and
  15639.                                         ; the lengths decreased and the branch taken back to here. If both string
  15640.                                         ; remainders become null at the same time, then an exact match exists.
  15641.  
  15642.                                         ;;;$3564
  15643. BYTE_COMP:      LD      A,H             ; test if the second string
  15644.                 OR      L               ; is the null string and hold flags.
  15645.                 EX      (SP),HL         ; put length2 on stack, bring start2 to HL *.
  15646.                 LD      A,B             ; hi byte of length1 to A
  15647.                 JR      NZ,SEC_PLUS     ; forward to SEC_PLUS if second not null.
  15648.  
  15649.                 OR      C               ; test length of first string.
  15650.  
  15651.                                         ;;;$356B
  15652. SECND_LOW:      POP     BC              ; pop the second length off stack.
  15653.                 JR      Z,BOTH_NULL     ; forward to BOTH_NULL if first string is also
  15654.                                         ; of zero length.
  15655.  
  15656.                                         ; the true condition - first is longer than second (SECND-LESS)
  15657.  
  15658.                 POP     AF              ; restore carry (set if eql/neql)
  15659.                 CCF                     ; complement carry flag.
  15660.                                         ; Note. equality becomes false.
  15661.                                         ; Inequality is true. By swapping or applying
  15662.                                         ; a terminal 'not', all comparisons have been
  15663.                                         ; manipulated so that this is success path.
  15664.                 JR      STR_TEST        ; forward to leave via STR_TEST
  15665.  
  15666.                                         ; the branch was here with a match
  15667.  
  15668.                                         ;;;$3572
  15669. BOTH_NULL:      POP     AF              ; restore carry - set for eql/neql
  15670.                 JR      STR_TEST        ; forward to STR_TEST
  15671.  
  15672.                                         ; the branch was here when 2nd string not null and low byte of first is yet
  15673.                                         ; to be tested.
  15674.  
  15675.                                         ;;;$3575
  15676. SEC_PLUS:       OR      C               ; test the length of first string.
  15677.                 JR      Z,FRST_LESS     ; forward to FRST_LESS if length is zero.
  15678.  
  15679.                                         ; both strings have at least one character left.
  15680.  
  15681.                 LD      A,(DE)          ; fetch character of first string.
  15682.                 SUB     (HL)            ; subtract with that of 2nd string.
  15683.                 JR      C,FRST_LESS     ; forward to FRST_LESS if carry set
  15684.  
  15685.                 JR      NZ,SECND_LOW    ; back to SECND_LOW and then STR_TEST
  15686.                                         ; if not exact match.
  15687.  
  15688.                 DEC     BC              ; decrease length of 1st string.
  15689.                 INC     DE              ; increment 1st string pointer.
  15690.                 INC     HL              ; increment 2nd string pointer.
  15691.                 EX      (SP),HL         ; swap with length on stack
  15692.                 DEC     HL              ; decrement 2nd string length
  15693.                 JR      BYTE_COMP       ; back to BYTE_COMP
  15694.  
  15695.                                         ; the false condition.
  15696.  
  15697.                                         ;;;$3585
  15698. FRST_LESS:      POP     BC              ; discard length
  15699.                 POP     AF              ; pop A
  15700.                 AND     A               ; clear the carry for false result.
  15701.  
  15702.                                         ; exact match and x$>y$ rejoin here
  15703.  
  15704.                                         ;;;$3588
  15705. STR_TEST:       PUSH    AF              ; save A and carry
  15706.                 RST     28H             ;; FP_CALC
  15707.                 DEFB    $A0             ;;STK_ZERO      an initial false value.
  15708.                 DEFB    $38             ;;END_CALC
  15709.  
  15710.                                         ; both numeric and string paths converge here.
  15711.  
  15712.                                         ;;;$358C
  15713. END_TESTS:      POP     AF              ; pop carry  - will be set if eql/neql
  15714.                 PUSH    AF              ; save it again.
  15715.                 CALL    C,NOT_          ; routine NOT sets true(1) if equal(0)
  15716.                                         ; or, for strings, applies true result.
  15717.                 POP     AF              ; pop carry and
  15718.                 PUSH    AF              ; save A
  15719.                 CALL    NC,GREATER_0    ; routine GREATER_0 tests numeric subtraction
  15720.                                         ; result but also needlessly tests the string
  15721.                                         ; value for zero - it must be.
  15722.                 POP     AF              ; pop A
  15723.                 RRCA                    ; the third RRCA - test for '<=', '>=' or '<>'.
  15724.                 CALL    NC,NOT_         ; apply a terminal NOT if so.
  15725.                 RET                     ; return.
  15726.  
  15727. ;---------------------------
  15728. ; String concatenation ($17)
  15729. ;---------------------------
  15730. ; This literal combines two strings into one e.g. LET a$ = b$ + c$
  15731. ; The two parameters of the two strings to be combined are on the stack.
  15732.  
  15733.                                         ;;;$359C
  15734. STRS_ADD:       CALL    STK_FETCH       ; routine STK_FETCH fetches string parameters
  15735.                                         ; and deletes calculator stack entry.
  15736.                 PUSH    DE              ; save start address.
  15737.                 PUSH    BC              ; and length.
  15738.                 CALL    STK_FETCH       ; routine STK_FETCH for first string
  15739.                 POP     HL              ; re-fetch first length
  15740.                 PUSH    HL              ; and save again
  15741.                 PUSH    DE              ; save start of second string
  15742.                 PUSH    BC              ; and it's length.
  15743.                 ADD     HL,BC           ; add the two lengths.
  15744.                 LD      B,H             ; transfer to BC
  15745.                 LD      C,L             ; and create
  15746.                 RST     30H             ; BC_SPACES in workspace.
  15747.                                         ; DE points to start of space.
  15748.                 CALL    STK_STO_D       ; routine STK_STO_D stores parameters
  15749.                                         ; of new string updating STKEND.
  15750.                 POP     BC              ; length of first
  15751.                 POP     HL              ; address of start
  15752.                 LD      A,B             ; test for
  15753.                 OR      C               ; zero length.
  15754.                 JR      Z,OTHER_STR     ; to OTHER_STR if null string
  15755.  
  15756.                 LDIR                    ; copy string to workspace.
  15757.  
  15758.                                         ;;;$35B7
  15759. OTHER_STR:      POP     BC              ; now second length
  15760.                 POP     HL              ; and start of string
  15761.                 LD      A,B             ; test this one
  15762.                 OR      C               ; for zero length
  15763.                 JR      Z,STK_PNTRS     ; skip forward to STK_PNTRS if so as complete.
  15764.  
  15765.                 LDIR                    ; else copy the bytes.
  15766.                                         ; and continue into next routine which
  15767.                                         ; sets the calculator stack pointers.
  15768.  
  15769. ;---------------------
  15770. ; Check stack pointers
  15771. ;---------------------
  15772. ; Register DE is set to STKEND and HL, the result pointer, is set to five
  15773. ; locations below this.
  15774. ; This routine is used when it is inconvenient to save these values at the
  15775. ; time the calculator stack is manipulated due to other activity on the
  15776. ; machine stack.
  15777. ; This routine is also used to terminate the VAL and READ_IN  routines for
  15778. ; the same reason and to initialize the calculator stack at the start of
  15779. ; the CALCULATE routine.
  15780.  
  15781.                                         ;;;$35BF
  15782. STK_PNTRS:      LD      HL,(STKEND)     ; fetch STKEND value from system variable.
  15783.                 LD      DE,$FFFB        ; the value -5
  15784.                 PUSH    HL              ; push STKEND value.
  15785.                 ADD     HL,DE           ; subtract 5 from HL.
  15786.                 POP     DE              ; pop STKEND to DE.
  15787.                 RET                     ; return.
  15788.  
  15789. ;------------------
  15790. ; Handle CHR$ ($2F)
  15791. ;------------------
  15792. ; This function returns a single character string that is a result of
  15793. ; converting a number in the range 0-255 to a string e.g. CHR$ 65 = "A".
  15794.  
  15795.                                         ;;;$35C9
  15796. CHRS:           CALL    FP_TO_A         ; routine FP_TO_A puts the number in A.
  15797.                 JR      C,REPORT_BD     ; forward to REPORT_BD if overflow
  15798.                 JR      NZ,REPORT_BD    ; forward to REPORT_BD if negative
  15799.  
  15800.                 PUSH    AF              ; save the argument.
  15801.                 LD      BC,$0001        ; one space required.
  15802.                 RST     30H             ; BC_SPACES makes DE point to start
  15803.                 POP     AF              ; restore the number.
  15804.                 LD      (DE),A          ; and store in workspace
  15805.                 CALL    STK_STO_D       ; routine STK_STO_D stacks descriptor.
  15806.                 EX      DE,HL           ; make HL point to result and DE to STKEND.
  15807.                 RET                     ; return.
  15808.  
  15809.                                         ;;;$35DC
  15810. REPORT_BD:      RST     08H             ; ERROR_1
  15811.                 DEFB    $0A             ; Error Report: Integer out of range
  15812.  
  15813. ;-------------------------------
  15814. ; Handle VAL and VAL$ ($1D, $18)
  15815. ;-------------------------------
  15816. ; VAL treats the characters in a string as a numeric expression.
  15817. ;       e.g. VAL "2.3" = 2.3, VAL "2+4" = 6, VAL ("2" + "4") = 24.
  15818. ; VAL$ treats the characters in a string as a string expression.
  15819. ;       e.g. VAL$ (z$+"(2)") = a$(2) if z$ happens to be "a$".
  15820.  
  15821.                                         ;;;$35DE
  15822. VAL:
  15823. VALS:
  15824.                 LD      HL,(CH_ADD)     ; fetch value of system variable CH_ADD
  15825.                 PUSH    HL              ; and save on the machine stack.
  15826.                 LD      A,B             ; fetch the literal $1D or $18.
  15827.                 ADD     A,$E3           ; add $E3 to form $00 (setting carry) or $FB.
  15828.                 SBC     A,A             ; now form $FF bit 6 = numeric result
  15829.                                         ; or $00 bit 6 = string result.
  15830.                 PUSH    AF              ; save this mask on the stack
  15831.                 CALL    STK_FETCH       ; routine STK_FETCH fetches the string operand
  15832.                                         ; from calculator stack.
  15833.                 PUSH    DE              ; save the address of the start of the string.
  15834.                 INC     BC              ; increment the length for a carriage return.
  15835.                 RST     30H             ; BC_SPACES creates the space in workspace.
  15836.                 POP     HL              ; restore start of string to HL.
  15837.                 LD      (CH_ADD),DE     ; load CH_ADD with start DE in workspace.
  15838.                 PUSH    DE              ; save the start in workspace
  15839.                 LDIR                    ; copy string from program or variables or
  15840.                                         ; workspace to the workspace area.
  15841.                 EX      DE,HL           ; end of string + 1 to HL
  15842.                 DEC     HL              ; decrement HL to point to end of new area.
  15843.                 LD      (HL),$0D        ; insert a carriage return at end.
  15844.                 RES     7,(IY+$01)      ; update FLAGS  - signal checking syntax.
  15845.                 CALL    SCANNING        ; routine SCANNING evaluates string
  15846.                                         ; expression and result.
  15847.                 RST     18H             ; GET_CHAR fetches next character.
  15848.                 CP      $0D             ; is it the expected carriage return ?
  15849.                 JR      NZ,V_RPORT_C    ; forward to V_RPORT_C if not
  15850.                                         ; 'Nonsense in Basic'.
  15851.                 POP     HL              ; restore start of string in workspace.
  15852.                 POP     AF              ; restore expected result flag (bit 6).
  15853.                 XOR     (IY+$01)        ; xor with FLAGS now updated by SCANNING.
  15854.                 AND     $40             ; test bit 6 - should be zero if result types match.
  15855.  
  15856.                                         ;;;$360C
  15857. V_RPORT_C:      JP      NZ,REPORT_C     ; jump back to REPORT_C with a result mismatch.
  15858.                 LD      (CH_ADD),HL     ; set CH_ADD to the start of the string again.
  15859.                 SET     7,(IY+$01)      ; update FLAGS  - signal running program.
  15860.                 CALL    SCANNING        ; routine SCANNING evaluates the string
  15861.                                         ; in full leaving result on calculator stack.
  15862.                 POP     HL              ; restore saved character address in program.
  15863.                 LD      (CH_ADD),HL     ; and reset the system variable CH_ADD.
  15864.                 JR      STK_PNTRS       ; back to exit via STK_PNTRS.
  15865.                                         ; resetting the calculator stack pointers
  15866.                                         ; HL and DE from STKEND as it wasn't possible
  15867.                                         ; to preserve them during this routine.
  15868.  
  15869. ;------------------
  15870. ; Handle STR$ ($2E)
  15871. ;------------------
  15872.  
  15873.                                         ;;;$361F
  15874. STRS:           LD      BC,$0001        ; create an initial byte in workspace
  15875.                 RST     30H             ; using BC_SPACES restart.
  15876.                 LD      (K_CUR),HL      ; set system variable K_CUR to new location.
  15877.                 PUSH    HL              ; and save start on machine stack also.
  15878.                 LD      HL,(CURCHL)     ; fetch value of system variable CURCHL
  15879.                 PUSH    HL              ; and save that too.
  15880.                 LD      A,$FF           ; select system channel 'R'.
  15881.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN opens it.
  15882.                 CALL    PRINT_FP        ; routine PRINT_FP outputs the number to
  15883.                                         ; workspace updating K-CUR.
  15884.                 POP     HL              ; restore current channel.
  15885.                 CALL    CHAN_FLAG       ; routine CHAN_FLAG resets flags.
  15886.                 POP     DE              ; fetch saved start of string to DE.
  15887.                 LD      HL,(K_CUR)      ; load HL with end of string from K_CUR.
  15888.                 AND     A               ; prepare for true subtraction.
  15889.                 SBC     HL,DE           ; subtract start from end to give length.
  15890.                 LD      B,H             ; transfer the length to
  15891.                 LD      C,L             ; the BC register pair.
  15892.                 CALL    STK_STO_D       ; routine STK_STO_D stores string parameters
  15893.                                         ; on the calculator stack.
  15894.                 EX      DE,HL           ; HL = last value, DE = STKEND.
  15895.                 RET                     ; return.
  15896.  
  15897. ;--------------
  15898. ; Read-in ($1A)
  15899. ;--------------
  15900. ; This is the calculator literal used by the INKEY$ function when a '#'
  15901. ; is encountered after the keyword.
  15902. ; INKEY$ # does not interact correctly with the keyboard, #0 or #1, and
  15903. ; it's uses are for other channels.
  15904.  
  15905.                                         ;;;$3645
  15906. READ_IN:        CALL    FIND_INT1       ; routine FIND_INT1 fetches stream to A
  15907.                 CP      $10             ; compare with 16 decimal.
  15908.                 JP      NC,REPORT_BB    ; jump to REPORT_BB if not in range 0 - 15.
  15909.                                         ; 'Integer out of range'
  15910.                                         ; (REPORT_BD is within range)
  15911.                 LD      HL,(CURCHL)     ; fetch current channel CURCHL
  15912.                 PUSH    HL              ; save it
  15913.                 CALL    CHAN_OPEN       ; routine CHAN_OPEN opens channel
  15914.                 CALL    INPUT_AD        ; routine INPUT_AD - the channel must have an
  15915.                                         ; input stream or else error here from stream stub.
  15916.                 LD      BC,$0000        ; initialize length of string to zero
  15917.                 JR      NC,R_I_STORE    ; forward to R_I_STORE if no key detected.
  15918.                 INC     C               ; increase length to one.
  15919.                 RST     30H             ; BC_SPACES creates space for one character in workspace.
  15920.                 LD      (DE),A          ; the character is inserted.
  15921.  
  15922.                                         ;;;$365F
  15923. R_I_STORE:      CALL    STK_STO_D       ; routine STK_STO_D stacks the string parameters.
  15924.                 POP     HL              ; restore current channel address
  15925.                 CALL    CHAN_FLAG       ; routine CHAN_FLAG resets current channel
  15926.                                         ; system variable and flags.
  15927.                 JP      STK_PNTRS       ; jump back to STK_PNTRS
  15928.  
  15929. ;------------------
  15930. ; Handle CODE ($1C)
  15931. ;------------------
  15932. ; Returns the ascii code of a character or first character of a string
  15933. ; e.g. CODE "Aardvark" = 65, CODE "" = 0.
  15934.  
  15935.                                         ;;;$3669
  15936. CODE:   CALL    STK_FETCH               ; routine STK_FETCH to fetch and delete the
  15937.                                         ; string parameters.
  15938.                                         ; DE points to the start, BC holds the length.
  15939.                 LD      A,B             ; test length
  15940.                 OR      C               ; of the string.
  15941.                 JR      Z,STK_CODE      ; skip to STK_CODE with zero if the null string.
  15942.  
  15943.                 LD      A,(DE)          ; else fetch the first character.
  15944.  
  15945.                                         ;;;$3671
  15946. STK_CODE:       JP      STACK_A         ; jump back to STACK_A (with memory check)
  15947.  
  15948. ;-----------------
  15949. ; Handle LEN ($1E)
  15950. ;-----------------
  15951. ; Returns the length of a string.
  15952. ; In Sinclair Basic strings can be more than twenty thousand characters long
  15953. ; so a sixteen-bit register is required to store the length
  15954.  
  15955.                                         ;;;$3674
  15956. LEN:            CALL    STK_FETCH       ; routine STK_FETCH to fetch and delete the
  15957.                                         ; string parameters from the calculator stack.
  15958.                                         ; register BC now holds the length of string.
  15959.                 JP      STACK_BC        ; jump back to STACK_BC to save result on the
  15960.                                         ; calculator stack (with memory check).
  15961.  
  15962. ;---------------------------
  15963. ; Decrease the counter ($35)
  15964. ;---------------------------
  15965. ; The calculator has an instruction that decrements a single-byte
  15966. ; pseudo-register and makes consequential relative jumps just like
  15967. ; the Z80's DJNZ instruction.
  15968.  
  15969.                                         ;;;$367A
  15970. DEC_JR_NZ:      EXX                     ; switch in set that addresses code
  15971.                 PUSH    HL              ; save pointer to offset byte
  15972.                 LD      HL,BREG         ; address BREG in system variables
  15973.                 DEC     (HL)            ; decrement it
  15974.                 POP     HL              ; restore pointer
  15975.                 JR      NZ,JUMP_2       ; to JUMP_2 if not zero
  15976.  
  15977.                 INC     HL              ; step past the jump length.
  15978.                 EXX                     ; switch in the main set.
  15979.                 RET                     ; return.
  15980.  
  15981.                                         ; Note. as a general rule the calculator avoids using the IY register
  15982.                                         ; otherwise the cumbersome 4 instructions in the middle could be replaced by
  15983.                                         ; dec (iy+$2d) - three bytes instead of six.
  15984.  
  15985. ;-----------
  15986. ; Jump ($33)
  15987. ;-----------
  15988. ; This enables the calculator to perform relative jumps just like
  15989. ; the Z80 chip's JR instruction
  15990.  
  15991.                                         ;;;$3686
  15992. JUMP:           EXX                     ;switch in pointer set
  15993.  
  15994.                                         ;;;$3687
  15995. JUMP_2:         LD      E,(HL)          ; the jump byte 0-127 forward, 128-255 back.
  15996.                 LD      A,E             ; transfer to accumulator.
  15997.                 RLA                     ; if backward jump, carry is set.
  15998.                 SBC     A,A             ; will be $FF if backward or $00 if forward.
  15999.                 LD      D,A             ; transfer to high byte.
  16000.                 ADD     HL,DE           ; advance calculator pointer forward or back.
  16001.                 EXX                     ; switch back.
  16002.                 RET                     ; return.
  16003.  
  16004. ;-------------------
  16005. ; Jump on true ($00)
  16006. ;-------------------
  16007. ; This enables the calculator to perform conditional relative jumps
  16008. ; dependent on whether the last test gave a true result
  16009.  
  16010.                                         ;;;$368F
  16011. JUMP_TRUE:      INC     DE              ; collect the
  16012.                 INC     DE              ; third byte
  16013.                 LD      A,(DE)          ; of the test
  16014.                 DEC     DE              ; result and
  16015.                 DEC     DE              ; backtrack.
  16016.                 AND     A               ; is result 0 or 1 ?
  16017.                 JR      NZ,JUMP         ; back to JUMP if true (1).
  16018.  
  16019.                 EXX                     ; else switch in the pointer set.
  16020.                 INC     HL              ; step past the jump length.
  16021.                 EXX                     ; switch in the main set.
  16022.                 RET                     ; return.
  16023.  
  16024. ;-------------------------
  16025. ; End of calculation ($38)
  16026. ;-------------------------
  16027. ; The END_CALC literal terminates a mini-program written in the Spectrum's
  16028. ; internal language.
  16029.  
  16030.                                         ;;;$369B
  16031. END_CALC:       POP     AF              ; drop the calculator return address RE_ENTRY
  16032.                 EXX                     ; switch to the other set.
  16033.                 EX      (SP),HL         ; transfer H'L' to machine stack for the
  16034.                                         ; return address.
  16035.                                         ; when exiting recursion then the previous
  16036.                                         ; pointer is transferred to H'L'.
  16037.                 EXX                     ; back to main set.
  16038.                 RET                     ; return.
  16039.  
  16040.  
  16041. ;-------------
  16042. ; Modulus ($32)
  16043. ;-------------
  16044.  
  16045.                                         ;;;$36A0
  16046. N_MOD_M:        RST     28H             ;; FP_CALC      17, 3.
  16047.                 DEFB    $C0             ;;st-mem-0      17, 3.
  16048.                 DEFB    $02             ;;DELETE        17.
  16049.                 DEFB    $31             ;;DUPLICATE     17, 17.
  16050.                 DEFB    $E0             ;;get-mem-0     17, 17, 3.
  16051.                 DEFB    $05             ;;DIVISION      17, 17/3.
  16052.                 DEFB    $27             ;;INT           17, 5.
  16053.                 DEFB    $E0             ;;get-mem-0     17, 5, 3.
  16054.                 DEFB    $01             ;;EXCHANGE      17, 3, 5.
  16055.                 DEFB    $C0             ;;st-mem-0      17, 3, 5.
  16056.                 DEFB    $04             ;;MULTIPLY      17, 15.
  16057.                 DEFB    $03             ;;SUBTRACT      2.
  16058.                 DEFB    $E0             ;;get-mem-0     2, 5.
  16059.                 DEFB    $38             ;;END_CALC      2, 5.
  16060.  
  16061.                 RET                     ; return.
  16062.  
  16063.  
  16064. ;-----------------
  16065. ; Handle INT ($27)
  16066. ;-----------------
  16067. ; This function returns the integer of x, which is just the same as truncate
  16068. ; for positive numbers. The truncate literal truncates negative numbers
  16069. ; upwards so that -3.4 gives -3 whereas the Basic INT function has to
  16070. ; truncate negative numbers down so that INT -3.4 is 4.
  16071. ; It is best to work through using +-3.4 as examples.
  16072.  
  16073.                                         ;;;$36AF
  16074. INT:            RST     28H             ;; FP_CALC              x.      (= 3.4 or -3.4).
  16075.                 DEFB    $31             ;;DUPLICATE             x, x.
  16076.                 DEFB    $36             ;;LESS_0                x, (1/0)
  16077.                 DEFB    $00             ;;JUMP_TRUE             x, (1/0)
  16078.                 DEFB    $04             ;;to X_NEG
  16079.                 DEFB    $3A             ;;TRUNCATE              trunc 3.4 = 3.
  16080.                 DEFB    $38             ;;END_CALC              3.
  16081.  
  16082.                 RET                     ; return with + int x on stack.
  16083.  
  16084.                                         ;;;$36B7
  16085. X_NEG:          DEFB    $31             ;;DUPLICATE             -3.4, -3.4.
  16086.                 DEFB    $3A             ;;TRUNCATE              -3.4, -3.
  16087.                 DEFB    $C0             ;;st-mem-0              -3.4, -3.
  16088.                 DEFB    $03             ;;SUBTRACT              -.4
  16089.                 DEFB    $E0             ;;get-mem-0             -.4, -3.
  16090.                 DEFB    $01             ;;EXCHANGE              -3, -.4.
  16091.                 DEFB    $30             ;;NOT                   -3, (0).
  16092.                 DEFB    $00             ;;JUMP_TRUE             -3.
  16093.                 DEFB    $03             ;;to EXIT               -3.
  16094.                 DEFB    $A1             ;;STK_ONE               -3, 1.
  16095.                 DEFB    $03             ;;SUBTRACT              -4.
  16096.  
  16097.                                         ;;;$36C2
  16098. EXIT:           DEFB    $38             ;;END_CALC              -4.
  16099.  
  16100.                 RET                     ; return.
  16101.  
  16102. ;-----------------
  16103. ; Exponential ($26)
  16104. ;-----------------
  16105.  
  16106.                                         ;;;$36C4
  16107. EXP:            RST     28H             ;; FP_CALC
  16108.                 DEFB    $3D             ;;RE_STACK
  16109.                 DEFB    $34             ;;STK_DATA
  16110.                 DEFB    $F1             ;;Exponent: $81, Bytes: 4
  16111.                 DEFB    $38,$AA,$3B,$29 ;;
  16112.                 DEFB    $04             ;;MULTIPLY
  16113.                 DEFB    $31             ;;DUPLICATE
  16114.                 DEFB    $27             ;;INT
  16115.                 DEFB    $C3             ;;st-mem-3
  16116.                 DEFB    $03             ;;SUBTRACT
  16117.                 DEFB    $31             ;;DUPLICATE
  16118.                 DEFB    $0F             ;;ADDITION
  16119.                 DEFB    $A1             ;;STK_ONE
  16120.                 DEFB    $03             ;;SUBTRACT
  16121.                 DEFB    $88             ;;series-08
  16122.                 DEFB    $13             ;;Exponent: $63, Bytes: 1
  16123.                 DEFB    $36             ;;(+00,+00,+00)
  16124.                 DEFB    $58             ;;Exponent: $68, Bytes: 2
  16125.                 DEFB    $65,$66         ;;(+00,+00)
  16126.                 DEFB    $9D             ;;Exponent: $6D, Bytes: 3
  16127.                 DEFB    $78,$65,$40     ;;(+00)
  16128.                 DEFB    $A2             ;;Exponent: $72, Bytes: 3
  16129.                 DEFB    $60,$32,$C9     ;;(+00)
  16130.                 DEFB    $E7             ;;Exponent: $77, Bytes: 4
  16131.                 DEFB    $21,$F7,$AF,$24 ;;
  16132.                 DEFB    $EB             ;;Exponent: $7B, Bytes: 4
  16133.                 DEFB    $2F,$B0,$B0,$14 ;;
  16134.                 DEFB    $EE             ;;Exponent: $7E, Bytes: 4
  16135.                 DEFB    $7E,$BB,$94,$58 ;;
  16136.                 DEFB    $F1             ;;Exponent: $81, Bytes: 4
  16137.                 DEFB    $3A,$7E,$F8,$CF ;;
  16138.                 DEFB    $E3             ;;get-mem-3
  16139.                 DEFB    $38             ;;END_CALC
  16140.  
  16141.                 CALL    FP_TO_A         ; routine FP_TO_A
  16142.                 JR      NZ,N_NEGTV      ; to N_NEGTV
  16143.  
  16144.                 JR      C,REPORT_6B     ; to REPORT_6B
  16145.  
  16146.                 ADD     A,(HL)          ;
  16147.                 JR      NC,RESULT_OK    ; to RESULT_OK
  16148.  
  16149.                                         ;;;$3703
  16150. REPORT_6B:      RST     08H             ; ERROR_1
  16151.                 DEFB    $05             ; Error Report: Number too big
  16152.  
  16153.                                         ;; N_NEGTV
  16154. N_NEGTV:        JR      C,RSLT_ZERO     ; to RSLT_ZERO
  16155.  
  16156.                 SUB     (HL)
  16157.                 JR      NC,RSLT_ZERO    ; to RSLT_ZERO
  16158.  
  16159.                 NEG                     ; Negate
  16160.  
  16161.                                         ;;;$370C
  16162. RESULT_OK:      LD      (HL),A
  16163.                 RET                     ; return.
  16164.  
  16165.                                         ;;;$370E
  16166. RSLT_ZERO:      RST     28H             ;; FP_CALC
  16167.                 DEFB    $02             ;;DELETE
  16168.                 DEFB    $A0             ;;STK_ZERO
  16169.                 DEFB    $38             ;;END_CALC
  16170.  
  16171.                 RET                     ; return.
  16172.  
  16173.  
  16174. ;------------------------
  16175. ; Natural logarithm ($25)
  16176. ;------------------------
  16177.  
  16178.                                         ;;;$3713
  16179. LN:             RST     28H             ;; FP_CALC
  16180.                 DEFB    $3D             ;;RE_STACK
  16181.                 DEFB    $31             ;;DUPLICATE
  16182.                 DEFB    $37             ;;GREATER_0
  16183.                 DEFB    $00             ;;JUMP_TRUE
  16184.                 DEFB    $04             ;;to VALID
  16185.                 DEFB    $38             ;;END_CALC
  16186.  
  16187.                                         ;;;$371A
  16188. REPORT_AB:      RST     08H             ; ERROR_1
  16189.                 DEFB    $09             ; Error Report: Invalid argument
  16190.  
  16191.                                         ;;;$371C
  16192. VALID:          DEFB    $A0             ;;STK_ZERO
  16193.                 DEFB    $02             ;;DELETE
  16194.                 DEFB    $38             ;;END_CALC
  16195.  
  16196.                 LD      A,(HL) 
  16197.                 LD      (HL),$80
  16198.                 CALL    STACK_A         ; routine STACK_A
  16199.                 RST     28H             ;; FP_CALC
  16200.                 DEFB    $34             ;;STK_DATA
  16201.                 DEFB    $38             ;;Exponent: $88, Bytes: 1
  16202.                 DEFB    $00             ;;(+00,+00,+00)
  16203.                 DEFB    $03             ;;SUBTRACT
  16204.                 DEFB    $01             ;;EXCHANGE
  16205.                 DEFB    $31             ;;DUPLICATE
  16206.                 DEFB    $34             ;;STK_DATA
  16207.                 DEFB    $F0             ;;Exponent: $80, Bytes: 4
  16208.                 DEFB    $4C,$CC,$CC,$CD ;;
  16209.                 DEFB    $03             ;;SUBTRACT
  16210.                 DEFB    $37             ;;GREATER_0
  16211.                 DEFB    $00             ;;JUMP_TRUE
  16212.                 DEFB    $08             ;;to GRE_8
  16213.                 DEFB    $01             ;;EXCHANGE
  16214.                 DEFB    $A1             ;;STK_ONE
  16215.                 DEFB    $03             ;;SUBTRACT
  16216.                 DEFB    $01             ;;EXCHANGE
  16217.                 DEFB    $38             ;;END_CALC
  16218.  
  16219.                 INC     (HL)
  16220.                 RST     28H             ;; FP_CALC
  16221.  
  16222.                                         ;;;$373D
  16223. GRE_8:          DEFB    $01             ;;EXCHANGE
  16224.                 DEFB    $34             ;;STK_DATA
  16225.                 DEFB    $F0             ;;Exponent: $80, Bytes: 4
  16226.                 DEFB    $31,$72,$17,$F8 ;;
  16227.                 DEFB    $04             ;;MULTIPLY
  16228.                 DEFB    $01             ;;EXCHANGE
  16229.                 DEFB    $A2             ;;STK_HALF
  16230.                 DEFB    $03             ;;SUBTRACT
  16231.                 DEFB    $A2             ;;STK_HALF
  16232.                 DEFB    $03             ;;SUBTRACT
  16233.                 DEFB    $31             ;;DUPLICATE
  16234.                 DEFB    $34             ;;STK_DATA
  16235.                 DEFB    $32             ;;Exponent: $82, Bytes: 1
  16236.                 DEFB    $20             ;;(+00,+00,+00)
  16237.                 DEFB    $04             ;;MULTIPLY
  16238.                 DEFB    $A2             ;;STK_HALF
  16239.                 DEFB    $03             ;;SUBTRACT
  16240.                 DEFB    $8C             ;;series-0C
  16241.                 DEFB    $11             ;;Exponent: $61, Bytes: 1
  16242.                 DEFB    $AC             ;;(+00,+00,+00)
  16243.                 DEFB    $14             ;;Exponent: $64, Bytes: 1
  16244.                 DEFB    $09             ;;(+00,+00,+00)
  16245.                 DEFB    $56             ;;Exponent: $66, Bytes: 2
  16246.                 DEFB    $DA,$A5         ;;(+00,+00)
  16247.                 DEFB    $59             ;;Exponent: $69, Bytes: 2
  16248.                 DEFB    $30,$C5         ;;(+00,+00)
  16249.                 DEFB    $5C             ;;Exponent: $6C, Bytes: 2
  16250.                 DEFB    $90,$AA         ;;(+00,+00)
  16251.                 DEFB    $9E             ;;Exponent: $6E, Bytes: 3
  16252.                 DEFB    $70,$6F,$61     ;;(+00)
  16253.                 DEFB    $A1             ;;Exponent: $71, Bytes: 3
  16254.                 DEFB    $CB,$DA,$96     ;;(+00)
  16255.                 DEFB    $A4             ;;Exponent: $74, Bytes: 3
  16256.                 DEFB    $31,$9F,$B4     ;;(+00)
  16257.                 DEFB    $E7             ;;Exponent: $77, Bytes: 4
  16258.                 DEFB    $A0,$FE,$5C,$FC ;;
  16259.                 DEFB    $EA             ;;Exponent: $7A, Bytes: 4
  16260.                 DEFB    $1B,$43,$CA,$36 ;;
  16261.                 DEFB    $ED             ;;Exponent: $7D, Bytes: 4
  16262.                 DEFB    $A7,$9C,$7E,$5E ;;
  16263.                 DEFB    $F0             ;;Exponent: $80, Bytes: 4
  16264.                 DEFB    $6E,$23,$80,$93 ;;
  16265.                 DEFB    $04             ;;MULTIPLY
  16266.                 DEFB    $0F             ;;ADDITION
  16267.                 DEFB    $38             ;;END_CALC
  16268.  
  16269.                 RET                     ; return.
  16270.  
  16271. ;----------------------
  16272. ; Reduce argument ($39)
  16273. ;----------------------
  16274.  
  16275.                                         ;;;$3783
  16276. GET_ARGT:       RST     28H             ;; FP_CALC
  16277.                 DEFB    $3D             ;;RE_STACK
  16278.                 DEFB    $34             ;;STK_DATA
  16279.                 DEFB    $EE             ;;Exponent: $7E, Bytes: 4
  16280.                 DEFB    $22,$F9,$83,$6E
  16281.                 DEFB    $04             ;;MULTIPLY
  16282.                 DEFB    $31             ;;DUPLICATE
  16283.                 DEFB    $A2             ;;STK_HALF
  16284.                 DEFB    $0F             ;;ADDITION
  16285.                 DEFB    $27             ;;INT
  16286.                 DEFB    $03             ;;SUBTRACT
  16287.                 DEFB    $31             ;;DUPLICATE
  16288.                 DEFB    $0F             ;;ADDITION
  16289.                 DEFB    $31             ;;DUPLICATE
  16290.                 DEFB    $0F             ;;ADDITION
  16291.                 DEFB    $31             ;;DUPLICATE
  16292.                 DEFB    $2A             ;;ABS
  16293.                 DEFB    $A1             ;;STK_ONE
  16294.                 DEFB    $03             ;;SUBTRACT
  16295.                 DEFB    $31             ;;DUPLICATE
  16296.                 DEFB    $37             ;;GREATER_0
  16297.                 DEFB    $C0             ;;st-mem-0
  16298.                 DEFB    $00             ;;JUMP_TRUE
  16299.                 DEFB    $04             ;;to ZPLUS
  16300.                 DEFB    $02             ;;DELETE
  16301.                 DEFB    $38             ;;END_CALC
  16302.  
  16303.                 RET                     ; return.
  16304.  
  16305.                                         ;;;$37A1
  16306. ZPLUS:          DEFB    $A1             ;;STK_ONE
  16307.                 DEFB    $03             ;;SUBTRACT
  16308.                 DEFB    $01             ;;EXCHANGE
  16309.                 DEFB    $36             ;;LESS_0
  16310.                 DEFB    $00             ;;JUMP_TRUE
  16311.                 DEFB    $02             ;;to YNEG
  16312.                 DEFB    $1B             ;;NEGATE
  16313.  
  16314.                                         ;;;$37A8
  16315. YNEG:           DEFB    $38             ;;END_CALC
  16316.  
  16317.                 RET                     ; return.
  16318.  
  16319. ;--------------------
  16320. ; Handle cosine ($20)
  16321. ;--------------------
  16322.  
  16323.                                         ;;;$37AA
  16324. COS_:           RST     28H             ;; FP_CALC
  16325.                 DEFB    $39             ;;GET_ARGT
  16326.                 DEFB    $2A             ;;ABS
  16327.                 DEFB    $A1             ;;STK_ONE
  16328.                 DEFB    $03             ;;SUBTRACT
  16329.                 DEFB    $E0             ;;get-mem-0
  16330.                 DEFB    $00             ;;JUMP_TRUE
  16331.                 DEFB    $06             ;;fwd to C_ENT
  16332.                 DEFB    $1B             ;;NEGATE
  16333.                 DEFB    $33             ;;jump
  16334.                 DEFB    $03             ;;fwd to C_ENT
  16335.  
  16336. ;------------------
  16337. ; Handle sine ($1F)
  16338. ;------------------
  16339.  
  16340.                                         ;;;$37B5
  16341. SIN_:           RST     28H             ;; FP_CALC
  16342.                 DEFB    $39             ;;GET_ARGT
  16343.  
  16344.                                         ;;;$37B7
  16345. C_ENT:          DEFB    $31             ;;DUPLICATE
  16346.                 DEFB    $31             ;;DUPLICATE
  16347.                 DEFB    $04             ;;MULTIPLY
  16348.                 DEFB    $31             ;;DUPLICATE
  16349.                 DEFB    $0F             ;;ADDITION
  16350.                 DEFB    $A1             ;;STK_ONE
  16351.                 DEFB    $03             ;;SUBTRACT
  16352.                 DEFB    $86             ;;series-06
  16353.                 DEFB    $14             ;;Exponent: $64, Bytes: 1
  16354.                 DEFB    $E6             ;;(+00,+00,+00)
  16355.                 DEFB    $5C             ;;Exponent: $6C, Bytes: 2
  16356.                 DEFB    $1F,$0B         ;;(+00,+00)
  16357.                 DEFB    $A3             ;;Exponent: $73, Bytes: 3
  16358.                 DEFB    $8F,$38,$EE     ;;(+00)
  16359.                 DEFB    $E9             ;;Exponent: $79, Bytes: 4
  16360.                 DEFB    $15,$63,$BB,$23 ;;
  16361.                 DEFB    $EE             ;;Exponent: $7E, Bytes: 4
  16362.                 DEFB    $92,$0D,$CD,$ED ;;
  16363.                 DEFB    $F1             ;;Exponent: $81, Bytes: 4
  16364.                 DEFB    $23,$5D,$1B,$EA ;;
  16365.                 DEFB    $04             ;;MULTIPLY
  16366.                 DEFB    $38             ;;END_CALC
  16367.  
  16368.                 RET                     ; return.
  16369.  
  16370.  
  16371. ;---------------------
  16372. ; Handle tangent ($21)
  16373. ;---------------------
  16374. ; Evaluates tangent x as sin x/cos x.
  16375.  
  16376.                                         ;;;$37DA
  16377. TAN:            RST     28H             ;; FP_CALC      x.
  16378.                 DEFB    $31             ;;DUPLICATE     x, x.
  16379.                 DEFB    $1F             ;;SIN_          x, sin x.
  16380.                 DEFB    $01             ;;EXCHANGE      sin x, x.
  16381.                 DEFB    $20             ;;COS_          sin x, cos x.
  16382.                 DEFB    $05             ;;DIVISION      sin x/cos x (= tan x).
  16383.                 DEFB    $38             ;;END_CALC      tan x.
  16384.  
  16385.                 RET                     ; return.
  16386.  
  16387. ;-------------------
  16388. ; Handle arctan ($24)
  16389. ;-------------------
  16390. ; the inverse tangent function with the result in radians.
  16391.  
  16392.                                         ;;;$37E2
  16393. ATN:            CALL    RE_STACK        ; routine RE_STACK
  16394.                 LD      A,(HL)
  16395.                 CP      $81
  16396.                 JR      C,SMALL         ; to SMALL
  16397.  
  16398.                 RST     28H             ;; FP_CALC
  16399.                 DEFB    $A1             ;;STK_ONE
  16400.                 DEFB    $1B             ;;NEGATE
  16401.                 DEFB    $01             ;;EXCHANGE
  16402.                 DEFB    $05             ;;DIVISION
  16403.                 DEFB    $31             ;;DUPLICATE
  16404.                 DEFB    $36             ;;LESS_0
  16405.                 DEFB    $A3             ;;STK_PI_2
  16406.                 DEFB    $01             ;;EXCHANGE
  16407.                 DEFB    $00             ;;JUMP_TRUE
  16408.                 DEFB    $06             ;;to CASES
  16409.                 DEFB    $1B             ;;NEGATE
  16410.                 DEFB    $33             ;;jump
  16411.                 DEFB    $03             ;;to CASES
  16412.  
  16413.                                         ;;;$37F8
  16414. SMALL:          RST     28H             ;; FP_CALC
  16415.                 DEFB    $A0             ;;STK_ZERO
  16416.  
  16417.                                         ;;;$37FA
  16418. CASES:          DEFB    $01             ;;EXCHANGE
  16419.                 DEFB    $31             ;;DUPLICATE
  16420.                 DEFB    $31             ;;DUPLICATE
  16421.                 DEFB    $04             ;;MULTIPLY
  16422.                 DEFB    $31             ;;DUPLICATE
  16423.                 DEFB    $0F             ;;ADDITION
  16424.                 DEFB    $A1             ;;STK_ONE
  16425.                 DEFB    $03             ;;SUBTRACT
  16426.                 DEFB    $8C             ;;series-0C
  16427.                 DEFB    $10             ;;Exponent: $60, Bytes: 1
  16428.                 DEFB    $B2             ;;(+00,+00,+00)
  16429.                 DEFB    $13             ;;Exponent: $63, Bytes: 1
  16430.                 DEFB    $0E             ;;(+00,+00,+00)
  16431.                 DEFB    $55             ;;Exponent: $65, Bytes: 2
  16432.                 DEFB    $E4,$8D         ;;(+00,+00)
  16433.                 DEFB    $58             ;;Exponent: $68, Bytes: 2
  16434.                 DEFB    $39,$BC         ;;(+00,+00)
  16435.                 DEFB    $5B             ;;Exponent: $6B, Bytes: 2
  16436.                 DEFB    $98,$FD         ;;(+00,+00)
  16437.                 DEFB    $9E             ;;Exponent: $6E, Bytes: 3
  16438.                 DEFB    $00,$36,$75     ;;(+00)
  16439.                 DEFB    $A0             ;;Exponent: $70, Bytes: 3
  16440.                 DEFB    $DB,$E8,$B4     ;;(+00)
  16441.                 DEFB    $63             ;;Exponent: $73, Bytes: 2
  16442.                 DEFB    $42,$C4         ;;(+00,+00)
  16443.                 DEFB    $E6             ;;Exponent: $76, Bytes: 4
  16444.                 DEFB    $B5,$09,$36,$BE ;;
  16445.                 DEFB    $E9             ;;Exponent: $79, Bytes: 4
  16446.                 DEFB    $36,$73,$1B,$5D ;;
  16447.                 DEFB    $EC             ;;Exponent: $7C, Bytes: 4
  16448.                 DEFB    $D8,$DE,$63,$BE ;;
  16449.                 DEFB    $F0             ;;Exponent: $80, Bytes: 4
  16450.                 DEFB    $61,$A1,$B3,$0C ;;
  16451.                 DEFB    $04             ;;MULTIPLY
  16452.                 DEFB    $0F             ;;ADDITION
  16453.                 DEFB    $38             ;;END_CALC
  16454.  
  16455.                 RET                     ; return.
  16456.  
  16457.  
  16458. ;--------------------
  16459. ; Handle arcsin ($22)
  16460. ;--------------------
  16461. ; the inverse sine function with result in radians.
  16462. ; Error A unless the argument is between -1 and +1.
  16463.  
  16464.                                         ;;;$3833
  16465. ASN:            RST     28H             ;; FP_CALC
  16466.                 DEFB    $31             ;;DUPLICATE
  16467.                 DEFB    $31             ;;DUPLICATE
  16468.                 DEFB    $04             ;;MULTIPLY
  16469.                 DEFB    $A1             ;;STK_ONE
  16470.                 DEFB    $03             ;;SUBTRACT
  16471.                 DEFB    $1B             ;;NEGATE
  16472.                 DEFB    $28             ;;SQR
  16473.                 DEFB    $A1             ;;STK_ONE
  16474.                 DEFB    $0F             ;;ADDITION
  16475.                 DEFB    $05             ;;DIVISION
  16476.                 DEFB    $24             ;;ATN
  16477.                 DEFB    $31             ;;DUPLICATE
  16478.                 DEFB    $0F             ;;ADDITION
  16479.                 DEFB    $38             ;;END_CALC
  16480.  
  16481.                 RET                     ; return.
  16482.  
  16483.  
  16484. ;--------------------
  16485. ; Handle arccos ($23)
  16486. ;--------------------
  16487. ; the inverse cosine function with the result in radians.
  16488. ; Error A unless the argument is between -1 and +1.
  16489.  
  16490.                                         ;;;$3843
  16491. ACS:            RST     28H             ;; FP_CALC
  16492.                 DEFB    $22             ;;ASN
  16493.                 DEFB    $A3             ;;STK_PI_2
  16494.                 DEFB    $03             ;;SUBTRACT
  16495.                 DEFB    $1B             ;;NEGATE
  16496.                 DEFB    $38             ;;END_CALC
  16497.  
  16498.                 RET                     ; return.
  16499.  
  16500.  
  16501. ;-------------------------
  16502. ; Handle square root ($28)
  16503. ;-------------------------
  16504. ; This routine is remarkable only in it's brevity - 7 bytes.
  16505. ; It wasn't written here but in the ZX81 where the programmers had to squeeze
  16506. ; a bulky operating sytem into an 8K ROM. it simply calculates
  16507. ;
  16508.  
  16509.                                         ;;;$384A
  16510. SQR:            RST     28H             ;; FP_CALC
  16511.                 DEFB    $31             ;;DUPLICATE
  16512.                 DEFB    $30             ;;NOT
  16513.                 DEFB    $00             ;;JUMP_TRUE
  16514.                 DEFB    $1E             ;;to LAST
  16515.                 DEFB    $A2             ;;STK_HALF
  16516.                 DEFB    $38             ;;END_CALC
  16517.  
  16518.  
  16519. ;-------------------------
  16520. ; Handle exponential ($06)
  16521. ;-------------------------
  16522.  
  16523.                                         ;;;$3851
  16524. TO_POWER:       RST     28H             ;; FP_CALC
  16525.                 DEFB    $01             ;;EXCHANGE
  16526.                 DEFB    $31             ;;DUPLICATE
  16527.                 DEFB    $30             ;;NOT
  16528.                 DEFB    $00             ;;JUMP_TRUE
  16529.                 DEFB    $07             ;;to XISO
  16530.                 DEFB    $25             ;;LN
  16531.                 DEFB    $04             ;;MULTIPLY
  16532.                 DEFB    $38             ;;END_CALC
  16533.  
  16534.                 JP      EXP             ; to EXP
  16535.  
  16536.                                         ;;;$385D
  16537. XISO:           DEFB    $02             ;;DELETE
  16538.                 DEFB    $31             ;;DUPLICATE
  16539.                 DEFB    $30             ;;NOT
  16540.                 DEFB    $00             ;;JUMP_TRUE
  16541.                 DEFB    $09             ;;to ONE
  16542.                 DEFB    $A0             ;;STK_ZERO
  16543.                 DEFB    $01             ;;EXCHANGE
  16544.                 DEFB    $37             ;;GREATER_0
  16545.                 DEFB    $00             ;;JUMP_TRUE
  16546.                 DEFB    $06             ;;to LAST
  16547.                 DEFB    $A1             ;;STK_ONE
  16548.                 DEFB    $01             ;;EXCHANGE
  16549.                 DEFB    $05             ;;DIVISION
  16550.  
  16551.                                         ;;;$386A
  16552. ONE:            DEFB    $02             ;;DELETE
  16553.                 DEFB    $A1             ;;STK_ONE
  16554.  
  16555.                                         ;;;$386C
  16556. LAST:           DEFB    $38             ;;END_CALC
  16557.  
  16558.                 RET                     ; return
  16559.  
  16560. ;----------------
  16561. ; Spare Locations
  16562. ;----------------
  16563.  
  16564.                                         ;;;$386E
  16565. SPARE:          DEFB    $FF, $FF
  16566.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16567.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16568.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16569.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16570.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16571.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16572.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16573.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16574.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16575.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16576.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16577.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16578.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16579.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16580.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16581.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16582.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16583.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16584.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16585.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16586.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16587.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16588.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16589.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16590.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16591.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16592.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16593.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16594.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16595.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16596.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16597.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16598.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16599.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16600.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16601.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16602.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16603.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16604.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16605.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16606.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16607.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16608.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16609.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16610.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16611.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16612.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16613.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16614.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16615.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16616.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16617.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16618.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16619.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16620.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16621.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16622.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16623.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16624.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16625.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16626.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16627.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16628.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16629.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16630.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16631.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16632.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16633.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16634.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16635.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16636.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16637.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16638.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16639.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16640.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16641.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16642.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16643.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16644.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16645.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16646.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16647.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16648.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16649.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16650.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16651.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16652.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16653.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16654.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16655.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16656.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16657.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16658.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16659.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16660.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16661.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16662.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16663.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16664.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16665.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16666.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16667.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16668.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16669.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16670.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16671.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16672.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16673.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16674.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16675.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16676.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16677.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16678.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16679.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16680.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16681.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16682.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16683.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16684.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16685.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16686.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16687.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16688.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16689.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16690.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16691.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16692.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16693.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16694.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16695.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16696.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16697.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16698.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16699.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16700.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16701.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16702.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16703.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16704.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16705.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16706.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16707.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16708.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16709.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16710.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16711.                 DEFB    $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF;
  16712.  
  16713. ;--------------
  16714. ; Character set
  16715. ;--------------
  16716.  
  16717.                                         ;;;$3D00
  16718. CHAR_SET:       DEFB    %00000000
  16719.                 DEFB    %00000000
  16720.                 DEFB    %00000000
  16721.                 DEFB    %00000000
  16722.                 DEFB    %00000000
  16723.                 DEFB    %00000000
  16724.                 DEFB    %00000000
  16725.                 DEFB    %00000000
  16726. ; Character: !
  16727.                 DEFB    %00000000
  16728.                 DEFB    %00010000
  16729.                 DEFB    %00010000
  16730.                 DEFB    %00010000
  16731.                 DEFB    %00010000
  16732.                 DEFB    %00000000
  16733.                 DEFB    %00010000
  16734.                 DEFB    %00000000
  16735. ; Character: "
  16736.                 DEFB    %00000000
  16737.                 DEFB    %00100100
  16738.                 DEFB    %00100100
  16739.                 DEFB    %00000000
  16740.                 DEFB    %00000000
  16741.                 DEFB    %00000000
  16742.                 DEFB    %00000000
  16743.                 DEFB    %00000000
  16744. ; Character: #
  16745.                 DEFB    %00000000
  16746.                 DEFB    %00100100
  16747.                 DEFB    %01111110
  16748.                 DEFB    %00100100
  16749.                 DEFB    %00100100
  16750.                 DEFB    %01111110
  16751.                 DEFB    %00100100
  16752.                 DEFB    %00000000
  16753. ; Character: $
  16754.                 DEFB    %00000000
  16755.                 DEFB    %00001000
  16756.                 DEFB    %00111110
  16757.                 DEFB    %00101000
  16758.                 DEFB    %00111110
  16759.                 DEFB    %00001010
  16760.                 DEFB    %00111110
  16761.                 DEFB    %00001000
  16762. ; Character: %
  16763.                 DEFB    %00000000
  16764.                 DEFB    %01100010
  16765.                 DEFB    %01100100
  16766.                 DEFB    %00001000
  16767.                 DEFB    %00010000
  16768.                 DEFB    %00100110
  16769.                 DEFB    %01000110
  16770.                 DEFB    %00000000
  16771. ; Character: &
  16772.                 DEFB    %00000000
  16773.                 DEFB    %00010000
  16774.                 DEFB    %00101000
  16775.                 DEFB    %00010000
  16776.                 DEFB    %00101010
  16777.                 DEFB    %01000100
  16778.                 DEFB    %00111010
  16779.                 DEFB    %00000000
  16780. ; Character: '
  16781.                 DEFB    %00000000
  16782.                 DEFB    %00001000
  16783.                 DEFB    %00010000
  16784.                 DEFB    %00000000
  16785.                 DEFB    %00000000
  16786.                 DEFB    %00000000
  16787.                 DEFB    %00000000
  16788.                 DEFB    %00000000
  16789. ; Character: (
  16790.                 DEFB    %00000000
  16791.                 DEFB    %00000100
  16792.                 DEFB    %00001000
  16793.                 DEFB    %00001000
  16794.                 DEFB    %00001000
  16795.                 DEFB    %00001000
  16796.                 DEFB    %00000100
  16797.                 DEFB    %00000000
  16798. ; Character: )
  16799.                 DEFB    %00000000
  16800.                 DEFB    %00100000
  16801.                 DEFB    %00010000
  16802.                 DEFB    %00010000
  16803.                 DEFB    %00010000
  16804.                 DEFB    %00010000
  16805.                 DEFB    %00100000
  16806.                 DEFB    %00000000
  16807. ; Character: *
  16808.                 DEFB    %00000000
  16809.                 DEFB    %00000000
  16810.                 DEFB    %00010100
  16811.                 DEFB    %00001000
  16812.                 DEFB    %00111110
  16813.                 DEFB    %00001000
  16814.                 DEFB    %00010100
  16815.                 DEFB    %00000000
  16816. ; Character: +
  16817.                 DEFB    %00000000
  16818.                 DEFB    %00000000
  16819.                 DEFB    %00001000
  16820.                 DEFB    %00001000
  16821.                 DEFB    %00111110
  16822.                 DEFB    %00001000
  16823.                 DEFB    %00001000
  16824.                 DEFB    %00000000
  16825. ; Character: ,
  16826.                 DEFB    %00000000
  16827.                 DEFB    %00000000
  16828.                 DEFB    %00000000
  16829.                 DEFB    %00000000
  16830.                 DEFB    %00000000
  16831.                 DEFB    %00001000
  16832.                 DEFB    %00001000
  16833.                 DEFB    %00010000
  16834. ; Character: -
  16835.                 DEFB    %00000000
  16836.                 DEFB    %00000000
  16837.                 DEFB    %00000000
  16838.                 DEFB    %00000000
  16839.                 DEFB    %00111110
  16840.                 DEFB    %00000000
  16841.                 DEFB    %00000000
  16842.                 DEFB    %00000000
  16843. ; Character: .
  16844.                 DEFB    %00000000
  16845.                 DEFB    %00000000
  16846.                 DEFB    %00000000
  16847.                 DEFB    %00000000
  16848.                 DEFB    %00000000
  16849.                 DEFB    %00011000
  16850.                 DEFB    %00011000
  16851.                 DEFB    %00000000
  16852. ; Character: /
  16853.                 DEFB    %00000000
  16854.                 DEFB    %00000000
  16855.                 DEFB    %00000010
  16856.                 DEFB    %00000100
  16857.                 DEFB    %00001000
  16858.                 DEFB    %00010000
  16859.                 DEFB    %00100000
  16860.                 DEFB    %00000000
  16861. ; Character: 0
  16862.                 DEFB    %00000000
  16863.                 DEFB    %00111100
  16864.                 DEFB    %01000110
  16865.                 DEFB    %01001010
  16866.                 DEFB    %01010010
  16867.                 DEFB    %01100010
  16868.                 DEFB    %00111100
  16869.                 DEFB    %00000000
  16870. ; Character: 1
  16871.                 DEFB    %00000000
  16872.                 DEFB    %00011000
  16873.                 DEFB    %00101000
  16874.                 DEFB    %00001000
  16875.                 DEFB    %00001000
  16876.                 DEFB    %00001000
  16877.                 DEFB    %00111110
  16878.                 DEFB    %00000000
  16879. ; Character: 2
  16880.                 DEFB    %00000000
  16881.                 DEFB    %00111100
  16882.                 DEFB    %01000010
  16883.                 DEFB    %00000010
  16884.                 DEFB    %00111100
  16885.                 DEFB    %01000000
  16886.                 DEFB    %01111110
  16887.                 DEFB    %00000000
  16888. ; Character: 3
  16889.                 DEFB    %00000000
  16890.                 DEFB    %00111100
  16891.                 DEFB    %01000010
  16892.                 DEFB    %00001100
  16893.                 DEFB    %00000010
  16894.                 DEFB    %01000010
  16895.                 DEFB    %00111100
  16896.                 DEFB    %00000000
  16897. ; Character: 4
  16898.                 DEFB    %00000000
  16899.                 DEFB    %00001000
  16900.                 DEFB    %00011000
  16901.                 DEFB    %00101000
  16902.                 DEFB    %01001000
  16903.                 DEFB    %01111110
  16904.                 DEFB    %00001000
  16905.                 DEFB    %00000000
  16906. ; Character: 5
  16907.                 DEFB    %00000000
  16908.                 DEFB    %01111110
  16909.                 DEFB    %01000000
  16910.                 DEFB    %01111100
  16911.                 DEFB    %00000010
  16912.                 DEFB    %01000010
  16913.                 DEFB    %00111100
  16914.                 DEFB    %00000000
  16915. ; Character: 6
  16916.                 DEFB    %00000000
  16917.                 DEFB    %00111100
  16918.                 DEFB    %01000000
  16919.                 DEFB    %01111100
  16920.                 DEFB    %01000010
  16921.                 DEFB    %01000010
  16922.                 DEFB    %00111100
  16923.                 DEFB    %00000000
  16924. ; Character: 7
  16925.                 DEFB    %00000000
  16926.                 DEFB    %01111110
  16927.                 DEFB    %00000010
  16928.                 DEFB    %00000100
  16929.                 DEFB    %00001000
  16930.                 DEFB    %00010000
  16931.                 DEFB    %00010000
  16932.                 DEFB    %00000000
  16933. ; Character: 8
  16934.                 DEFB    %00000000
  16935.                 DEFB    %00111100
  16936.                 DEFB    %01000010
  16937.                 DEFB    %00111100
  16938.                 DEFB    %01000010
  16939.                 DEFB    %01000010
  16940.                 DEFB    %00111100
  16941.                 DEFB    %00000000
  16942. ; Character: 9
  16943.                 DEFB    %00000000
  16944.                 DEFB    %00111100
  16945.                 DEFB    %01000010
  16946.                 DEFB    %01000010
  16947.                 DEFB    %00111110
  16948.                 DEFB    %00000010
  16949.                 DEFB    %00111100
  16950.                 DEFB    %00000000
  16951. ; Character: :
  16952.                 DEFB    %00000000
  16953.                 DEFB    %00000000
  16954.                 DEFB    %00000000
  16955.                 DEFB    %00010000
  16956.                 DEFB    %00000000
  16957.                 DEFB    %00000000
  16958.                 DEFB    %00010000
  16959.                 DEFB    %00000000
  16960. ; Character: ;
  16961.                 DEFB    %00000000
  16962.                 DEFB    %00000000
  16963.                 DEFB    %00010000
  16964.                 DEFB    %00000000
  16965.                 DEFB    %00000000
  16966.                 DEFB    %00010000
  16967.                 DEFB    %00010000
  16968.                 DEFB    %00100000
  16969. ; Character: <
  16970.                 DEFB    %00000000
  16971.                 DEFB    %00000000
  16972.                 DEFB    %00000100
  16973.                 DEFB    %00001000
  16974.                 DEFB    %00010000
  16975.                 DEFB    %00001000
  16976.                 DEFB    %00000100
  16977.                 DEFB    %00000000
  16978. ; Character: =
  16979.                 DEFB    %00000000
  16980.                 DEFB    %00000000
  16981.                 DEFB    %00000000
  16982.                 DEFB    %00111110
  16983.                 DEFB    %00000000
  16984.                 DEFB    %00111110
  16985.                 DEFB    %00000000
  16986.                 DEFB    %00000000
  16987. ; Character: >
  16988.                 DEFB    %00000000
  16989.                 DEFB    %00000000
  16990.                 DEFB    %00010000
  16991.                 DEFB    %00001000
  16992.                 DEFB    %00000100
  16993.                 DEFB    %00001000
  16994.                 DEFB    %00010000
  16995.                 DEFB    %00000000
  16996. ; Character: ?
  16997.                 DEFB    %00000000
  16998.                 DEFB    %00111100
  16999.                 DEFB    %01000010
  17000.                 DEFB    %00000100
  17001.                 DEFB    %00001000
  17002.                 DEFB    %00000000
  17003.                 DEFB    %00001000
  17004.                 DEFB    %00000000
  17005. ; Character: @
  17006.                 DEFB    %00000000
  17007.                 DEFB    %00111100
  17008.                 DEFB    %01001010
  17009.                 DEFB    %01010110
  17010.                 DEFB    %01011110
  17011.                 DEFB    %01000000
  17012.                 DEFB    %00111100
  17013.                 DEFB    %00000000
  17014. ; Character: A
  17015.                 DEFB    %00000000
  17016.                 DEFB    %00111100
  17017.                 DEFB    %01000010
  17018.                 DEFB    %01000010
  17019.                 DEFB    %01111110
  17020.                 DEFB    %01000010
  17021.                 DEFB    %01000010
  17022.                 DEFB    %00000000
  17023. ; Character: B
  17024.                 DEFB    %00000000
  17025.                 DEFB    %01111100
  17026.                 DEFB    %01000010
  17027.                 DEFB    %01111100
  17028.                 DEFB    %01000010
  17029.                 DEFB    %01000010
  17030.                 DEFB    %01111100
  17031.                 DEFB    %00000000
  17032. ; Character: C
  17033.                 DEFB    %00000000
  17034.                 DEFB    %00111100
  17035.                 DEFB    %01000010
  17036.                 DEFB    %01000000
  17037.                 DEFB    %01000000
  17038.                 DEFB    %01000010
  17039.                 DEFB    %00111100
  17040.                 DEFB    %00000000
  17041. ; Character: D
  17042.                 DEFB    %00000000
  17043.                 DEFB    %01111000
  17044.                 DEFB    %01000100
  17045.                 DEFB    %01000010
  17046.                 DEFB    %01000010
  17047.                 DEFB    %01000100
  17048.                 DEFB    %01111000
  17049.                 DEFB    %00000000
  17050. ; Character: E
  17051.                 DEFB    %00000000
  17052.                 DEFB    %01111110
  17053.                 DEFB    %01000000
  17054.                 DEFB    %01111100
  17055.                 DEFB    %01000000
  17056.                 DEFB    %01000000
  17057.                 DEFB    %01111110
  17058.                 DEFB    %00000000
  17059. ; Character: F
  17060.                 DEFB    %00000000
  17061.                 DEFB    %01111110
  17062.                 DEFB    %01000000
  17063.                 DEFB    %01111100
  17064.                 DEFB    %01000000
  17065.                 DEFB    %01000000
  17066.                 DEFB    %01000000
  17067.                 DEFB    %00000000
  17068. ; Character: G
  17069.                 DEFB    %00000000
  17070.                 DEFB    %00111100
  17071.                 DEFB    %01000010
  17072.                 DEFB    %01000000
  17073.                 DEFB    %01001110
  17074.                 DEFB    %01000010
  17075.                 DEFB    %00111100
  17076.                 DEFB    %00000000
  17077. ; Character: H
  17078.                 DEFB    %00000000
  17079.                 DEFB    %01000010
  17080.                 DEFB    %01000010
  17081.                 DEFB    %01111110
  17082.                 DEFB    %01000010
  17083.                 DEFB    %01000010
  17084.                 DEFB    %01000010
  17085.                 DEFB    %00000000
  17086. ; Character: I
  17087.                 DEFB    %00000000
  17088.                 DEFB    %00111110
  17089.                 DEFB    %00001000
  17090.                 DEFB    %00001000
  17091.                 DEFB    %00001000
  17092.                 DEFB    %00001000
  17093.                 DEFB    %00111110
  17094.                 DEFB    %00000000
  17095. ; Character: J
  17096.                 DEFB    %00000000
  17097.                 DEFB    %00000010
  17098.                 DEFB    %00000010
  17099.                 DEFB    %00000010
  17100.                 DEFB    %01000010
  17101.                 DEFB    %01000010
  17102.                 DEFB    %00111100
  17103.                 DEFB    %00000000
  17104. ; Character: K
  17105.                 DEFB    %00000000
  17106.                 DEFB    %01000100
  17107.                 DEFB    %01001000
  17108.                 DEFB    %01110000
  17109.                 DEFB    %01001000
  17110.                 DEFB    %01000100
  17111.                 DEFB    %01000010
  17112.                 DEFB    %00000000
  17113. ; Character: L
  17114.                 DEFB    %00000000
  17115.                 DEFB    %01000000
  17116.                 DEFB    %01000000
  17117.                 DEFB    %01000000
  17118.                 DEFB    %01000000
  17119.                 DEFB    %01000000
  17120.                 DEFB    %01111110
  17121.                 DEFB    %00000000
  17122. ; Character: M
  17123.                 DEFB    %00000000
  17124.                 DEFB    %01000010
  17125.                 DEFB    %01100110
  17126.                 DEFB    %01011010
  17127.                 DEFB    %01000010
  17128.                 DEFB    %01000010
  17129.                 DEFB    %01000010
  17130.                 DEFB    %00000000
  17131. ; Character: N
  17132.                 DEFB    %00000000
  17133.                 DEFB    %01000010
  17134.                 DEFB    %01100010
  17135.                 DEFB    %01010010
  17136.                 DEFB    %01001010
  17137.                 DEFB    %01000110
  17138.                 DEFB    %01000010
  17139.                 DEFB    %00000000
  17140. ; Character: O
  17141.                 DEFB    %00000000
  17142.                 DEFB    %00111100
  17143.                 DEFB    %01000010
  17144.                 DEFB    %01000010
  17145.                 DEFB    %01000010
  17146.                 DEFB    %01000010
  17147.                 DEFB    %00111100
  17148.                 DEFB    %00000000
  17149. ; Character: P
  17150.                 DEFB    %00000000
  17151.                 DEFB    %01111100
  17152.                 DEFB    %01000010
  17153.                 DEFB    %01000010
  17154.                 DEFB    %01111100
  17155.                 DEFB    %01000000
  17156.                 DEFB    %01000000
  17157.                 DEFB    %00000000
  17158. ; Character: Q
  17159.                 DEFB    %00000000
  17160.                 DEFB    %00111100
  17161.                 DEFB    %01000010
  17162.                 DEFB    %01000010
  17163.                 DEFB    %01010010
  17164.                 DEFB    %01001010
  17165.                 DEFB    %00111100
  17166.                 DEFB    %00000000
  17167. ; Character: R
  17168.                 DEFB    %00000000
  17169.                 DEFB    %01111100
  17170.                 DEFB    %01000010
  17171.                 DEFB    %01000010
  17172.                 DEFB    %01111100
  17173.                 DEFB    %01000100
  17174.                 DEFB    %01000010
  17175.                 DEFB    %00000000
  17176. ; Character: S
  17177.                 DEFB    %00000000
  17178.                 DEFB    %00111100
  17179.                 DEFB    %01000000
  17180.                 DEFB    %00111100
  17181.                 DEFB    %00000010
  17182.                 DEFB    %01000010
  17183.                 DEFB    %00111100
  17184.                 DEFB    %00000000
  17185. ; Character: T
  17186.                 DEFB    %00000000
  17187.                 DEFB    %11111110
  17188.                 DEFB    %00010000
  17189.                 DEFB    %00010000
  17190.                 DEFB    %00010000
  17191.                 DEFB    %00010000
  17192.                 DEFB    %00010000
  17193.                 DEFB    %00000000
  17194. ; Character: U
  17195.                 DEFB    %00000000
  17196.                 DEFB    %01000010
  17197.                 DEFB    %01000010
  17198.                 DEFB    %01000010
  17199.                 DEFB    %01000010
  17200.                 DEFB    %01000010
  17201.                 DEFB    %00111100
  17202.                 DEFB    %00000000
  17203. ; Character: V
  17204.                 DEFB    %00000000
  17205.                 DEFB    %01000010
  17206.                 DEFB    %01000010
  17207.                 DEFB    %01000010
  17208.                 DEFB    %01000010
  17209.                 DEFB    %00100100
  17210.                 DEFB    %00011000
  17211.                 DEFB    %00000000
  17212. ; Character: W
  17213.                 DEFB    %00000000
  17214.                 DEFB    %01000010
  17215.                 DEFB    %01000010
  17216.                 DEFB    %01000010
  17217.                 DEFB    %01000010
  17218.                 DEFB    %01011010
  17219.                 DEFB    %00100100
  17220.                 DEFB    %00000000
  17221. ; Character: X
  17222.                 DEFB    %00000000
  17223.                 DEFB    %01000010
  17224.                 DEFB    %00100100
  17225.                 DEFB    %00011000
  17226.                 DEFB    %00011000
  17227.                 DEFB    %00100100
  17228.                 DEFB    %01000010
  17229.                 DEFB    %00000000
  17230. ; Character: Y
  17231.                 DEFB    %00000000
  17232.                 DEFB    %10000010
  17233.                 DEFB    %01000100
  17234.                 DEFB    %00101000
  17235.                 DEFB    %00010000
  17236.                 DEFB    %00010000
  17237.                 DEFB    %00010000
  17238.                 DEFB    %00000000
  17239. ; Character: Z
  17240.                 DEFB    %00000000
  17241.                 DEFB    %01111110
  17242.                 DEFB    %00000100
  17243.                 DEFB    %00001000
  17244.                 DEFB    %00010000
  17245.                 DEFB    %00100000
  17246.                 DEFB    %01111110
  17247.                 DEFB    %00000000
  17248. ; Character: [
  17249.                 DEFB    %00000000
  17250.                 DEFB    %00001110
  17251.                 DEFB    %00001000
  17252.                 DEFB    %00001000
  17253.                 DEFB    %00001000
  17254.                 DEFB    %00001000
  17255.                 DEFB    %00001110
  17256.                 DEFB    %00000000
  17257. ; Character: \
  17258.                 DEFB    %00000000
  17259.                 DEFB    %00000000
  17260.                 DEFB    %01000000
  17261.                 DEFB    %00100000
  17262.                 DEFB    %00010000
  17263.                 DEFB    %00001000
  17264.                 DEFB    %00000100
  17265.                 DEFB    %00000000
  17266. ; Character: ]
  17267.                 DEFB    %00000000
  17268.                 DEFB    %01110000
  17269.                 DEFB    %00010000
  17270.                 DEFB    %00010000
  17271.                 DEFB    %00010000
  17272.                 DEFB    %00010000
  17273.                 DEFB    %01110000
  17274.                 DEFB    %00000000
  17275. ; Character: ^
  17276.                 DEFB    %00000000
  17277.                 DEFB    %00010000
  17278.                 DEFB    %00111000
  17279.                 DEFB    %01010100
  17280.                 DEFB    %00010000
  17281.                 DEFB    %00010000
  17282.                 DEFB    %00010000
  17283.                 DEFB    %00000000
  17284. ; Character: _
  17285.                 DEFB    %00000000
  17286.                 DEFB    %00000000
  17287.                 DEFB    %00000000
  17288.                 DEFB    %00000000
  17289.                 DEFB    %00000000
  17290.                 DEFB    %00000000
  17291.                 DEFB    %00000000
  17292.                 DEFB    %11111111
  17293. ; Character: Pound
  17294.                 DEFB    %00000000
  17295.                 DEFB    %00011100
  17296.                 DEFB    %00100010
  17297.                 DEFB    %01111000
  17298.                 DEFB    %00100000
  17299.                 DEFB    %00100000
  17300.                 DEFB    %01111110
  17301.                 DEFB    %00000000
  17302. ; Character: a
  17303.                 DEFB    %00000000
  17304.                 DEFB    %00000000
  17305.                 DEFB    %00111000
  17306.                 DEFB    %00000100
  17307.                 DEFB    %00111100
  17308.                 DEFB    %01000100
  17309.                 DEFB    %00111100
  17310.                 DEFB    %00000000
  17311. ; Character: b
  17312.                 DEFB    %00000000
  17313.                 DEFB    %00100000
  17314.                 DEFB    %00100000
  17315.                 DEFB    %00111100
  17316.                 DEFB    %00100010
  17317.                 DEFB    %00100010
  17318.                 DEFB    %00111100
  17319.                 DEFB    %00000000
  17320. ; Character: c
  17321.                 DEFB    %00000000
  17322.                 DEFB    %00000000
  17323.                 DEFB    %00011100
  17324.                 DEFB    %00100000
  17325.                 DEFB    %00100000
  17326.                 DEFB    %00100000
  17327.                 DEFB    %00011100
  17328.                 DEFB    %00000000
  17329. ; Character: d
  17330.                 DEFB    %00000000
  17331.                 DEFB    %00000100
  17332.                 DEFB    %00000100
  17333.                 DEFB    %00111100
  17334.                 DEFB    %01000100
  17335.                 DEFB    %01000100
  17336.                 DEFB    %00111100
  17337.                 DEFB    %00000000
  17338. ; Character: e
  17339.                 DEFB    %00000000
  17340.                 DEFB    %00000000
  17341.                 DEFB    %00111000
  17342.                 DEFB    %01000100
  17343.                 DEFB    %01111000
  17344.                 DEFB    %01000000
  17345.                 DEFB    %00111100
  17346.                 DEFB    %00000000
  17347. ; Character: f
  17348.                 DEFB    %00000000
  17349.                 DEFB    %00001100
  17350.                 DEFB    %00010000
  17351.                 DEFB    %00011000
  17352.                 DEFB    %00010000
  17353.                 DEFB    %00010000
  17354.                 DEFB    %00010000
  17355.                 DEFB    %00000000
  17356. ; Character: g
  17357.                 DEFB    %00000000
  17358.                 DEFB    %00000000
  17359.                 DEFB    %00111100
  17360.                 DEFB    %01000100
  17361.                 DEFB    %01000100
  17362.                 DEFB    %00111100
  17363.                 DEFB    %00000100
  17364.                 DEFB    %00111000
  17365. ; Character: h
  17366.                 DEFB    %00000000
  17367.                 DEFB    %01000000
  17368.                 DEFB    %01000000
  17369.                 DEFB    %01111000
  17370.                 DEFB    %01000100
  17371.                 DEFB    %01000100
  17372.                 DEFB    %01000100
  17373.                 DEFB    %00000000
  17374. ; Character: i
  17375.                 DEFB    %00000000
  17376.                 DEFB    %00010000
  17377.                 DEFB    %00000000
  17378.                 DEFB    %00110000
  17379.                 DEFB    %00010000
  17380.                 DEFB    %00010000
  17381.                 DEFB    %00111000
  17382.                 DEFB    %00000000
  17383. ; Character: j
  17384.                 DEFB    %00000000
  17385.                 DEFB    %00000100
  17386.                 DEFB    %00000000
  17387.                 DEFB    %00000100
  17388.                 DEFB    %00000100
  17389.                 DEFB    %00000100
  17390.                 DEFB    %00100100
  17391.                 DEFB    %00011000
  17392. ; Character: k
  17393.                 DEFB    %00000000
  17394.                 DEFB    %00100000
  17395.                 DEFB    %00101000
  17396.                 DEFB    %00110000
  17397.                 DEFB    %00110000
  17398.                 DEFB    %00101000
  17399.                 DEFB    %00100100
  17400.                 DEFB    %00000000
  17401. ; Character: l
  17402.                 DEFB    %00000000
  17403.                 DEFB    %00010000
  17404.                 DEFB    %00010000
  17405.                 DEFB    %00010000
  17406.                 DEFB    %00010000
  17407.                 DEFB    %00010000
  17408.                 DEFB    %00001100
  17409.                 DEFB    %00000000
  17410. ; Character: m
  17411.                 DEFB    %00000000
  17412.                 DEFB    %00000000
  17413.                 DEFB    %01101000
  17414.                 DEFB    %01010100
  17415.                 DEFB    %01010100
  17416.                 DEFB    %01010100
  17417.                 DEFB    %01010100
  17418.                 DEFB    %00000000
  17419. ; Character: n
  17420.                 DEFB    %00000000
  17421.                 DEFB    %00000000
  17422.                 DEFB    %01111000
  17423.                 DEFB    %01000100
  17424.                 DEFB    %01000100
  17425.                 DEFB    %01000100
  17426.                 DEFB    %01000100
  17427.                 DEFB    %00000000
  17428. ; Character: o
  17429.                 DEFB    %00000000
  17430.                 DEFB    %00000000
  17431.                 DEFB    %00111000
  17432.                 DEFB    %01000100
  17433.                 DEFB    %01000100
  17434.                 DEFB    %01000100
  17435.                 DEFB    %00111000
  17436.                 DEFB    %00000000
  17437. ; Character: p
  17438.                 DEFB    %00000000
  17439.                 DEFB    %00000000
  17440.                 DEFB    %01111000
  17441.                 DEFB    %01000100
  17442.                 DEFB    %01000100
  17443.                 DEFB    %01111000
  17444.                 DEFB    %01000000
  17445.                 DEFB    %01000000
  17446. ; Character: q
  17447.                 DEFB    %00000000
  17448.                 DEFB    %00000000
  17449.                 DEFB    %00111100
  17450.                 DEFB    %01000100
  17451.                 DEFB    %01000100
  17452.                 DEFB    %00111100
  17453.                 DEFB    %00000100
  17454.                 DEFB    %00000110
  17455. ; Character: r
  17456.                 DEFB    %00000000
  17457.                 DEFB    %00000000
  17458.                 DEFB    %00011100
  17459.                 DEFB    %00100000
  17460.                 DEFB    %00100000
  17461.                 DEFB    %00100000
  17462.                 DEFB    %00100000
  17463.                 DEFB    %00000000
  17464. ; Character: s
  17465.                 DEFB    %00000000
  17466.                 DEFB    %00000000
  17467.                 DEFB    %00111000
  17468.                 DEFB    %01000000
  17469.                 DEFB    %00111000
  17470.                 DEFB    %00000100
  17471.                 DEFB    %01111000
  17472.                 DEFB    %00000000
  17473. ; Character: t
  17474.                 DEFB    %00000000
  17475.                 DEFB    %00010000
  17476.                 DEFB    %00111000
  17477.                 DEFB    %00010000
  17478.                 DEFB    %00010000
  17479.                 DEFB    %00010000
  17480.                 DEFB    %00001100
  17481.                 DEFB    %00000000
  17482. ; Character: u
  17483.                 DEFB    %00000000
  17484.                 DEFB    %00000000
  17485.                 DEFB    %01000100
  17486.                 DEFB    %01000100
  17487.                 DEFB    %01000100
  17488.                 DEFB    %01000100
  17489.                 DEFB    %00111000
  17490.                 DEFB    %00000000
  17491. ; Character: v
  17492.                 DEFB    %00000000
  17493.                 DEFB    %00000000
  17494.                 DEFB    %01000100
  17495.                 DEFB    %01000100
  17496.                 DEFB    %00101000
  17497.                 DEFB    %00101000
  17498.                 DEFB    %00010000
  17499.                 DEFB    %00000000
  17500. ; Character: w
  17501.                 DEFB    %00000000
  17502.                 DEFB    %00000000
  17503.                 DEFB    %01000100
  17504.                 DEFB    %01010100
  17505.                 DEFB    %01010100
  17506.                 DEFB    %01010100
  17507.                 DEFB    %00101000
  17508.                 DEFB    %00000000
  17509. ; Character: x
  17510.                 DEFB    %00000000
  17511.                 DEFB    %00000000
  17512.                 DEFB    %01000100
  17513.                 DEFB    %00101000
  17514.                 DEFB    %00010000
  17515.                 DEFB    %00101000
  17516.                 DEFB    %01000100
  17517.                 DEFB    %00000000
  17518. ; Character: y
  17519.                 DEFB    %00000000
  17520.                 DEFB    %00000000
  17521.                 DEFB    %01000100
  17522.                 DEFB    %01000100
  17523.                 DEFB    %01000100
  17524.                 DEFB    %00111100
  17525.                 DEFB    %00000100
  17526.                 DEFB    %00111000
  17527. ; Character: z
  17528.                 DEFB    %00000000
  17529.                 DEFB    %00000000
  17530.                 DEFB    %01111100
  17531.                 DEFB    %00001000
  17532.                 DEFB    %00010000
  17533.                 DEFB    %00100000
  17534.                 DEFB    %01111100
  17535.                 DEFB    %00000000
  17536. ; Character: {
  17537.                 DEFB    %00000000
  17538.                 DEFB    %00001110
  17539.                 DEFB    %00001000
  17540.                 DEFB    %00110000
  17541.                 DEFB    %00001000
  17542.                 DEFB    %00001000
  17543.                 DEFB    %00001110
  17544.                 DEFB    %00000000
  17545. ; Character: |
  17546.                 DEFB    %00000000
  17547.                 DEFB    %00001000
  17548.                 DEFB    %00001000
  17549.                 DEFB    %00001000
  17550.                 DEFB    %00001000
  17551.                 DEFB    %00001000
  17552.                 DEFB    %00001000
  17553.                 DEFB    %00000000
  17554. ; Character: }
  17555.                 DEFB    %00000000
  17556.                 DEFB    %01110000
  17557.                 DEFB    %00010000
  17558.                 DEFB    %00001100
  17559.                 DEFB    %00010000
  17560.                 DEFB    %00010000
  17561.                 DEFB    %01110000
  17562.                 DEFB    %00000000
  17563. ; Character: ~
  17564.                 DEFB    %00000000
  17565.                 DEFB    %00010100
  17566.                 DEFB    %00101000
  17567.                 DEFB    %00000000
  17568.                 DEFB    %00000000
  17569.                 DEFB    %00000000
  17570.                 DEFB    %00000000
  17571.                 DEFB    %00000000
  17572. ; Character: Copyright
  17573.                 DEFB    %00111100
  17574.                 DEFB    %01000010
  17575.                 DEFB    %10011001
  17576.                 DEFB    %10100001
  17577.                 DEFB    %10100001
  17578.                 DEFB    %10011001
  17579.                 DEFB    %01000010
  17580.                 DEFB    %00111100
  17581.