Subversion Repositories pentevo

Rev

Rev 550 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

  1.  
  2. ;www.fruitcake.plus.com
  3.  
  4. ;LAST UPDATE: 10.02.2013 savelij
  5.  
  6.                 include ../../macros.a80
  7.  
  8. ; **************************************
  9. ; *** SPECTRUM 128 ROM 0 DISASSEMBLY ***
  10. ; **************************************
  11.  
  12. ; The Spectrum ROMs are copyright Amstrad, who have kindly given permission
  13. ; to reverse engineer and publish Spectrum ROM disassemblies.
  14.  
  15.  
  16. ; =====
  17. ; NOTES
  18. ; =====
  19.  
  20. ; ------------
  21. ; Release Date
  22. ; ------------
  23. ; 4th November 2010
  24.  
  25. ; ------------------------
  26. ; Disassembly Contributors
  27. ; ------------------------
  28. ; Matthew Wilson  (www.matthew-wilson.net/spectrum/rom/)
  29. ; Andrew Owen     (cheveron-AT-gmail.com)
  30. ; Geoff Wearmouth (gwearmouth-AT-hotmail.com)
  31. ; Rui Tunes
  32. ; Paul Farrow     (www.fruitcake.plus.com)
  33.  
  34. ; -------
  35. ; Markers
  36. ; -------
  37. ; The following markers appear throughout the disassembly:
  38. ;
  39. ; [...] = Indicates a comment about the code.
  40. ; ????  = Information to be determined.
  41. ;
  42. ; For bugs, the following marker format is used:
  43. ;
  44. ; [*BUG* - xxxx. Credit: yyyy]  = Indicates a confirmed bug, with a description 'xxxx' of it and the discoverer 'yyyy'.
  45. ; [*BUG*? - xxxx. Credit: yyyy] = Indicates a suspected bug, with a description 'xxxx' of it and the discoverer 'yyyy'.
  46. ;
  47. ; Since many of the Spectrum 128 ROM routines were re-used in the Spectrum +2 and +3, where a bug was originally identified
  48. ; in the Spectrum +2 or +3 the discoverer is acknowledged along with who located the corresponding bug in the Spectrum 128.
  49. ;
  50. ; For every bug identified, an example fix is provided and the author acknowledged. Some of these fixes can be made directly within the routines
  51. ; affected since they do not increase the length of those routines. Others require the insertion of extra instructions and hence these cannot be
  52. ; completely fitted within the routines affected. Instead a jump must be made to a patch routine located within a spare area of the ROM.
  53. ; Fortunately there is 0.5K of unused routines located at $2336-$2536 (ROM 0) which are remnants of the original Spanish 128, and another unused routine
  54. ; located at $3FC3-$3FCE (ROM 0). This is sufficient space to implement all of the bug fixes suggested.
  55.  
  56.  
  57. ; =================
  58. ; ASSEMBLER DEFINES
  59. ; =================
  60.  
  61. ;TASM directives:
  62.  
  63. ;#DEFINE DB .BYTE
  64. ;#DEFINE DEFW .WORD
  65. ;#DEFINE DEFM .TEXT
  66. ;#DEFINE DEFS .FILL
  67. ;#DEFINE END  .END
  68. ;#DEFINE EQU  .EQU
  69. ;#DEFINE ORG  .ORG
  70.  
  71.  
  72. ; ==============================
  73. ; REFERENCE INFORMATION - PART 1
  74. ; ==============================
  75.  
  76. ; ==========================
  77. ; 128 BASIC Mode Limitations
  78. ; ==========================
  79. ; There are a number of limitations when using 128 BASIC mode, some of which are not present when using the equivalent 48 BASIC mode operations.
  80. ; These are more design decisions than bugs.
  81. ;
  82. ; - The RAM disk VERIFY command does not verify but simply performs a LOAD.
  83. ; - The renumber facility will not renumber line numbers that are defined as an expression, e.g. GO TO VAL "10".
  84. ; - The printer output routine cannot handle binary data and hence EPSON printer ESC codes cannot be sent.
  85. ; - The Editor has the following limitations:
  86. ;   - Variables cannot have the same name as a keyword. This only applies when entering a program and not when one is loaded in.
  87. ;   - Line number 0 is not supported and will not list properly. It is not possible to directly insert such a line, not even in 48 BASIC mode,
  88. ;     and so line number 0 is not officially supported.
  89. ;   - There is a practical limitation on the size of lines that can be entered. It is limited to 20 indented rows, which is the size of the editing buffers.
  90. ;     Typed lines greater than 20 rows get inserted into the BASIC program, but only the first 20 rows are shown on screen. Editing such a line causes
  91. ;     it to be truncated to 20 rows. There is no warning when the 20 row limit is exceeded.
  92. ;   - It is not possible to directly enter embedded control codes, or to correctly edit loaded in programs that contain them. Loaded programs that
  93. ;     contain them will run correctly so long as the lines are not edited.
  94. ;   - It is not possible to embed the string of characters ">=", "<=" or "<>" into a string or REM statement without them being tokenized
  95. ;     (this is perhaps more an oversight than a design decision).
  96. ;   - In 48 BASIC mode if the line '10 REM abc: PRINT xyz' is typed then the word PRINT is stored as a new keyword since the colon (arguably incorrectly)
  97. ;     reverts to 'K' mode. In 128 BASIC mode, typing the same line stores each letter as a separate character.
  98.  
  99.  
  100. ; ==================
  101. ; Timing Information
  102. ; ==================
  103. ; Clock Speed   = 3.54690 MHz (48K Spectrum clock speed was 3.50000 MHz)
  104. ; Scan line     = 228 T-states (48K Spectrum was 224 T-states).
  105. ; TV scan lines = 311 total, 63 above picture (48K Spectrum had 312 total, 64 above picture).
  106.  
  107.  
  108. ; ===========
  109. ; I/O Details
  110. ; ===========
  111.  
  112. ; -------------
  113. ; Memory Paging
  114. ; -------------
  115. ; Memory paging is controlled by I/O port:
  116. ; $7FFD (Out) - Bits 0-2: RAM bank (0-7) to page into memory map at $C000.
  117. ;               Bit 3   : 0=SCREEN 0 (normal display file in bank 5), 1=SCREEN 1 (shadow display file in bank 7).
  118. ;               Bit 4   : 0=ROM 0 (128K Editor), 1=ROM 1 (48K BASIC).
  119. ;               Bit 5   : 1=Disable further output to this port until a hard reset occurs.
  120. ;               Bit 6-7 : Not used (always write 0).
  121. ;
  122. ; The Editor ROM (ROM 0) always places a copy of the last value written to port $7FFD
  123. ; into new system variable BANK_M ($5B5C).
  124. ;
  125. ; ----------
  126. ; Memory Map
  127. ; ----------
  128. ; ROM 0 or 1 resides at $0000-$3FFF.
  129. ; RAM bank 5 resides at $4000-$7FFF always.
  130. ; RAM bank 2 resides at $8000-$BFFF always.
  131. ; Any RAM bank may reside at $C000-$FFFF.
  132. ;
  133. ; -------------------
  134. ; Shadow Display File
  135. ; -------------------
  136. ; The shadow screen may be active even when not paged into the memory map.
  137. ;
  138. ; ----------------
  139. ; Contended Memory
  140. ; ----------------
  141. ; Physical RAM banks 1, 3, 5 and 7 are contended with the ULA.
  142. ;
  143. ; -----------------
  144. ; Logical RAM Banks
  145. ; -----------------
  146. ; Throughout ROM 0, memory banks are accessed using a logical numbering scheme, which
  147. ; maps to physical RAM banks as follows:
  148. ;
  149. ; Logical Bank   Physical Bank
  150. ; ------------   -------------
  151. ;     $00             $01
  152. ;     $01             $03
  153. ;     $02             $04
  154. ;     $03             $06
  155. ;     $04             $07
  156. ;     $05             $00
  157. ;
  158. ; This scheme makes the RAM disk code simpler than having to deal directly with physical RAM bank numbers.
  159.  
  160. ; -------------------------
  161. ; AY-3-8912 Sound Generator
  162. ; -------------------------
  163. ; The AY-3-8912 sound generator is controlled by two I/O ports:
  164. ; $FFFD (Out)    - Select a register 0-14.
  165. ; $FFFD (In)     - Read from the selected register.
  166. ; $BFFD (In/Out) - Write to the selected register. The status of the register can also be read back.
  167. ;
  168. ; The AY-3-8912 I/O port A is used to drive the RS232 and Keypad sockets.
  169. ;
  170. ; Register       Function                        Range
  171. ; --------       --------                        -----
  172. ; 0              Channel A fine pitch            8-bit (0-255)
  173. ; 1              Channel A course pitch          4-bit (0-15)
  174. ; 2              Channel B fine pitch            8-bit (0-255)
  175. ; 3              Channel B course pitch          4-bit (0-15)
  176. ; 4              Channel C fine pitch            8-bit (0-255)
  177. ; 5              Channel C course pitch          4-bit (0-15)
  178. ; 6              Noise pitch                     5-bit (0-31)
  179. ; 7              Mixer                           8-bit (see end of file for description)
  180. ; 8              Channel A volume                4-bit (0-15, see end of file for description)
  181. ; 9              Channel B volume                4-bit (0-15, see end of file for description)
  182. ; 10             Channel C volume                4-bit (0-15, see end of file for description)
  183. ; 11             Envelope fine duration          8-bit (0-255)
  184. ; 12             Envelope course duration        8-bit (0-255)
  185. ; 13             Envelope shape                  4-bit (0-15)
  186. ; 14             I/O port A                      8-bit (0-255)
  187. ;
  188. ; See the end of this document for description on the sound generator registers.
  189. ;
  190. ; ----------------------------------
  191. ; I/O Port A (AY-3-8912 Register 14)
  192. ; ----------------------------------
  193. ; This controls the RS232 and Keypad sockets.
  194. ; Select the port via a write to port $FFFD with 14, then read via port $FFFD and write via port $BFFD. The state of port $BFFD can also be read back.
  195. ;
  196. ; Bit 0: KEYPAD CTS (out) - 0=Spectrum ready to receive, 1=Busy
  197. ; Bit 1: KEYPAD RXD (out) - 0=Transmit high bit,         1=Transmit low bit
  198. ; Bit 2: RS232  CTS (out) - 0=Spectrum ready to receive, 1=Busy
  199. ; Bit 3: RS232  RXD (out) - 0=Transmit high bit,         1=Transmit low bit
  200. ; Bit 4: KEYPAD DTR (in)  - 0=Keypad ready for data,     1=Busy
  201. ; Bit 5: KEYPAD TXD (in)  - 0=Receive high bit,          1=Receive low bit
  202. ; Bit 6: RS232  DTR (in)  - 0=Device ready for data,     1=Busy
  203. ; Bit 7: RS232  TXD (in)  - 0=Receive high bit,          1=Receive low bit
  204. ;
  205. ; See the end of this document for the pinouts for the RS232 and KEYPAD sockets.
  206.  
  207. ; ------------------
  208. ; Standard I/O Ports
  209. ; ------------------
  210. ; See the end of this document for descriptions of the standard Spectrum I/O ports.
  211.  
  212.  
  213. ; ==================
  214. ; Error Report Codes
  215. ; ==================
  216.  
  217. ; ---------------------------
  218. ; Standard Error Report Codes
  219. ; ---------------------------
  220. ; See the end of this document for descriptions of the standard error report codes.
  221.  
  222. ; ----------------------
  223. ; New Error Report Codes
  224. ; ----------------------
  225. ; a - MERGE error                      MERGE! would not execute for some reason - either size or file type wrong.
  226. ; b - Wrong file type                  A file of an inappropriate type was specified during RAM disk operation, for instance a CODE file in LOAD!"name".
  227. ; c - CODE error                       The size of the file would lead to an overrun of the top of memory.
  228. ; d - Too many brackets                Too many brackets around a repeated phrase in one of the arguments.
  229. ; e - File already exists              The file name specified has already been used.
  230. ; f - Invalid name                     The file name specified is empty or above 10 characters in length.
  231. ; g - File does not exist              [Never used by the ROM].
  232. ; h - File does not exist              The specified file could not be found.
  233. ; i - Invalid device                   The device name following the FORMAT command does not exist or correspond to a physical device.
  234. ; j - Invalid baud rate                The baud rate for the RS232 was set to 0.
  235. ; k - Invalid note name                PLAY came across a note or command it didn't recognise, or a command which was in lower case.
  236. ; l - Number too big                   A parameter for a command is an order of magnitude too big.
  237. ; m - Note out of range                A series of sharps or flats has taken a note beyond the range of the sound chip.
  238. ; n - Out of range                     A parameter for a command is too big or too small. If the error is very large, error L results.
  239. ; o - Too many tied notes              An attempt was made to tie too many notes together.
  240. ; p - (c) 1986 Sinclair Research Ltd   This error is given when too many PLAY channel strings are specified. Up to 8 PLAY channel strings are supported
  241. ;                                      by MIDI devices such as synthesisers, drum machines or sequencers. Note that a PLAY command with more than 8 strings
  242. ;                                      cannot be entered directly from the Editor. The Spanish 128 produces "p Bad parameter" for this error. It could be
  243. ;                                      that the intention was to save memory by using the existing error message of "Q Parameter error" but the change of report
  244. ;                                      code byte was overlooked.
  245.  
  246.  
  247. ; ================
  248. ; System Variables
  249. ; ================
  250.  
  251. ; --------------------
  252. ; New System Variables
  253. ; --------------------
  254. ; These are held in the old ZX Printer buffer at $5B00-$5BFF.
  255. ; Note that some of these names conflict with the system variables used by the ZX Interface 1.
  256.  
  257. SWAP        EQU $5B00  ; 20   Swap paging subroutine.
  258. YOUNGER     EQU $5B14  ;  9   Return paging subroutine.
  259. ONERR       EQU $5B1D  ; 18   Error handler paging subroutine.
  260. PIN         EQU $5B2F  ;  5   RS232 input pre-routine.
  261. POUT        EQU $5B34  ; 22   RS232 token output pre-routine. This can be patched to bypass the control code filter.
  262. POUT2       EQU $5B4A  ; 14   RS232 character output pre-routine.
  263. TARGET      EQU $5B58  ;  2   Address of subroutine to call in ROM 1.
  264. RETADDR     EQU $5B5A  ;  2   Return address in ROM 0.
  265. BANK_M      EQU $5B5C  ;  2   Copy of last byte output to I/O port $7FFD.
  266. RAMRST      EQU $5B5D  ;  1   Stores instruction RST $08 and used to produce a standard ROM error. Changing this instruction allows 128 BASIC to be extended (see end of this document for details).
  267. RAMERR      EQU $5B5E  ;  1   Error number for use by RST $08 held in RAMRST.
  268. BAUD        EQU $5B5F  ;  2   Baud rate timing constant for RS232 socket. Default value of 11. [Name clash with ZX Interface 1 system variable at $5CC3]
  269. SERFL       EQU $5B61  ;  2   Second character received flag:
  270.                        ;        Bit 0   : 1=Character in buffer.
  271.                        ;        Bits 1-7: Not used (always hold 0).
  272.               ; $5B62  ;      Received Character.
  273. COL         EQU $5B63  ;  1   Current column from 1 to WIDTH.
  274. WIDTH       EQU $5B64  ;  1   Paper column width. Default value of 80. [Name clash with ZX Interface 1 Edition 2 system variable at $5CB1]
  275. TVPARS      EQU $5B65  ;  1   Number of inline parameters expected by RS232 (e.g. 2 for AT).
  276. FLAGS3      EQU $5B66  ;  1   Flags: [Name clashes with the ZX Interface 1 system variable at $5CB6]
  277.                        ;        Bit 0: 1=BASIC/Calculator mode, 0=Editor/Menu mode.
  278.                        ;        Bit 1: 1=Auto-run loaded BASIC program. [Set but never tested by the ROM]
  279.                        ;        Bit 2: 1=Editing RAM disk catalogue.
  280.                        ;        Bit 3: 1=Using RAM disk commands, 0=Using cassette commands.
  281.                        ;        Bit 4: 1=Indicate LOAD.
  282.                        ;        Bit 5: 1=Indicate SAVE.
  283.                        ;        Bit 6; 1=Indicate MERGE.
  284.                        ;        Bit 7: 1=Indicate VERIFY.
  285. N_STR1      EQU $5B67  ; 10   Used by RAM disk to store a filename. [Name clash with ZX Interface 1 system variable at $5CDA]
  286.                        ;      Used by the renumber routine to store the address of the BASIC line being examined.
  287. HD_00       EQU $5B71  ;  1   Used by RAM disk to store file header information (see RAM disk Catalogue section below for details). [Name clash with ZX Interface 1 system variable at $5CE6]
  288.                        ;      Used as column pixel counter in COPY routine.
  289.                        ;      Used by FORMAT command to store specified baud rate.
  290.                        ;      Used by renumber routine to store the number of digits in a pre-renumbered line number reference. [Name clash with ZX Interface 1 system variable at $5CE7]
  291. HD_0B       EQU $5B72  ;  2   Used by RAM disk to store header info - length of block.
  292.                        ;      Used as half row counter in COPY routine.
  293.                        ;      Used by renumber routine to generate ASCII representation of a new line number.
  294. HD_0D       EQU $5B74  ;  2   Used by RAM disk to store file header information (see RAM disk Catalogue section below for details). [Name clash with ZX Interface 1 system variable at $5CE9]
  295. HD_0F       EQU $5B76  ;  2   Used by RAM disk to store file header information (see RAM disk Catalogue section below for details). [Name clash with ZX Interface 1 system variable at $5CEB]
  296.                        ;      Used by renumber routine to store the address of a referenced BASIC line.
  297. HD_11       EQU $5B78  ;  2   Used by RAM disk to store file header information (see RAM disk Catalogue section below for details). [Name clash with ZX Interface 1 system variable at $5CED]
  298.                        ;      Used by renumber routine to store existing VARS address/current address within a line.
  299. SC_00       EQU $5B7A  ;  1   Used by RAM disk to store alternate file header information (see RAM disk Catalogue section below for details).
  300. SC_0B       EQU $5B7B  ;  2   Used by RAM disk to store alternate file header information (see RAM disk Catalogue section below for details).
  301. SC_0D       EQU $5B7D  ;  2   Used by RAM disk to store alternate file header information (see RAM disk Catalogue section below for details).
  302. SC_0F       EQU $5B7F  ;  2   Used by RAM disk to store alternate file header information (see RAM disk Catalogue section below for details).
  303. OLDSP       EQU $5B81  ;  2   Stores old stack pointer when TSTACK in use.
  304. SFNEXT      EQU $5B83  ;  2   End of RAM disk catalogue marker. Pointer to first empty catalogue entry.
  305. SFSPACE     EQU $5B85  ;  3   Number of bytes free in RAM disk (3 bytes, 17 bit, LSB first).
  306. ROW01       EQU $5B88  ;  1   Stores keypad data for row 3, and flags:
  307.                        ;        Bit 0   : 1=Key '+' pressed.
  308.                        ;        Bit 1   : 1=Key '6' pressed.
  309.                        ;        Bit 2   : 1=Key '5' pressed.
  310.                        ;        Bit 3   : 1=Key '4' pressed.
  311.                        ;        Bits 4-5: Always 0.
  312.                        ;        Bit 6   : 1=Indicates successful communications to the keypad.
  313.                        ;        Bit 7   : 1=If communications to the keypad established.
  314. ROW23       EQU $5B89  ;  1   Stores keypad key press data for rows 1 and 2:
  315.                        ;        Bit 0: 1=Key ')' pressed.
  316.                        ;        Bit 1: 1=Key '(' pressed.
  317.                        ;        Bit 2: 1=Key '*' pressed.
  318.                        ;        Bit 3: 1=Key '/' pressed.
  319.                        ;        Bit 4: 1=Key '-' pressed.
  320.                        ;        Bit 5: 1=Key '9' pressed.
  321.                        ;        Bit 6: 1=Key '8' pressed.
  322.                        ;        Bit 7: 1=Key '7' pressed.
  323. ROW45       EQU $5B8A  ;  1   Stores keypad key press data for rows 4 and 5:
  324.                        ;        Bit 0: Always 0.
  325.                        ;        Bit 1: 1=Key '.' pressed.
  326.                        ;        Bit 2: Always 0.
  327.                        ;        Bit 3: 1=Key '0' pressed.
  328.                        ;        Bit 4: 1=Key 'ENTER' pressed.
  329.                        ;        Bit 5: 1=Key '3' pressed.
  330.                        ;        Bit 6: 1=Key '2' pressed.
  331.                        ;        Bit 7: 1=Key '1' pressed.
  332. SYNRET      EQU $5B8B  ;  2   Return address for ONERR routine.
  333. LASTV       EQU $5B8D  ;  5   Last value printed by calculator.
  334. RNLINE      EQU $5B92  ;  2   Address of the length bytes in the line currently being renumbered.
  335. RNFIRST     EQU $5B94  ;  2   Starting line number when renumbering. Default value of 10.
  336. RNSTEP      EQU $5B96  ;  2   Step size when renumbering. Default value of 10.
  337. STRIP1      EQU $5B98  ; 32   Used as RAM disk transfer buffer (32 bytes to $5BB7).
  338.                        ;      Used to hold Sinclair stripe character patterns (16d bytes to $5BA7).
  339.                        ;      ...
  340. TSTACK      EQU $5BFF  ;  n   Temporary stack (grows downwards). The byte at $5BFF is not actually used.
  341.  
  342. ; -------------------------
  343. ; Standard System Variables
  344. ; -------------------------
  345. ; These occupy addresses $5C00-$5CB5.
  346. ; See the end of this document for descriptions of the standard system variables.
  347.  
  348. ; ------------------
  349. ; RAM Disk Catalogue
  350. ; ------------------
  351. ; The catalogue can occupy addresses $C000-$EBFF in physical RAM bank 7, starting at $EBFF and growing downwards.
  352. ;
  353. ; Each entry contains 20 bytes:
  354. ;   Bytes $00-$09: Filename.
  355. ;   Bytes $0A-$0C: Start address of file in RAM disk area.
  356. ;   Bytes $0D-$0F: Length of file in RAM disk area.
  357. ;   Bytes $10-$12: End address of file in RAM disk area (used as current position indicator when loading/saving).
  358. ;   Byte  $13    : Flags:
  359. ;                     Bit 0   : 1=Entry requires updating.
  360. ;                     Bits 1-7: Not used (always hold 0).
  361. ;
  362. ; The catalogue can store up to 562 entries, and hence the RAM disk can never hold more than 562 files no matter
  363. ; how small the files themselves are. Note that filenames are case sensitive.
  364. ;
  365. ; The shadow screen (SCREEN 1) also resides in physical RAM bank 7 and so if more than 217 catalogue
  366. ; entries are created then SCREEN 1 will become corrupted [Credit: Toni Baker, ZX Computing Monthly].
  367. ; However, since screen 1 cannot be used from BASIC, it may have been a design decision to allow the
  368. ; RAM disk to overwrite it.
  369. ;
  370. ; The actual files are stored in physical RAM banks 1, 3, 4 and 6 (logical banks 0, 1, 2, 3),
  371. ; starting from $C000 in physical RAM bank 1 and growing upwards.
  372. ;
  373. ; A file consists of a 9 byte header followed by the data for the file. The header bytes
  374. ; have the following meaning:
  375. ;   Byte  $00    : File type - $00=Program, $01=Numeric array, $02=Character array, $03=Code/Screen$.
  376. ;   Bytes $01-$02: Length of program/code block/screen$/array ($1B00 for screen$).
  377. ;   Bytes $03-$04: Start of code block/screen$ ($4000 for screen$).
  378. ;   Bytes $05-$06: Offset to the variables (i.e. length of program) if a program. For an array, $05 holds the variable name.
  379. ;   Bytes $07-$08: Auto-run line number for a program ($80 in high byte if no auto-run).
  380.  
  381. ; --------------------------
  382. ; Editor Workspace Variables
  383. ; --------------------------
  384. ; These occupy addresses $EC00-$FFFF in physical RAM bank 7, and form a workspace used by 128 BASIC Editor.
  385. ;
  386. ; $EC00    3   Byte 0: Flags used when inserting a line into the BASIC program (first 4 bits are mutually exclusive).
  387. ;                Bit 0: 1=First row of the BASIC line off top of screen.
  388. ;                Bit 1: 1=On first row of the BASIC line.
  389. ;                Bit 2: 1=Using lower screen and only first row of the BASIC line visible.
  390. ;                Bit 3: 1=At the end of the last row of the BASIC line.
  391. ;                Bit 4: Not used (always 0).
  392. ;                Bit 5: Not used (always 0).
  393. ;                Bit 6: Not used (always 0).
  394. ;                Bit 7: 1=Column with cursor not yet found.
  395. ;              Byte 1: Column number of current position within the BASIC line being inserted. Used when fetching characters.
  396. ;              Byte 2: Row number of current position within the BASIC line is being inserted. Used when fetching characters.
  397. ; $EC03    3   Byte 0: Flags used upon an error when inserting a line into the BASIC program (first 4 bits are mutually exclusive).
  398. ;                Bit 0: 1=First row of the BASIC line off top of screen.
  399. ;                Bit 1: 1=On first row of the BASIC line.
  400. ;                Bit 2: 1=Using lower screen and only first row of the BASIC line visible.
  401. ;                Bit 3: 1=At the end of the last row of the BASIC line.
  402. ;                Bit 4: Not used (always 0).
  403. ;                Bit 5: Not used (always 0).
  404. ;                Bit 6: Not used (always 0).
  405. ;                Bit 7: 1=Column with cursor not yet found.
  406. ;              Byte 1: Start column number where BASIC line is being entered. Always holds 0.
  407. ;              Byte 2: Start row number where BASIC line is being entered.
  408. ; $EC06    2   Count of the number of editable characters in the BASIC line up to the cursor within the Screen Line Edit Buffer.
  409. ; $EC08    2   Version of E_PPC used by BASIC Editor to hold last line number enter.
  410. ; $EC0C    1   Current menu index.
  411. ; $EC0D    1   Flags used by 128 BASIC Editor:
  412. ;                Bit 0: 1=Screen Line Edit Buffer (including Below-Screen Line Edit Buffer) is full.
  413. ;                Bit 1: 1=Menu is displayed.
  414. ;                Bit 2: 1=Using RAM disk.
  415. ;                Bit 3: 1=Current line has been altered.
  416. ;                Bit 4: 1=Return to calculator, 0=Return to main menu.
  417. ;                Bit 5: 1=Do not process the BASIC line (used by the Calculator).
  418. ;                Bit 6: 1=Editing area is the lower screen, 0=Editing area is the main screen.
  419. ;                Bit 7: 1=Waiting for key press, 0=Got key press.
  420. ; $EC0E    1   Mode:
  421. ;                $00 = Edit Menu mode.
  422. ;                $04 = Calculator mode.
  423. ;                $07 = Tape Loader mode. [Effectively not used as overwritten by $FF]
  424. ;                $FF = Tape Loader mode.
  425. ; $EC0F    1   Main screen colours used by the 128 BASIC Editor - alternate ATTR_P.
  426. ; $EC10    1   Main screen colours used by the 128 BASIC Editor - alternate MASK_P.
  427. ; $EC11    1   Temporary screen colours used by the 128 BASIC Editor - alternate ATTR_T.
  428. ; $EC12    1   Temporary screen colours used by the 128 BASIC Editor - alternate MASK_T.
  429. ; $EC13    1   Temporary store for P_FLAG:
  430. ;                Bit 0: 1=OVER 1, 0=OVER 0.
  431. ;                Bit 1: Not used (always 0).
  432. ;                Bit 2: 1=INVERSE 1, INVERSE 0.
  433. ;                Bit 3: Not used (always 0).
  434. ;                Bit 4: 1=Using INK 9.
  435. ;                Bit 5: Not used (always 0).
  436. ;                Bit 6: 1=Using PAPER 9.
  437. ;                Bit 7: Not used (always 0).
  438. ; $EC14    1   Not used.
  439. ; $EC15    1   Holds the number of editing lines: 20 for the main screen, 1 for the lower screen.
  440. ; $EC16  735   Screen Line Edit Buffer. This represents the text on screen that can be edited. It holds 21 rows,
  441. ;              with each row consisting of 32 characters followed by 3 data bytes. Areas of white
  442. ;              space that do not contain any editable characters (e.g. the indent that starts subsequent
  443. ;              rows of a BASIC line) contain the value $00.
  444. ;                Data Byte 0:
  445. ;                  Bit 0: 1=The first row of the BASIC line.
  446. ;                  Bit 1: 1=Spans onto next row.
  447. ;                  Bit 2: Not used (always 0).
  448. ;                  Bit 3: 1=The last row of the BASIC line.
  449. ;                  Bit 4: 1=Associated line number stored.
  450. ;                  Bit 5: Not used (always 0).
  451. ;                  Bit 6: Not used (always 0).
  452. ;                  Bit 7: Not used (always 0).
  453. ;                Data Bytes 1-2: Line number of corresponding BASIC line (stored for the first row of the BASIC line only, holds $0000).
  454. ; $EEF5    1   Flags used when listing the BASIC program:
  455. ;                Bit 0   : 0=Not on the current line, 1=On the current line.
  456. ;                Bit 1   : 0=Previously found the current line, 1=Not yet found the current line.
  457. ;                Bit 2   : 0=Enable display file updates, 1=Disable display file updates.
  458. ;                Bits 3-7: Not used (always 0).
  459. ; $EEF6    1   Store for temporarily saving the value of TVFLAG.
  460. ; $EEF7    1   Store for temporarily saving the value of COORDS.
  461. ; $EEF9    1   Store for temporarily saving the value of P_POSN.
  462. ; $EEFA    2   Store for temporarily saving the value of PRCC.
  463. ; $EEFC    2   Store for temporarily saving the value of ECHO_E.
  464. ; $EEFE    2   Store for temporarily saving the value of DF_CC.
  465. ; $EF00    2   Store for temporarily saving the value of DF_CCL.
  466. ; $EF01    1   Store for temporarily saving the value of S_POSN.
  467. ; $EF03    2   Store for temporarily saving the value of SPOSNL.
  468. ; $EF05    1   Store for temporarily saving the value of SCR_CT.
  469. ; $EF06    1   Store for temporarily saving the value of ATTR_P.
  470. ; $EF07    1   Store for temporarily saving the value of MASK_P.
  471. ; $EF08    1   Store for temporarily saving the value of ATTR_T.
  472. ; $EF09 1512   Used to store screen area (12 rows of 14 columns) where menu will be shown.
  473. ;              The rows are stored one after the other, with each row consisting of the following:
  474. ;                - 8 lines of 14 display file bytes.
  475. ;                - 14 attribute file bytes.
  476. ; $F4F1-$F6E9  Not used. 505d bytes.
  477. ; $F6EA    2   The jump table address for the current menu.
  478. ; $F6EC    2   The text table address for the current menu.
  479. ; $F6EE    1   Cursor position info - Current row number.
  480. ; $F6EF    1   Cursor position info - Current column number.
  481. ; $F6F0    1   Cursor position info - Preferred column number. Holds the last user selected column position. The Editor will attempt to
  482. ;              place the cursor on this column when the user moves up or down to a new line.
  483. ; $F6F1    1   Edit area info - Top row threshold for scrolling up.
  484. ; $F6F2    1   Edit area info - Bottom row threshold for scrolling down.
  485. ; $F6F3    1   Edit area info - Number of rows in the editing area.
  486. ; $F6F4    1   Flags used when deleting:
  487. ;                Bit 0   : 1=Deleting on last row of the BASIC line, 0=Deleting on row other than the last row of the BASIC line.
  488. ;                Bits 1-7: Not used (always 0).
  489. ; $F6F5    1   Number of rows held in the Below-Screen Line Edit Buffer.
  490. ; $F6F6    2   Intended to point to the next location to access within the Below-Screen Line Edit Buffer, but incorrectly initialised to $0000 by the routine at $30D6 (ROM 0) and then never used.
  491. ; $F6F8  735   Below-Screen Line Edit Buffer. Holds the remainder of a BASIC line that has overflowed off the bottom of the Screen Line Edit Buffer. It can hold 21 rows, with each row
  492. ;              consisting of 32 characters followed by 3 data bytes. Areas of white space that do not contain any editable characters (e.g. the indent that starts subsequent rows of a BASIC line)
  493. ;              contain the value $00.
  494. ;                Data Byte 0:
  495. ;                  Bit 0: 1=The first row of the BASIC line.
  496. ;                  Bit 1: 1=Spans onto next row.
  497. ;                  Bit 2: Not used (always 0).
  498. ;                  Bit 3: 1=The last row of the BASIC line.
  499. ;                  Bit 4: 1=Associated line number stored.
  500. ;                  Bit 5: Not used (always 0).
  501. ;                  Bit 6: Not used (always 0).
  502. ;                  Bit 7: Not used (always 0).
  503. ;                Data Bytes 1-2: Line number of corresponding BASIC line (stored for the first row of the BASIC line only, holds $0000).
  504. ; $F9D7    2   Line number of the BASIC line in the program area being edited (or $0000 for no line).
  505. ; $F9DB    1   Number of rows held in the Above-Screen Line Edit Buffer.
  506. ; $F9DC    2   Points to the next location to access within the Above-Screen Line Edit Buffer.
  507. ; $F9DE  700   Above-Screen Line Edit Buffer. Holds the rows of a BASIC line that has overflowed off the top of the Screen Line Edit Buffer.
  508. ;              It can hold 20 rows, with each row consisting of 32 characters followed by 3 data bytes. Areas of white space that do not
  509. ;              contain any editable characters (e.g. the indent that starts subsequent rows of a BASIC line) contain the value $00.
  510. ;                Data Byte 0:
  511. ;                  Bit 0: 1=The first row of the BASIC line.
  512. ;                  Bit 1: 1=Spans onto next row.
  513. ;                  Bit 2: Not used (always 0).
  514. ;                  Bit 3: 1=The last row of the BASIC line.
  515. ;                  Bit 4: 1=Associated line number stored.
  516. ;                  Bit 5: Not used (always 0).
  517. ;                  Bit 6: Not used (always 0).
  518. ;                  Bit 7: Not used (always 0).
  519. ;                Data Bytes 1-2: Line number of corresponding BASIC line (stored for the first row of the BASIC line only, holds $0000).
  520. ; $FC9A    2   The line number at the top of the screen, or $0000 for the first line.
  521. ; $FC9E    1   $00=Print a leading space when constructing keyword.
  522. ; $FC9F    2   Address of the next character to fetch within the BASIC line in the program area, or $0000 for no next character.
  523. ; $FCA1    2   Address of the next character to fetch from the Keyword Construction Buffer, or $0000 for no next character.
  524. ; $FCA3   11   Keyword Construction Buffer. Holds either a line number or keyword string representation.
  525. ; $FCAE-$FCFC  Construct a BASIC Line routine.                       <<< RAM routine - See end of file for description >>>
  526. ; $FCFD-$FD2D  Copy String Into Keyword Construction Buffer routine. <<< RAM routine - See end of file for description >>>
  527. ; $FD2E-$FD69  Identify Character Code of Token String routine.      <<< RAM routine - See end of file for description >>>
  528. ; $FD6A    1   Flags used when shifting BASIC lines within edit buffer rows [Redundant]:
  529. ;                Bit 0  : 1=Set to 1 but never reset or tested. Possibly intended to indicate the start of a new BASIC line and hence whether indentation required.
  530. ;                Bit 1-7: Not used (always 0).
  531. ; $FD6B    1   The number of characters to indent subsequent rows of a BASIC line by.
  532. ; $FD6C    1   Cursor settings (indexed by IX+$00) - initialised to $00, but never used.
  533. ; $FD6D    1   Cursor settings (indexed by IX+$01) - number of rows above the editing area.
  534. ; $FD6E    1   Cursor settings (indexed by IX+$02) - initialised to $00 (when using lower screen) or $14 (when using main screen), but never subsequently used.
  535. ; $FD6F    1   Cursor settings (indexed by IX+$03) - initialised to $00, but never subsequently used.
  536. ; $FD70    1   Cursor settings (indexed by IX+$04) - initialised to $00, but never subsequently used.
  537. ; $FD71    1   Cursor settings (indexed by IX+$05) - initialised to $00, but never subsequently used.
  538. ; $FD72    1   Cursor settings (indexed by IX+$06) - attribute colour.
  539. ; $FD73    1   Cursor settings (indexed by IX+$07) - screen attribute where cursor is displayed.
  540. ; $FD74    9   The Keyword Conversion Buffer holding text to examine to see if it is a keyword.
  541. ; $FD7D    2   Address of next available location within the Keyword Conversion Buffer.
  542. ; $FD7F    2   Address of the space character between words in the Keyword Conversion Buffer.
  543. ; $FD81    1   Keyword Conversion Buffer flags, used when tokenizing a BASIC line:
  544. ;                Bit 0   : 1=Buffer contains characters.
  545. ;                Bit 1   : 1=Indicates within quotes.
  546. ;                Bit 2   : 1=Indicates within a REM.
  547. ;                Bits 3-7: Not used (always reset to 0).
  548. ; $FD82    2   Address of the position to insert the next character within the BASIC line workspace. The BASIC line
  549. ;              is created at the spare space pointed to by E_LINE.
  550. ; $FD84    1   BASIC line insertion flags, used when inserting a characters into the BASIC line workspace:
  551. ;                Bit 0   : 1=The last character was a token.
  552. ;                Bit 1   : 1=The last character was a space.
  553. ;                Bits 2-7: Not used (always 0).
  554. ; $FD85    2   Count of the number of characters in the typed BASIC line being inserted.
  555. ; $FD87    2   Count of the number of characters in the tokenized version of the BASIC line being inserted.
  556. ; $FD89    1   Holds '<' or '>' if this was the previously examined character during tokenization of a BASIC line, else $00.
  557. ; $FD8A    1   Locate Error Marker flag, holding $01 is a syntax error was detected on the BASIC line being inserted and the equivalent position within
  558. ;              the typed BASIC line needs to be found with, else it holds $00 when tokenizing a BASIC line.
  559. ; $FD8B    2   Stores the stack pointer for restoration upon an insertion error into the BASIC line workspace.
  560. ; $FD8C-$FF23  Not used. 408 bytes.
  561. ; $FF24    2   Never used. An attempt is made to set it to $EC00. This is a remnant from the Spanish 128, which stored the address of the Screen Buffer here.
  562. ;              The value is written to RAM bank 0 instead of RAM bank 7, and the value never subsequently accessed.
  563. ; $FF26    2   Not used.
  564. ; $FF28-$FF60  Not used. On the Spanish 128 this memory holds a routine that copies a character into the display file. The code to copy to routine into RAM,
  565. ;              and the routine itself are present in ROM 0 but are never executed. <<< RAM routine - See end of file for description >>>
  566. ; $FF61-$FFFF  Not used. 159 bytes.
  567.  
  568.  
  569. ; ========================
  570. ; Called ROM 1 Subroutines
  571. ; ========================
  572.  
  573. ERROR_1     EQU $0008
  574. PRINT_A_1   EQU $0010
  575. GET_CHAR    EQU $0018
  576. NEXT_CHAR   EQU $0020
  577. BC_SPACES   EQU $0030
  578. TOKENS      EQU $0095
  579. BEEPER      EQU $03B5
  580. BEEP        EQU $03F8
  581. SA_ALL      EQU $075A
  582. ME_CONTRL   EQU $08B6
  583. SA_CONTROL  EQU $0970
  584. PRINT_OUT   EQU $09F4
  585. PO_T_UDG    EQU $0B52
  586. PO_MSG      EQU $0C0A
  587. TEMPS       EQU $0D4D
  588. CLS         EQU $0D6B
  589. CLS_LOWER   EQU $0D6E
  590. CL_ALL      EQU $0DAF
  591. CL_ATTR     EQU $0E88
  592. CL_ADDR     EQU $0E9B
  593. CLEAR_PRB   EQU $0EDF
  594. ADD_CHAR    EQU $0F81
  595. ED_ERROR    EQU $107F
  596. CLEAR_SP    EQU $1097
  597. KEY_INPUT   EQU $10A8
  598. KEY_M_CL    EQU $10DB
  599. MAIN_4      EQU $1303
  600. ERROR_MSGS  EQU $1391
  601. MESSAGES    EQU $1537
  602. REPORT_J    EQU $15C4
  603. OUT_CODE    EQU $15EF
  604. CHAN_OPEN   EQU $1601
  605. CHAN_FLAG   EQU $1615
  606. POINTERS    EQU $1664
  607. CLOSE       EQU $16E5
  608. MAKE_ROOM   EQU $1655
  609. LINE_NO     EQU $1695
  610. SET_MIN     EQU $16B0
  611. SET_WORK    EQU $16BF
  612. SET_STK     EQU $16C5
  613. OPEN        EQU $1736
  614. LIST_5      EQU $1822
  615. NUMBER      EQU $18B6
  616. LINE_ADDR   EQU $196E
  617. EACH_STMT   EQU $198B
  618. NEXT_ONE    EQU $19B8
  619. RECLAIM     EQU $19E5
  620. RECLAIM_2   EQU $19E8
  621. E_LINE_NO   EQU $19FB
  622. OUT_NUM_1   EQU $1A1B
  623. CLASS_01    EQU $1C1F
  624. VAL_FET_1   EQU $1C56
  625. CLASS_04    EQU $1C6C
  626. EXPT_2NUM   EQU $1C7A
  627. EXPT_1NUM   EQU $1C82
  628. EXPT_EXP    EQU $1C8C
  629. CLASS_09    EQU $1CBE
  630. FETCH_NUM   EQU $1CDE
  631. USE_ZERO    EQU $1CE6
  632. STOP        EQU $1CEE
  633. F_REORDER   EQU $1D16
  634. LOOK_PROG   EQU $1D86
  635. NEXT        EQU $1DAB
  636. PASS_BY     EQU $1E39
  637. RESTORE     EQU $1E42
  638. REST_RUN    EQU $1E45
  639. RANDOMIZE   EQU $1E4F
  640. CONTINUE    EQU $1E5F
  641. GO_TO       EQU $1E67
  642. COUT        EQU $1E7A     ; Should be OUT but renamed since some assemblers detect this as an instruction.
  643. POKE        EQU $1E80
  644. FIND_INT2   EQU $1E99
  645. TEST_ROOM   EQU $1F05
  646. PAUSE       EQU $1F3A
  647. PRINT_2     EQU $1FDF
  648. PR_ST_END   EQU $2048
  649. STR_ALTER   EQU $2070
  650. INPUT_1     EQU $2096
  651. IN_ITEM_1   EQU $20C1
  652. CO_TEMP_4   EQU $21FC
  653. BORDER      EQU $2294
  654. PIXEL_ADDR  EQU $22AA
  655. PLOT        EQU $22DC
  656. PLOT_SUB    EQU $22E5
  657. CIRCLE      EQU $2320
  658. DR_3_PRMS   EQU $238D
  659. LINE_DRAW   EQU $2477
  660. SCANNING    EQU $24FB
  661. SYNTAX_Z    EQU $2530
  662. LOOK_VARS   EQU $28B2
  663. STK_VAR     EQU $2996
  664. STK_FETCH   EQU $2BF1
  665. D_RUN       EQU $2C15
  666. ALPHA       EQU $2C8D
  667. NUMERIC     EQU $2D1B
  668. STACK_BC    EQU $2D2B
  669. FP_TO_BC    EQU $2DA2
  670. PRINT_FP    EQU $2DE3
  671. HL_MULT_DE  EQU $30A9
  672. STACK_NUM   EQU $33B4
  673. TEST_ZERO   EQU $34E9
  674. KP_SCAN     EQU $3C01
  675. TEST_SCREEN EQU $3C04
  676. CHAR_SET    EQU $3D00
  677.  
  678.  
  679. ;**************************************************
  680.  
  681. ; =========================
  682. ; RESTART ROUTINES - PART 1
  683. ; =========================
  684. ; RST $10, $18 and $20 call the equivalent subroutines in ROM 1, via RST $28.
  685. ;
  686. ; RST $00 - Reset the machine.
  687. ; RST $08 - Not used. Would have invoked the ZX Interface 1 if fitted.
  688. ; RST $10 - Print a character      (equivalent to RST $10 ROM 1).
  689. ; RST $18 - Collect a character    (equivalent to RST $18 ROM 1).
  690. ; RST $20 - Collect next character (equivalent to RST $20 ROM 1).
  691. ; RST $28 - Call routine in ROM 1.
  692. ; RST $30 - Not used.
  693. ; RST $38 - Not used.
  694.  
  695. ; -----------------------
  696. ; RST $00 - Reset Machine
  697. ; -----------------------
  698.  
  699.         ORG $0000
  700.  
  701. L0000:  DI                ; Ensure interrupts are disabled.
  702.         LD   BC,$692B     ;
  703.  
  704. L0004:  DEC  BC           ; Delay about 0.2s to allow screen switching mechanism to settle.
  705.         LD   A,B          ;
  706.         OR   C            ;
  707.         JR   NZ,L0004     ; [There is no RST $08. No instruction fetch at $0008 hence ZX Interface 1 will not be paged in from this ROM. Credit: Paul Farrow].
  708.  
  709.         JP   L00C7        ; to the main reset routine.
  710.  
  711. L000C:  DB $00, $00     ; [Spare bytes]
  712.         DB $00, $00     ;
  713.  
  714. ; ---------------------------
  715. ; RST $10 - Print A Character
  716. ; ---------------------------
  717.  
  718. L0010:  RST  28H          ; Call corresponding routine in ROM 1.
  719.         DEFW PRINT_A_1    ; $0010.
  720.         RET               ;
  721.  
  722. L0014:  DB $00, $00     ; [Spare bytes]
  723.         DB $00, $00     ;
  724.  
  725. ; -----------------------------
  726. ; RST $18 - Collect A Character
  727. ; -----------------------------
  728.  
  729. L0018:  RST  28H          ; Call corresponding routine in ROM 1.
  730.         DEFW GET_CHAR     ; $0018.
  731.         RET               ;
  732.  
  733. L001C:  DB $00, $00     ; [Spare bytes]
  734.         DB $00, $00     ;
  735.  
  736. ; --------------------------------
  737. ; RST $20 - Collect Next Character
  738. ; --------------------------------
  739.  
  740. L0020:  RST  28H          ; Call corresponding routine in ROM 1.
  741.         DEFW NEXT_CHAR    ; $0020.
  742.         RET               ;
  743.  
  744. L0024:  DB $00, $00     ; [Spare bytes]
  745.         DB $00, $00     ;
  746.  
  747. ; -------------------------------
  748. ; RST $28 - Call Routine in ROM 1
  749. ; -------------------------------
  750. ; RST 28 calls a routine in ROM 1 (or alternatively a routine in RAM while
  751. ; ROM 1 is paged in). Call as follows: RST 28 / DEFW address.
  752.  
  753. L0028:  EX   (SP),HL      ; Get the address after the RST $28 into HL,
  754.                           ; saving HL on the stack.
  755.         PUSH AF           ; Save the AF registers.
  756.         LD   A,(HL)       ; Fetch the first address byte.
  757.         INC  HL           ; Point HL to the byte after
  758.         INC  HL           ; the required address.
  759.         LD   (RETADDR),HL ; $5B5A. Store this in RETADDR.
  760.         DEC  HL           ; (There is no RST $30)
  761.         LD   H,(HL)       ; Fetch the second address byte.
  762.         LD   L,A          ; HL=Subroutine to call.
  763.         POP  AF           ; Restore AF.
  764.         JP   L005C        ; Jump ahead to continue.
  765.  
  766. L0037:  DB $00          ; [Spare byte]
  767.  
  768.  
  769. ; ==========================
  770. ; MASKABLE INTERRUPT ROUTINE
  771. ; ==========================
  772. ; This routine preserves the Hl register pair. It then performs the following:
  773. ; - Execute the ROM switching code held in RAM to switch to ROM 1.
  774. ; - Execute the maskable interrupt routine in ROM 1.
  775. ; - Execute the ROM switching code held in RAM to return to ROM 0.
  776. ; - Return to address $0048 (ROM 0).
  777.  
  778. L0038:  PUSH HL           ; Save HL register pair.
  779.         LD   HL,L0048     ; Return address of $0048 (ROM 0).
  780.         PUSH HL           ;
  781.         LD   HL,SWAP      ; $5B00. Address of swap ROM routine held in RAM at $5B00.
  782.         PUSH HL           ;
  783.         LD   HL,L0038     ; Maskable interrupt routine address $0038 (ROM 0).
  784.         PUSH HL           ;
  785.         JP   SWAP         ; $5B00. Switch to other ROM (ROM 1) via routine held in RAM at $5B00.
  786.  
  787. L0048:  POP  HL           ; Restore the HL register pair.
  788.         RET               ; End of interrupt routine.
  789.  
  790.  
  791. ; ===============================
  792. ; ERROR HANDLER ROUTINES - PART 1
  793. ; ===============================
  794.  
  795. ; ------------------
  796. ; 128K Error Routine
  797. ; ------------------
  798.  
  799. L004A:  LD   BC,$7FFD     ;
  800.         XOR  A            ; ROM 0, Bank 0, Screen 0, 128K mode.
  801.         DI                ; Ensure interrupts are disabled whilst paging.
  802.         OUT  (C),A        ;
  803.         LD   (BANK_M),A   ; $5B5C. Note the new paging status.
  804.         EI                ; Re-enable interrupts.
  805.         DEC  A            ; A=$FF.
  806.         LD   (IY+$00),A   ; Set ERR_NR to no error ($FF).
  807.         JP   L0321        ; Jump ahead to continue.
  808.  
  809.  
  810. ; =========================
  811. ; RESTART ROUTINES - PART 2
  812. ; =========================
  813.  
  814. ; -----------------------------------------
  815. ; Call ROM 1 Routine (RST $28 Continuation)
  816. ; -----------------------------------------
  817. ; Continuation from routine at $0028 (ROM 0).
  818.  
  819. L005C:  LD   (TARGET),HL  ; $5B58. Save the address in ROM 0 to call.
  820.         LD   HL,YOUNGER   ; $5B14. HL='Return to ROM 0' routine held in RAM.
  821.         EX   (SP),HL      ; Stack HL.
  822.         PUSH HL           ; Save previous stack address.
  823.         LD   HL,(TARGET)  ; $5B58. HL=Retrieve address to call. [There is no NMI code. Credit: Andrew Owen].
  824.         EX   (SP),HL      ; Stack HL.
  825.         JP   SWAP         ; $5B00. Switch to other ROM (ROM 1) and return to address to call.
  826.  
  827.  
  828. ; ============
  829. ; RAM ROUTINES
  830. ; ============
  831. ; The following code will be copied to locations $5B00 to $5B57, within the old ZX Printer buffer.
  832.  
  833. ; -----------------
  834. ; Swap to Other ROM (copied to $5B00)
  835. ; -----------------
  836. ; Switch to the other ROM from that currently paged in.
  837.  
  838. ; [The switching between the two ROMs invariably enables interrupts, which may not always be desired
  839. ; (see the bug at $09CD (ROM 0) in the PLAY command). To overcome this issue would require a rewrite
  840. ; of the SWAP routine as follows, but this is larger than the existing routine and so cannot simply be
  841. ; used in direct replacement of it. A work-around solution is to poke a JP instruction at the start of
  842. ; the SWAP routine in the ZX Printer buffer and direct control to the replacement routine held somewhere
  843. ; else in RAM. Credit: Toni Baker, ZX Computing Monthly]
  844. ;
  845. ; [However, the PLAY commnad bug may be fixed in another manner within the PLAY command itself, in which
  846. ; case there is no need to modify the SWAP routine.]
  847. ;
  848. ; SWAP:
  849. ;       PUSH AF           ; Stack AF.
  850. ;       PUSH BC           ; Stack BC.
  851. ;
  852. ;       LD   A,R          ; P/V flag=Interrupt status.
  853. ;       PUSH AF           ; Stack interrupt status.
  854. ;
  855. ;       LD   BC,$7FFD     ; BC=Port number required for paging.
  856. ;       LD   A,(BANK_M)   ; A=Current paging configuration.
  857. ;       XOR  $10          ; Complement 'ROM' bit.
  858. ;       DI                ; Disable interrupts (in case an interrupt occurs between the next two instructions).
  859. ;       LD   (BANK_M),A   ; Store revised paging configuration.
  860. ;       OUT  (C),A        ; Page ROM.
  861. ;
  862. ;       POP  AF           ; P/V flag=Former interrupt status.
  863. ;       JP   PO,SWAP_EXIT ; Jump if interrupts were previously disabled.
  864. ;
  865. ;       EI                ; Re-enable interrupts.
  866. ;
  867. ; SWAP_EXIT:
  868. ;       POP BC            ; Restore BC.
  869. ;       POP AF            ; Restore AF.
  870. ;       RET               ;
  871.  
  872. ;SWAP
  873. L006B:  PUSH AF           ; Save AF and BC.
  874.         PUSH BC           ;
  875.         LD   BC,$7FFD     ;
  876.         LD   A,(BANK_M)   ; $5B5C.
  877.         XOR  $10          ; Select other ROM.
  878.         DI                ; Disable interrupts whilst switching ROMs.
  879.         LD   (BANK_M),A   ; $5B5C.
  880.         OUT  (C),A        ; Switch to the other ROM.
  881.         EI                ;
  882.         POP  BC           ; Restore BC and AF.
  883.         POP  AF           ;
  884.         RET               ;
  885.  
  886. ; ---------------------------
  887. ; Return to Other ROM Routine (copied to $5B14)
  888. ; ---------------------------
  889. ; Switch to the other ROM from that currently paged in
  890. ; and then return to the address held in RETADDR.
  891.  
  892. ;YOUNGER
  893. L007F:  CALL SWAP         ; $5B00. Toggle to the other ROM.
  894.         PUSH HL           ;
  895.         LD   HL,(RETADDR) ; $5B5A.
  896.         EX   (SP),HL      ;
  897.         RET               ; Return to the address held in RETADDR.
  898.  
  899. ; ---------------------
  900. ; Error Handler Routine (copied to $5B1D)
  901. ; ---------------------
  902. ; This error handler routine switches back to ROM 0 and then
  903. ; executes the routine pointed to by system variable TARGET.
  904.  
  905. ;ONERR
  906. L0088:  DI                ; Ensure interrupts are disabled whilst paging.
  907.         LD   A,(BANK_M)   ; $5B5C. Fetch current paging configuration.
  908.         AND  $EF          ; Select ROM 0.
  909.         LD   (BANK_M),A   ; $5B5C. Save the new configuration
  910.         LD   BC,$7FFD     ;
  911.         OUT  (C),A        ; Switch to ROM 0.
  912.         EI                ;
  913.         JP   L00C3        ; Jump to $00C3 (ROM 0) to continue.
  914.  
  915. ; -------------------------
  916. ; 'P' Channel Input Routine (copied to $5B2F)
  917. ; -------------------------
  918. ; Called when data is read from channel 'P'.
  919. ; It causes ROM 0 to be paged in so that the new RS232 routines
  920. ; can be accessed.
  921.  
  922. ;PIN
  923. L009A:  LD   HL,L06D8     ; RS232 input routine within ROM 0.
  924.         JR   L00A2        ;
  925.  
  926. ; --------------------------
  927. ; 'P' Channel Output Routine (copied to $5B34)
  928. ; --------------------------
  929. ; Called when data is written to channel 'P'.
  930. ; It causes ROM 0 to be paged in so that the new RS232 routines
  931. ; can be accessed.
  932. ; Entry: A=Byte to send.
  933.  
  934. ;POUT
  935. L009F:  LD   HL,L07CA     ; RS232 output routine within ROM 0.
  936.  
  937. L00A2:  EX   AF,AF'       ; Save AF registers.
  938.        LD   BC,$7FFD     ;
  939.        LD   A,(BANK_M)   ; $5B5C. Fetch the current paging configuration
  940.        PUSH AF           ; and save it.
  941.        AND  $EF          ; Select ROM 0.
  942.        DI                ; Ensure interrupts are disabled whilst paging.
  943.        LD   (BANK_M),A   ; $5B5C. Store the new paging configuration.
  944.        OUT  (C),A        ; Switch to ROM 0.
  945.        JP   L05E6        ; Jump to the RS232 channel input/output handler routine.
  946.  
  947. ; ------------------------
  948. ; 'P' Channel Exit Routine (copied to $5B4A)
  949. ; ------------------------
  950. ; Used when returning from a channel 'P' read or write operation.
  951. ; It causes the original ROM to be paged back in and returns back to
  952. ; the calling routine.
  953.  
  954. ;POUT2
  955. L00B5:  EX   AF,AF'       ; Save AF registers. For a read, A holds the byte read and the flags the success status.
  956.         POP  AF           ; Retrieve original paging configuration.
  957.         LD   BC,$7FFD     ;
  958.         DI                ; Ensure interrupts are disabled whilst paging.
  959.         LD   (BANK_M),A   ; $5B5C. Store original paging configuration.
  960.         OUT  (C),A        ; Switch back to original paging configuration.
  961.         EI                ;
  962.         EX   AF,AF'       ; Restore AF registers. For a read, A holds the byte read and the flags the success status.
  963.        RET               ; <<< End of RAM Routines >>>
  964.  
  965.  
  966. ; ===============================
  967. ; ERROR HANDLER ROUTINES - PART 2
  968. ; ===============================
  969.  
  970. ; ---------------
  971. ; Call Subroutine
  972. ; ---------------
  973. ; Called from ONERR ($5B1D) to execute the routine pointed
  974. ; to by system variable SYNRET.
  975.  
  976. L00C3:  LD   HL,(SYNRET)  ; $5B8B. Fetch the address to call.
  977.        JP   (HL)         ; and execute it.
  978.  
  979.  
  980. ; ================================
  981. ; INITIALISATION ROUTINES - PART 1
  982. ; ================================
  983.  
  984. ; --------------------------------------------
  985. ; Reset Routine (RST $00 Continuation, Part 1)
  986. ; --------------------------------------------
  987. ; Continuation from routine at $0000 (ROM 0). It performs a test on all RAM banks.
  988. ; This test is crude and can fail to detect a variety of RAM errors.
  989.  
  990. L00C7:  LD   B,$08        ; Loop through all RAM banks.
  991.  
  992. L00C9:  LD   A,B          ;
  993.        EXX               ; Save B register.
  994.        DEC  A            ; RAM bank number 0 to 7. 128K mode, ROM 0, Screen 0.
  995.        LD   BC,$7FFD     ;
  996.        OUT  (C),A        ; Switch RAM bank.
  997.  
  998.        LD   HL,$C000     ; Start of the current RAM bank.
  999.        LD   DE,$C001     ;
  1000.        LD   BC,$3FFF     ; All 16K of RAM bank.
  1001.        LD   A,$FF        ;
  1002.        LD   (HL),A       ; Store $FF into RAM location.
  1003.        CP   (HL)         ; Check RAM integrity.
  1004.        JR   NZ,L0131     ; Jump if RAM error found.
  1005.  
  1006.        XOR  A            ;
  1007.        LD   (HL),A       ; Store $00 into RAM location.
  1008.        CP   (HL)         ; Check RAM integrity.
  1009.        JR   NZ,L0131     ; Jump if difference found.
  1010.  
  1011.        LDIR              ; Clear the whole page
  1012.        EXX               ; Restore B registers.
  1013.        DJNZ L00C9        ; Repeat for other RAM banks.
  1014.  
  1015.        LD   (ROW01),A    ; $5B88. Signal no communications in progress to the keypad.
  1016.  
  1017.        LD   C,$FD        ;
  1018.        LD   D,$FF        ;
  1019.        LD   E,$BF        ;
  1020.        LD   B,D          ; BC=$FFFD, DE=$FFBF.
  1021.        LD   A,$0E        ;
  1022.        OUT  (C),A        ; Select AY register 14.
  1023.        LD   B,E          ; BC=$BFFD.
  1024.        LD   A,$FF        ;
  1025.        OUT  (C),A        ; Set AY register 14 to $FF. This will force a communications reset to the keypad if present.
  1026.        JR   L0137        ; Jump ahead to continue.
  1027.  
  1028. L00FF:  DB $00          ; [Spare byte]
  1029.  
  1030.  
  1031. ; ====================
  1032. ; ROUTINE VECTOR TABLE
  1033. ; ====================
  1034.  
  1035. L0100:  JP   L17AF        ; BASIC interpreter parser.
  1036. L0103:  JP   L1838        ; 'Line Run' entry point.
  1037. L0106:  JP   L1ECF        ; Transfer bytes to logical RAM bank 4.
  1038. L0109:  JP   L1F04        ; Transfer bytes from logical RAM bank 4.
  1039. L010C:  JP   L004A        ; 128K error routine.
  1040. L010F:  JP   L03A2        ; Error routine.               Called from patch at $3B3B in ROM 1.
  1041. L0112:  JP   L182A        ; 'Statement Return' routine.  Called from patch at $3B4D in ROM 1.
  1042. L0115:  JP   L18A8        ; 'Statement Next' routine.    Called from patch at $3B5D in ROM 1.
  1043. L0118:  JP   L012D        ; Scan the keypad.
  1044. L011B:  JP   L0A05        ; Play music strings.
  1045. L011E:  JP   L11A3        ; MIDI byte output routine.
  1046. L0121:  JP   L06D8        ; RS232 byte input routine.
  1047. L0124:  JP   L07CA        ; RS232 text output routine.
  1048. L0127:  JP   L08A3        ; RS232 byte output routine.
  1049. L012A:  JP   L08F0        ; COPY (screen dump) routine.
  1050. L012D:  RST  28H          ; Call keypad scan routine in ROM 1.
  1051.        DEFW KP_SCAN-$0100 ; $3B01. [*BUG* - The address jumps into the middle of the keypad decode routine in ROM 1. It
  1052.        RET               ;                  looks like it is supposed to deal with the keypad and so the most likely
  1053.                          ;                  addresses are $3A42 (read keypad) or $39A0 (scan keypad). At $3C01 in
  1054.                          ;                  ROM 1 is a vector jump command to $39A0 to scan the keypad and this is
  1055.                          ;                  similar enough to the $3B01 to imply a simple error in one of the bytes. Credit: Paul Farrow]
  1056.  
  1057.  
  1058. ; ================================
  1059. ; INITIALISATION ROUTINES - PART 2
  1060. ; ================================
  1061.  
  1062. ; ---------------
  1063. ; Fatal RAM Error
  1064. ; ---------------
  1065. ; Set the border colour to indicate which RAM bank was found faulty:
  1066. ; RAM bank 7 - Black.
  1067. ; RAM bank 6 - White.
  1068. ; RAM bank 5 - Yellow.
  1069. ; RAM bank 4 - Cyan.
  1070. ; RAM bank 3 - Green.
  1071. ; RAM bank 2 - Magenta.
  1072. ; RAM bank 1 - Red.
  1073. ; RAM bank 0 - Blue.
  1074.  
  1075. L0131:  EXX               ; Retrieve RAM bank number + 1 in B.
  1076.        LD   A,B          ; Indicate which RAM bank failed by
  1077.        OUT  ($FE),A      ; setting the border colour.
  1078.  
  1079. L0135:  JR   L0135        ; Infinite loop.
  1080.  
  1081. ; --------------------------------------------
  1082. ; Reset Routine (RST $00 Continuation, Part 2)
  1083. ; --------------------------------------------
  1084. ; Continuation from routine at $00C7 (ROM 0).
  1085.  
  1086. L0137:  LD   B,D          ; Complete setting up the sound chip registers.
  1087.        LD   A,$07        ;
  1088.        OUT  (C),A        ; Select AY register 7.
  1089.        LD   B,E          ;
  1090.        LD   A,$FF        ; Disable AY-3-8912 sound channels.
  1091.        OUT  (C),A        ;
  1092.  
  1093.        LD   DE,SWAP      ; $5B00. Copy the various paging routines to the old printer buffer.
  1094.        LD   HL,L006B     ; The source is in this ROM.
  1095.        LD   BC,$0058     ; There are eighty eight bytes to copy.
  1096.        LDIR              ; Copy the block of bytes.
  1097.  
  1098.        LD   A,$CF        ; Load A with the code for the Z80 instruction 'RST $08'.
  1099.        LD   (RAMRST),A   ; $5B5D. Insert into new System Variable RAMRST.
  1100.        LD   SP,TSTACK    ; $5BFF. Set the stack pointer to last location of old buffer.
  1101.  
  1102.        LD   A,$04        ;
  1103.        CALL L1C64        ; Page in logical RAM bank 4 (physical RAM bank 7).
  1104.  
  1105.        LD   IX,$EBEC     ; First free entry in RAM disk.
  1106.        LD   (SFNEXT),IX  ; $5B83.
  1107.        LD   (IX+$0A),$00 ;
  1108.        LD   (IX+$0B),$C0 ;
  1109.        LD   (IX+$0C),$00 ;
  1110.        LD   HL,$2BEC     ;
  1111.        LD   A,$01        ; AHL=Free space in RAM disk.
  1112.        LD   (SFSPACE),HL ; $5B85. Current address.
  1113.        LD   (SFSPACE+2),A ; $5B87. Current RAM bank.
  1114.  
  1115.        LD   A,$05        ;
  1116.        CALL L1C64        ; Page in logical RAM bank 5 (physical RAM bank 0).
  1117.  
  1118.        LD   HL,$FFFF     ; Load HL with known last working byte - 65535.
  1119.        LD   ($5CB4),HL   ; P_RAMT. Set physical RAM top to 65535.
  1120.  
  1121.        LD   DE,CHAR_SET+$01AF ; $3EAF. Set DE to address of the last bitmap of 'U' in ROM 1.
  1122.        LD   BC,$00A8     ; There are 21 User Defined Graphics to copy.
  1123.        EX   DE,HL        ; Swap so destination is $FFFF.
  1124.        RST  28H          ;
  1125.        DEFW MAKE_ROOM+$000C ; Calling this address (LDDR/RET) in the main ROM
  1126.                          ; cleverly copies the 21 characters to the end of RAM.
  1127.  
  1128.        EX   DE,HL        ; Transfer DE to HL.
  1129.        INC  HL           ; Increment to address first byte of UDG 'A'.
  1130.        LD   ($5C7B),HL   ; UDG. Update standard System Variable UDG.
  1131.  
  1132.        DEC  HL           ;
  1133.        LD   BC,$0040     ; Set values 0 for PIP and 64 for RASP.
  1134.        LD   ($5C38),BC   ; RASP. Update standard System Variables RASP and PIP.
  1135.        LD   ($5CB2),HL   ; RAMTOP. Update standard System Variable RAMTOP - the last
  1136.                          ; byte of the BASIC system area. Any machine code and
  1137.                          ; graphics above this address are protected from NEW.
  1138.  
  1139. ; Entry point for NEW with interrupts disabled and physical RAM bank 0 occupying
  1140. ; the upper RAM region $C000 - $FFFF, i.e. the normal BASIC memory configuration.
  1141.  
  1142. L019D:  LD   HL,CHAR_SET-$0100 ; $3C00. Set HL to where, in theory character zero would be.
  1143.        LD   ($5C36),HL   ; CHARS. Update standard System Variable CHARS.
  1144.  
  1145.        LD   HL,($5CB2)   ; RAMTOP. Load HL with value of System Variable RAMTOP.
  1146.        INC  HL           ; Address next location.
  1147.        LD   SP,HL        ; Set the Stack Pointer.
  1148.        IM   1            ; Select Interrupt Mode 1.
  1149.        LD   IY,$5C3A     ; Set the IY register to address the standard System
  1150.                          ; Variables and many of the new System Variables and
  1151.                          ; even those of ZX Interface 1 in some cases.
  1152.        SET  4,(IY+$01)   ; FLAGS. Signal 128K mode.
  1153.                          ; [This bit was unused and therefore never set by 48K BASIC]
  1154.  
  1155.        EI                ; With a stack and the IY register set, interrupts can
  1156.                          ; be enabled.
  1157.  
  1158.        LD   HL,$000B     ; Set HL to eleven, timing constant for 9600 baud.
  1159.        LD   (BAUD),HL    ; $5B5F. Select default RS232 baud rate of 9600 baud.
  1160.  
  1161.        XOR  A            ; Clear accumulator.
  1162.        LD   (SERFL),A    ; $5B61. Indicate no byte waiting in RS232 receive buffer.
  1163.        LD   (COL),A      ; $5B63. Set RS232 output column position to 0.
  1164.        LD   (TVPARS),A   ; $5B65. Indicate no control code parameters expected.
  1165.  
  1166.        LD   HL,$EC00     ; [*BUG* - Should write to RAM bank 7. Main RAM has now been corrupted. The value stored is subsequently never used. Credit: Geoff Wearmouth]
  1167.        LD   ($FF24),HL   ; This is a remnant from the Spanish 128, which used this workspace variable to hold the location of the Screen Buffer. It also suffered from the
  1168.                          ; same bug, and in fact there was never a need to write to the value at this point since it was written again later during the initialisation process.
  1169.  
  1170. ; [The 1985 Sinclair Research ESPAGNOL source code says that this instruction will write to the (previously cleared)
  1171. ; main BASIC RAM during initialization but that a different page of RAM will be present during NEW.
  1172. ; Stuff and Nonsense! Assemblers and other utilities present above RAMTOP will be corrupted by the BASIC NEW command
  1173. ; since $FF24, and later $EC13, will be written to even if they are above RAMTOP.]
  1174.  
  1175.        LD   A,$50        ; Set printer width to a default of 80.
  1176.        LD   (WIDTH),A    ; $5B64. Set RS232 printer output width to 80 columns.
  1177.  
  1178.        LD   HL,$000A     ; Set HL to ten, the initial renumber line and also the increment.
  1179.        LD   (RNFIRST),HL ; $5B94. Store it as the initial line number when renumbering.
  1180.        LD   (RNSTEP),HL  ; $5B96. Store it as the renumber line increment.
  1181.  
  1182.        LD   HL,$5CB6     ; Load HL with the address following the System Variables.
  1183.        LD   ($5C4F),HL   ; CHANS. Set standard System Variable CHANS.
  1184.  
  1185.        LD   DE,L0589     ; Point to Initial Channel Information in this ROM.
  1186.                          ; This is similar to that in main ROM but
  1187.                          ; channel 'P' has input and output addresses in the
  1188.                          ; new $5Bxx region.
  1189.        LD   BC,$0015     ; There are 21 bytes to copy.
  1190.        EX   DE,HL        ; Switch pointer so destination is CHANS.
  1191.        LDIR              ; Copy the block of bytes.
  1192.  
  1193.        EX   DE,HL        ; Transfer DE to HL.
  1194.        DEC  HL           ; Decrement to point to $80 end-marker.
  1195.        LD   ($5C57),HL   ; DATADD. Update standard System Variable DATADD to this
  1196.                          ; resting address.
  1197.        INC  HL           ; Bump address.
  1198.        LD   ($5C53),HL   ; PROG. Set standard System Variable PROG.
  1199.        LD   ($5C4B),HL   ; VARS. Set standard System Variable VARS.
  1200.        LD   (HL),$80     ; Insert the Variables end-marker.
  1201.        INC  HL           ; Increment the address.
  1202.        LD   ($5C59),HL   ; E_LINE.Set standard System Variable E_LINE.
  1203.        LD   (HL),$0D     ; Insert a carriage return.
  1204.        INC  HL           ; Increment address.
  1205.        LD   (HL),$80     ; Insert the $80 end-marker.
  1206.        INC  HL           ; increment address.
  1207.        LD   ($5C61),HL   ; WORKSP. Set the standard System Variable WORKSP.
  1208.        LD   ($5C63),HL   ; STKBOT.Set the standard System Variable STKBOT.
  1209.        LD   ($5C65),HL   ; STKEND. Set the standard System Variable STKEND.
  1210.  
  1211.        LD   A,$38        ; Set colour attribute to black ink on white paper.
  1212.        LD   ($5C8D),A    ; ATTR_P. Set the standard System Variable ATTR_P.
  1213.        LD   ($5C8F),A    ; MASK_P. Set the standard System Variable MASK_P.
  1214.        LD   ($5C48),A    ; BORDCR. Set the standard System Variable BORDCR.
  1215.  
  1216.        XOR  A            ; Clear the accumulator.
  1217.        LD   ($EC13),A    ; Temporary P_FLAG. Temporary store for P-FLAG.
  1218.                          ; [*BUG* - Should write to RAM bank 7. Main RAM has now been corrupted again. The effect of the bug can
  1219.                          ; be seen by typing INVERSE 1: PRINT "Hello", followed by NEW, followed by PRINT "World", and will cause
  1220.                          ; the second word to also be printed in inverse. Credit: Geoff Wearmouth]
  1221.  
  1222.        LD   A,$07        ; Load the accumulator with colour for white.
  1223.        OUT  ($FE),A      ; Output to port $FE changing border to white.
  1224.  
  1225.        LD   HL,$0523     ; The values five and thirty five.
  1226.        LD   ($5C09),HL   ; REPDEL. Set the standard System Variables REPDEL and REPPER.
  1227.  
  1228.        DEC  (IY-$3A)     ; Set KSTATE+0 to $FF.
  1229.        DEC  (IY-$36)     ; Set KSTATE+4 to $FF.
  1230.  
  1231.        LD   HL,L059E     ; Set source to Initial Stream Data in this ROM (which is identical to that in main ROM).
  1232.        LD   DE,$5C10     ; Set destination to standard System Variable STRMS-FD
  1233.        LD   BC,$000E     ; There are fourteen bytes to copy.
  1234.        LDIR              ; Block copy the bytes.
  1235.  
  1236.        RES  1,(IY+$01)   ; Update FLAGS - signal printer not is use.
  1237.        LD   (IY+$00),$FF ; Set standard System Variable ERR_NR to $FF (OK-1).
  1238.        LD   (IY+$31),$02 ; Set standard System Variable DF_SZ to two lines.
  1239.  
  1240.        RST  28H          ;
  1241.        DEFW CLS          ; $0D6B. Clear screen.
  1242.        RST  28H          ; Attempt to display TV tuning test screen.
  1243.        DEFW TEST_SCREEN  ; $3C04. Will return if BREAK is not being pressed.
  1244.  
  1245.        LD   DE,L0561     ; Sinclair copyright message.
  1246.        CALL L057D        ; Print a message terminated by having bit 7 set.
  1247.  
  1248.        LD   (IY+$31),$02 ; Set standard System Variable DF_SZ to two lines.
  1249.        SET  5,(IY+$02)   ; TV_FLAG. Signal lower screen will require clearing.
  1250.  
  1251.        LD   HL,TSTACK    ; $5BFF. Set HL to location of temporary stack and
  1252.        LD   (OLDSP),HL   ; $5B81.  store in OLDSP.
  1253.  
  1254.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  1255.  
  1256.        LD   A,$38        ; Set colours to black ink on white paper.
  1257.        LD   ($EC11),A    ; Temporary ATTR_T used by the 128 BASIC Editor.
  1258.        LD   ($EC0F),A    ; Temporary ATTR_P used by the 128 BASIC Editor.
  1259.  
  1260. ; [Note this is where $EC13 (temporary P_FLAG) and $FF24 should be set]
  1261.  
  1262.        CALL L2584        ; Initialise mode and cursor settings. IX will point at editing settings information.
  1263.  
  1264.        CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  1265.        JP   L259F        ; Jump to show the Main menu.
  1266.  
  1267.  
  1268. ; ===================================
  1269. ; COMMAND EXECUTION ROUTINES - PART 1
  1270. ; ===================================
  1271.  
  1272. ; --------------------
  1273. ; Execute Command Line
  1274. ; --------------------
  1275. ; A typed in command resides in the editing workspace. Execute it.
  1276. ; The command could either be a new line to insert, or a line number to delete, or a numerical expression to evaluate.
  1277.  
  1278. L026B:  LD   HL,FLAGS3    ; $5B66.
  1279.        SET  0,(HL)       ; Select BASIC/Calculator mode.
  1280.  
  1281.        LD   (IY+$00),$FF ; ERR_NR. Set to '0 OK' status.
  1282.        LD   (IY+$31),$02 ; DF_SZ. Reset the number of rows in the lower screen.
  1283.  
  1284.        LD   HL,ONERR     ; $5B1D. Return address should an error occur.
  1285.        PUSH HL           ; Stack it.
  1286.  
  1287.        LD   ($5C3D),SP   ; Save the stack pointer in ERR_SP.
  1288.  
  1289.        LD   HL,L02BA     ; Return address in ROM 0 after syntax checking.
  1290.        LD   (SYNRET),HL  ; $5B8B. Store it in SYNRET.
  1291.  
  1292.        CALL L228E        ; Point to start of typed in BASIC command.
  1293.        CALL L22CB        ; Is the first character a function token, i.e. the start of a numerical expression?
  1294.        JP   Z,L21F8      ; Jump if so to evaluate it.
  1295.  
  1296.        CP   '('          ; $28. Is the first character the start of an expression?
  1297.        JP   Z,L21F8      ; Jump if so to evaluate it.
  1298.  
  1299.        CP   '-'          ; $2D. Is the first character the start of an expression?
  1300.        JP   Z,L21F8      ; Jump if so to evaluate it.
  1301.  
  1302.        CP   '+'          ; $2B. Is the first character the start of an expression?
  1303.        JP   Z,L21F8      ; Jump if so to evaluate it.
  1304.  
  1305.        CALL L22E0        ; Is text just a number or a numerical expression?
  1306.        JP   Z,L21F8      ; Jump if a numerical expression to evaluate it.
  1307.  
  1308.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  1309.        LD   A,($EC0E)    ; Fetch mode.
  1310.        CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  1311.  
  1312.        CP   $04          ; Calculator mode?
  1313.        JP   NZ,L17AF     ; Jump if not to parse and execute the BASIC command line, returning to $02BA (ROM 0).
  1314.  
  1315. ;Calculator mode
  1316.  
  1317.        CALL L2297        ; Is it a single LET command?
  1318.        JP   Z,L17AF      ; Jump if so to parse and execute the BASIC command line, returning to $02BA (ROM 0).
  1319.  
  1320. ;Otherwise ignore the command
  1321.  
  1322.        POP  HL           ; Drop ONERR return address.
  1323.        RET               ;
  1324.  
  1325. ; -----------------------------------
  1326. ; Return from BASIC Line Syntax Check
  1327. ; -----------------------------------
  1328. ; This routine is returned to when a BASIC line has been syntax checked.
  1329.  
  1330. L02BA:  BIT  7,(IY+$00)   ; Test ERR_NR.
  1331.        JR   NZ,L02C1     ; Jump ahead if no error.
  1332.  
  1333.        RET               ; Simply return if an error.
  1334.  
  1335. ;The syntax check was successful, so now proceed to parse the line for insertion or execution
  1336.  
  1337. L02C1:  LD   HL,($5C59)   ; ELINE. Point to start of editing area.
  1338.        LD   ($5C5D),HL   ; Store in CH_ADD.
  1339.        RST  28H          ;
  1340.        DEFW E_LINE_NO    ; $19FB. Call E_LINE_NO in ROM 1 to read the line number into editing area.
  1341.        LD   A,B          ;
  1342.        OR   C            ;
  1343.        JP   NZ,L03F7     ; Jump ahead if there was a line number.
  1344.  
  1345. ; --------------------------------------
  1346. ; Parse a BASIC Line with No Line Number
  1347. ; --------------------------------------
  1348.  
  1349.        RST  18H          ; Get character.
  1350.        CP   $0D          ; End of the line reached, i.e. no BASIC statement?
  1351.        RET  Z            ; Return if so.
  1352.  
  1353.        CALL L21EF        ; Clear screen if it requires it.
  1354.  
  1355.        BIT  6,(IY+$02)   ; TVFLAG. Clear lower screen?
  1356.        JR   NZ,L02DF     ; Jump ahead if no need to clear lower screen.
  1357.  
  1358.        RST  28H          ;
  1359.        DEFW CLS_LOWER    ; $0D6E. Clear the lower screen.
  1360.  
  1361. L02DF:  RES  6,(IY+$02)   ; TVFLAG. Signal to clear lower screen.
  1362.  
  1363.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  1364.  
  1365.        LD   HL,$EC0D     ; Editor flags.
  1366.        BIT  6,(HL)       ; Using lower screen area for editing?
  1367.        JR   NZ,L02F4     ; Jump ahead if so.
  1368.  
  1369.        INC  HL           ;
  1370.        LD   A,(HL)       ; Fetch the mode.
  1371.        CP   $00          ; In Edit Menu mode?
  1372.        CALL Z,L3881      ; If so then clear lower editing area display.
  1373.  
  1374. L02F4:  CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  1375.  
  1376.        LD   HL,$5C3C     ; TVFLAG.
  1377.        RES  3,(HL)       ; Signal mode has not changed.
  1378.  
  1379.        LD   A,$19        ; 25.
  1380.        SUB  (IY+$4F)     ; S_POSN+1. Subtract the current print row position.
  1381.        LD   ($5C8C),A    ; SCR_CT. Set the number of scrolls.
  1382.  
  1383.        SET  7,(IY+$01)   ; FLAGS. Not syntax checking.
  1384.  
  1385.        LD   (IY+$0A),$01 ; NSPPC. Set line to be jumped to as line 1.
  1386.  
  1387.        LD   HL,$3E00     ; The end of GO SUB stack marker.
  1388.        PUSH HL           ; Place it on the stack.
  1389.  
  1390.        LD   HL,ONERR     ; $5B1D. The return address should an error occur.
  1391.        PUSH HL           ; Place it on the stack.
  1392.  
  1393.        LD   ($5C3D),SP   ; ERR_SP. Store error routine address.
  1394.  
  1395.        LD   HL,L0321     ; Address of error handler routine in ROM 0.
  1396.        LD   (SYNRET),HL  ; $5B8B. Store it in SYNRET.
  1397.  
  1398.        JP   L1838        ; Jump ahead to the main parser routine to execute the line.
  1399.  
  1400.  
  1401. ; ===============================
  1402. ; ERROR HANDLER ROUTINES - PART 3
  1403. ; ===============================
  1404.  
  1405. ; ---------------------
  1406. ; Error Handler Routine
  1407. ; ---------------------
  1408.  
  1409. L0321:  LD   SP,($5CB2)   ; RAMTOP.
  1410.        INC  SP           ; Reset SP to top of memory map.
  1411.        LD   HL,TSTACK    ; $5BFF.
  1412.        LD   (OLDSP),HL   ; $5B81.
  1413.  
  1414.        HALT              ; Trap error conditions where interrupts are disabled.
  1415.  
  1416.        RES  5,(IY+$01)   ; FLAGS. Signal ready for a new key press.
  1417.        LD   HL,FLAGS3    ; $5B66.
  1418.        BIT  2,(HL)       ; Editing RAM disk catalogue?
  1419.        JR   Z,L034A      ; Jump if not.
  1420.  
  1421.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  1422.  
  1423.        LD   IX,(SFNEXT)  ; $5B83.
  1424.        LD   BC,$0014     ; Catalogue entry size.
  1425.        ADD  IX,BC        ; Remove last entry.
  1426.        CALL L1D56        ; Update catalogue entry (leaves logical RAM bank 4 paged in)
  1427.  
  1428.        CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  1429.  
  1430. ;Print error code held in ERR_NR
  1431.  
  1432. L034A:  LD   A,($5C3A)    ; Fetch error code from ERR_NR.
  1433.        INC  A            ; Increment error code.
  1434.  
  1435. L034E:  PUSH AF           ; Save the error code.
  1436.  
  1437.        LD   HL,$0000     ;
  1438.        LD   (IY+$37),H   ; Clear ATTR_T.
  1439.        LD   (IY+$26),H   ; Clear STRLEN.
  1440.        LD   ($5C0B),HL   ; Clear DEFADD.
  1441.  
  1442.        LD   HL,$0001     ;
  1443.        LD   ($5C16),HL   ; STRMS+$0006. Restore channel 'K' stream data.
  1444.  
  1445.        RST  28H          ;
  1446.        DEFW SET_MIN      ; $16B0. Clears editing area and areas after it.
  1447.        RES  5,(IY+$37)   ; FLAGX. Signal not INPUT mode.
  1448.  
  1449.        RST  28H          ;
  1450.        DEFW CLS_LOWER    ; $0D6E. Clear lower editing screen.
  1451.        SET  5,(IY+$02)   ; TVFLAG. Indicate lower screen does not require clearing.
  1452.  
  1453.        POP  AF           ; Retrieve error code.
  1454.        LD   B,A          ; Store error code in B.
  1455.        CP   $0A          ; Is it a numeric error code (1-9)?
  1456.        JR   C,L037F      ; If so jump ahead to print it.
  1457.  
  1458.        CP   $1D          ; Is it one of the standard errors (A-R)?
  1459.        JR   C,L037D      ; If so jump ahead to add 7 and print.
  1460.  
  1461.        ADD  A,$14        ; Otherwise add 20 to create code for lower case letters.
  1462.        JR   L037F        ; and jump ahead to print.
  1463.                          ; [Could have saved 2 bytes by using ADD A,$0C instead
  1464.                          ; of these two instructions]
  1465.  
  1466. L037D:  ADD  A,$07        ; Increase code to point to upper case letters.
  1467.  
  1468. L037F:  RST  28H          ;
  1469.        DEFW OUT_CODE     ; $15EF. Print the character held in the A register.
  1470.  
  1471.        LD   A,$20        ; Print a space.
  1472.        RST  10H          ;
  1473.        LD   A,B          ; Retrieve the error code.
  1474.        CP   $1D          ; Is it one of the standard errors (A-R)?
  1475.        JR   C,L039C      ; Jump if an standard error message (A-R).
  1476.  
  1477. ;Print a new error message
  1478.  
  1479. ; [Note that there is no check to range check the error code value and therefore whether a message exists for it.
  1480. ; Poking directly to system variable ERR_NR with an invalid code (43 or above) will more than likely cause a crash]
  1481.  
  1482.        SUB  $1D          ; A=Code $00 - $0E.
  1483.        LD   B,$00        ;
  1484.        LD   C,A          ; Pass code to BC.
  1485.        LD   HL,L046C     ; Error message vector table.
  1486.        ADD  HL,BC        ;
  1487.        ADD  HL,BC        ; Find address in error message vector table.
  1488.  
  1489.        LD   E,(HL)       ;
  1490.        INC  HL           ;
  1491.        LD   D,(HL)       ; DE=Address of message to print.
  1492.  
  1493.        CALL L057D        ; Print error message.
  1494.        JR   L03A2        ; Jump ahead.
  1495.  
  1496. ;Print a standard error message.
  1497.  
  1498. L039C:  LD   DE,ERROR_MSGS ; $1391. Position of the error messages in ROM 1.
  1499.        RST  28H          ; A holds the error code.
  1500.        DEFW PO_MSG       ; $0C0A. Call message printing routine.
  1501.  
  1502. ;Continue to print the line and statement number
  1503.  
  1504. L03A2:  XOR  A            ; Select the first message ", " (a 'comma' and a 'space').
  1505.        LD   DE,MESSAGES-1 ; $1536. Message base address in ROM 1.
  1506.        RST  28H          ;
  1507.        DEFW PO_MSG       ; Print a comma followed by a space.
  1508.  
  1509.        LD   BC,($5C45)   ; PPC. Fetch current line number.
  1510.        RST  28H          ;
  1511.        DEFW OUT_NUM_1    ; $1A1B. Print the line number.
  1512.  
  1513.        LD   A,$3A        ; Print ':'.
  1514.        RST  10H          ;
  1515.  
  1516.        LD   C,(IY+$0D)   ; SUBPPC. Fetch current statement number.
  1517.        LD   B,$00        ;
  1518.        RST  28H          ;
  1519.        DEFW OUT_NUM_1    ; $1A1B. Print the statement number.
  1520.  
  1521.        RST  28H          ;
  1522.        DEFW CLEAR_SP     ; $1097. Clear editing and workspace areas.
  1523.  
  1524.        LD   A,($5C3A)    ; ERR_NR. Fetch the error code.
  1525.        INC  A
  1526.        JR   Z,L03DF      ; Jump ahead for "0 OK".
  1527.  
  1528.        CP   $09          ;
  1529.        JR   Z,L03CC      ; Jump for "A Invalid argument", thereby advancing to the next statement.
  1530.  
  1531.        CP   $15          ;
  1532.        JR   NZ,L03CF     ; Jump unless "M Ramtop no good".
  1533.  
  1534. L03CC:  INC  (IY+$0D)     ; SUBPPC. Advance to the next statement.
  1535.  
  1536. L03CF:  LD   BC,$0003     ;
  1537.        LD   DE,$5C70     ; OSPPC. Continue statement number.
  1538.        LD   HL,$5C44     ; NSPPC. Next statement number.
  1539.        BIT  7,(HL)       ; Is there a statement number?
  1540.        JR   Z,L03DD      ; Jump if so.
  1541.  
  1542.        ADD  HL,BC        ; HL=SUBPPC. The current statement number.
  1543.  
  1544. L03DD:  LDDR              ; Copy SUBPPC and PPC to OSPPC and OLDPPC, for use by CONTINUE.
  1545.  
  1546. L03DF:  LD   (IY+$0A),$FF ; NSPPC. Signal no current statement number.
  1547.        RES  3,(IY+$01)   ; FLAGS. Select K-Mode.
  1548.        LD   HL,FLAGS3    ; $5B66.
  1549.        RES  0,(HL)       ; Select 128 Editor mode.
  1550.        JP   L25CB        ; Jump ahead to return control to the Editor.
  1551.  
  1552. ; ---------------------------------------------
  1553. ; Error Handler Routine When Parsing BASIC Line
  1554. ; ---------------------------------------------
  1555.  
  1556. L03EF:  LD   A,$10        ; Error code 'G - No room for line'.
  1557.        LD   BC,$0000     ;
  1558.        JP   L034E        ; Jump to print the error code.
  1559.  
  1560.  
  1561. ; ===================================
  1562. ; COMMAND EXECUTION ROUTINES - PART 2
  1563. ; ===================================
  1564.  
  1565. ; -------------------------------------
  1566. ; Parse a BASIC Line with a Line Number
  1567. ; -------------------------------------
  1568. ; This routine handles executing a BASIC line with a line number specified, or just a line number
  1569. ; specified on its own, i.e. delete the line.
  1570.  
  1571. L03F7:  LD   ($5C49),BC   ; E_PPC. Store the line as the current line number with the program cursor.
  1572.  
  1573.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  1574.  
  1575.        LD   A,B          ; [This test could have been performed before paging in bank 7 and hence could have benefited from a slight speed improvement.
  1576.        OR   C            ; The test is redundant since BC holds a non-zero line number]
  1577.        JR   Z,L040A      ; Jump if no line number.
  1578.  
  1579.        LD   ($5C49),BC   ; E_PPC. Current edit line number. [Redundant instruction - Line number has already been stored]
  1580.        LD   ($EC08),BC   ; Temporary E_PPC used by BASIC Editor.
  1581.  
  1582. L040A:  CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  1583.  
  1584.        LD   HL,($5C5D)   ; CH_ADD. Point to the next character in the BASIC line.
  1585.        EX   DE,HL        ;
  1586.  
  1587.        LD   HL,L03EF     ; Address of error handler routine should there be no room for the line.
  1588.        PUSH HL           ; Stack it.
  1589.  
  1590.        LD   HL,($5C61)   ; WORKSP.
  1591.        SCF               ;
  1592.        SBC  HL,DE        ; HL=Length of BASIC line.
  1593.        PUSH HL           ; Stack it.
  1594.  
  1595.        LD   H,B          ;
  1596.        LD   L,C          ; Transfer edit line number to HL.
  1597.        RST  28H          ;
  1598.        DEFW LINE_ADDR    ; $196E. Returns address of the line in HL.
  1599.        JR   NZ,L0429     ; Jump if the line does not exist.
  1600.  
  1601. ;The line already exists so delete it
  1602.  
  1603.        RST  28H          ;
  1604.        DEFW NEXT_ONE     ; $19B8. Find the address of the next line.
  1605.        RST  28H          ;
  1606.        DEFW RECLAIM_2    ; $19E8. Delete the line.
  1607.  
  1608. L0429:  POP  BC           ; BC=Length of the BASIC line.
  1609.        LD   A,C          ;
  1610.        DEC  A            ; Is it 1, i.e. just an 'Enter' character, and hence only
  1611.        OR   B            ; a line number was entered?
  1612.        JR   NZ,L0442     ; Jump if there is a BASIC statement.
  1613.  
  1614. ;Just a line number entered. The requested line has already been deleted so move the program cursor to the next line
  1615.  
  1616.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  1617.        PUSH HL           ; Save the address of the line.
  1618.  
  1619.        LD   HL,($5C49)   ; E_PPC. Fetch current edit line number.
  1620.        CALL L334A        ; Find closest line number (or $0000 if no line).
  1621.        LD   ($5C49),HL   ; E_PPC. Store current edit line number. Effectively refresh E_PPC.
  1622.  
  1623.        POP  HL           ; HL=Address of the line.
  1624.        CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  1625.        JR   L046A        ; Jump ahead to exit.
  1626.  
  1627. L0442:  PUSH BC           ; BC=Length of the BASIC line. Stack it.
  1628.  
  1629.        INC  BC           ;
  1630.        INC  BC           ;
  1631.        INC  BC           ;
  1632.        INC  BC           ; BC=BC+4. Allow for line number and length bytes.
  1633.  
  1634.        DEC  HL           ; Point to before the current line, i.e. the location to insert bytes at.
  1635.  
  1636.        LD   DE,($5C53)   ; PROG. Get start address of the BASIC program.
  1637.        PUSH DE           ; Stack it.
  1638.  
  1639.        RST  28H          ;
  1640.        DEFW MAKE_ROOM    ; $1655. Insert BC spaces at address HL.
  1641.  
  1642.        POP HL            ; HL=Start address of BASIC program.
  1643.        LD   ($5C53),HL   ; PROG. Save start address of BASIC program.
  1644.  
  1645.        POP  BC           ; BC=Length of the BASIC line.
  1646.        PUSH BC           ;
  1647.  
  1648.        INC  DE           ; Point to the first location of the newly created space.
  1649.        LD   HL,($5C61)   ; WORKSP. Address of end of the BASIC line in the workspace.
  1650.        DEC  HL           ;
  1651.        DEC  HL           ; Skip over the newline and terminator bytes.
  1652.        LDDR              ; Copy the BASIC line from the workspace into the program area.
  1653.        LD   HL,($5C49)   ; E_PPC. Current edit line number.
  1654.        EX   DE,HL        ;
  1655.  
  1656.        POP  BC           ; BC=Length of BASIC line.
  1657.        LD   (HL),B       ; Store the line length.
  1658.        DEC  HL           ;
  1659.        LD   (HL),C       ;
  1660.        DEC  HL           ;
  1661.        LD   (HL),E       ; DE=line number.
  1662.        DEC  HL           ;
  1663.        LD   (HL),D       ; Store the line number.
  1664.  
  1665. L046A:  POP  AF           ; Drop item (address of error handler routine).
  1666.        RET               ; Exit with HL=Address of the line.
  1667.  
  1668.  
  1669. ; ===============================
  1670. ; ERROR HANDLER ROUTINES - PART 4
  1671. ; ===============================
  1672.  
  1673. ; ------------------------------
  1674. ; New Error Message Vector Table
  1675. ; ------------------------------
  1676. ; Pointers into the new error message table.
  1677.  
  1678. L046C:  DEFW L048C        ; Error report 'a'.
  1679.        DEFW L0497        ; Error report 'b'.
  1680.        DEFW L04A6        ; Error report 'c'.
  1681.        DEFW L04B0        ; Error report 'd'.
  1682.        DEFW L04C1        ; Error report 'e'.
  1683.        DEFW L04D4        ; Error report 'f'.
  1684.        DEFW L04E0        ; Error report 'g'.
  1685.        DEFW L04E0        ; Error report 'h'.
  1686.        DEFW L04F3        ; Error report 'i'.
  1687.        DEFW L0501        ; Error report 'j'.
  1688.        DEFW L0512        ; Error report 'k'.
  1689.        DEFW L0523        ; Error report 'l'
  1690.        DEFW L0531        ; Error report 'm'.
  1691.        DEFW L0542        ; Error report 'n'.
  1692.        DEFW L054E        ; Error report 'o'.
  1693.        DEFW L0561        ; Error report 'p'.
  1694.  
  1695. ; -----------------------
  1696. ; New Error Message Table
  1697. ; -----------------------
  1698.  
  1699. L048C           DC "MERGE error"                ;DEFM "MERGE erro"                  ; Report 'a'.
  1700.                                                 ;DB 'r'+$80
  1701. L0497           DC "Wrong file type"            ;DEFM "Wrong file typ"              ; Report 'b'.
  1702.                                                 ;DB 'e'+$80
  1703. L04A6           DC "CODE error"                 ;DEFM "CODE erro"                   ; Report 'c'.
  1704.                                                 ;DB 'r'+$80
  1705. L04B0           DC "Too many brackets"          ;DEFM "Too many bracket"            ; Report 'd'.
  1706.                                                 ;DB 's'+$80
  1707. L04C1           DC "File already exists"        ;DEFM "File already exist"          ; Report 'e'.
  1708.                                                 ;DB 's'+$80
  1709. L04D4           DC "Invalid name"               ;DEFM "Invalid nam"                 ; Report 'f'.
  1710.                                                 ;DB 'e'+$80
  1711. L04E0           DC "File does not exist"        ;DEFM "File does not exis"          ; Report 'g' & 'h'.
  1712.                                                 ;DB 't'+$80
  1713. L04F3           DC "Invalid device"             ;DEFM "Invalid devic"               ; Report 'i'.
  1714.                                                 ;DB 'e'+$80
  1715. L0501           DC "Invalid baud rate"          ;DEFM "Invalid baud rat"            ; Report 'j'.
  1716.                                                 ;DB 'e'+$80
  1717. L0512           DC "Invalid note name"          ;DEFM "Invalid note nam"            ; Report 'k'.
  1718.                                                 ;DB 'e'+$80
  1719. L0523           DC "Number too big"             ;DEFM "Number too bi"               ; Report 'l'.
  1720.                                                 ;DB 'g'+$80
  1721. L0531           DC "Note out of range"          ;DEFM "Note out of rang"            ; Report 'm'.
  1722.                                                 ;DB 'e'+$80
  1723. L0542           DC "Out of range"               ;DEFM "Out of rang"                 ; Report 'n'.
  1724.                                                 ;DB 'e'+$80
  1725. L054E           DC "Too many tied notes"        ;DEFM "Too many tied note"          ; Report 'o'.
  1726.                                                 ;DB 's'+$80
  1727. L0561           DB $7F                          ; '(c)'.
  1728.                 DC " 1986 Sinclair Research Ltd";DEFM " 1986 Sinclair Research Lt"  ; Copyright. [There should have been an error report "p Bad parameterr" here as there was in the Spanish 128,
  1729.                                                 ;DB 'd'+$80                       ; or the error code byte at $232F (ROM 0) should have been $19 for "Q Parameter error"]
  1730.  
  1731. ; -------------
  1732. ; Print Message
  1733. ; -------------
  1734. ; Print a message which is terminated by having bit 7 set, pointed at by DE.
  1735.  
  1736. L057D:  LD   A,(DE)       ; Fetch next byte.
  1737.        AND  $7F          ; Mask off top bit.
  1738.        PUSH DE           ; Save address of current message byte.
  1739.        RST  10H          ; Print character.
  1740.        POP  DE           ; Restore message byte pointer.
  1741.        LD   A,(DE)       ;
  1742.        INC  DE           ;
  1743.        ADD  A,A          ; Carry flag will be set if byte is $FF.
  1744.        JR   NC,L057D     ; Else print next character.
  1745.  
  1746.        RET               ;
  1747.  
  1748. ; ================================
  1749. ; INITIALISATION ROUTINES - PART 3
  1750. ; ================================
  1751.  
  1752. ; ---------------------------------
  1753. ; The 'Initial Channel Information'
  1754. ; ---------------------------------
  1755. ; Initially there are four channels ('K', 'S', 'R', & 'P') for communicating with the 'keyboard', 'screen', 'work space' and 'printer'.
  1756. ; For each channel the output routine address comes before the input routine address and the channel's code.
  1757. ; This table is almost identical to that in ROM 1 at $15AF but with changes to the channel P routines to use the RS232 port
  1758. ; instead of the ZX Printer.
  1759. ; Used at $01DD (ROM 0).
  1760.  
  1761. L0589:  DEFW PRINT_OUT    ; $09F4 - K channel output routine.
  1762.         DEFW KEY_INPUT    ; $10A8 - K channel input routine.
  1763.         DB 'K'          ; $4B   - Channel identifier 'K'.
  1764.         DEFW PRINT_OUT    ; $09F4 - S channel output routine.
  1765.         DEFW REPORT_J     ; $15C4 - S channel input routine.
  1766.         DB 'S'          ; $53   - Channel identifier 'S'.
  1767.         DEFW ADD_CHAR     ; $0F81 - R channel output routine.
  1768.         DEFW REPORT_J     ; $15C4 - R channel input routine.
  1769.         DB 'R'          ; $52   - Channel identifier 'R'.
  1770.         DEFW POUT         ; $5B34 - P Channel output routine.
  1771.         DEFW PIN          ; $5B2F - P Channel input routine.
  1772.         DB 'P'          ; $50   - Channel identifier 'P'.
  1773.         DB $80          ; End marker.
  1774.  
  1775. ; -------------------------
  1776. ; The 'Initial Stream Data'
  1777. ; -------------------------
  1778. ; Initially there are seven streams - $FD to $03.
  1779. ; This table is identical to that in ROM 1 at $15C6.
  1780. ; Used at $0226 (ROM 0).
  1781.  
  1782. L059E:  DB $01, $00     ; Stream $FD leads to channel 'K'.
  1783.         DB $06, $00     ; Stream $FE leads to channel 'S'.
  1784.         DB $0B, $00     ; Stream $FF leads to channel 'R'.
  1785.         DB $01, $00     ; Stream $00 leads to channel 'K'.
  1786.         DB $01, $00     ; Stream $01 leads to channel 'K'.
  1787.         DB $06, $00     ; Stream $02 leads to channel 'S'.
  1788.         DB $10, $00     ; Stream $03 leads to channel 'P'.
  1789.  
  1790.  
  1791. ; ===============================
  1792. ; ERROR HANDLER ROUTINES - PART 5
  1793. ; ===============================
  1794.  
  1795. ; --------------------
  1796. ; Produce Error Report
  1797. ; --------------------
  1798.  
  1799. L05AC:  POP  HL           ; Point to the error byte.
  1800.         LD   BC,$7FFD     ;
  1801.         XOR  A            ; ROM 0, Screen 0, Bank 0, 128 mode.
  1802.         DI                ; Ensure interrupts disable whilst paging.
  1803.         LD   (BANK_M),A   ; $5B5C. Store new state in BANK_M.
  1804.         OUT  (C),A        ; Switch to ROM 0.
  1805.         EI                ;
  1806.  
  1807.         LD   SP,($5C3D)   ; Restore SP from ERR_SP.
  1808.         LD   A,(HL)       ; Fetch the error number.
  1809.         LD   (RAMERR),A   ; $5B5E. Store the error number.
  1810.         INC  A            ;
  1811.         CP   $1E          ; [*BUG* - This should be $1D. As such, error code 'a' will be diverted to ROM 1 for handling. Credit: Paul Farrow]
  1812.         JR   NC,L05C8     ; Jump if not a standard error code.
  1813.  
  1814. ;Handle a standard error code
  1815.  
  1816.         RST  28H          ;
  1817.         DEFW RAMRST       ; $5B5D. Call the error handler routine in ROM 1.
  1818.  
  1819. ;Handle a new error code
  1820.  
  1821. L05C8:  DEC  A            ;
  1822.         LD   (IY+$00),A   ; Store in ERR_NR.
  1823.         LD   HL,($5C5D)   ; CH_ADD.
  1824.         LD   ($5C5F),HL   ; X_PTR. Set up the address of the character after the '?' marker.
  1825.  
  1826.         RST  28H          ;
  1827.         DEFW SET_STK      ; $16C5. Set the calculator stack.
  1828.         RET               ; Return to the error routine.
  1829.  
  1830. ; ----------------------------
  1831. ; Check for BREAK into Program
  1832. ; ----------------------------
  1833.  
  1834. L05D6:  LD   A,$7F        ; Read keyboard row B - SPACE.
  1835.         IN   A,($FE)      ;
  1836.         RRA               ; Extract the SPACE key.
  1837.         RET  C            ; Return if SPACE not pressed.
  1838.  
  1839.         LD   A,$FE        ; Read keyboard row CAPS SHIFT - V.
  1840.         IN   A,($FE)      ;
  1841.         RRA               ; Extract the CAPS SHIFT key.
  1842.         RET  C            ; Return if CAPS SHIFT not pressed.
  1843.  
  1844.         CALL L05AC        ; Produce an error.
  1845.         DB $14          ; "L Break into program"
  1846.  
  1847.  
  1848. ; ======================
  1849. ; RS232 PRINTER ROUTINES
  1850. ; ======================
  1851.  
  1852. ; ------------------------------
  1853. ; RS232 Channel Handler Routines
  1854. ; ------------------------------
  1855. ; This routine handles input and output RS232 requested. It is similar to the
  1856. ; routine in the ZX Interface 1 ROM at $0D5A, but in that ROM the routine is only used
  1857. ; for input.
  1858.  
  1859. L05E6:  EI                ; Enabled interrupts.
  1860.         EX   AF,AF'       ; Save AF registers.
  1861.        LD   DE,POUT2     ; $5B4A. Address of the RS232 exit routine held in RAM.
  1862.        PUSH DE           ; Stack it.
  1863.  
  1864.        RES  3,(IY+$02)   ; TVFLAG. Indicate not automatic listing.
  1865.        PUSH HL           ; Save the input/output routine address.
  1866.  
  1867.        LD   HL,($5C3D)   ; Fetch location of error handler routine from ERR_SP.
  1868.        LD   E,(HL)       ;
  1869.        INC  HL           ;
  1870.        LD   D,(HL)       ; DE=Address of error handler routine.
  1871.        AND  A            ;
  1872.        LD   HL,ED_ERROR  ; $107F in ROM 1.
  1873.        SBC  HL,DE        ;
  1874.        JR   NZ,L0637     ; Jump if error handler address is different, i.e. due to INKEY$# or PRINT#.
  1875.  
  1876. ; Handle INPUT#
  1877. ; -------------
  1878.  
  1879.        POP  HL           ; Retrieve the input/output routine address.
  1880.        LD   SP,($5C3D)   ; ERR_SP.
  1881.        POP  DE           ; Discard the error handler routine address.
  1882.        POP  DE           ; Fetch the original address of ERR_SP (this was stacked at the beginning of the INPUT routine in ROM 1).
  1883.        LD   ($5C3D),DE   ; ERR_SP.
  1884.  
  1885. L060A:  PUSH HL           ; Save the input/output routine address.
  1886.        LD   DE,L0610     ; Address to return to.
  1887.        PUSH DE           ; Stack the address.
  1888.        JP   (HL)         ; Jump to the RS232 input/output routine.
  1889.  
  1890. ;Return here from the input/output routine
  1891.  
  1892. L0610:  JR   C,L061B      ; Jump if a character was received.
  1893.        JR   Z,L0618      ; Jump if a character was not received.
  1894.  
  1895. L0614:  CALL L05AC        ; Produce an error "8 End of file".
  1896.        DB $07          ;
  1897.  
  1898. ;A character was not received
  1899.  
  1900. L0618:  POP  HL           ; Retrieve the input routine address.
  1901.        JR   L060A        ; Jump back to await another character.
  1902.  
  1903. ;A character was received
  1904.  
  1905. L061B:  CP   $0D          ; Is it a carriage return?
  1906.        JR   Z,L062D      ; Jump ahead if so.
  1907.  
  1908.        LD   HL,(RETADDR) ; $5B5A. Fetch the return address.
  1909.        PUSH HL           ;
  1910.  
  1911.        RST  28H          ;
  1912.        DEFW ADD_CHAR+4   ; $0F85. Insert the character into the INPUT line.
  1913.  
  1914.        POP  HL           ;
  1915.        LD   (RETADDR),HL ; $5B5A. Restore the return address.
  1916.  
  1917.        POP  HL           ; Retrieve the input routine address.
  1918.        JR   L060A        ; Jump back to await another character.
  1919.  
  1920. ;Enter was received so end reading the stream
  1921.  
  1922. L062D:  POP  HL           ; Discard the input routine address.
  1923.        LD   A,(BANK_M)   ; $5B5C. Fetch current paging configuration.
  1924.        OR   $10          ; Select ROM 1.
  1925.        PUSH AF           ; Stack the required paging configuration.
  1926.        JP   POUT2        ; $5B4A. Exit.
  1927.  
  1928. ; Handle INKEY$# and PRINT#
  1929. ; -------------------------
  1930.  
  1931. L0637:  POP  HL           ; Retrieve the input/output routine address.
  1932.        LD   DE,L063D     ;
  1933.        PUSH DE           ; Stack the return address.
  1934.        JP   (HL)         ; Jump to input or output routine.
  1935.  
  1936. ;Return here from the input/output routine. When returning from the output routine, either the carry or zero flags should always
  1937. ;be set to avoid the false generation of error report "8 End of file" [though this is not always the case - see bugs starting at $086C (ROM 0)].
  1938.  
  1939. L063D:  RET  C            ; Return if a character was received.
  1940.        RET  Z            ; Return if a character was not received or was written.
  1941.  
  1942.        JR   L0614        ; Produce error report "8 End of file".
  1943.  
  1944. ; --------------
  1945. ; FORMAT Routine
  1946. ; --------------
  1947. ; The format command sets the RS232 baud rate, e.g. FORMAT "P"; 9600.
  1948. ; It attempts to match against one of the supported baud rates, or uses the next
  1949. ; higher baud rate if a non-standard value is requested. The maximum baud rate supported
  1950. ; is 9600, and this is used for any rates specified that are higher than this.
  1951.  
  1952. L0641:  RST  28H          ; [Could just do RST $18]
  1953.        DEFW GET_CHAR     ; $0018.
  1954.        RST  28H          ; Get an expression.
  1955.        DEFW EXPT_EXP     ; $1C8C.
  1956.        BIT  7,(IY+$01)   ; FLAGS.
  1957.        JR   Z,L0661      ; Jump ahead if syntax checking.
  1958.  
  1959.        RST  28H          ;
  1960.        DEFW STK_FETCH    ; $2BF1. Fetch the expression.
  1961.        LD   A,C          ;
  1962.        DEC  A            ;
  1963.        OR   B            ;
  1964.        JR   Z,L0659      ; Jump ahead if string is 1 character long.
  1965.  
  1966.        CALL L05AC        ; Produce error report.
  1967.        DB $24          ; "i Invalid device".
  1968.  
  1969. L0659:  LD   A,(DE)       ; Get character.
  1970.        AND  $DF          ; Convert to upper case.
  1971.        CP   'P'          ; $50. Is it channel 'P'?
  1972.        JP   NZ,L1912     ; Jump if not to produce error report "C Nonsense in BASIC".
  1973.  
  1974. L0661:  LD   HL,($5C5D)   ; CH_ADD. Next character to be interpreted.
  1975.        LD   A,(HL)       ;
  1976.        CP   $3B          ; Next character must be ';'.
  1977.         JP   NZ,L1912     ; Jump if not to produce error report "C Nonsense in BASIC".
  1978.  
  1979.         RST  28H          ; Skip past the ';' character.
  1980.         DEFW NEXT_CHAR    ; $0020. [Could just do RST $20]
  1981.         RST  28H          ; Get a numeric expression from the line.
  1982.         DEFW EXPT_1NUM    ; $1C82.
  1983.         BIT  7,(IY+$01)   ; FLAGS. Checking syntax mode?
  1984.         JR   Z,L067D      ; Jump ahead if so.
  1985.  
  1986.         RST  28H          ; Get the result as an integer.
  1987.         DEFW FIND_INT2    ; $1E99.
  1988.         LD   (HD_00),BC   ; $5B71. Store the result temporarily for use later.
  1989.  
  1990. L067D:  RST  28H          ; [Could just do RST $18]
  1991.         DEFW GET_CHAR     ; $0018. Get the next character in the BASIC line.
  1992.         CP   $0D          ; It should be ENTER.
  1993.         JR   Z,L0689      ; Jump ahead if it is.
  1994.  
  1995.         CP   ':'          ; $3A. Or the character is allowed to be ':'.
  1996.         JP   NZ,L1912     ; Jump if not to produce error report "C Nonsense in BASIC".
  1997.  
  1998. L0689:  CALL L18A1        ; Check for end of line.
  1999.         LD   BC,(HD_00)   ; $5B71. Get the baud rate saved earlier.
  2000.         LD   A,B          ; Is it zero?
  2001.         OR   C            ;
  2002.         JR   NZ,L0698     ; Jump if not, i.e. a numeric value was specified.
  2003.  
  2004.         CALL L05AC        ; Produce error report.
  2005.         DB $25          ; "j invalid baud rate"
  2006.  
  2007. ;Lookup the timing constant to use for the specified baud rate
  2008.  
  2009. L0698:  LD   HL,L06B8     ; Table of supported baud rates.
  2010.  
  2011. L069B:  LD   E,(HL)       ;
  2012.         INC  HL           ;
  2013.         LD   D,(HL)       ;
  2014.         INC  HL           ;
  2015.         EX   DE,HL        ; HL=Supported baud rate value.
  2016.         LD   A,H          ;
  2017.         CP   $25          ; Reached the last baud rate value in the table?
  2018.         JR   NC,L06AF     ; Jump is so to use a default baud rate of 9600.
  2019.  
  2020.         AND  A            ;
  2021.         SBC  HL,BC        ; Table entry matches or is higher than requested baud rate?
  2022.         JR   NC,L06AF     ; Jump ahead if so to use this baud rate.
  2023.  
  2024.         EX   DE,HL        ;
  2025.         INC  HL           ; Skip past the timing constant value
  2026.         INC  HL           ; for this baud rate entry.
  2027.         JR   L069B        ;
  2028.  
  2029. ;The baud rate has been matched
  2030.  
  2031. L06AF:  EX   DE,HL        ; HL points to timing value for the baud rate.
  2032.         LD   E,(HL)       ;
  2033.         INC  HL           ;
  2034.         LD   D,(HL)       ; DE=Timing value for the baud rate.
  2035.         LD   (BAUD),DE    ; $5B71. Store new value in system variable BAUD.
  2036.         RET               ;
  2037.  
  2038. ; ---------------
  2039. ; Baud Rate Table
  2040. ; ---------------
  2041. ; Consists of entries of baud rate value followed by timing constant to use in the RS232 routines.
  2042.  
  2043. L06B8:  DEFW $0032, $0AA5  ; Baud=50.
  2044.         DEFW $006E, $04D4  ; Baud=110.
  2045.         DEFW $012C, $01C3  ; Baud=300.
  2046.         DEFW $0258, $00E0  ; Baud=600.
  2047.         DEFW $04B0, $006E  ; Baud=1200.
  2048.         DEFW $0960, $0036  ; Baud=2400.
  2049.         DEFW $12C0, $0019  ; Baud=4800.
  2050.         DEFW $2580, $000B  ; Baud=9600.
  2051.  
  2052. ; -------------------
  2053. ; RS232 Input Routine
  2054. ; -------------------
  2055. ; Exit: Carry flag set if a byte was read with the byte in A. Carry flag reset upon error.
  2056.  
  2057. L06D8:  LD   HL,SERFL     ; $5B61. SERFL holds second char that can be received
  2058.         LD   A,(HL)       ; Is the second-character received flag set?
  2059.         AND  A            ; i.e. have we already received data?
  2060.         JR   Z,L06E5      ; Jump ahead if not.
  2061.  
  2062.         LD   (HL),$00     ; Otherwise clear the flag
  2063.         INC  HL           ;
  2064.         LD   A,(HL)       ; and return the data which we received earlier.
  2065.         SCF               ; Set carry flag to indicate success
  2066.         RET               ;
  2067.  
  2068. ; -------------------------
  2069. ; Read Byte from RS232 Port
  2070. ; -------------------------
  2071. ; The timing of the routine is achieved using the timing constant held in system variable BAUD.
  2072. ; Exit: Carry flag set if a byte was read, or reset upon error.
  2073. ;       A=Byte read in.
  2074.  
  2075. L06E5:  CALL L05D6        ; Check the BREAK key, and produce error message if it is being pressed.
  2076.  
  2077.         DI                ; Ensure interrupts are disabled to achieve accurate timing.
  2078.  
  2079.         EXX               ;
  2080.  
  2081.         LD   DE,(BAUD)    ; $5B71. Fetch the baud rate timing constant.
  2082.         LD   HL,(BAUD)    ; $5B71.
  2083.         SRL  H            ;
  2084.         RR   L            ; HL=BAUD/2. So that will sync to half way point in each bit.
  2085.  
  2086.         OR   A            ; [Redundant byte]
  2087.  
  2088.         LD   B,$FA        ; Waiting time for start bit.
  2089.         EXX               ; Save B.
  2090.         LD   C,$FD        ;
  2091.         LD   D,$FF        ;
  2092.         LD   E,$BF        ;
  2093.         LD   B,D          ;
  2094.         LD   A,$0E        ;
  2095.         OUT  (C),A        ; Selects register 14, port I/O of AY-3-8912.
  2096.  
  2097.         IN   A,(C)        ; Read the current state of the I/O lines.
  2098.         OR   $F0          ; %11110000. Default all input lines to 1.
  2099.         AND  $FB          ; %11111011. Force CTS line to 0.
  2100.         LD   B,E          ; B=$BF.
  2101.         OUT  (C),A        ; Make CTS (Clear To Send) low to indicate ready to receive.
  2102.  
  2103.         LD   H,A          ; Store status of other I/O lines.
  2104.  
  2105. ;Look for the start bit
  2106.  
  2107. L070E:  LD   B,D          ;
  2108.         IN   A,(C)        ; Read the input line.
  2109.         AND  $80          ; %10000000. Test TXD (input) line.
  2110.         JR   Z,L071E      ; Jump if START BIT found.
  2111.  
  2112. L0715:  EXX               ; Fetch timeout counter
  2113.         DEC  B            ; and decrement it.
  2114.         EXX               ; Store it.
  2115.         JR   NZ,L070E     ; Continue to wait for start bit if not timed out.
  2116.  
  2117.         XOR  A            ; Reset carry flag to indicate no byte read.
  2118.         PUSH AF           ; Save the failure flag.
  2119.         JR   L0757        ; Timed out waiting for START BIT.
  2120.  
  2121. L071E:  IN   A,(C)        ; Second test of START BIT - it should still be 0.
  2122.         AND  $80          ; Test TXD (input) line.
  2123.         JR   NZ,L0715     ; Jump back if it is no longer 0.
  2124.  
  2125.         IN   A,(C)        ; Third test of START BIT - it should still be 0.
  2126.         AND  $80          ; Test TXD (input) line.
  2127.         JR   NZ,L0715     ; Jump back if it is no longer 0.
  2128.  
  2129. ;A start bit has been found, so the 8 data bits are now read in.
  2130. ;As each bit is read in, it is shifted into the msb of A. Bit 7 of A is preloaded with a 1
  2131. ;to represent the start bit and when this is shifted into the carry flag it signifies that 8
  2132. ;data bits have been read in.
  2133.  
  2134.         EXX               ;
  2135.         LD   BC,$FFFD     ;
  2136.         LD   A,$80        ; Preload A with the START BIT. It forms a shift counter used to count
  2137.         EX   AF,AF'       ; the number of bits to read in.
  2138.  
  2139. L0731:  ADD  HL,DE        ; HL=1.5*(BAUD).
  2140.  
  2141.        NOP               ; (4) Fine tune the following delay.
  2142.        NOP               ;
  2143.        NOP               ;
  2144.        NOP               ;
  2145.  
  2146. ;BD-DELAY
  2147. L0736:  DEC  HL           ; (6) Delay for 26*BAUD.
  2148.        LD   A,H          ; (4)
  2149.        OR   L            ; (4)
  2150.        JR   NZ,L0736     ; (12) Jump back to until delay completed.
  2151.  
  2152.        IN   A,(C)        ; Read a bit.
  2153.        AND  $80          ; Test TXD (input) line.
  2154.        JP   Z,L074B      ; Jump if a 0 received.
  2155.  
  2156. ;Received one 1
  2157.  
  2158.        EX   AF,AF'       ; Fetch the bit counter.
  2159.         SCF               ; Set carry flag to indicate received a 1.
  2160.         RRA               ; Shift received bit into the byte (C->76543210->C).
  2161.         JR   C,L0754      ; Jump if START BIT has been shifted out indicating all data bits have been received.
  2162.  
  2163.         EX   AF,AF'       ; Save the bit counter.
  2164.        JP   L0731        ; Jump back to read the next bit.
  2165.  
  2166. ;Received one 0
  2167.  
  2168. L074B:  EX   AF,AF'       ; Fetch the bit counter.
  2169.         OR   A            ; Clear carry flag to indicate received a 0.
  2170.         RRA               ; Shift received bit into the byte (C->76543210->C).
  2171.         JR   C,L0754      ; Jump if START BIT has been shifted out indicating all data bits have been received.
  2172.  
  2173.         EX   AF,AF'       ; Save the bit counter.
  2174.        JP   L0731        ; Jump back to read next bit.
  2175.  
  2176. ;After looping 8 times to read the 8 data bits, the start bit in the bit counter will be shifted out
  2177. ;and hence A will contain a received byte.
  2178.  
  2179. L0754:  SCF               ; Signal success.
  2180.        PUSH AF           ; Push success flag.
  2181.        EXX
  2182.  
  2183. ;The success and failure paths converge here
  2184.  
  2185. L0757:  LD   A,H          ;
  2186.        OR   $04          ; A=%1111x1xx. Force CTS line to 1.
  2187.  
  2188.        LD   B,E          ; B=$BF.
  2189.        OUT  (C),A        ; Make CTS (Clear To Send) high to indicate not ready to receive.
  2190.        EXX
  2191.  
  2192.        LD   H,D          ;
  2193.        LD   L,E          ; HL=(BAUD).
  2194.        LD   BC,$0007     ;
  2195.        OR   A            ;
  2196.        SBC  HL,BC        ; HL=(BAUD)-7.
  2197.  
  2198. L0766:  DEC  HL           ; Delay for the stop bit.
  2199.        LD   A,H          ;
  2200.        OR   L            ;
  2201.        JR   NZ,L0766     ; Jump back until delay completed.
  2202.  
  2203.        LD   BC,$FFFD     ; HL will be $0000.
  2204.        ADD  HL,DE        ; DE=(BAUD).
  2205.        ADD  HL,DE        ;
  2206.        ADD  HL,DE        ; HL=3*(BAUD). This is how long to wait for the next start bit.
  2207.  
  2208. ;The device at the other end of the cable may send a second byte even though
  2209. ;CTS is low. So repeat the procedure to read another byte.
  2210.  
  2211. L0771:  IN   A,(C)        ; Read the input line.
  2212.        AND  $80          ; %10000000. Test TXD (input) line.
  2213.        JR   Z,L077F      ; Jump if START BIT found.
  2214.  
  2215.        DEC  HL           ; Decrement timeout counter.
  2216.        LD   A,H          ;
  2217.        OR   L            ;
  2218.        JR   NZ,L0771     ; Jump back looping for a start bit until a timeout occurs.
  2219.  
  2220. ;No second byte incoming so return status of the first byte read attempt
  2221.  
  2222.        POP  AF           ; Return status of first byte read attempt - carry flag reset for no byte received or
  2223.        EI                ; carry flag set and A holds the received byte.
  2224.        RET
  2225.  
  2226. L077F:  IN   A,(C)        ; Second test of START BIT - it should still be 0.
  2227.        AND  $80          ; Test TXD (input) line.
  2228.        JR   NZ,L0771     ; Jump back if it is no longer 0.
  2229.  
  2230.        IN   A,(C)        ; Third test of START BIT - it should still be 0.
  2231.        AND  $80          ; Test TXD (input) line.
  2232.        JR   NZ,L0771     ; Jump back if it is no longer 0.
  2233.  
  2234. ;A second byte is on its way and is received exactly as before
  2235.  
  2236.        LD   H,D          ;
  2237.        LD   L,E          ; HL=(BAUD).
  2238.        LD   BC,$0002     ;
  2239.        SRL  H            ;
  2240.        RR   L            ; HL=(BAUD)/2.
  2241.        OR   A            ;
  2242.        SBC  HL,BC        ; HL=(BAUD)/2 - 2.
  2243.  
  2244.        LD   BC,$FFFD     ;
  2245.        LD   A,$80        ; Preload A with the START BIT. It forms a shift counter used to count
  2246.        EX   AF,AF'       ; the number of bits to read in.
  2247.  
  2248. L079D:  NOP               ; Fine tune the following delay.
  2249.         NOP               ;
  2250.         NOP               ;
  2251.         NOP               ;
  2252.  
  2253.         ADD  HL,DE        ; HL=1.5*(BAUD).
  2254.  
  2255. L07A2:  DEC  HL           ; Delay for 26*(BAUD).
  2256.         LD   A,H          ;
  2257.         OR   L            ;
  2258.         JR   NZ,L07A2     ; Jump back to until delay completed.
  2259.  
  2260.         IN   A,(C)        ; Read a bit.
  2261.         AND  $80          ; Test TXD (input) line.
  2262.         JP   Z,L07B7      ; Jump if a 0 received.
  2263.  
  2264. ;Received one 1
  2265.  
  2266.         EX   AF,AF'       ; Fetch the bit counter.
  2267.        SCF               ; Set carry flag to indicate received a 1.
  2268.        RRA               ; Shift received bit into the byte (C->76543210->C).
  2269.        JR   C,L07C0      ; Jump if START BIT has been shifted out indicating all data bits have been received.
  2270.  
  2271.        EX   AF,AF'       ; Save the bit counter.
  2272.         JP   L079D        ; Jump back to read the next bit.
  2273.  
  2274. ;Received one 0
  2275.  
  2276. L07B7:  EX   AF,AF'       ; Fetch the bit counter.
  2277.        OR   A            ; Clear carry flag to indicate received a 0.
  2278.        RRA               ; Shift received bit into the byte (C->76543210->C).
  2279.        JR   C,L07C0      ; Jump if START BIT has been shifted out indicating all data bits have been received.
  2280.  
  2281.        EX   AF,AF'       ; Save the bit counter.
  2282.         JP   L079D        ; Jump back to read next bit.
  2283.  
  2284. ;Exit with the byte that was read in
  2285.  
  2286. L07C0:  LD   HL,SERFL     ; $5B61.
  2287.         LD   (HL),$01     ; Set the flag indicating a second byte is in the buffer.
  2288.         INC  HL           ;
  2289.         LD   (HL),A       ; Store the second byte read in the buffer.
  2290.         POP  AF           ; Return the first byte.
  2291.  
  2292.         EI                ; Re-enable interrupts.
  2293.         RET
  2294.  
  2295. ; --------------------
  2296. ; RS232 Output Routine
  2297. ; --------------------
  2298. ; This routine handles control codes, token expansion, graphics and UDGs. It therefore cannot send binary data and hence cannot support
  2299. ; EPSON format ESC control codes [Credit: Andrew Owen].
  2300. ; The routine suffers from a number of bugs as described in the comments below. It also suffers from a minor flaw in the design, which prevents
  2301. ; interlacing screen and printer control codes and their parameters. For example, the following will not work correctly:
  2302. ;
  2303. ; 10 LPRINT CHR$ 16;
  2304. ; 20 PRINT AT 0,0;
  2305. ; 30 LPRINT CHR$ 0;"ABC"
  2306. ;
  2307. ; The control byte 16 gets stored in TVDATA so that the system knows how to interpret its parameter byte. However, the AT control code 22
  2308. ; in line 20 will overwrite it. When line 30 is executed, TVDATA still holds the control code for 'AT' and so this line is interpreted as
  2309. ; PRINT AT instead of PRINT INK. [Credit: Ian Collier (+3)]
  2310. ;
  2311. ; Entry: A=character to output.
  2312. ; Exit : Carry flag reset indicates success.
  2313.  
  2314. L07CA:  PUSH AF           ; Save the character to print.
  2315.         LD   A,(TVPARS)   ; $5B65. Number of parameters expected.
  2316.         OR   A            ;
  2317.         JR   Z,L07E0      ; Jump if no parameters.
  2318.  
  2319.         DEC  A            ; Ignore the parameter.
  2320.         LD   (TVPARS),A   ; $5B65.
  2321.         JR   NZ,L07DB     ; Jump ahead if we have not processed all parameters.
  2322.  
  2323. ;All parameters processed
  2324.  
  2325.         POP  AF           ; Retrieve character to print.
  2326.         JP   L0872        ; Jump ahead to continue.
  2327.  
  2328. L07DB:  POP  AF           ; Retrieve character to print.
  2329.         LD   ($5C0F),A    ; TVDATA+1. Store it for use later.
  2330.         RET               ;
  2331.  
  2332. L07E0:  POP  AF           ; Retrieve character to print.
  2333.         CP   $A3          ; Test against code for 'SPECTRUM'.
  2334.         JR   C,L07F2      ; Jump ahead if not a token.
  2335.  
  2336. ;Process tokens
  2337.  
  2338.         LD   HL,(RETADDR) ; $5B5A. Save RETADDR temporarily.
  2339.         PUSH HL           ;
  2340.         RST  28H          ;
  2341.         DEFW PO_T_UDG     ; $0B52. Print tokens via call to ROM 1 routine PO-T&UDG.
  2342.         POP  HL           ;
  2343.         LD   (RETADDR),HL ; $5B5A. Restore the original contents of RETADDR.
  2344.         SCF               ;
  2345.         RET               ;
  2346.  
  2347. L07F2:  LD   HL,$5C3B     ; FLAGS.
  2348.         RES  0,(HL)       ; Suppress printing a leading space.
  2349.         CP   ' '          ; $20. Is character to output a space?
  2350.         JR   NZ,L07FD     ; Jump ahead if not a space.
  2351.  
  2352.         SET  0,(HL)       ; Signal leading space required.
  2353.  
  2354. L07FD:  CP   $7F          ; Compare against copyright symbol.
  2355.         JR   C,L0803      ; Jump ahead if not a graphic or UDG character.
  2356.  
  2357.         LD   A,'?'        ; $3F. Print a '?' for all graphic and UDG characters.
  2358.  
  2359. L0803:  CP   $20          ; Is it a control character?
  2360.         JR   C,L081E      ; Jump ahead if so.
  2361.  
  2362. ;Printable character
  2363.  
  2364. L0807:  PUSH AF           ; Save the character to print.
  2365.         LD   HL,COL       ; $5B63. Point to the column number.
  2366.         INC  (HL)         ; Increment the column number.
  2367.         LD   A,(WIDTH)    ; $5B64. Fetch the number of columns.
  2368.         CP   (HL)         ;
  2369.         JR   NC,L081A     ; Jump if end of row not reached.
  2370.  
  2371.         CALL L0822        ; Print a carriage return and line feed.
  2372.  
  2373.         LD   A,$01        ;
  2374.         LD   (COL),A      ; $5B63. Set the print position to column 1.
  2375.  
  2376. L081A:  POP  AF           ; Retrieve character to print.
  2377.         JP   L08A3        ; Jump ahead to print the character.
  2378.  
  2379. ;Process control codes
  2380.  
  2381. L081E:  CP   $0D          ; Is it a carriage return?
  2382.         JR   NZ,L0830     ; Jump ahead if not.
  2383.  
  2384. ;Handle a carriage return
  2385.  
  2386. L0822:  XOR  A            ;
  2387.         LD   (COL),A      ; $5B63. Set the print position back to column 0.
  2388.  
  2389.         LD   A,$0D        ;
  2390.         CALL L08A3        ; Print a carriage return.
  2391.  
  2392.         LD   A,$0A        ;
  2393.         JP   L08A3        ; Print a line feed.
  2394.  
  2395. L0830:  CP   $06          ; Is it a comma?
  2396.         JR   NZ,L0853     ; Jump ahead if not.
  2397.  
  2398. ;Handle a comma
  2399.  
  2400.         LD   BC,(COL)     ; $5B63. Fetch the column position.
  2401.         LD   E,$00        ; Will count number of columns to move across to reach next comma position.
  2402.  
  2403. L083A:  INC  E            ; Increment column counter.
  2404.         INC  C            ; Increment column position.
  2405.         LD   A,C          ;
  2406.         CP   B            ; End of row reached?
  2407.         JR   Z,L0848      ; Jump if so.
  2408.  
  2409. L0840:  SUB  $08          ;
  2410.         JR   Z,L0848      ; Jump if column 8, 16 or 32 reached.
  2411.  
  2412.         JR   NC,L0840     ; Column position greater so subtract another 8.
  2413.  
  2414.         JR   L083A        ; Jump back and increment column position again.
  2415.  
  2416. ;Column 8, 16 or 32 reached. Output multiple spaces until the desired column position is reached.
  2417.  
  2418. L0848:  PUSH DE           ; Save column counter in E.
  2419.         LD   A,$20        ;
  2420.         CALL L07CA        ; Output a space via a recursive call.
  2421.         POP  DE           ; Retrieve column counter to E.
  2422.         DEC  E            ; More spaces to output?
  2423.         RET  Z            ; Return if no more to output.
  2424.  
  2425.         JR   L0848        ; Repeat for the next space to output.
  2426.  
  2427. L0853:  CP   $16          ; Is it AT?
  2428.         JR   Z,L0860      ; Jump ahead to handle AT.
  2429.  
  2430.         CP   $17          ; Is it TAB?
  2431.         JR   Z,L0860      ; Jump ahead to handle TAB.
  2432.  
  2433.         CP   $10          ; Check for INK, PAPER, FLASH, BRIGHT, INVERSE, OVER.
  2434.         RET  C            ; Ignore if not one of these.
  2435.  
  2436.         JR   L0869        ; Jump ahead to handle INK, PAPER, FLASH, BRIGHT, INVERSE, OVER.
  2437.  
  2438. ;Handle AT and TAB
  2439.  
  2440. L0860:  LD   ($5C0E),A    ; TV_DATA. Store the control code for use later, $16 (AT) or $17 (TAB).
  2441.         LD   A,$02        ; Two parameters expected (even for TAB).
  2442.         LD   (TVPARS),A   ; $5B65.
  2443.         RET               ; Return with zero flag set.
  2444.  
  2445. ;Handle INK, PAPER, FLASH, BRIGHT, INVERSE, OVER
  2446.  
  2447. L0869:  LD   ($5C0E),A    ; TV_DATA. Store the control code for use later.
  2448.         LD   A,$02        ; Two parameters expected. [*BUG* - Should be 1 parameter. 'LPRINT INK 4' will produce error report 'C Nonsense in BASIC'. Credit: Toni Baker, ZX Computing Monthly].
  2449.         LD   (TVPARS),A   ; $5B65.
  2450.         RET               ; [*BUG* - Should return with the carry flag reset and the zero flag set. It causes a statement such as 'LPRINT INK 1;' to produce error report '8 End of file'.
  2451.                           ; It is due to the main RS232 processing loop using the state of the flags to determine the success/failure response of the RS232 output routine. Credit: Ian Collier (+3), Andrew Owen (128)]
  2452.                           ; [The bug can be fixed by inserting a XOR A instruction before the RET instruction. Credit: Paul Farrow]
  2453.  
  2454. ;All parameters processed
  2455.  
  2456. L0872:  LD   D,A          ; D=Character to print.
  2457.         LD   A,($5C0E)    ; TV_DATA. Fetch the control code.
  2458.         CP   $16          ; Is it AT?
  2459.         JR   Z,L0882      ; Jump ahead to handle AT parameter.
  2460.  
  2461.         CP   $17          ; Is it TAB?
  2462.         CCF               ; [*BUG* - Should return with the carry flag reset and the zero flag set. It causes a statement such as 'LPRINT INK 1;' to produce error report '8 End of file'.
  2463.                           ; It is due to the main RS232 processing loop using the state of the flags to determine the success/failure response of the RS232 output routine. Credit: Toni Baker, ZX Computing Monthly]
  2464.         RET  NZ           ; Ignore if not TAB.
  2465.  
  2466. ; [The bug can be fixed by replacing the instructions CCF and RET NZ with the following. Credit: Paul Farrow.
  2467. ;
  2468. ;       JR   Z,NOT_TAB
  2469. ;
  2470. ;       XOR  A
  2471. ;       RET
  2472. ;
  2473. ;NOT_TAB:                 ; ]
  2474.  
  2475. ;Handle TAB parameter
  2476.  
  2477.         LD   A,($5C0F)    ; TV_DATA+1. Fetch the saved parameter.
  2478.         LD   D,A          ; Fetch parameter to D.
  2479.  
  2480. ;Process AT and TAB
  2481.  
  2482. L0882:  LD   A,(WIDTH)    ; $5B64.
  2483.         CP   D            ; Reached end of row?
  2484.         JR   Z,L088A      ; Jump ahead if so.
  2485.  
  2486.         JR   NC,L0890     ; Jump ahead if before end of row.
  2487.  
  2488. ;Column position equal or greater than length of row requested
  2489.  
  2490. L088A:  LD   B,A          ; (WIDTH).
  2491.         LD   A,D          ; TAB/AT column position.
  2492.         SUB  B            ; TAB/AT position - WIDTH.
  2493.         LD   D,A          ; The new required column position.
  2494.         JR   L0882        ; Handle the new TAB/AT position.
  2495.  
  2496. L0890:  LD   A,D          ; Fetch the desired column number.
  2497.         OR   A            ;
  2498.         JP   Z,L0822      ; Jump to output a carriage return if column 0 required.
  2499.  
  2500. L0895:  LD   A,(COL)      ; $5B63. Fetch the current column position.
  2501.         CP   D            ; Compare against desired column position.
  2502.         RET  Z            ; Done if reached requested column.
  2503.  
  2504.         PUSH DE           ; Save the number of spaces to output.
  2505.         LD   A,$20        ;
  2506.         CALL L07CA        ; Output a space via a recursive call.
  2507.         POP  DE           ; Retrieve number of spaces to output.
  2508.         JR   L0895        ; Keep outputting spaces until desired column reached.
  2509.  
  2510. ; ------------------------
  2511. ; Write Byte to RS232 Port
  2512. ; ------------------------
  2513. ; The timing of the routine is achieved using the timing constant held in system variable BAUD.
  2514. ; Entry: A holds character to send.
  2515. ; Exit:  Carry and zero flags reset.
  2516.  
  2517. L08A3:  PUSH AF           ; Save the byte to send.
  2518.  
  2519.         LD   C,$FD        ;
  2520.         LD   D,$FF        ;
  2521.  
  2522.         LD   E,$BF        ;
  2523.         LD   B,D          ;
  2524.         LD   A,$0E        ;
  2525.         OUT  (C),A        ; Select AY register 14 to control the RS232 port.
  2526.  
  2527. L08AF:  CALL L05D6        ; Check the BREAK key, and produce error message if it is being pressed.
  2528.  
  2529.         IN   A,(C)        ; Read status of data register.
  2530.         AND  $40          ; %01000000. Test the DTR line.
  2531.         JR   NZ,L08AF     ; Jump back until device is ready for data.
  2532.  
  2533.         LD   HL,(BAUD)    ; $5B5F. HL=Baud rate timing constant.
  2534.         LD   DE,$0002     ;
  2535.         OR   A            ;
  2536.         SBC  HL,DE        ;
  2537.         EX   DE,HL        ; DE=(BAUD)-2.
  2538.  
  2539.         POP  AF           ; Retrieve the byte to send.
  2540.         CPL               ; Invert the bits of the byte (RS232 logic is inverted).
  2541.         SCF               ; Carry is used to send START BIT.
  2542.         LD   B,$0B        ; B=Number of bits to send (1 start + 8 data + 2 stop).
  2543.  
  2544.         DI                ; Disable interrupts to ensure accurate timing.
  2545.  
  2546. ;Transmit each bit
  2547.  
  2548. L08C8:  PUSH BC           ; Save the number of bits to send.
  2549.         PUSH AF           ; Save the data bits.
  2550.  
  2551.         LD   A,$FE        ;
  2552.         LD   H,D          ;
  2553.         LD   L,E          ; HL=(BAUD)-2.
  2554.         LD   BC,$BFFD     ; AY-3-8912 data register.
  2555.  
  2556.         JP   NC,L08DA     ; Branch to transmit a 1 or a 0 (initially sending a 0 for the start bit).
  2557.  
  2558. ;Transmit a 0
  2559.  
  2560.         AND  $F7          ; Clear the RXD (out) line.
  2561.         OUT  (C),A        ; Send out a 0 (high level).
  2562.         JR   L08E0        ; Jump ahead to continue with next bit.
  2563.  
  2564. ;Transmit a 1
  2565.  
  2566. L08DA:  OR   $08          ; Set the RXD (out) line.
  2567.         OUT  (C),A        ; Send out a 1 (low level).
  2568.         JR   L08E0        ; Jump ahead to continue with next bit.
  2569.  
  2570. ;Delay the length of a bit
  2571.  
  2572. L08E0:  DEC  HL           ; (6) Delay 26*BAUD cycles.
  2573.         LD   A,H          ; (4)
  2574.         OR   L            ; (4)
  2575.         JR   NZ,L08E0     ; (12) Jump back until delay is completed.
  2576.  
  2577.         NOP               ; (4) Fine tune the timing.
  2578.         NOP               ; (4)
  2579.         NOP               ; (4)
  2580.  
  2581.         POP  AF           ; Retrieve the data bits to send.
  2582.         POP  BC           ; Retrieve the number of bits left to send.
  2583.         OR   A            ; Clear carry flag.
  2584.         RRA               ; Shift the next bit to send into the carry flag.
  2585.         DJNZ L08C8        ; Jump back to send next bit until all bits sent.
  2586.  
  2587.         EI                ; Re-enable interrupts.
  2588.         RET               ; Return with carry and zero flags reset.
  2589.  
  2590. ; --------------------
  2591. ; COPY Command Routine
  2592. ; --------------------
  2593. ; This routine copies 22 rows of the screen, outputting them to the printer a
  2594. ; half row at a time. It is designed for EPSON compatible printers supporting
  2595. ; double density bit graphics and 7/72 inch line spacing.
  2596. ; Only the pixel information is processed; the attributes are ignored.
  2597.  
  2598. L08F0:  LD   HL,HD_0B     ; Half row counter.
  2599.         LD   (HL),$2B     ; Set the half row counter to 43 half rows (will output 44 half rows in total).
  2600.  
  2601. L08F5:  LD   HL,L0979     ; Point to printer configuration data (7/72 inch line spacing, double density bit graphics).
  2602.         CALL L095F        ; Send the configuration data to printer.
  2603.  
  2604.         CALL L0915        ; Output a half row, at double height.
  2605.  
  2606.         LD   HL,L0980     ; Table holds a line feed only.
  2607.         CALL L095F        ; Send a line feed to printer.
  2608.  
  2609.         LD   HL,HD_0B     ; $5B72. The half row counter is tested to see if it is zero
  2610.         XOR  A            ; and if so then the line spacing is reset to its
  2611.         CP   (HL)         ; original value.
  2612.         JR   Z,L090E      ; Jump if done, resetting printer line spacing.
  2613.  
  2614.         DEC  (HL)         ; Decrement half row counter.
  2615.         JR   L08F5        ; Repeat for the next half row.
  2616.  
  2617. ;Copy done so reset printer line spacing before exiting
  2618.  
  2619. L090E:  LD   HL,L0982     ; Point to printer configuration data (1/6 inch line spacing).
  2620.         CALL L095F        ; Send the configuration data to printer.
  2621.         RET               ; [Could have saved 1 byte by using JP $095F (ROM 0)]
  2622.  
  2623. ; ---------------
  2624. ; Output Half Row
  2625. ; ---------------
  2626.  
  2627. L0915:  LD   HL,HD_00     ; $5B71. Pixel column counter.
  2628.         LD   (HL),$FF     ; Set pixel column counter to 255 pixels.
  2629.  
  2630. L091A:  CALL L0926        ; Output a column of pixels, at double height.
  2631.  
  2632.         LD   HL,HD_00     ; $5B71. Pixel column counter.
  2633.         XOR  A            ;
  2634.         CP   (HL)         ; Check if all pixels in this row have been output.
  2635.         RET  Z            ; Return if so.
  2636.  
  2637.         DEC  (HL)         ; Decrement pixel column counter.
  2638.         JR   L091A        ; Repeat for all pixels in this row.
  2639.  
  2640. ;Output a column of pixels (at double height)
  2641.  
  2642. L0926:  LD   DE,$C000     ; D=%11000000. Used to hold the double height pixel.
  2643.         LD   BC,(HD_00)   ; $5B71. C=Pixel column counter, B=Half row counter.
  2644.         SCF               ;
  2645.         RL   B            ; B=2xB+1
  2646.         SCF               ;
  2647.         RL   B            ; B=4xB+3. The pixel row coordinate.
  2648.  
  2649.         LD   A,C          ; Pixel column counter.
  2650.         CPL               ;
  2651.         LD   C,A          ; C=255-C. The pixel column coordinate.
  2652.  
  2653.         XOR  A            ; Clear A. Used to generate double height nibble of pixels to output.
  2654.         PUSH AF           ;
  2655.  
  2656.         PUSH DE           ;
  2657.         PUSH BC           ; Save registers.
  2658.  
  2659. L093A:  CALL L096D        ; Test whether pixel (B,C) is set
  2660.  
  2661.         POP  BC           ;
  2662.         POP  DE           ; Restore registers.
  2663.  
  2664.         LD   E,$00        ; Set double height pixel = 0.
  2665.         JR   Z,L0944      ; Jump if pixel is reset.
  2666.  
  2667.         LD   E,D          ; The double height pixel to output (%11000000, %00110000, %00001100 or %00000011).
  2668.  
  2669. L0944:  POP  AF           ;
  2670.         OR   E            ; Add the double height pixel value to the byte to output.
  2671.         PUSH AF           ;
  2672.  
  2673.         DEC  B            ; Decrement half row coordinate.
  2674.         SRL  D            ;
  2675.         SRL  D            ; Create next double height pixel value (%00110000, %00001100 or %00000011).
  2676.  
  2677.         PUSH DE           ;
  2678.         PUSH BC           ;
  2679.         JR   NC,L093A     ; Repeat for all four pixels in the half row.
  2680.  
  2681.         POP  BC           ;
  2682.         POP  DE           ; Unload the stack.
  2683.  
  2684.         POP  AF           ;
  2685.         LD   B,$03        ; Send double height nibble of pixels output 3 times.
  2686.  
  2687. ; -----------------------
  2688. ; Output Nibble of Pixels
  2689. ; -----------------------
  2690. ; Send each nibble of pixels (i.e. column of 4 pixels) output 3 times so that
  2691. ; the width of a pixel is the same size as its height.
  2692.  
  2693. L0955:  PUSH BC           ;
  2694.         PUSH AF           ;
  2695.         CALL L08A3        ; Send byte to RS232 port.
  2696.         POP  AF           ;
  2697.         POP  BC           ;
  2698.         DJNZ L0955        ;
  2699.  
  2700.         RET               ;
  2701.  
  2702. ; ----------------------------
  2703. ; Output Characters from Table
  2704. ; ----------------------------
  2705. ; This routine is used to send a sequence of EPSON printer control codes out to the RS232 port.
  2706. ; It sends (HL) characters starting from HL+1.
  2707.  
  2708. L095F:  LD   B,(HL)       ; Get number of bytes to send.
  2709.         INC  HL           ; Point to the data to send.
  2710.  
  2711. L0961:  LD   A,(HL)       ; Retrieve value.
  2712.         PUSH HL           ;
  2713.         PUSH BC           ;
  2714.         CALL L08A3        ; Send byte to RS232 port.
  2715.         POP  BC           ;
  2716.         POP  HL           ;
  2717.         INC  HL           ; Point to next data byte to send.
  2718.         DJNZ L0961        ; Repeat for all bytes.
  2719.  
  2720.         RET               ;
  2721.  
  2722. ; -------------------------------
  2723. ; Test Whether Pixel (B,C) is Set
  2724. ; -------------------------------
  2725. ; Entry: B=Pixel line
  2726. ;        C=Pixel column.
  2727. ; Exit : A=$00 if pixel is reset
  2728. ;        A>$00 if pixel is set (actually the value of the bit corresponding to the pixel within the byte).
  2729.  
  2730. L096D:  RST  28H          ; Get address of (B,C) pixel into HL and pixel position within byte into A.
  2731.         DEFW PIXEL_ADDR   ; $22AA.
  2732.         LD   B,A          ; B=Pixel position within byte (0-7).
  2733.         INC  B            ;
  2734.  
  2735.         XOR  A            ; Pixel mask.
  2736.         SCF               ; Carry flag holds bit to be rotated into the mask.
  2737.  
  2738. L0974:  RRA               ; Shift the mask bit into the required bit position.
  2739.         DJNZ L0974        ;
  2740.  
  2741.         AND  (HL)         ; Isolate this pixel from A.
  2742.         RET               ;
  2743.  
  2744. ; ---------------------------------
  2745. ; EPSON Printer Control Code Tables
  2746. ; ---------------------------------
  2747.  
  2748. L0979:  DB $06                 ; 6 characters follow.
  2749.         DB $1B, $31            ; ESC '1'     - 7/72 inch line spacing.
  2750.         DB $1B, $4C, $00, $03  ; ESC 'L' 0 3 - Double density (768 bytes per row).
  2751.  
  2752. L0980:  DB $01                 ; 1 character follows.
  2753.         DB $0A                 ; Line feed.
  2754.  
  2755. L0982:  DB $02                 ; 2 characters follow.
  2756.         DB $1B, $32            ; ESC '2' - 1/6 inch line spacing.
  2757.  
  2758.  
  2759. ; =====================
  2760. ; PLAY COMMAND ROUTINES
  2761. ; =====================
  2762. ; Up to 3 channels of music/noise are supported by the AY-3-8912 sound generator.
  2763. ; Up to 8 channels of music can be sent to support synthesisers, drum machines or sequencers via the MIDI interface,
  2764. ; with the first 3 channels also played by the AY-3-8912 sound generator. For each channel of music, a MIDI channel
  2765. ; can be assigned to it using the 'Y' command.
  2766. ;
  2767. ; The PLAY command reserves and initialises space for the PLAY command. This comprises a block of $003C bytes
  2768. ; used to manage the PLAY command (IY points to this command data block) and a block of $0037 bytes for each
  2769. ; channel string (IX is used to point to the channel data block for the current channel). [Note that the command
  2770. ; data block is $04 bytes larger than it needs to be, and each channel data block is $11 bytes larger than it
  2771. ; needs to be]
  2772. ;
  2773. ; Entry: B=The number of strings in the PLAY command (1..8).
  2774.  
  2775. ; -------------------------
  2776. ; Command Data Block Format
  2777. ; -------------------------
  2778. ; IY+$00 / IY+$01 = Channel 0 data block pointer. Points to the data for channel 0 (string 1).
  2779. ; IY+$02 / IY+$03 = Channel 1 data block pointer. Points to the data for channel 1 (string 2).
  2780. ; IY+$04 / IY+$05 = Channel 2 data block pointer. Points to the data for channel 2 (string 3).
  2781. ; IY+$06 / IY+$07 = Channel 3 data block pointer. Points to the data for channel 3 (string 4).
  2782. ; IY+$08 / IY+$09 = Channel 4 data block pointer. Points to the data for channel 4 (string 5).
  2783. ; IY+$0A / IY+$0B = Channel 5 data block pointer. Points to the data for channel 5 (string 6).
  2784. ; IY+$0C / IY+$0D = Channel 6 data block pointer. Points to the data for channel 6 (string 7).
  2785. ; IY+$0E / IY+$0F = Channel 7 data block pointer. Points to the data for channel 7 (string 8).
  2786. ; IY+$10          = Channel bitmap. Initialised to $FF and a 0 rotated in to the left for each string parameters
  2787. ;                   of the PLAY command, thereby indicating the channels in use.
  2788. ; IY+$11 / IY+$12 = Channel data block duration pointer. Points to duration length store in channel 0 data block (string 1).
  2789. ; IY+$13 / IY+$14 = Channel data block duration pointer. Points to duration length store in channel 1 data block (string 2).
  2790. ; IY+$15 / IY+$16 = Channel data block duration pointer. Points to duration length store in channel 2 data block (string 3).
  2791. ; IY+$17 / IY+$18 = Channel data block duration pointer. Points to duration length store in channel 3 data block (string 4).
  2792. ; IY+$19 / IY+$1A = Channel data block duration pointer. Points to duration length store in channel 4 data block (string 5).
  2793. ; IY+$1B / IY+$1C = Channel data block duration pointer. Points to duration length store in channel 5 data block (string 6).
  2794. ; IY+$1D / IY+$1E = Channel data block duration pointer. Points to duration length store in channel 6 data block (string 7).
  2795. ; IY+$1F / IY+$20 = Channel data block duration pointer. Points to duration length store in channel 7 data block (string 8).
  2796. ; IY+$21          = Channel selector. It is used as a shift register with bit 0 initially set and then shift to the left
  2797. ;                   until a carry occurs, thereby indicating all 8 possible channels have been processed.
  2798. ; IY+$22          = Temporary channel bitmap, used to hold a working copy of the channel bitmap at IY+$10.
  2799. ; IY+$23 / IY+$24 = Address of the channel data block pointers, or address of the channel data block duration pointers
  2800. ;                   (allows the routine at $0A6E (ROM 0) to be used with both set of pointers).
  2801. ; IY+$25 / IY+$26 = Stores the smallest duration length of all currently playing channel notes.
  2802. ; IY+$27 / IY+$28 = The current tempo timing value (derived from the tempo parameter 60..240 beats per second).
  2803. ; IY+$29          = The current effect waveform value.
  2804. ; IY+$2A          = Temporary string counter selector.
  2805. ; IY+$2B..IY+$37  = Holds a floating point calculator routine.
  2806. ; IY+$38..IY+$3B  = Not used.
  2807.  
  2808. ; -------------------------
  2809. ; Channel Data Block Format
  2810. ; -------------------------
  2811. ; IX+$00          = The note number being played on this channel (equivalent to index offset into the note table).
  2812. ; IX+$01          = MIDI channel assigned to this string (range 0 to 15).
  2813. ; IX+$02          = Channel number (range 0 to 7), i.e. index position of the string within the PLAY command.
  2814. ; IX+$03          = 12*Octave number (0, 12, 24, 36, 48, 60, 72, 84 or 96).
  2815. ; IX+$04          = Current volume (range 0 to 15, or if bit 4 set then using envelope).
  2816. ; IX+$05          = Last note duration value as specified in the string (range 1 to 9).
  2817. ; IX+$06 / IX+$07 = Address of current position in the string.
  2818. ; IX+$08 / IX+$09 = Address of byte after the end of the string.
  2819. ; IX+$0A          = Flags:
  2820. ;                     Bit 0   : 1=Single closing bracket found (repeat string indefinitely).
  2821. ;                     Bits 1-7: Not used (always 0).
  2822. ; IX+$0B          = Open bracket nesting level (range $00 to $04).
  2823. ; IX+$0C / IX+$0D = Return address for opening bracket nesting level 0 (points to character after the bracket).
  2824. ; IX+$0E / IX+$0F = Return address for opening bracket nesting level 1 (points to character after the bracket).
  2825. ; IX+$10 / IX+$11 = Return address for opening bracket nesting level 2 (points to character after the bracket).
  2826. ; IX+$12 / IX+$13 = Return address for opening bracket nesting level 3 (points to character after the bracket).
  2827. ; IX+$14 / IX+$15 = Return address for opening bracket nesting level 4 (points to character after the bracket).
  2828. ; IX+$16          = Closing bracket nesting level (range $FF to $04).
  2829. ; IX+$17...IX+$18 = Return address for closing bracket nesting level 0 (points to character after the bracket).
  2830. ; IX+$19...IX+$1A = Return address for closing bracket nesting level 1 (points to character after the bracket).
  2831. ; IX+$1B...IX+$1C = Return address for closing bracket nesting level 2 (points to character after the bracket).
  2832. ; IX+$1D...IX+$1E = Return address for closing bracket nesting level 3 (points to character after the bracket).
  2833. ; IX+$1F...IX+$20 = Return address for closing bracket nesting level 4 (points to character after the bracket).
  2834. ; IX+$21          = Tied notes counter (for a single note the value is 1).
  2835. ; IX+$22 / IX+$23 = Duration length, specified in 96ths of a note.
  2836. ; IX+$24...IX+$25 = Subsequent note duration length (used only with triplets), specified in 96ths of a note.
  2837. ; IX+$26...IX+$36 = Not used.
  2838.  
  2839. L0985:  DI                ; Disable interrupts to ensure accurate timing.
  2840.  
  2841. ;Create a workspace for the play channel command strings
  2842.  
  2843.         PUSH BC           ; B=Number of channel string (range 1 to 8). Also used as string index number in the following loop.
  2844.  
  2845.         LD   DE,$0037     ;
  2846.         LD   HL,$003C     ;
  2847.  
  2848. L098D:  ADD  HL,DE        ; Calculate HL=$003C + ($0037 * B).
  2849.         DJNZ L098D        ;
  2850.  
  2851.         LD   C,L          ;
  2852.         LD   B,H          ; BC=Space required (maximum = $01F4).
  2853.         RST  28H          ;
  2854.         DEFW BC_SPACES    ; $0030. Make BC bytes of space in the workspace.
  2855.  
  2856.         DI                ; Interrupts get re-enabled by the call mechanism to ROM 1 so disable them again.
  2857.  
  2858.         PUSH DE           ;
  2859.         POP  IY           ; IY=Points at first new byte - the command data block.
  2860.  
  2861.         PUSH HL           ;
  2862.         POP  IX           ; IX=Points at last new byte - byte after all channel information blocks.
  2863.  
  2864.         LD   (IY+$10),$FF ; Initial channel bitmap with value meaning 'zero strings'
  2865.  
  2866. ;Loop over each string to be played
  2867.  
  2868. L09A0:  LD   BC,$FFC9     ; $-37 ($37 bytes is the size of a play channel string information block).
  2869.         ADD  IX,BC        ; IX points to start of space for the last channel.
  2870.         LD   (IX+$03),$3C ; Default octave is 5.
  2871.         LD   (IX+$01),$FF ; No MIDI channel assigned.
  2872.         LD   (IX+$04),$0F ; Default volume is 15.
  2873.         LD   (IX+$05),$05 ; Default note duration.
  2874.         LD   (IX+$21),$00 ; Count of the number of tied notes.
  2875.         LD   (IX+$0A),$00 ; Signal not to repeat the string indefinitely.
  2876.         LD   (IX+$0B),$00 ; No opening bracket nesting level.
  2877.         LD   (IX+$16),$FF ; No closing bracket nesting level.
  2878.         LD   (IX+$17),$00 ; Return address for closing bracket nesting level 0.
  2879.         LD   (IX+$18),$00 ; [No need to initialise this since it is written to before it is ever tested]
  2880.  
  2881. ; [*BUG* - At this point interrupts are disabled and IY is now being used as a pointer to the master
  2882. ;          PLAY information block. Unfortunately, interrupts are enabled during the STK_FETCH call and
  2883. ;          IY is left containing the wrong value. This means that if an interrupt were to occur during
  2884. ;          execution of the subroutine then there would be a one in 65536 chance that (IY+$40) will be
  2885. ;          corrupted - this corresponds to the volume setting for music channel A.
  2886. ;          Rewriting the SWAP routine to only re-enable interrupts if they were originally enabled
  2887. ;          would cure this bug (see end of file for description of her suggested fix). Credit: Toni Baker, ZX Computing Monthly]
  2888.  
  2889. ; [An alternative and simpler solution to the fix Toni Baker describes would be to stack IY, set IY to point
  2890. ; to the system variables at $5C3A, call STK_FETCH, disable interrupts, then pop the stacked value back to IY. Credit: Paul Farrow]
  2891.  
  2892.         RST  28H          ; Get the details of the string from the stack.
  2893.         DEFW STK_FETCH    ; $2BF1.
  2894.  
  2895.         DI                ; Interrupts get re-enabled by the call mechanism to ROM 1 so disable them again.
  2896.  
  2897.         LD   (IX+$06),E   ; Store the current position within in the string, i.e. the beginning of it.
  2898.         LD   (IX+$07),D   ;
  2899.         LD   (IX+$0C),E   ; Store the return position within the string for a closing bracket,
  2900.         LD   (IX+$0D),D   ; which is initially the start of the string in case a single closing bracket is found.
  2901.  
  2902.         EX   DE,HL        ; HL=Points to start of string. BC=Length of string.
  2903.         ADD  HL,BC        ; HL=Points to address of byte after the string.
  2904.         LD   (IX+$08),L   ; Store the address of the character just
  2905.         LD   (IX+$09),H   ; after the string.
  2906.  
  2907.         POP  BC           ; B=String index number (range 1 to 8).
  2908.         PUSH BC           ; Save it on the stack again.
  2909.         DEC  B            ; Reduce the index so it ranges from 0 to 7.
  2910.  
  2911.         LD   C,B          ;
  2912.         LD   B,$00        ;
  2913.         SLA  C            ; BC=String index*2.
  2914.  
  2915.         PUSH IY           ;
  2916.         POP  HL           ; HL=Address of the command data block.
  2917.         ADD  HL,BC        ; Skip 8 channel data pointer words.
  2918.  
  2919.         PUSH IX           ;
  2920.         POP  BC           ; BC=Address of current channel information block.
  2921.  
  2922.         LD   (HL),C       ; Store the pointer to the channel information block.
  2923.         INC  HL           ;
  2924.         LD   (HL),B       ;
  2925.  
  2926.         OR   A            ; Clear the carry flag.
  2927.         RL   (IY+$10)     ; Rotate one zero-bit into the least significant bit of the channel bitmap.
  2928.                           ; This initially holds $FF but once this loop is over, this byte has
  2929.                           ; a zero bit for each string parameter of the PLAY command.
  2930.  
  2931.         POP  BC           ; B=Current string index.
  2932.         DEC  B            ; Decrement string index so it ranges from 0 to 7.
  2933.         PUSH BC           ; Save it for future use on the next iteration.
  2934.         LD   (IX+$02),B   ; Store the channel number.
  2935.  
  2936.         JR   NZ,L09A0     ; Jump back while more channel strings to process.
  2937.  
  2938.         POP  BC           ; Drop item left on the stack.
  2939.  
  2940. ;Entry point here from the vector table at $011B
  2941.  
  2942. L0A05:  LD   (IY+$27),$1A ; Set the initial tempo timing value.
  2943.         LD   (IY+$28),$0B ; Corresponds to a 'T' command value of 120, and gives two crotchets per second.
  2944.  
  2945.         PUSH IY           ;
  2946.         POP  HL           ; HL=Points to the command data block.
  2947.  
  2948.         LD   BC,$002B     ;
  2949.         ADD  HL,BC        ;
  2950.         EX   DE,HL        ; DE=Address to store RAM routine.
  2951.         LD   HL,L0A31     ; HL=Address of the RAM routine bytes.
  2952.         LD   BC,$000D     ;
  2953.         LDIR              ; Copy the calculator routine to RAM.
  2954.  
  2955.         LD   D,$07        ; Register 7 - Mixer.
  2956.         LD   E,$F8        ; I/O ports are inputs, noise output off, tone output on.
  2957.         CALL L0E7C        ; Write to sound generator register.
  2958.  
  2959.         LD   D,$0B        ; Register 11 - Envelope Period (Fine).
  2960.         LD   E,$FF        ; Set period to maximum.
  2961.         CALL L0E7C        ; Write to sound generator register.
  2962.  
  2963.         INC  D            ; Register 12 - Envelope Period (Coarse).
  2964.         CALL L0E7C        ; Write to sound generator register.
  2965.  
  2966.         JR   L0A7D        ; Jump ahead to continue.
  2967.                           ; [Could have saved these 2 bytes by having the code at $0A7D (ROM 0) immediately follow]
  2968.  
  2969. ; -------------------------------------------------
  2970. ; Calculate Timing Loop Counter <<< RAM Routine >>>
  2971. ; -------------------------------------------------
  2972. ; This routine is copied into the command data block (offset $2B..$37) by
  2973. ; the routine at $0A05 (ROM 0).
  2974. ; It uses the floating point calculator found in ROM 1, which is usually
  2975. ; invoked via a RST $28 instruction. Since ROM 0 uses RST $28 to call a
  2976. ; routine in ROM 1, it is unable to invoke the floating point calculator
  2977. ; this way. It therefore copies the following routine to RAM and calls it
  2978. ; with ROM 1 paged in.
  2979. ;
  2980. ; The routine calculates (10/x)/7.33e-6, where x is the tempo 'T' parameter value
  2981. ; multiplied by 4. The result is used an inner loop counter in the wait routine at $0F76 (ROM 0).
  2982. ; Each iteration of this loop takes 26 T-states. The time taken by 26 T-states
  2983. ; is 7.33e-6 seconds. So the total time for the loop to execute is 2.5/TEMPO seconds.
  2984. ;
  2985. ; Entry: The value 4*TEMPO exists on the calculator stack (where TEMPO is in the range 60..240).
  2986. ; Exit : The calculator stack holds the result.
  2987.  
  2988. L0A31:  RST 28H           ; Invoke the floating point calculator.
  2989.         DB $A4          ; stk-ten.   = x, 10
  2990.         DB $01          ; exchange.  = 10, x
  2991.         DB $05          ; division.  = 10/x
  2992.         DB $34          ; stk-data.  = 10/x, 7.33e-6
  2993.         DB $DF          ; - exponent $6F (floating point number 7.33e-6).
  2994.         DB $75          ; - mantissa byte 1
  2995.         DB $F4          ; - mantissa byte 2
  2996.         DB $38          ; - mantissa byte 3
  2997.         DB $75          ; - mantissa byte 4
  2998.         DB $05          ; division.  = (10/x)/7.33e-6
  2999.         DB $38          ; end-calc.
  3000.         RET               ;
  3001.  
  3002. ; --------------
  3003. ; Test BREAK Key
  3004. ; --------------
  3005. ; Test for BREAK being pressed.
  3006. ; Exit: Carry flag reset if BREAK is being pressed.
  3007.  
  3008. L0A3E:  LD   A,$7F        ;
  3009.         IN   A,($FE)      ;
  3010.         RRA               ;
  3011.         RET  C            ; Return with carry flag set if SPACE not pressed.
  3012.  
  3013.         LD   A,$FE        ;
  3014.         IN   A,($FE)      ;
  3015.         RRA               ;
  3016.         RET               ; Return with carry flag set if CAPS not pressed.
  3017.  
  3018. ; -------------------------------------------
  3019. ; Select Channel Data Block Duration Pointers
  3020. ; -------------------------------------------
  3021. ; Point to the start of the channel data block duration pointers within the command data block.
  3022. ; Entry: IY=Address of the command data block.
  3023. ; Exit : HL=Address of current channel pointer.
  3024.  
  3025. L0A4A:  LD   BC,$0011     ; Offset to the channel data block duration pointers table.
  3026.         JR   L0A52        ; Jump ahead to continue.
  3027.  
  3028. ; ----------------------------------
  3029. ; Select Channel Data Block Pointers
  3030. ; ----------------------------------
  3031. ; Point to the start of the channel data block pointers within the command data block.
  3032. ; Entry: IY=Address of the command data block.
  3033. ; Exit : HL=Address of current channel pointer.
  3034.  
  3035. L0A4F:  LD   BC,$0000     ; Offset to the channel data block pointers table.
  3036.  
  3037. L0A52:  PUSH IY           ;
  3038.         POP  HL           ; HL=Point to the command data block.
  3039.  
  3040.         ADD  HL,BC        ; Point to the desired channel pointers table.
  3041.  
  3042.         LD   (IY+$23),L   ;
  3043.         LD   (IY+$24),H   ; Store the start address of channels pointer table.
  3044.  
  3045.         LD   A,(IY+$10)   ; Fetch the channel bitmap.
  3046.         LD   (IY+$22),A   ; Initialise the working copy.
  3047.  
  3048.         LD   (IY+$21),$01 ; Channel selector. Set the shift register to indicate the first channel.
  3049.         RET               ;
  3050.  
  3051. ; -------------------------------------------------
  3052. ; Get Channel Data Block Address for Current String
  3053. ; -------------------------------------------------
  3054. ; Entry: HL=Address of channel data block pointer.
  3055. ; Exit : IX=Address of current channel data block.
  3056.  
  3057. L0A67:  LD   E,(HL)       ;
  3058.         INC  HL           ;
  3059.         LD   D,(HL)       ; Fetch the address of the current channel data block.
  3060.  
  3061.         PUSH DE           ;
  3062.         POP  IX           ; Return it in IX.
  3063.         RET               ;
  3064.  
  3065. ; -------------------------
  3066. ; Next Channel Data Pointer
  3067. ; -------------------------
  3068.  
  3069. L0A6E:  LD   L,(IY+$23)   ; The address of current channel data pointer.
  3070.         LD   H,(IY+$24)   ;
  3071.         INC  HL           ;
  3072.         INC  HL           ; Advance to the next channel data pointer.
  3073.         LD   (IY+$23),L   ;
  3074.         LD   (IY+$24),H   ; The address of new channel data pointer.
  3075.         RET               ;
  3076.  
  3077. ; ---------------------------
  3078. ; PLAY Command (Continuation)
  3079. ; ---------------------------
  3080. ; This section is responsible for processing the PLAY command and is a continuation of the routine
  3081. ; at $0985 (ROM 0). It begins by determining the first note to play on each channel and then enters
  3082. ; a loop to play these notes, fetching the subsequent notes to play at the appropriate times.
  3083.  
  3084. L0A7D:  CALL L0A4F        ; Select channel data block pointers.
  3085.  
  3086. L0A80:  RR   (IY+$22)     ; Working copy of channel bitmap. Test if next string present.
  3087.         JR   C,L0A8C      ; Jump ahead if there is no string for this channel.
  3088.  
  3089. ;HL=Address of channel data pointer.
  3090.  
  3091.         CALL L0A67        ; Get address of channel data block for the current string into IX.
  3092.         CALL L0B5C        ; Find the first note to play for this channel from its play string.
  3093.  
  3094. L0A8C:  SLA  (IY+$21)     ; Have all channels been processed?
  3095.         JR   C,L0A97      ; Jump ahead if so.
  3096.  
  3097.         CALL L0A6E        ; Advance to the next channel data block pointer.
  3098.         JR   L0A80        ; Jump back to process the next channel.
  3099.  
  3100. ;The first notes to play for each channel have now been determined. A loop is entered that coordinates playing
  3101. ;the notes and fetching subsequent notes when required. Notes across channels may be of different lengths and
  3102. ;so the shortest one is determined, the tones for all channels set and then a waiting delay entered for the shortest
  3103. ;note delay. This delay length is then subtracted from all channel note lengths to leave the remaining lengths that
  3104. ;each note needs to be played for. For the channel with the smallest note length, this will now have completely played
  3105. ;and so a new note is fetched for it. The smallest length of the current notes is then determined again and the process
  3106. ;described above repeated. A test is made on each iteration to see if all channels have run out of data to play, and if
  3107. ;so this ends the PLAY command.
  3108.  
  3109. L0A97:  CALL L0F91        ; Find smallest duration length of the current notes across all channels.
  3110.  
  3111.         PUSH DE           ; Save the smallest duration length.
  3112.         CALL L0F42        ; Play a note on each channel.
  3113.         POP  DE           ; DE=The smallest duration length.
  3114.  
  3115. L0A9F:  LD   A,(IY+$10)   ; Channel bitmap.
  3116.         CP   $FF          ; Is there anything to play?
  3117.         JR   NZ,L0AAB     ; Jump if there is.
  3118.  
  3119.         CALL L0E93        ; Turn off all sound and restore IY.
  3120.         EI                ; Re-enable interrupts.
  3121.         RET               ; End of play command.
  3122.  
  3123. L0AAB:  DEC  DE           ; DE=Smallest channel duration length, i.e. duration until the next channel state change.
  3124.         CALL L0F76        ; Perform a wait.
  3125.         CALL L0FC1        ; Play a note on each channel and update the channel duration lengths.
  3126.  
  3127.         CALL L0F91        ; Find smallest duration length of the current notes across all channels.
  3128.         JR   L0A9F        ; Jump back to see if there is more to process.
  3129.  
  3130. ; ----------------------------
  3131. ; PLAY Command Character Table
  3132. ; ----------------------------
  3133. ; Recognised characters in PLAY commands.
  3134.  
  3135. L0AB7           DB "HZYXWUVMT)(NO!"     ;DEFM "HZYXWUVMT)(NO!"
  3136.  
  3137. ; ------------------
  3138. ; Get Play Character
  3139. ; ------------------
  3140. ; Get the current character from the PLAY string and then increment the
  3141. ; character pointer within the string.
  3142. ; Exit: Carry flag set if string has been fully processed.
  3143. ;       Carry flag reset if character is available.
  3144. ;       A=Character available.
  3145.  
  3146. L0AC5:  CALL L0EE3        ; Get the current character from the play string for this channel.
  3147.         RET  C            ; Return if no more characters.
  3148.  
  3149.         INC  (IX+$06)     ; Increment the low byte of the string pointer.
  3150.         RET  NZ           ; Return if it has not overflowed.
  3151.  
  3152.         INC  (IX+$07)     ; Else increment the high byte of the string pointer.
  3153.         RET               ; Returns with carry flag reset.
  3154.  
  3155. ; --------------------------
  3156. ; Get Next Note in Semitones
  3157. ; --------------------------
  3158. ; Finds the number of semitones above C for the next note in the string,
  3159. ; Entry: IX=Address of the channel data block.
  3160. ; Exit : A=Number of semitones above C, or $80 for a rest.
  3161.  
  3162. L0AD1:  PUSH HL           ; Save HL.
  3163.  
  3164.         LD   C,$00        ; Default is for a 'natural' note, i.e. no adjustment.
  3165.  
  3166. L0AD4:  CALL L0AC5        ; Get the current character from the PLAY string, and advance the position pointer.
  3167.         JR   C,L0AE1      ; Jump if at the end of the string.
  3168.  
  3169.         CP   '&'          ; $26. Is it a rest?
  3170.         JR   NZ,L0AEC     ; Jump ahead if not.
  3171.  
  3172.         LD   A,$80        ; Signal that it is a rest.
  3173.  
  3174. L0ADF:  POP  HL           ; Restore HL.
  3175.         RET               ;
  3176.  
  3177. L0AE1:  LD   A,(IY+$21)   ; Fetch the channel selector.
  3178.         OR   (IY+$10)     ; Clear the channel flag for this string.
  3179.         LD   (IY+$10),A   ; Store the new channel bitmap.
  3180.         JR   L0ADF        ; Jump back to return.
  3181.  
  3182. L0AEC:  CP   '#'          ; $23. Is it a sharpen?
  3183.         JR   NZ,L0AF3     ; Jump ahead if not.
  3184.  
  3185.         INC  C            ; Increment by a semitone.
  3186.         JR   L0AD4        ; Jump back to get the next character.
  3187.  
  3188. L0AF3:  CP   '$'          ; $24. Is it a flatten?
  3189.         JR   NZ,L0AFA     ; Jump ahead if not.
  3190.  
  3191.         DEC  C            ; Decrement by a semitone.
  3192.         JR   L0AD4        ; Jump back to get the next character.
  3193.  
  3194. L0AFA:  BIT  5,A          ; Is it a lower case letter?
  3195.         JR   NZ,L0B04     ; Jump ahead if lower case.
  3196.  
  3197.         PUSH AF           ; It is an upper case letter so
  3198.         LD   A,$0C        ; increase an octave
  3199.         ADD  A,C          ; by adding 12 semitones.
  3200.         LD   C,A          ;
  3201.         POP  AF           ;
  3202.  
  3203. L0B04:  AND  $DF          ; Convert to upper case.
  3204.         SUB  $41          ; Reduce to range 'A'->0 .. 'G'->6.
  3205.         JP   C,L0F22      ; Jump if below 'A' to produce error report "k Invalid note name".
  3206.  
  3207.         CP   $07          ; Is it 7 or above?
  3208.         JP   NC,L0F22     ; Jump if so to produce error report "k Invalid note name".
  3209.  
  3210.         PUSH BC           ; C=Number of semitones.
  3211.  
  3212.         LD   B,$00        ;
  3213.         LD   C,A          ; BC holds 0..6 for 'a'..'g'.
  3214.         LD   HL,L0DF9     ; Look up the number of semitones above note C for the note.
  3215.         ADD  HL,BC        ;
  3216.         LD   A,(HL)       ; A=Number of semitones above note C.
  3217.  
  3218.         POP  BC           ; C=Number of semitones due to sharpen/flatten characters.
  3219.         ADD  A,C          ; Adjust number of semitones above note C for the sharpen/flatten characters.
  3220.  
  3221.         POP  HL           ; Restore HL.
  3222.         RET               ;
  3223.  
  3224. ; ----------------------------------
  3225. ; Get Numeric Value from Play String
  3226. ; ----------------------------------
  3227. ; Get a numeric value from a PLAY string, returning 0 if no numeric value present.
  3228. ; Entry: IX=Address of the channel data block.
  3229. ; Exit : BC=Numeric value, or 0 if no numeric value found.
  3230.  
  3231. L0B1D:  PUSH HL           ; Save registers.
  3232.         PUSH DE           ;
  3233.  
  3234.         LD   L,(IX+$06)   ; Get the pointer into the PLAY string.
  3235.         LD   H,(IX+$07)   ;
  3236.  
  3237.         LD   DE,$0000     ; Initialise result to 0.
  3238.  
  3239. L0B28:  LD   A,(HL)       ;
  3240.         CP   '0'          ; $30. Is character numeric?
  3241.         JR   C,L0B45      ; Jump ahead if not.
  3242.  
  3243.         CP   ':'          ; $3A. Is character numeric?
  3244.         JR   NC,L0B45     ; Jump ahead if not.
  3245.  
  3246.         INC  HL           ; Advance to the next character.
  3247.         PUSH HL           ; Save the pointer into the string.
  3248.  
  3249.         CALL L0B50        ; Multiply result so far by 10.
  3250.         SUB  '0'          ; $30. Convert ASCII digit to numeric value.
  3251.         LD   H,$00        ;
  3252.         LD   L,A          ; HL=Numeric digit value.
  3253.         ADD  HL,DE        ; Add the numeric value to the result so far.
  3254.         JR   C,L0B42      ; Jump ahead if an overflow to produce error report "l number too big".
  3255.  
  3256.         EX   DE,HL        ; Transfer the result into DE.
  3257.  
  3258.         POP  HL           ; Retrieve the pointer into the string.
  3259.         JR   L0B28        ; Loop back to handle any further numeric digits.
  3260.  
  3261. L0B42:  JP   L0F1A        ; Jump to produce error report "l number too big".
  3262.                           ; [Could have saved 1 byte by directly using JP C,$0F1A (ROM 0) instead of using this JP and
  3263.                           ; the two JR C,$0B42 (ROM 0) instructions that come here]
  3264.  
  3265. ;The end of the numeric value was reached
  3266.  
  3267. L0B45:  LD   (IX+$06),L   ; Store the new pointer position into the string.
  3268.         LD   (IX+$07),H   ;
  3269.  
  3270.         PUSH DE           ;
  3271.         POP  BC           ; Return the result in BC.
  3272.  
  3273.         POP  DE           ; Restore registers.
  3274.         POP  HL           ;
  3275.         RET               ;
  3276.  
  3277. ; -----------------
  3278. ; Multiply DE by 10
  3279. ; -----------------
  3280. ; Entry: DE=Value to multiple by 10.
  3281. ; Exit : DE=Value*10.
  3282.  
  3283. L0B50:  LD   HL,$0000     ;
  3284.         LD   B,$0A        ; Add DE to HL ten times.
  3285.  
  3286. L0B55:  ADD  HL,DE        ;
  3287.         JR   C,L0B42      ; Jump ahead if an overflow to produce error report "l number too big".
  3288.  
  3289.         DJNZ L0B55        ;
  3290.  
  3291.         EX   DE,HL        ; Transfer the result into DE.
  3292.         RET               ;
  3293.  
  3294. ; ----------------------------------
  3295. ; Find Next Note from Channel String
  3296. ; ----------------------------------
  3297. ; Entry: IX=Address of channel data block.
  3298.  
  3299. L0B5C:  CALL L0A3E        ; Test for BREAK being pressed.
  3300.         JR   C,L0B69      ; Jump ahead if not pressed.
  3301.  
  3302.         CALL L0E93        ; Turn off all sound and restore IY.
  3303.         EI                ; Re-enable interrupts.
  3304.  
  3305.         CALL L05AC        ; Produce error report. [Could have saved 1 byte by using JP $05D6 (ROM 0)]
  3306.         DB $14          ; "L Break into program"
  3307.  
  3308. L0B69:  CALL L0AC5        ; Get the current character from the PLAY string, and advance the position pointer.
  3309.         JP   C,L0DA2      ; Jump if at the end of the string.
  3310.  
  3311.         CALL L0DF0        ; Find the handler routine for the PLAY command character.
  3312.  
  3313.         LD   B,$00        ;
  3314.         SLA  C            ; Generate the offset into the
  3315.         LD   HL,L0DCA     ; command vector table.
  3316.         ADD  HL,BC        ; HL points to handler routine for this command character.
  3317.  
  3318.         LD   E,(HL)       ;
  3319.         INC  HL           ;
  3320.         LD   D,(HL)       ; Fetch the handler routine address.
  3321.  
  3322.         EX   DE,HL        ; HL=Handler routine address for this command character.
  3323.         CALL L0B84        ; Make an indirect call to the handler routine.
  3324.         JR   L0B5C        ; Jump back to handle the next character in the string.
  3325.  
  3326. ;Comes here after processing a non-numeric digit that does not have a specific command routine handler
  3327. ;Hence the next note to play has been determined and so a return is made to process the other channels.
  3328.  
  3329. L0B83:  RET               ; Just make a return.
  3330.  
  3331. L0B84:  JP   (HL)         ; Jump to the command handler routine.
  3332.  
  3333. ; --------------------------
  3334. ; Play Command '!' (Comment)
  3335. ; --------------------------
  3336. ; A comment is enclosed within exclamation marks, e.g. "! A comment !".
  3337. ; Entry: IX=Address of the channel data block.
  3338.  
  3339. L0B85:  CALL L0AC5        ; Get the current character from the PLAY string, and advance the position pointer.
  3340.         JP   C,L0DA1      ; Jump if at the end of the string.
  3341.  
  3342.         CP   '!'          ; $21. Is it the end-of-comment character?
  3343.         RET  Z            ; Return if it is.
  3344.  
  3345.         JR   L0B85        ; Jump back to test the next character.
  3346.  
  3347. ; -------------------------
  3348. ; Play Command 'O' (Octave)
  3349. ; -------------------------
  3350. ; The 'O' command is followed by a numeric value within the range 0 to 8,
  3351. ; although due to loose range checking the value MOD 256 only needs to be
  3352. ; within 0 to 8. Hence O256 operates the same as O0.
  3353. ; Entry: IX=Address of the channel data block.
  3354.  
  3355. L0B90:  CALL L0B1D        ; Get following numeric value from the string into BC.
  3356.  
  3357.         LD   A,C          ; Is it between 0 and 8?
  3358.         CP   $09          ;
  3359.         JP   NC,L0F12     ; Jump if above 8 to produce error report "n Out of range".
  3360.  
  3361.         SLA  A            ; Multiply A by 12.
  3362.         SLA  A            ;
  3363.         LD   B,A          ;
  3364.         SLA  A            ;
  3365.         ADD  A,B          ;
  3366.  
  3367.         LD   (IX+$03),A   ; Store the octave value.
  3368.         RET               ;
  3369.  
  3370. ; ----------------------------
  3371. ; Play Command 'N' (Separator)
  3372. ; ----------------------------
  3373. ; The 'N' command is simply a separator marker and so is ignored.
  3374. ; Entry: IX=Address of the channel data block.
  3375.  
  3376. L0BA5:  RET               ; Nothing to do so make an immediate return.
  3377.  
  3378. ; ----------------------------------
  3379. ; Play Command '(' (Start of Repeat)
  3380. ; ----------------------------------
  3381. ; A phrase can be enclosed within brackets causing it to be repeated, i.e. played twice.
  3382. ; Entry: IX=Address of the channel data block.
  3383.  
  3384. L0BA6:  LD   A,(IX+$0B)   ; A=Current level of open bracket nesting.
  3385.         INC  A            ; Increment the count.
  3386.         CP   $05          ; Only 4 levels supported.
  3387.         JP   Z,L0F2A      ; Jump if this is the fifth to produce error report "d Too many brackets".
  3388.  
  3389.         LD   (IX+$0B),A   ; Store the new open bracket nesting level.
  3390.  
  3391.         LD   DE,$000C     ; Offset to the bracket level return position stores.
  3392.         CALL L0C27        ; HL=Address of the pointer in which to store the return location of the bracket.
  3393.  
  3394.         LD   A,(IX+$06)   ; Store the current string position as the return address of the open bracket.
  3395.         LD   (HL),A       ;
  3396.         INC  HL           ;
  3397.         LD   A,(IX+$07)   ;
  3398.         LD   (HL),A       ;
  3399.         RET               ;
  3400.  
  3401. ; --------------------------------
  3402. ; Play Command ')' (End of Repeat)
  3403. ; --------------------------------
  3404. ; A phrase can be enclosed within brackets causing it to be repeated, i.e. played twice.
  3405. ; Brackets can also be nested within each other, to 4 levels deep.
  3406. ; If a closing bracket if used without a matching opening bracket then the whole string up
  3407. ; until that point is repeated indefinitely.
  3408. ; Entry: IX=Address of the channel data block.
  3409.  
  3410. L0BC2:  LD   A,(IX+$16)   ; Fetch the nesting level of closing brackets.
  3411.         LD   DE,$0017     ; Offset to the closing bracket return address store.
  3412.         OR   A            ; Is there any bracket nesting so far?
  3413.         JP   M,L0BF0      ; Jump if none. [Could have been faster by jumping to $0BF3 (ROM 0)]
  3414.  
  3415. ;Has the bracket level been repeated, i.e. re-reached the same position in the string as the closing bracket return address?
  3416.  
  3417.         CALL L0C27        ; HL=Address of the pointer to the corresponding closing bracket return address store.
  3418.         LD   A,(IX+$06)   ; Fetch the low byte of the current address.
  3419.         CP   (HL)         ; Re-reached the closing bracket?
  3420.         JR   NZ,L0BF0     ; Jump ahead if not.
  3421.  
  3422.         INC  HL           ; Point to the high byte.
  3423.         LD   A,(IX+$07)   ; Fetch the high byte address of the current address.
  3424.         CP   (HL)         ; Re-reached the closing bracket?
  3425.         JR   NZ,L0BF0     ; Jump ahead if not.
  3426.  
  3427. ;The bracket level has been repeated. Now check whether this was the outer bracket level.
  3428.  
  3429.         DEC  (IX+$16)     ; Decrement the closing bracket nesting level since this level has been repeated.
  3430.         LD   A,(IX+$16)   ; [There is no need for the LD A,(IX+$16) and OR A instructions since the DEC (IX+$16) already set the flags]
  3431.         OR   A            ; Reached the outer bracket nesting level?
  3432.         RET  P            ; Return if not the outer bracket nesting level such that the character
  3433.                           ; after the closing bracket is processed next.
  3434.  
  3435. ;The outer bracket level has been repeated
  3436.  
  3437.         BIT  0,(IX+$0A)   ; Was this a single closing bracket?
  3438.         RET  Z            ; Return if it was not.
  3439.  
  3440. ;The repeat was caused by a single closing bracket so re-initialise the repeat
  3441.  
  3442.         LD   (IX+$16),$00 ; Restore one level of closing bracket nesting.
  3443.         XOR  A            ; Select closing bracket nesting level 0.
  3444.         JR   L0C0B        ; Jump ahead to continue.
  3445.  
  3446. ;A new level of closing bracket nesting
  3447.  
  3448. L0BF0:  LD   A,(IX+$16)   ; Fetch the nesting level of closing brackets.
  3449.         INC  A            ; Increment the count.
  3450.         CP   $05          ; Only 5 levels supported (4 to match up with opening brackets and a 5th to repeat indefinitely).
  3451.         JP   Z,L0F2A      ; Jump if this is the fifth to produce error report "d Too many brackets".
  3452.  
  3453.         LD   (IX+$16),A   ; Store the new closing bracket nesting level.
  3454.  
  3455.         CALL L0C27        ; HL=Address of the pointer to the appropriate closing bracket return address store.
  3456.  
  3457.         LD   A,(IX+$06)   ; Store the current string position as the return address for the closing bracket.
  3458.         LD   (HL),A       ;
  3459.         INC  HL           ;
  3460.         LD   A,(IX+$07)   ;
  3461.         LD   (HL),A       ;
  3462.  
  3463.         LD   A,(IX+$0B)   ; Fetch the nesting level of opening brackets.
  3464.  
  3465. L0C0B:  LD   DE,$000C     ;
  3466.         CALL L0C27        ; HL=Address of the pointer to the opening bracket nesting level return address store.
  3467.  
  3468.         LD   A,(HL)       ; Set the return address of the nesting level's opening bracket
  3469.         LD   (IX+$06),A   ; as new current position within the string.
  3470.         INC  HL           ;
  3471.         LD   A,(HL)       ; For a single closing bracket only, this will be the start address of the string.
  3472.         LD   (IX+$07),A   ;
  3473.  
  3474.         DEC  (IX+$0B)     ; Decrement level of open bracket nesting.
  3475.         RET  P            ; Return if the closing bracket matched an open bracket.
  3476.  
  3477. ;There is one more closing bracket then opening brackets, i.e. repeat string indefinitely
  3478.  
  3479.         LD   (IX+$0B),$00 ; Set the opening brackets nesting level to 0.
  3480.         SET  0,(IX+$0A)   ; Signal a single closing bracket only, i.e. to repeat the string indefinitely.
  3481.         RET               ;
  3482.  
  3483. ; ------------------------------------
  3484. ; Get Address of Bracket Pointer Store
  3485. ; ------------------------------------
  3486. ; Entry: IX=Address of the channel data block.
  3487. ;        DE=Offset to the bracket pointer stores.
  3488. ;        A=Index into the bracket pointer stores.
  3489. ; Exit : HL=Address of the specified pointer store.
  3490.  
  3491. L0C27:  PUSH IX           ;
  3492.         POP  HL           ; HL=IX.
  3493.  
  3494.         ADD  HL,DE        ; HL=IX+DE.
  3495.         LD   B,$00        ;
  3496.         LD   C,A          ;
  3497.         SLA  C            ;
  3498.         ADD  HL,BC        ; HL=IX+DE+2*A.
  3499.         RET               ;
  3500.  
  3501. ; ------------------------
  3502. ; Play Command 'T' (Tempo)
  3503. ; ------------------------
  3504. ; A temp command must be specified in the first play string and is followed by a numeric
  3505. ; value in the range 60 to 240 representing the number of beats (crotchets) per minute.
  3506. ; Entry: IX=Address of the channel data block.
  3507.  
  3508. L0C32:  CALL L0B1D        ; Get following numeric value from the string into BC.
  3509.         LD   A,B          ;
  3510.         OR   A            ;
  3511.         JP   NZ,L0F12     ; Jump if 256 or above to produce error report "n Out of range".
  3512.  
  3513.         LD   A,C          ;
  3514.         CP   $3C          ;
  3515.         JP   C,L0F12      ; Jump if 59 or below to produce error report "n Out of range".
  3516.  
  3517.         CP   $F1          ;
  3518.         JP   NC,L0F12     ; Jump if 241 or above to produce error report "n Out of range".
  3519.  
  3520. ;A holds a value in the range 60 to 240
  3521.  
  3522.         LD   A,(IX+$02)   ; Fetch the channel number.
  3523.         OR   A            ; Tempo 'T' commands have to be specified in the first string.
  3524.         RET  NZ           ; If it is in a later string then ignore it.
  3525.  
  3526.         LD   B,$00        ; [Redundant instruction - B is already zero]
  3527.         PUSH BC           ; C=Tempo value.
  3528.         POP  HL           ;
  3529.         ADD  HL,HL        ;
  3530.         ADD  HL,HL        ; HL=Tempo*4.
  3531.  
  3532.         PUSH HL           ;
  3533.         POP  BC           ; BC=Tempo*4. [Would have been quicker to use the combination LD B,H and LD C,L]
  3534.  
  3535.         PUSH IY           ; Save the pointer to the play command data block.
  3536.         RST  28H          ;
  3537.         DEFW STACK_BC     ; $2D2B. Place the contents of BC onto the stack. The call restores IY to $5C3A.
  3538.         DI                ; Interrupts get re-enabled by the call mechanism to ROM 1 so disable them again.
  3539.         POP  IY           ; Restore IY to point at the play command data block.
  3540.  
  3541.         PUSH IY           ; Save the pointer to the play command data block.
  3542.  
  3543.         PUSH IY           ;
  3544.         POP  HL           ; HL=pointer to the play command data block.
  3545.  
  3546.         LD   BC,$002B     ;
  3547.         ADD  HL,BC        ; HL =IY+$002B.
  3548.         LD   IY,$5C3A     ; Reset IY to $5C3A since this is required by the floating point calculator.
  3549.         PUSH HL           ; HL=Points to the calculator RAM routine.
  3550.  
  3551.         LD   HL,L0C76     ;
  3552.         LD   (RETADDR),HL ; $5B5A. Set up the return address.
  3553.  
  3554.         LD   HL,YOUNGER   ;
  3555.         EX   (SP),HL      ; Stack the address of the swap routine used when returning to this ROM.
  3556.         PUSH HL           ; Re-stack the address of the calculator RAM routine.
  3557.  
  3558.         JP   SWAP         ; $5B00. Toggle to other ROM and make a return to the calculator RAM routine.
  3559.  
  3560. ; --------------------
  3561. ; Tempo Command Return
  3562. ; --------------------
  3563. ; The calculator stack now holds the value (10/(Tempo*4))/7.33e-6 and this is stored as the tempo value.
  3564. ; The result is used an inner loop counter in the wait routine at $0F76 (ROM 0). Each iteration of this loop
  3565. ; takes 26 T-states. The time taken by 26 T-states is 7.33e-6 seconds. So the total time for the loop
  3566. ; to execute is 2.5/TEMPO seconds.
  3567.  
  3568. L0C76:  DI                ; Interrupts get re-enabled by the call mechanism to ROM 1 so disable them again.
  3569.  
  3570.         RST  28H          ;
  3571.         DEFW FP_TO_BC     ; $2DA2. Fetch the value on the top of the calculator stack.
  3572.  
  3573.         DI                ; Interrupts get re-enabled by the call mechanism to ROM 1 so disable them again.
  3574.  
  3575.         POP  IY           ; Restore IY to point at the play command data block.
  3576.  
  3577.         LD   (IY+$27),C   ; Store tempo timing value.
  3578.         LD   (IY+$28),B   ;
  3579.         RET               ;
  3580.  
  3581. ; ------------------------
  3582. ; Play Command 'M' (Mixer)
  3583. ; ------------------------
  3584. ; This command is used to select whether to use tone and/or noise on each of the 3 channels.
  3585. ; It is followed by a numeric value in the range 1 to 63, although due to loose range checking the
  3586. ; value MOD 256 only needs to be within 0 to 63. Hence M256 operates the same as M0.
  3587. ; Entry: IX=Address of the channel data block.
  3588.  
  3589. L0C84:  CALL L0B1D        ; Get following numeric value from the string into BC.
  3590.         LD   A,C          ; A=Mixer value.
  3591.         CP   $40          ; Is it 64 or above?
  3592.         JP   NC,L0F12     ; Jump if so to produce error report "n Out of range".
  3593.  
  3594. ;Bit 0: 1=Enable channel A tone.
  3595. ;Bit 1: 1=Enable channel B tone.
  3596. ;Bit 2: 1=Enable channel C tone.
  3597. ;Bit 3: 1=Enable channel A noise.
  3598. ;Bit 4: 1=Enable channel B noise.
  3599. ;Bit 5: 1=Enable channel C noise.
  3600.  
  3601.         CPL               ; Invert the bits since the sound generator's mixer register uses active low enable.
  3602.                           ; This also sets bit 6 1, which selects the I/O port as an output.
  3603.         LD   E,A          ; E=Mixer value.
  3604.         LD   D,$07        ; D=Register 7 - Mixer.
  3605.         CALL L0E7C        ; Write to sound generator register to set the mixer.
  3606.         RET               ; [Could have saved 1 byte by using JP $0E7C (ROM 0)]
  3607.  
  3608. ; -------------------------
  3609. ; Play Command 'V' (Volume)
  3610. ; -------------------------
  3611. ; This sets the volume of a channel and is followed by a numeric value in the range
  3612. ; 0 (minimum) to 15 (maximum), although due to loose range checking the value MOD 256
  3613. ; only needs to be within 0 to 15. Hence V256 operates the same as V0.
  3614. ; Entry: IX=Address of the channel data block.
  3615.  
  3616. L0C95:  CALL L0B1D        ; Get following numeric value from the string into BC.
  3617.  
  3618.         LD   A,C          ;
  3619.         CP   $10          ; Is it 16 or above?
  3620.         JP   NC,L0F12     ; Jump if so to produce error report "n Out of range".
  3621.  
  3622.         LD   (IX+$04),A   ; Store the volume level.
  3623.  
  3624. ; [*BUG* - An attempt to set the volume for a sound chip channel is now made. However, this routine fails to take into account
  3625. ;          that it is also called to set the volume for a MIDI only channel, i.e. play strings 4 to 8. As a result, corruption
  3626. ;          occurs to various sound generator registers, causing spurious sound output. There is in fact no need for this routine
  3627. ;          to set the volume for any channels since this is done every time a new note is played - see routine at $0A97 (ROM 0).
  3628. ;          the bug fix is to simply to make a return at this point. This routine therefore contains 11 surplus bytes. Credit: Ian Collier (+3), Paul Farrow (128)]
  3629.  
  3630.         LD   E,(IX+$02)   ; E=Channel number.
  3631.         LD   A,$08        ; Offset by 8.
  3632.         ADD  A,E          ; A=8+index.
  3633.         LD   D,A          ; D=Sound generator register number for the channel.
  3634.  
  3635.         LD   E,C          ; E=Volume level.
  3636.         CALL L0E7C        ; Write to sound generator register to set the volume for the channel.
  3637.         RET               ; [Could have saved 1 byte by using JP $0E7C (ROM 0)]
  3638.  
  3639. ; ------------------------------------
  3640. ; Play Command 'U' (Use Volume Effect)
  3641. ; ------------------------------------
  3642. ; This command turns on envelope waveform effects for a particular sound chip channel. The volume level is now controlled by
  3643. ; the selected envelope waveform for the channel, as defined by the 'W' command. MIDI channels do not support envelope waveforms
  3644. ; and so the routine has the effect of setting the volume of a MIDI channel to maximum, i.e. 15. It might seem odd that the volume
  3645. ; for MIDI channels is set to 15 rather than just filtered out. However, the three sound chip channels can also drive three MIDI
  3646. ; channels and so it would be inconsistent for these MIDI channels to have their volume set to 15 but have the other MIDI channels
  3647. ; behave differently. However, it could be argued that all MIDI channels should be unaffected by the 'U' command.
  3648. ; There are no parameters to this command.
  3649. ; Entry: IX=Address of the channel data block.
  3650.  
  3651. L0CAD:  LD   E,(IX+$02)   ; Get the channel number.
  3652.         LD   A,$08        ; Offset by 8.
  3653.         ADD  A,E          ; A=8+index.
  3654.         LD   D,A          ; D=Sound generator register number for the channel. [This is not used and so there is no need to generate it. It was probably a left
  3655.                           ; over from copying and modifying the 'V' command routine. Deleting it would save 7 bytes. Credit: Ian Collier (+3), Paul Farrow (128)]
  3656.  
  3657.         LD   E,$1F        ; E=Select envelope defined by register 13, and reset volume bits to maximum (though these are not used with the envelope).
  3658.         LD   (IX+$04),E   ; Store that the envelope is being used (along with the reset volume level).
  3659.         RET               ;
  3660.  
  3661. ; ------------------------------------------
  3662. ; Play command 'W' (Volume Effect Specifier)
  3663. ; ------------------------------------------
  3664. ; This command selects the envelope waveform to use and is followed by a numeric value in the range
  3665. ; 0 to 7, although due to loose range checking the value MOD 256 only needs to be within 0 to 7.
  3666. ; Hence W256 operates the same as W0.
  3667. ; Entry: IX=Address of the channel data block.
  3668.  
  3669. L0CBA:  CALL L0B1D        ; Get following numeric value from the string into BC.
  3670.  
  3671.         LD   A,C          ;
  3672.         CP   $08          ; Is it 8 or above?
  3673.         JP   NC,L0F12     ; Jump if so to produce error report "n Out of range".
  3674.  
  3675.         LD   B,$00        ;
  3676.         LD   HL,L0DE8     ; Envelope waveform lookup table.
  3677.         ADD  HL,BC        ; HL points to the corresponding value in the table.
  3678.         LD   A,(HL)       ;
  3679.         LD   (IY+$29),A   ; Store new effect waveform value.
  3680.         RET               ;
  3681.  
  3682. ; -----------------------------------------
  3683. ; Play Command 'X' (Volume Effect Duration)
  3684. ; -----------------------------------------
  3685. ; This command allows the duration of a waveform effect to be specified, and is followed by a numeric
  3686. ; value in the range 0 to 65535. A value of 1 corresponds to the minimum duration, increasing up to 65535
  3687. ; and then maximum duration for a value of 0. If no numeric value is specified then the maximum duration is used.
  3688. ; Entry: IX=Address of the channel data block.
  3689.  
  3690. L0CCE:  CALL L0B1D        ; Get following numeric value from the string into BC.
  3691.  
  3692.         LD   D,$0B        ; Register 11 - Envelope Period Fine.
  3693.         LD   E,C          ;
  3694.         CALL L0E7C        ; Write to sound generator register to set the envelope period (low byte).
  3695.  
  3696.         INC  D            ; Register 12 - Envelope Period Coarse.
  3697.         LD   E,B          ;
  3698.         CALL L0E7C        ; Write to sound generator register to set the envelope period (high byte).
  3699.         RET               ; [Could have saved 1 byte by using JP $0E7C (ROM 0)]
  3700.  
  3701. ; -------------------------------
  3702. ; Play Command 'Y' (MIDI Channel)
  3703. ; -------------------------------
  3704. ; This command sets the MIDI channel number that the string is assigned to and is followed by a numeric
  3705. ; value in the range 1 to 16, although due to loose range checking the value MOD 256 only needs to be within 1 to 16.
  3706. ; Hence Y257 operates the same as Y1.
  3707. ; Entry: IX=Address of the channel data block.
  3708.  
  3709. L0CDD:  CALL L0B1D        ; Get following numeric value from the string into BC.
  3710.  
  3711.         LD   A,C          ;
  3712.         DEC  A            ; Is it 0?
  3713.         JP   M,L0F12      ; Jump if so to produce error report "n Out of range".
  3714.  
  3715.         CP   $10          ; Is it 10 or above?
  3716.         JP   NC,L0F12     ; Jump if so to produce error report "n Out of range".
  3717.  
  3718.         LD   (IX+$01),A   ; Store MIDI channel number that this string is assigned to.
  3719.         RET               ;
  3720.  
  3721. ; ----------------------------------------
  3722. ; Play Command 'Z' (MIDI Programming Code)
  3723. ; ----------------------------------------
  3724. ; This command is used to send a programming code to the MIDI port. It is followed by a numeric
  3725. ; value in the range 0 to 255, although due to loose range checking the value MOD 256 only needs
  3726. ; to be within 0 to 255. Hence Z256 operates the same as Z0.
  3727. ; Entry: IX=Address of the channel data block.
  3728.  
  3729. L0CEE:  CALL L0B1D        ; Get following numeric value from the string into BC.
  3730.  
  3731.         LD   A,C          ; A=(low byte of) the value.
  3732.         CALL L11A3        ; Write byte to MIDI device.
  3733.         RET               ; [Could have saved 1 byte by using JP $0E7C (ROM 0)]
  3734.  
  3735. ; -----------------------
  3736. ; Play Command 'H' (Stop)
  3737. ; -----------------------
  3738. ; This command stops further processing of a play command. It has no parameters.
  3739. ; Entry: IX=Address of the channel data block.
  3740.  
  3741. L0CF6:  LD   (IY+$10),$FF ; Indicate no channels to play, thereby causing
  3742.         RET               ; the play command to terminate.
  3743.  
  3744. ; --------------------------------------------------------
  3745. ; Play Commands 'a'..'g', 'A'..'G', '1'.."12", '&' and '_'
  3746. ; --------------------------------------------------------
  3747. ; This handler routine processes commands 'a'..'g', 'A'..'G', '1'.."12", '&' and '_',
  3748. ; and determines the length of the next note to play. It provides the handling of triplet and tied notes.
  3749. ; It stores the note duration in the channel data block's duration length entry, and sets a pointer in the command
  3750. ; data block's duration lengths pointer table to point at it. A single note letter is deemed to be a tied
  3751. ; note count of 1. Triplets are deemed a tied note count of at least 2.
  3752. ; Entry: IX=Address of the channel data block.
  3753. ;        A=Current character from play string.
  3754.  
  3755. L0CFB:  CALL L0E19        ; Is the current character a number?
  3756.         JP   C,L0D81      ; Jump if not number digit.
  3757.  
  3758. ;The character is a number digit
  3759.  
  3760.         CALL L0DAC        ; HL=Address of the duration length within the channel data block.
  3761.         CALL L0DB4        ; Store address of duration length in command data block's channel duration length pointer table.
  3762.  
  3763.         XOR  A            ;
  3764.         LD   (IX+$21),A   ; Set no tied notes.
  3765.  
  3766.         CALL L0EC8        ; Get the previous character in the string, the note duration.
  3767.         CALL L0B1D        ; Get following numeric value from the string into BC.
  3768.         LD   A,C          ;
  3769.         OR   A            ; Is the value 0?
  3770.         JP   Z,L0F12      ; Jump if so to produce error report "n Out of range".
  3771.  
  3772.         CP   $0D          ; Is it 13 or above?
  3773.         JP   NC,L0F12     ; Jump if so to produce error report "n Out of range".
  3774.  
  3775.         CP   $0A          ; Is it below 10?
  3776.         JR   C,L0D32      ; Jump if so.
  3777.  
  3778. ;It is a triplet semi-quaver (10), triplet quaver (11) or triplet crotchet (12)
  3779.  
  3780.         CALL L0E00        ; DE=Note duration length for the duration value.
  3781.         CALL L0D74        ; Increment the tied notes counter.
  3782.         LD   (HL),E       ; HL=Address of the duration length within the channel data block.
  3783.         INC  HL           ;
  3784.         LD   (HL),D       ; Store the duration length.
  3785.  
  3786. L0D28:  CALL L0D74        ; Increment the counter of tied notes.
  3787.  
  3788.         INC  HL           ;
  3789.         LD   (HL),E       ;
  3790.         INC  HL           ; Store the subsequent note duration length in the channel data block.
  3791.         LD   (HL),D       ;
  3792.         INC  HL           ;
  3793.         JR   L0D38        ; Jump ahead to continue.
  3794.  
  3795. ;The note duration was in the range 1 to 9
  3796.  
  3797. L0D32:  LD   (IX+$05),C   ; C=Note duration value (1..9).
  3798.         CALL L0E00        ; DE=Duration length for this duration value.
  3799.  
  3800. L0D38:  CALL L0D74        ; Increment the tied notes counter.
  3801.  
  3802. L0D3B:  CALL L0EE3        ; Get the current character from the play string for this channel.
  3803.  
  3804.         CP   '_'          ; $5F. Is it a tied note?
  3805.         JR   NZ,L0D6E     ; Jump ahead if not.
  3806.  
  3807.         CALL L0AC5        ; Get the current character from the PLAY string, and advance the position pointer.
  3808.         CALL L0B1D        ; Get following numeric value from the string into BC.
  3809.         LD   A,C          ; Place the value into A.
  3810.         CP   $0A          ; Is it below 10?
  3811.         JR   C,L0D5F      ; Jump ahead for 1 to 9 (semiquaver ... semibreve).
  3812.  
  3813. ;A triplet note was found as part of a tied note
  3814.  
  3815.         PUSH HL           ; HL=Address of the duration length within the channel data block.
  3816.         PUSH DE           ; DE=First tied note duration length.
  3817.         CALL L0E00        ; DE=Note duration length for this new duration value.
  3818.         POP  HL           ; HL=Current tied note duration length.
  3819.         ADD  HL,DE        ; HL=Current+new tied note duration lengths.
  3820.         LD   C,E          ;
  3821.         LD   B,D          ; BC=Note duration length for the duration value.
  3822.         EX   DE,HL        ; DE=Current+new tied note duration lengths.
  3823.         POP  HL           ; HL=Address of the duration length within the channel data block.
  3824.  
  3825.         LD   (HL),E       ;
  3826.         INC  HL           ;
  3827.         LD   (HL),D       ; Store the combined note duration length in the channel data block.
  3828.  
  3829.         LD   E,C          ;
  3830.         LD   D,B          ; DE=Note duration length for the second duration value.
  3831.         JR   L0D28        ; Jump back.
  3832.  
  3833. ;A non-triplet tied note
  3834.  
  3835. L0D5F:  LD   (IX+$05),C   ; Store the note duration value.
  3836.  
  3837.         PUSH HL           ; HL=Address of the duration length within the channel data block.
  3838.         PUSH DE           ; DE=First tied note duration length.
  3839.         CALL L0E00        ; DE=Note duration length for this new duration value.
  3840.         POP  HL           ; HL=Current tied note duration length.
  3841.         ADD  HL,DE        ; HL=Current+new tied not duration lengths.
  3842.         EX   DE,HL        ; DE=Current+new tied not duration lengths.
  3843.         POP  HL           ; HL=Address of the duration length within the channel data block.
  3844.  
  3845.         JP   L0D3B        ; Jump back to process the next character in case it is also part of a tied note.
  3846.  
  3847. ;The number found was not part of a tied note, so store the duration value
  3848.  
  3849. L0D6E:  LD   (HL),E       ; HL=Address of the duration length within the channel data block.
  3850.         INC  HL           ; (For triplet notes this could be the address of the subsequent note duration length)
  3851.         LD   (HL),D       ; Store the duration length.
  3852.         JP   L0D9C        ; Jump forward to make a return.
  3853.  
  3854. ; This subroutine is called to increment the tied notes counter
  3855.  
  3856. L0D74:  LD   A,(IX+$21)   ; Increment counter of tied notes.
  3857.         INC  A            ;
  3858.         CP   $0B          ; Has it reached 11?
  3859.         JP   Z,L0F3A      ; Jump if so to produce to error report "o too many tied notes".
  3860.  
  3861.         LD   (IX+$21),A   ; Store the new tied notes counter.
  3862.         RET               ;
  3863.  
  3864. ;The character is not a number digit so is 'A'..'G', '&' or '_'
  3865.  
  3866. L0D81:  CALL L0EC8        ; Get the previous character from the string.
  3867.  
  3868.         LD   (IX+$21),$01 ; Set the number of tied notes to 1.
  3869.  
  3870. ;Store a pointer to the channel data block's duration length into the command data block
  3871.  
  3872.         CALL L0DAC        ; HL=Address of the duration length within the channel data block.
  3873.         CALL L0DB4        ; Store address of duration length in command data block's channel duration length pointer table.
  3874.  
  3875.         LD   C,(IX+$05)   ; C=The duration value of the note (1 to 9).
  3876.         PUSH HL           ; [Not necessary]
  3877.         CALL L0E00        ; Find the duration length for the note duration value.
  3878.         POP  HL           ; [Not necessary]
  3879.  
  3880.         LD   (HL),E       ; Store it in the channel data block.
  3881.         INC  HL           ;
  3882.         LD   (HL),D       ;
  3883.         JP   L0D9C        ; Jump to the instruction below. [Redundant instruction]
  3884.  
  3885. L0D9C:  POP  HL           ;
  3886.         INC  HL           ;
  3887.         INC  HL           ; Modify the return address to point to the RET instruction at $0B83 (ROM 0).
  3888.         PUSH HL           ;
  3889.         RET               ; [Over elaborate when a simple POP followed by RET would have sufficed, saving 3 bytes]
  3890.  
  3891. ; -------------------
  3892. ; End of String Found
  3893. ; -------------------
  3894. ;This routine is called when the end of string is found within a comment. It marks the
  3895. ;string as having been processed and then returns to the main loop to process the next string.
  3896.  
  3897. L0DA1:  POP  HL           ; Drop the return address of the call to the comment command.
  3898.  
  3899. ;Enter here if the end of the string is found whilst processing a string.
  3900.  
  3901. L0DA2:  LD   A,(IY+$21)   ; Fetch the channel selector.
  3902.         OR   (IY+$10)     ; Clear the channel flag for this string.
  3903.         LD   (IY+$10),A   ; Store the new channel bitmap.
  3904.         RET               ;
  3905.  
  3906. ; --------------------------------------------------
  3907. ; Point to Duration Length within Channel Data Block
  3908. ; --------------------------------------------------
  3909. ; Entry: IX=Address of the channel data block.
  3910. ; Exit : HL=Address of the duration length within the channel data block.
  3911.  
  3912. L0DAC:  PUSH IX           ;
  3913.         POP  HL           ; HL=Address of the channel data block.
  3914.         LD   BC,$0022     ;
  3915.         ADD  HL,BC        ; HL=Address of the store for the duration length.
  3916.         RET               ;
  3917.  
  3918. ; -------------------------------------------------------------------------
  3919. ; Store Entry in Command Data Block's Channel Duration Length Pointer Table
  3920. ; -------------------------------------------------------------------------
  3921. ; Entry: IY=Address of the command data block.
  3922. ;        IX=Address of the channel data block for the current string.
  3923. ;        HL=Address of the duration length store within the channel data block.
  3924. ; Exit : HL=Address of the duration length store within the channel data block.
  3925. ;        DE=Channel duration.
  3926.  
  3927. L0DB4:  PUSH HL           ; Save the address of the duration length within the channel data block.
  3928.  
  3929.         PUSH IY           ;
  3930.         POP  HL           ; HL=Address of the command data block.
  3931.  
  3932.         LD   BC,$0011     ;
  3933.         ADD  HL,BC        ; HL=Address within the command data block of the channel duration length pointer table.
  3934.  
  3935.         LD   B,$00        ;
  3936.         LD   C,(IX+$02)   ; BC=Channel number.
  3937.  
  3938.         SLA  C            ; BC=2*Index number.
  3939.         ADD  HL,BC        ; HL=Address within the command data block of the pointer to the current channel's data block duration length.
  3940.  
  3941.         POP  DE           ; DE=Address of the duration length within the channel data block.
  3942.  
  3943.         LD   (HL),E       ; Store the pointer to the channel duration length in the command data block's channel duration pointer table.
  3944.         INC  HL           ;
  3945.         LD   (HL),D       ;
  3946.         EX   DE,HL        ;
  3947.         RET               ;
  3948.  
  3949. ; -----------------------
  3950. ; PLAY Command Jump Table
  3951. ; -----------------------
  3952. ; Handler routine jump table for all PLAY commands.
  3953.  
  3954. L0DCA:  DEFW L0CFB        ; Command handler routine for all other characters.
  3955.         DEFW L0B85        ; '!' command handler routine.
  3956.         DEFW L0B90        ; 'O' command handler routine.
  3957.         DEFW L0BA5        ; 'N' command handler routine.
  3958.         DEFW L0BA6        ; '(' command handler routine.
  3959.         DEFW L0BC2        ; ')' command handler routine.
  3960.         DEFW L0C32        ; 'T' command handler routine.
  3961.         DEFW L0C84        ; 'M' command handler routine.
  3962.         DEFW L0C95        ; 'V' command handler routine.
  3963.         DEFW L0CAD        ; 'U' command handler routine.
  3964.         DEFW L0CBA        ; 'W' command handler routine.
  3965.         DEFW L0CCE        ; 'X' command handler routine.
  3966.         DEFW L0CDD        ; 'Y' command handler routine.
  3967.         DEFW L0CEE        ; 'Z' command handler routine.
  3968.         DEFW L0CF6        ; 'H' command handler routine.
  3969.  
  3970. ; ------------------------------
  3971. ; Envelope Waveform Lookup Table
  3972. ; ------------------------------
  3973. ; Table used by the play 'W' command to find the corresponding envelope value
  3974. ; to write to the sound generator envelope shape register (register 13). This
  3975. ; filters out the two duplicate waveforms possible from the sound generator and
  3976. ; allows the order of the waveforms to be arranged in a more logical fashion.
  3977.  
  3978. L0DE8:  DB $00          ; W0 - Single decay then off.   (Continue off, attack off, alternate off, hold off)
  3979.         DB $04          ; W1 - Single attack then off.  (Continue off, attack on,  alternate off, hold off)
  3980.         DB $0B          ; W2 - Single decay then hold.  (Continue on,  attack off, alternate on,  hold on)
  3981.         DB $0D          ; W3 - Single attack then hold. (Continue on,  attack on,  alternate off, hold on)
  3982.         DB $08          ; W4 - Repeated decay.          (Continue on,  attack off, alternate off, hold off)
  3983.         DB $0C          ; W5 - Repeated attack.         (Continue on,  attack on,  alternate off, hold off)
  3984.         DB $0E          ; W6 - Repeated attack-decay.   (Continue on,  attack on,  alternate on,  hold off)
  3985.         DB $0A          ; W7 - Repeated decay-attack.   (Continue on,  attack off, alternate on,  hold off)
  3986.  
  3987. ; --------------------------
  3988. ; Identify Command Character
  3989. ; --------------------------
  3990. ; This routines attempts to match the command character to those in a table.
  3991. ; The index position of the match indicates which command handler routine is required
  3992. ; to process the character. Note that commands are case sensitive.
  3993. ; Entry: A=Command character.
  3994. ; Exit : Zero flag set if a match was found.
  3995. ;        BC=Indentifying the character matched, 1 to 15 for match and 0 for no match.
  3996.  
  3997. L0DF0:  LD   BC,$000F     ; Number of characters + 1 in command table.
  3998.         LD   HL,L0AB7     ; Start of command table.
  3999.         CPIR              ; Search for a match.
  4000.         RET               ;
  4001.  
  4002. ; ---------------
  4003. ; Semitones Table
  4004. ; ---------------
  4005. ; This table contains an entry for each note of the scale, A to G,
  4006. ; and is the number of semitones above the note C.
  4007.  
  4008. L0DF9:  DB $09          ; 'A'
  4009.         DB $0B          ; 'B'
  4010.         DB $00          ; 'C'
  4011.         DB $02          ; 'D'
  4012.         DB $04          ; 'E'
  4013.         DB $05          ; 'F'
  4014.         DB $07          ; 'G'
  4015.  
  4016. ; -------------------------
  4017. ; Find Note Duration Length
  4018. ; -------------------------
  4019. ; Entry: C=Duration value (0 to 12, although a value of 0 is never used).
  4020. ; Exit : DE=Note duration length.
  4021.  
  4022. L0E00:  PUSH HL           ; Save HL.
  4023.  
  4024.         LD   B,$00        ;
  4025.         LD   HL,L0E0C     ; Note duration table.
  4026.         ADD  HL,BC        ; Index into the table.
  4027.         LD   D,$00        ;
  4028.         LD   E,(HL)       ; Fetch the length from the table.
  4029.  
  4030.         POP  HL           ; Restore HL.
  4031.         RET               ;
  4032.  
  4033. ; -------------------
  4034. ; Note Duration Table
  4035. ; -------------------
  4036. ; A whole note is given by a value of 96d and other notes defined in relation to this.
  4037. ; The value of 96d is the lowest common denominator from which all note durations
  4038. ; can be defined.
  4039.  
  4040. L0E0C:  DB $80          ; Rest                 [Not used since table is always indexed into with a value of 1 or more]
  4041.         DB $06          ; Semi-quaver          (sixteenth note).
  4042.         DB $09          ; Dotted semi-quaver   (3/32th note).
  4043.         DB $0C          ; Quaver               (eighth note).
  4044.         DB $12          ; Dotted quaver        (3/16th note).
  4045.         DB $18          ; Crotchet             (quarter note).
  4046.         DB $24          ; Dotted crotchet      (3/8th note).
  4047.         DB $30          ; Minim                (half note).
  4048.         DB $48          ; Dotted minim         (3/4th note).
  4049.         DB $60          ; Semi-breve           (whole note).
  4050.         DB $04          ; Triplet semi-quaver  (1/24th note).
  4051.         DB $08          ; Triplet quaver       (1/12th note).
  4052.         DB $10          ; Triplet crochet      (1/6th note).
  4053.  
  4054. ; -----------------
  4055. ; Is Numeric Digit?
  4056. ; -----------------
  4057. ; Tests whether a character is a number digit.
  4058. ; Entry: A=Character.
  4059. ; Exit : Carry flag reset if a number digit.
  4060.  
  4061. L0E19:  CP   '0'          ; $30. Is it '0' or less?
  4062.         RET  C            ; Return with carry flag set if so.
  4063.  
  4064.         CP   ':'          ; $3A. Is it more than '9'?
  4065.         CCF               ;
  4066.         RET               ; Return with carry flag set if so.
  4067.  
  4068. ; -----------------------------------
  4069. ; Play a Note On a Sound Chip Channel
  4070. ; -----------------------------------
  4071. ; This routine plays the note at the current octave and current volume on a sound chip channel. For play strings 4 to 8,
  4072. ; it simply stores the note number and this is subsequently played later.
  4073. ; Entry: IX=Address of the channel data block.
  4074. ;        A=Note value as number of semitones above C (0..11).
  4075.  
  4076. L0E20:  LD   C,A          ; C=The note value.
  4077.         LD   A,(IX+$03)   ; Octave number * 12.
  4078.         ADD  A,C          ; Add the octave number and the note value to form the note number.
  4079.         CP   $80          ; Is note within range?
  4080.         JP   NC,L0F32     ; Jump if not to produce error report "m Note out of range".
  4081.  
  4082.         LD   C,A          ; C=Note number.
  4083.         LD   A,(IX+$02)   ; Get the channel number.
  4084.         OR   A            ; Is it the first channel?
  4085.         JR   NZ,L0E3F     ; Jump ahead if not.
  4086.  
  4087. ;Only set the noise generator frequency on the first channel
  4088.  
  4089.         LD   A,C          ; A=Note number (0..107), in ascending audio frequency.
  4090.         CPL               ; Invert since noise register value is in descending audio frequency.
  4091.         AND  $7F          ; Mask off bit 7.
  4092.         SRL  A            ;
  4093.         SRL  A            ; Divide by 4 to reduce range to 0..31.
  4094.         LD   D,$06        ; Register 6 - Noise pitch.
  4095.         LD   E,A          ;
  4096.         CALL L0E7C        ; Write to sound generator register.
  4097.  
  4098. L0E3F:  LD   (IX+$00),C   ; Store the note number.
  4099.         LD   A,(IX+$02)   ; Get the channel number.
  4100.         CP   $03          ; Is it channel 0, 1 or 2, i.e. a sound chip channel?
  4101.         RET  NC           ; Do not output anything for play strings 4 to 8.
  4102.  
  4103. ;Channel 0, 1 or 2
  4104.  
  4105.         LD   HL,L1096     ; Start of note lookup table.
  4106.         LD   B,$00        ; BC=Note number.
  4107.         LD   A,C          ; A=Note number.
  4108.         SUB  $15          ; A=Note number - 21.
  4109.         JR   NC,L0E57     ; Jump if note number was 21 or above.
  4110.  
  4111.         LD   DE,$0FBF     ; Note numbers $00 to $14 use the lowest note value.
  4112.         JR   L0E5E        ; [Could have saved 4 bytes by using XOR A and dropping through to $0E57 (ROM 0)]
  4113.  
  4114. ;Note number 21 to 107 (range 0 to 86)
  4115.  
  4116. L0E57:  LD   C,A          ;
  4117.         SLA  C            ; Generate offset into the table.
  4118.         ADD  HL,BC        ; Point to the entry in the table.
  4119.         LD   E,(HL)       ;
  4120.         INC  HL           ;
  4121.         LD   D,(HL)       ; DE=Word to write to the sound chip registers to produce this note.
  4122.  
  4123. L0E5E:  EX   DE,HL        ; HL=Register word value to produce the note.
  4124.  
  4125.         LD   D,(IX+$02)   ; Get the channel number.
  4126.         SLA  D            ; D=2*Channel number, to give the tone channel register (fine control) number 0, 2, or 4.
  4127.         LD   E,L          ; E=The low value byte.
  4128.         CALL L0E7C        ; Write to sound generator register.
  4129.  
  4130.         INC  D            ; D=Tone channel register (coarse control) number 1, 3, or 5.
  4131.         LD   E,H          ; E=The high value byte.
  4132.         CALL L0E7C        ; Write to sound generator register.
  4133.  
  4134.         BIT  4,(IX+$04)   ; Is the envelope waveform being used?
  4135.         RET  Z            ; Return if it is not.
  4136.  
  4137.         LD   D,$0D        ; Register 13 - Envelope Shape.
  4138.         LD   A,(IY+$29)   ; Get the effect waveform value.
  4139.         LD   E,A          ;
  4140.         CALL L0E7C        ; Write to sound generator register.
  4141.         RET               ; [Could have saved 4 bytes by dropping down into the routine below.]
  4142.  
  4143. ; ----------------------------
  4144. ; Set Sound Generator Register
  4145. ; ----------------------------
  4146. ; Entry: D=Register to write.
  4147. ;        E=Value to set register to.
  4148.  
  4149. L0E7C:  PUSH BC           ;
  4150.  
  4151.         LD   BC,$FFFD     ;
  4152.         OUT  (C),D        ; Select the register.
  4153.         LD   BC,$BFFD     ;
  4154.         OUT  (C),E        ; Write out the value.
  4155.  
  4156.         POP  BC           ;
  4157.         RET               ;
  4158.  
  4159. ; -----------------------------
  4160. ; Read Sound Generator Register
  4161. ; -----------------------------
  4162. ; Entry: A=Register to read.
  4163. ; Exit : A=Value of currently selected sound generator register.
  4164.  
  4165. L0E89:  PUSH BC           ;
  4166.  
  4167.         LD   BC,$FFFD     ;
  4168.         OUT  (C),A        ; Select the register.
  4169.         IN   A,(C)        ; Read the register's value.
  4170.  
  4171.         POP  BC           ;
  4172.         RET               ;
  4173.  
  4174. ; ------------------
  4175. ; Turn Off All Sound
  4176. ; ------------------
  4177.  
  4178. L0E93:  LD   D,$07        ; Register 7 - Mixer.
  4179.         LD   E,$FF        ; I/O ports are inputs, noise output off, tone output off.
  4180.         CALL L0E7C        ; Write to sound generator register.
  4181.  
  4182. ;Turn off the sound from the AY-3-8912
  4183.  
  4184.         LD   D,$08        ; Register 8 - Channel A volume.
  4185.         LD   E,$00        ; Volume of 0.
  4186.         CALL L0E7C        ; Write to sound generator register to set the volume to 0.
  4187.  
  4188.         INC  D            ; Register 9 - Channel B volume.
  4189.         CALL L0E7C        ; Write to sound generator register to set the volume to 0.
  4190.  
  4191.         INC  D            ; Register 10 - Channel C volume.
  4192.         CALL L0E7C        ; Write to sound generator register to set the volume to 0.
  4193.  
  4194.         CALL L0A4F        ; Select channel data block pointers.
  4195.  
  4196. ;Now reset all MIDI channels in use
  4197.  
  4198. L0EAC:  RR   (IY+$22)     ; Working copy of channel bitmap. Test if next string present.
  4199.         JR   C,L0EB8      ; Jump ahead if there is no string for this channel.
  4200.  
  4201.         CALL L0A67        ; Get address of channel data block for the current string into IX.
  4202.         CALL L118D        ; Turn off the MIDI channel sound assigned to this play string.
  4203.  
  4204. L0EB8:  SLA  (IY+$21)     ; Have all channels been processed?
  4205.         JR   C,L0EC3      ; Jump ahead if so.
  4206.  
  4207.         CALL L0A6E        ; Advance to the next channel data block pointer.
  4208.         JR   L0EAC        ; Jump back to process the next channel.
  4209.  
  4210. L0EC3:  LD   IY,$5C3A     ; Restore IY.
  4211.         RET               ;
  4212.  
  4213. ; ---------------------------------------
  4214. ; Get Previous Character from Play String
  4215. ; ---------------------------------------
  4216. ; Get the previous character from the PLAY string, skipping over spaces and 'Enter' characters.
  4217. ; Entry: IX=Address of the channel data block.
  4218.  
  4219. L0EC8:  PUSH HL           ; Save registers.
  4220.         PUSH DE           ;
  4221.  
  4222.         LD   L,(IX+$06)   ; Get the current pointer into the PLAY string.
  4223.         LD   H,(IX+$07)   ;
  4224.  
  4225. L0ED0:  DEC  HL           ; Point to previous character.
  4226.         LD   A,(HL)       ; Fetch the character.
  4227.         CP   ' '          ; $20. Is it a space?
  4228.         JR   Z,L0ED0      ; Jump back if a space.
  4229.  
  4230.         CP   $0D          ; Is it an 'Enter'?
  4231.         JR   Z,L0ED0      ; Jump back if an 'Enter'.
  4232.  
  4233.         LD   (IX+$06),L   ; Store this as the new current pointer into the PLAY string.
  4234.         LD   (IX+$07),H   ;
  4235.  
  4236.         POP  DE           ; Restore registers.
  4237.         POP  HL           ;
  4238.         RET               ;
  4239.  
  4240. ; --------------------------------------
  4241. ; Get Current Character from Play String
  4242. ; --------------------------------------
  4243. ; Get the current character from the PLAY string, skipping over spaces and 'Enter' characters.
  4244. ; Exit: Carry flag set if string has been fully processed.
  4245. ;       Carry flag reset if character is available.
  4246. ;       A=Character available.
  4247.  
  4248. L0EE3:  PUSH HL           ; Save registers.
  4249.         PUSH DE           ;
  4250.         PUSH BC           ;
  4251.  
  4252.         LD   L,(IX+$06)   ; HL=Pointer to next character to process within the PLAY string.
  4253.         LD   H,(IX+$07)   ;
  4254.  
  4255. L0EEC:  LD   A,H          ;
  4256.         CP   (IX+$09)     ; Reached end-of-string address high byte?
  4257.         JR   NZ,L0EFB     ; Jump forward if not.
  4258.  
  4259.         LD   A,L          ;
  4260.         CP   (IX+$08)     ; Reached end-of-string address low byte?
  4261.         JR   NZ,L0EFB     ; Jump forward if not.
  4262.  
  4263.         SCF               ; Indicate string all processed.
  4264.         JR   L0F05        ; Jump forward to return.
  4265.  
  4266. L0EFB:  LD   A,(HL)       ; Get the next play character.
  4267.         CP   ' '          ; $20. Is it a space?
  4268.         JR   Z,L0F09      ; Ignore the space by jumping ahead to process the next character.
  4269.  
  4270.         CP   $0D          ; Is it 'Enter'?
  4271.         JR   Z,L0F09      ; Ignore the 'Enter' by jumping ahead to process the next character.
  4272.  
  4273.         OR   A            ; Clear the carry flag to indicate a new character has been returned.
  4274.  
  4275. L0F05:  POP  BC           ; Restore registers.
  4276.         POP  DE           ;
  4277.         POP  HL           ;
  4278.         RET               ;
  4279.  
  4280. L0F09:  INC  HL           ; Point to the next character.
  4281.         LD   (IX+$06),L   ;
  4282.         LD   (IX+$07),H   ; Update the pointer to the next character to process with the PLAY string.
  4283.         JR   L0EEC        ; Jump back to get the next character.
  4284.  
  4285. ; --------------------------
  4286. ; Produce Play Error Reports
  4287. ; --------------------------
  4288.  
  4289. L0F12:  CALL L0E93        ; Turn off all sound and restore IY.
  4290.         EI                ;
  4291.         CALL L05AC        ; Produce error report.
  4292.         DB $29          ; "n Out of range"
  4293.  
  4294. L0F1A:  CALL L0E93        ; Turn off all sound and restore IY.
  4295.         EI                ;
  4296.         CALL L05AC        ; Produce error report.
  4297.         DB $27          ; "l Number too big"
  4298.  
  4299. L0F22:  CALL L0E93        ; Turn off all sound and restore IY.
  4300.         EI                ;
  4301.         CALL L05AC        ; Produce error report.
  4302.         DB $26          ; "k Invalid note name"
  4303.  
  4304. L0F2A:  CALL L0E93        ; Turn off all sound and restore IY.
  4305.         EI                ;
  4306.         CALL L05AC        ; Produce error report.
  4307.         DB $1F          ; "d Too many brackets"
  4308.  
  4309. L0F32:  CALL L0E93        ; Turn off all sound and restore IY.
  4310.         EI                ;
  4311.         CALL L05AC        ; Produce error report.
  4312.         DB $28          ; "m Note out of range"
  4313.  
  4314. L0F3A:  CALL L0E93        ; Turn off all sound and restore IY.
  4315.         EI                ;
  4316.         CALL L05AC        ; Produce error report.
  4317.         DB $2A          ; "o Too many tied notes"
  4318.  
  4319. ; -------------------------
  4320. ; Play Note on Each Channel
  4321. ; -------------------------
  4322. ; Play a note and set the volume on each channel for which a play string exists.
  4323.  
  4324. L0F42:  CALL L0A4F        ; Select channel data block pointers.
  4325.  
  4326. L0F45:  RR   (IY+$22)     ; Working copy of channel bitmap. Test if next string present.
  4327.         JR   C,L0F6C      ; Jump ahead if there is no string for this channel.
  4328.  
  4329.         CALL L0A67        ; Get address of channel data block for the current string into IX.
  4330.  
  4331.         CALL L0AD1        ; Get the next note in the string as number of semitones above note C.
  4332.         CP   $80          ; Is it a rest?
  4333.         JR   Z,L0F6C      ; Jump ahead if so and do nothing to the channel.
  4334.  
  4335.         CALL L0E20        ; Play the note if a sound chip channel.
  4336.  
  4337.         LD   A,(IX+$02)   ; Get channel number.
  4338.         CP   $03          ; Is it channel 0, 1 or 2, i.e. a sound chip channel?
  4339.         JR   NC,L0F69     ; Jump if not to skip setting the volume.
  4340.  
  4341. ;One of the 3 sound chip generator channels so set the channel's volume for the new note
  4342.  
  4343.         LD   D,$08        ;
  4344.         ADD  A,D          ; A=0 to 2.
  4345.         LD   D,A          ; D=Register (8 + string index), i.e. channel A, B or C volume register.
  4346.         LD   E,(IX+$04)   ; E=Volume for the current channel.
  4347.         CALL L0E7C        ; Write to sound generator register to set the output volume.
  4348.  
  4349. L0F69:  CALL L116E        ; Play a note and set the volume on the assigned MIDI channel.
  4350.  
  4351. L0F6C:  SLA  (IY+$21)     ; Have all channels been processed?
  4352.         RET  C            ; Return if so.
  4353.  
  4354.         CALL L0A6E        ; Advance to the next channel data block pointer.
  4355.         JR   L0F45        ; Jump back to process the next channel.
  4356.  
  4357. ; ------------------
  4358. ; Wait Note Duration
  4359. ; ------------------
  4360. ; This routine is the main timing control of the PLAY command.
  4361. ; It waits for the specified length of time, which will be the
  4362. ; lowest note duration of all active channels.
  4363. ; The actual duration of the wait is dictated by the current tempo.
  4364. ; Entry: DE=Note duration, where 96d represents a whole note.
  4365.  
  4366. ;Enter a loop waiting for (135+ ((26*(tempo-100))-5) )*DE+5 T-states
  4367.  
  4368. L0F76:  PUSH HL           ; (11) Save HL.
  4369.  
  4370.         LD   L,(IY+$27)   ; (19) Get the tempo timing value.
  4371.         LD   H,(IY+$28)   ; (19)
  4372.  
  4373.         LD   BC,$0064     ; (10) BC=100
  4374.         OR   A            ; (4)
  4375.         SBC  HL,BC        ; (15) HL=tempo timing value - 100.
  4376.  
  4377.         PUSH HL           ; (11)
  4378.         POP  BC           ; (10) BC=tempo timing value - 100.
  4379.  
  4380.         POP  HL           ; (10) Restore HL.
  4381.  
  4382. ;Tempo timing value = (10/(TEMPO*4))/7.33e-6, where 7.33e-6 is the time for 26 T-states.
  4383. ;The loop below takes 26 T-states per iteration, where the number of iterations is given by the tempo timing value.
  4384. ;So the time for the loop to execute is 2.5/TEMPO seconds.
  4385. ;
  4386. ;For a TEMPO of 60 beats (crotchets) per second, the time per crotchet is 1/24 second.
  4387. ;The duration of a crotchet is defined as 24 from the table at $0E0C, therefore the loop will get executed 24 times
  4388. ;and hence the total time taken will be 1 second.
  4389. ;
  4390. ;The tempo timing value above has 100 subtracted from it, presumably to approximately compensate for the overhead time
  4391. ;previously taken to prepare the notes for playing. This reduces the total time by 2600 T-states, or 733us.
  4392.  
  4393. L0F86:  DEC  BC           ; (6)  Wait for tempo-100 loops.
  4394.         LD   A,B          ; (4)
  4395.         OR   C            ; (4)
  4396.         JR   NZ,L0F86     ; (12/7)
  4397.  
  4398.         DEC  DE           ; (6) Repeat DE times
  4399.         LD   A,D          ; (4)
  4400.         OR   E            ; (4)
  4401.         JR   NZ,L0F76     ; (12/7)
  4402.  
  4403.         RET               ; (10)
  4404.  
  4405. ; -----------------------------
  4406. ; Find Smallest Duration Length
  4407. ; -----------------------------
  4408. ; This routine finds the smallest duration length for all current notes
  4409. ; being played across all channels.
  4410. ; Exit: DE=Smallest duration length.
  4411.  
  4412. L0F91:  LD   DE,$FFFF     ; Set smallest duration length to 'maximum'.
  4413.  
  4414.         CALL L0A4A        ; Select channel data block duration pointers.
  4415.  
  4416. L0F97:  RR   (IY+$22)     ; Working copy of channel bitmap. Test if next string present.
  4417.         JR   C,L0FAF      ; Jump ahead if there is no string for this channel.
  4418.  
  4419. ;HL=Address of channel data pointer. DE holds the smallest duration length found so far.
  4420.  
  4421.         PUSH DE           ; Save the smallest duration length.
  4422.  
  4423.         LD   E,(HL)       ;
  4424.         INC  HL           ;
  4425.         LD   D,(HL)       ;
  4426.         EX   DE,HL        ; DE=Channel data block duration length.
  4427.  
  4428.         LD   E,(HL)       ;
  4429.         INC  HL           ;
  4430.         LD   D,(HL)       ; DE=Channel duration length.
  4431.  
  4432.         PUSH DE           ;
  4433.         POP  HL           ; HL=Channel duration length.
  4434.  
  4435.         POP  BC           ; Last channel duration length.
  4436.         OR   A            ;
  4437.         SBC  HL,BC        ; Is current channel's duration length smaller than the smallest so far?
  4438.         JR   C,L0FAF      ; Jump ahead if so, with the new smallest value in DE.
  4439.  
  4440. ;The current channel's duration was not smaller so restore the last smallest into DE.
  4441.  
  4442.         PUSH BC           ;
  4443.         POP  DE           ; DE=Smallest duration length.
  4444.  
  4445. L0FAF:  SLA  (IY+$21)     ; Have all channel strings been processed?
  4446.         JR   C,L0FBA      ; Jump ahead if so.
  4447.  
  4448.         CALL L0A6E        ; Advance to the next channel data block duration pointer.
  4449.         JR   L0F97        ; Jump back to process the next channel.
  4450.  
  4451. L0FBA:  LD   (IY+$25),E   ;
  4452.         LD   (IY+$26),D   ; Store the smallest channel duration length.
  4453.         RET               ;
  4454.  
  4455. ; ---------------------------------------------------------------
  4456. ; Play a Note on Each Channel and Update Channel Duration Lengths
  4457. ; ---------------------------------------------------------------
  4458. ; This routine is used to play a note and set the volume on all channels.
  4459. ; It subtracts an amount of time from the duration lengths of all currently
  4460. ; playing channel note durations. The amount subtracted is equivalent to the
  4461. ; smallest note duration length currently being played, and as determined earlier.
  4462. ; Hence one channel's duration will go to 0 on each call of this routine, and the
  4463. ; others will show the remaining lengths of their corresponding notes.
  4464. ; Entry: IY=Address of the command data block.
  4465.  
  4466. L0FC1:  XOR  A            ;
  4467.         LD   (IY+$2A),A   ; Holds a temporary channel bitmap.
  4468.  
  4469.         CALL L0A4F        ; Select channel data block pointers.
  4470.  
  4471. L0FC8:  RR   (IY+$22)     ; Working copy of channel bitmap. Test if next string present.
  4472.         JP   C,L105A      ; Jump ahead if there is no string for this channel.
  4473.  
  4474.         CALL L0A67        ; Get address of channel data block for the current string into IX.
  4475.  
  4476.         PUSH IY           ;
  4477.         POP  HL           ; HL=Address of the command data block.
  4478.  
  4479.         LD   BC,$0011     ;
  4480.         ADD  HL,BC        ; HL=Address of channel data block duration pointers.
  4481.  
  4482.         LD   B,$00        ;
  4483.         LD   C,(IX+$02)   ; BC=Channel number.
  4484.         SLA  C            ; BC=2*Channel number.
  4485.         ADD  HL,BC        ; HL=Address of channel data block duration pointer for this channel.
  4486.  
  4487.         LD   E,(HL)       ;
  4488.         INC  HL           ;
  4489.         LD   D,(HL)       ; DE=Address of duration length within the channel data block.
  4490.  
  4491.         EX   DE,HL        ; HL=Address of duration length within the channel data block.
  4492.         PUSH HL           ; Save it.
  4493.  
  4494.         LD   E,(HL)       ;
  4495.         INC  HL           ;
  4496.         LD   D,(HL)       ; DE=Duration length for this channel.
  4497.  
  4498.         EX   DE,HL        ; HL=Duration length for this channel.
  4499.  
  4500.         LD   E,(IY+$25)   ;
  4501.         LD   D,(IY+$26)   ; DE=Smallest duration length of all current channel notes.
  4502.  
  4503.         OR   A            ;
  4504.         SBC  HL,DE        ; HL=Duration length - smallest duration length.
  4505.         EX   DE,HL        ; DE=Duration length - smallest duration length.
  4506.  
  4507.         POP  HL           ; HL=Address of duration length within the channel data block.
  4508.         JR   Z,L0FFC      ; Jump if this channel uses the smallest found duration length.
  4509.  
  4510.         LD   (HL),E       ;
  4511.         INC  HL           ; Update the duration length for this channel with the remaining length.
  4512.         LD   (HL),D       ;
  4513.  
  4514.         JR   L105A        ; Jump ahead to update the next channel.
  4515.  
  4516. ;The current channel uses the smallest found duration length
  4517.  
  4518. ; [A note has been completed and so the channel volume is set to 0 prior to the next note being played.
  4519. ; This occurs on both sound chip channels and MIDI channels. When a MIDI channel is assigned to more than
  4520. ; one play string and a rest is used in one of those strings. As soon as the end of the rest period is
  4521. ; encountered, the channel's volume is set to off even though one of the other play strings controlling
  4522. ; the MIDI channel may still be playing. This can be seen using the command PLAY "Y1a&", "Y1N9a". Here,
  4523. ; string 1 starts playing 'a' for the period of a crotchet (1/4 of a note), where as string 2 starts playing
  4524. ; 'a' for nine periods of a crotchet (9/4 of a note). When string 1 completes its crotchet, it requests
  4525. ; to play a period of silence via the rest '&'. This turns the volume of the MIDI channel off even though
  4526. ; string 2 is still timing its way through its nine crotchets. The play command will therefore continue for
  4527. ; a further seven crotchets but in silence. This is because the volume for note is set only at its start
  4528. ; and no coordination occurs between strings to turn the volume back on for the second string. It is arguably
  4529. ; what the correct behaviour should be in such a circumstance where the strings are providing conflicting instructions,
  4530. ; but having the latest command or note take precedence seems a logical approach. Credit: Ian Collier (+3), Paul Farrow (128)]
  4531.  
  4532. L0FFC:  LD   A,(IX+$02)   ; Get the channel number.
  4533.         CP   $03          ; Is it channel 0, 1 or 2, i.e. a sound chip channel?
  4534.         JR   NC,L100C     ; Jump ahead if not a sound generator channel.
  4535.  
  4536.         LD   D,$08        ;
  4537.         ADD  A,D          ;
  4538.         LD   D,A          ; D=Register (8+channel number) - Channel volume.
  4539.         LD   E,$00        ; E=Volume level of 0.
  4540.         CALL L0E7C        ; Write to sound generator register to turn the volume off.
  4541.  
  4542. L100C:  CALL L118D        ; Turn off the assigned MIDI channel sound.
  4543.  
  4544.         PUSH IX           ;
  4545.         POP  HL           ; HL=Address of channel data block.
  4546.  
  4547.         LD   BC,$0021     ;
  4548.         ADD  HL,BC        ; HL=Points to the tied notes counter.
  4549.  
  4550.         DEC  (HL)         ; Decrement the tied notes counter. [This contains a value of 1 for a single note]
  4551.         JR   NZ,L1026     ; Jump ahead if there are more tied notes.
  4552.  
  4553.         CALL L0B5C        ; Find the next note to play for this channel from its play string.
  4554.  
  4555.         LD   A,(IY+$21)   ; Fetch the channel selector.
  4556.         AND  (IY+$10)     ; Test whether this channel has further data in its play string.
  4557.         JR   NZ,L105A     ; Jump to process the next channel if this channel does not have a play string.
  4558.  
  4559.         JR   L103D        ; The channel has more data in its play string so jump ahead.
  4560.  
  4561. ;The channel has more tied notes
  4562.  
  4563. L1026:  PUSH IY           ;
  4564.         POP  HL           ; HL=Address of the command data block.
  4565.  
  4566.         LD   BC,$0011     ;
  4567.         ADD  HL,BC        ; HL=Address of channel data block duration pointers.
  4568.  
  4569.         LD   B,$00        ;
  4570.         LD   C,(IX+$02)   ; BC=Channel number.
  4571.         SLA  C            ; BC=2*Channel number.
  4572.         ADD  HL,BC        ; HL=Address of channel data block duration pointer for this channel.
  4573.  
  4574.         LD   E,(HL)       ;
  4575.         INC  HL           ;
  4576.         LD   D,(HL)       ; DE=Address of duration length within the channel data block.
  4577.  
  4578.         INC  DE           ;
  4579.         INC  DE           ; Point to the subsequent note duration length.
  4580.  
  4581.         LD   (HL),D       ;
  4582.         DEC  HL           ;
  4583.         LD   (HL),E       ; Store the new duration length.
  4584.  
  4585. L103D:  CALL L0AD1        ; Get next note in the string as number of semitones above note C.
  4586.         LD   C,A          ; C=Number of semitones.
  4587.  
  4588.         LD   A,(IY+$21)   ; Fetch the channel selector.
  4589.         AND  (IY+$10)     ; Test whether this channel has a play string.
  4590.         JR   NZ,L105A     ; Jump to process the next channel if this channel does not have a play string.
  4591.  
  4592.         LD   A,C          ; A=Number of semitones.
  4593.         CP   $80          ; Is it a rest?
  4594.         JR   Z,L105A      ; Jump to process the next channel if it is.
  4595.  
  4596.         CALL L0E20        ; Play the new note on this channel at the current volume if a sound chip channel, or simply store the note for play strings 4 to 8.
  4597.  
  4598.         LD   A,(IY+$21)   ; Fetch the channel selector.
  4599.         OR   (IY+$2A)     ; Insert a bit in the temporary channel bitmap to indicate this channel has more to play.
  4600.         LD   (IY+$2A),A   ; Store it.
  4601.  
  4602. ;Check whether another channel needs its duration length updated
  4603.  
  4604. L105A:  SLA  (IY+$21)     ; Have all channel strings been processed?
  4605.         JR   C,L1066      ; Jump ahead if so.
  4606.  
  4607.         CALL L0A6E        ; Advance to the next channel data pointer.
  4608.         JP   L0FC8        ; Jump back to update the duration length for the next channel.
  4609.  
  4610. ; [*BUG* - By this point, the volume for both sound chip and MIDI channels has been set to 0, i.e. off. So although the new notes have been
  4611. ;          set playing on the sound chip channels, no sound is audible. For MIDI channels, no new notes have yet been output and hence these
  4612. ;          are also silent. If the time from turning the volume off for the current note to the time to turn the volume on for the next note
  4613. ;          is short enough, then it will not be noticeable. However, the code at $1066 (ROM 0) introduces a 1/96th of a note delay and as a result a
  4614. ;          1/96th of a note period of silence between notes. The bug can be resolved by simply deleting the two instructions below that introduce
  4615. ;          the delay. A positive side effect of the bug in the 'V' volume command at $0C95 (ROM 0) is that it can be used to overcome the gaps of silence
  4616. ;          between notes for sound chip channels. By interspersing volume commands between notes, a new volume level is immediately set before
  4617. ;          the 1/96th of a note delay is introduced for the new note. Therefore, the delay occurs when the new note is audible instead of when it
  4618. ;          is silent. For example, PLAY "cV15cV15c" instead of PLAY "ccc". The note durations are still 1/96th of a note longer than they should
  4619. ;          be though. This technique will only work on the sound chip channels and not for any MIDI channels. Credit: Ian Collier (+3), Paul Farrow (128)]
  4620.  
  4621. L1066:  LD   DE,$0001     ; Delay for 1/96th of a note.
  4622.         CALL L0F76        ;
  4623.  
  4624.         CALL L0A4F        ; Select channel data block pointers.
  4625.  
  4626. ;All channel durations have been updated. Update the volume on each sound chip channel, and the volume and note on each MIDI channel
  4627.  
  4628. L106F:  RR   (IY+$2A)     ; Temporary channel bitmap. Test if next string present.
  4629.         JR   NC,L108C     ; Jump ahead if there is no string for this channel.
  4630.  
  4631.         CALL L0A67        ; Get address of channel data block for the current string into IX.
  4632.  
  4633.         LD   A,(IX+$02)   ; Get the channel number.
  4634.         CP   $03          ; Is it channel 0, 1 or 2, i.e. a sound chip channel?
  4635.         JR   NC,L1089     ; Jump ahead if so to process the next channel.
  4636.  
  4637.         LD   D,$08        ;
  4638.         ADD  A,D          ;
  4639.         LD   D,A          ; D=Register (8+channel number) - Channel volume.
  4640.         LD   E,(IX+$04)   ; Get the current volume.
  4641.         CALL L0E7C        ; Write to sound generator register to set the volume of the channel.
  4642.  
  4643. L1089:  CALL L116E        ; Play a note and set the volume on the assigned MIDI channel.
  4644.  
  4645. L108C:  SLA  (IY+$21)     ; Have all channels been processed?
  4646.         RET  C            ; Return if so.
  4647.  
  4648.         CALL L0A6E        ; Advance to the next channel data pointer.
  4649.         JR   L106F        ; Jump back to process the next channel.
  4650.  
  4651. ; -----------------
  4652. ; Note Lookup Table
  4653. ; -----------------
  4654. ; Each word gives the value of the sound generator tone registers for a given note.
  4655. ; There are 9 octaves, containing a total of 108 notes. These represent notes 21 to
  4656. ; 128. Notes 0 to 20 cannot be reproduced on the sound chip and so note 21 will be
  4657. ; used for all of these (they will however be sent to a MIDI device if one is assigned
  4658. ; to a channel). [Note that both the sound chip and the MIDI port can not play note 128
  4659. ; and so its inclusion in the table is a waste of 2 bytes]. The PLAY command does not allow
  4660. ; octaves higher than 8 to be selected directly. Using PLAY "O8G" will select note 115. To
  4661. ; select higher notes, sharps must be included, e.g. PLAY "O8#G" for note 116, PLAY "O8##G"
  4662. ; for note 117, etc, up to PLAY "O8############G" for note 127. Attempting to access note
  4663. ; 128 using PLAY "O8#############G" will lead to error report "m Note out of range".
  4664.  
  4665. L1096:  DEFW $0FBF        ; Octave  1, Note  21 - A  (27.50Hz, Ideal=27.50Hz, Error=-0.01%) C0
  4666.         DEFW $0EDC        ; Octave  1, Note  22 - A# (29.14Hz, Ideal=29.16Hz, Error=-0.08%)
  4667.         DEFW $0E07        ; Octave  1, Note  23 - B  (30.87Hz, Ideal=30.87Hz, Error=-0.00%)
  4668.  
  4669.         DEFW $0D3D        ; Octave  2, Note  24 - C  (32.71Hz, Ideal=32.70Hz, Error=+0.01%) C1
  4670.         DEFW $0C7F        ; Octave  2, Note  25 - C# (34.65Hz, Ideal=34.65Hz, Error=-0.00%)
  4671.         DEFW $0BCC        ; Octave  2, Note  26 - D  (36.70Hz, Ideal=36.71Hz, Error=-0.01%)
  4672.         DEFW $0B22        ; Octave  2, Note  27 - D# (38.89Hz, Ideal=38.89Hz, Error=+0.01%)
  4673.         DEFW $0A82        ; Octave  2, Note  28 - E  (41.20Hz, Ideal=41.20Hz, Error=+0.00%)
  4674.         DEFW $09EB        ; Octave  2, Note  29 - F  (43.66Hz, Ideal=43.65Hz, Error=+0.00%)
  4675.         DEFW $095D        ; Octave  2, Note  30 - F# (46.24Hz, Ideal=46.25Hz, Error=-0.02%)
  4676.         DEFW $08D6        ; Octave  2, Note  31 - G  (49.00Hz, Ideal=49.00Hz, Error=+0.00%)
  4677.         DEFW $0857        ; Octave  2, Note  32 - G# (51.92Hz, Ideal=51.91Hz, Error=+0.01%)
  4678.         DEFW $07DF        ; Octave  2, Note  33 - A  (55.01Hz, Ideal=55.00Hz, Error=+0.01%)
  4679.         DEFW $076E        ; Octave  2, Note  34 - A# (58.28Hz, Ideal=58.33Hz, Error=-0.08%)
  4680.         DEFW $0703        ; Octave  2, Note  35 - B  (61.75Hz, Ideal=61.74Hz, Error=+0.02%)
  4681.  
  4682.         DEFW $069F        ; Octave  3, Note  36 - C  ( 65.39Hz, Ideal= 65.41Hz, Error=-0.02%) C2
  4683.         DEFW $0640        ; Octave  3, Note  37 - C# ( 69.28Hz, Ideal= 69.30Hz, Error=-0.04%)
  4684.         DEFW $05E6        ; Octave  3, Note  38 - D  ( 73.40Hz, Ideal= 73.42Hz, Error=-0.01%)
  4685.         DEFW $0591        ; Octave  3, Note  39 - D# ( 77.78Hz, Ideal= 77.78Hz, Error=+0.01%)
  4686.         DEFW $0541        ; Octave  3, Note  40 - E  ( 82.41Hz, Ideal= 82.41Hz, Error=+0.00%)
  4687.         DEFW $04F6        ; Octave  3, Note  41 - F  ( 87.28Hz, Ideal= 87.31Hz, Error=-0.04%)
  4688.         DEFW $04AE        ; Octave  3, Note  42 - F# ( 92.52Hz, Ideal= 92.50Hz, Error=+0.02%)
  4689.         DEFW $046B        ; Octave  3, Note  43 - G  ( 98.00Hz, Ideal= 98.00Hz, Error=+0.00%)
  4690.         DEFW $042C        ; Octave  3, Note  44 - G# (103.78Hz, Ideal=103.83Hz, Error=-0.04%)
  4691.         DEFW $03F0        ; Octave  3, Note  45 - A  (109.96Hz, Ideal=110.00Hz, Error=-0.04%)
  4692.         DEFW $03B7        ; Octave  3, Note  46 - A# (116.55Hz, Ideal=116.65Hz, Error=-0.08%)
  4693.         DEFW $0382        ; Octave  3, Note  47 - B  (123.43Hz, Ideal=123.47Hz, Error=-0.03%)
  4694.  
  4695.         DEFW $034F        ; Octave  4, Note  48 - C  (130.86Hz, Ideal=130.82Hz, Error=+0.04%) C3
  4696.         DEFW $0320        ; Octave  4, Note  49 - C# (138.55Hz, Ideal=138.60Hz, Error=-0.04%)
  4697.         DEFW $02F3        ; Octave  4, Note  50 - D  (146.81Hz, Ideal=146.83Hz, Error=-0.01%)
  4698.         DEFW $02C8        ; Octave  4, Note  51 - D# (155.68Hz, Ideal=155.55Hz, Error=+0.08%)
  4699.         DEFW $02A1        ; Octave  4, Note  52 - E  (164.70Hz, Ideal=164.82Hz, Error=-0.07%)
  4700.         DEFW $027B        ; Octave  4, Note  53 - F  (174.55Hz, Ideal=174.62Hz, Error=-0.04%)
  4701.         DEFW $0257        ; Octave  4, Note  54 - F# (185.04Hz, Ideal=185.00Hz, Error=+0.02%)
  4702.         DEFW $0236        ; Octave  4, Note  55 - G  (195.83Hz, Ideal=196.00Hz, Error=-0.09%)
  4703.         DEFW $0216        ; Octave  4, Note  56 - G# (207.57Hz, Ideal=207.65Hz, Error=-0.04%)
  4704.         DEFW $01F8        ; Octave  4, Note  57 - A  (219.92Hz, Ideal=220.00Hz, Error=-0.04%)
  4705.         DEFW $01DC        ; Octave  4, Note  58 - A# (232.86Hz, Ideal=233.30Hz, Error=-0.19%)
  4706.         DEFW $01C1        ; Octave  4, Note  59 - B  (246.86Hz, Ideal=246.94Hz, Error=-0.03%)
  4707.  
  4708.         DEFW $01A8        ; Octave  5, Note  60 - C  (261.42Hz, Ideal=261.63Hz, Error=-0.08%) C4 Middle C
  4709.         DEFW $0190        ; Octave  5, Note  61 - C# (277.10Hz, Ideal=277.20Hz, Error=-0.04%)
  4710.         DEFW $0179        ; Octave  5, Note  62 - D  (294.01Hz, Ideal=293.66Hz, Error=+0.12%)
  4711.         DEFW $0164        ; Octave  5, Note  63 - D# (311.35Hz, Ideal=311.10Hz, Error=+0.08%)
  4712.         DEFW $0150        ; Octave  5, Note  64 - E  (329.88Hz, Ideal=329.63Hz, Error=+0.08%)
  4713.         DEFW $013D        ; Octave  5, Note  65 - F  (349.65Hz, Ideal=349.23Hz, Error=+0.12%)
  4714.         DEFW $012C        ; Octave  5, Note  66 - F# (369.47Hz, Ideal=370.00Hz, Error=-0.14%)
  4715.         DEFW $011B        ; Octave  5, Note  67 - G  (391.66Hz, Ideal=392.00Hz, Error=-0.09%)
  4716.         DEFW $010B        ; Octave  5, Note  68 - G# (415.13Hz, Ideal=415.30Hz, Error=-0.04%)
  4717.         DEFW $00FC        ; Octave  5, Note  69 - A  (439.84Hz, Ideal=440.00Hz, Error=-0.04%)
  4718.         DEFW $00EE        ; Octave  5, Note  70 - A# (465.72Hz, Ideal=466.60Hz, Error=-0.19%)
  4719.         DEFW $00E0        ; Octave  5, Note  71 - B  (494.82Hz, Ideal=493.88Hz, Error=+0.19%)
  4720.  
  4721.         DEFW $00D4        ; Octave  6, Note  72 - C  (522.83Hz, Ideal=523.26Hz, Error=-0.08%) C5
  4722.         DEFW $00C8        ; Octave  6, Note  73 - C# (554.20Hz, Ideal=554.40Hz, Error=-0.04%)
  4723.         DEFW $00BD        ; Octave  6, Note  74 - D  (586.46Hz, Ideal=587.32Hz, Error=-0.15%)
  4724.         DEFW $00B2        ; Octave  6, Note  75 - D# (622.70Hz, Ideal=622.20Hz, Error=+0.08%)
  4725.         DEFW $00A8        ; Octave  6, Note  76 - E  (659.77Hz, Ideal=659.26Hz, Error=+0.08%)
  4726.         DEFW $009F        ; Octave  6, Note  77 - F  (697.11Hz, Ideal=698.46Hz, Error=-0.19%)
  4727.         DEFW $0096        ; Octave  6, Note  78 - F# (738.94Hz, Ideal=740.00Hz, Error=-0.14%)
  4728.         DEFW $008D        ; Octave  6, Note  79 - G  (786.10Hz, Ideal=784.00Hz, Error=+0.27%)
  4729.         DEFW $0085        ; Octave  6, Note  80 - G# (833.39Hz, Ideal=830.60Hz, Error=+0.34%)
  4730.         DEFW $007E        ; Octave  6, Note  81 - A  (879.69Hz, Ideal=880.00Hz, Error=-0.04%)
  4731.         DEFW $0077        ; Octave  6, Note  82 - A# (931.43Hz, Ideal=933.20Hz, Error=-0.19%)
  4732.         DEFW $0070        ; Octave  6, Note  83 - B  (989.65Hz, Ideal=987.76Hz, Error=+0.19%)
  4733.  
  4734.         DEFW $006A        ; Octave  7, Note  84 - C  (1045.67Hz, Ideal=1046.52Hz, Error=-0.08%) C6
  4735.         DEFW $0064        ; Octave  7, Note  85 - C# (1108.41Hz, Ideal=1108.80Hz, Error=-0.04%)
  4736.         DEFW $005E        ; Octave  7, Note  86 - D  (1179.16Hz, Ideal=1174.64Hz, Error=+0.38%)
  4737.         DEFW $0059        ; Octave  7, Note  87 - D# (1245.40Hz, Ideal=1244.40Hz, Error=+0.08%)
  4738.         DEFW $0054        ; Octave  7, Note  88 - E  (1319.53Hz, Ideal=1318.52Hz, Error=+0.08%)
  4739.         DEFW $004F        ; Octave  7, Note  89 - F  (1403.05Hz, Ideal=1396.92Hz, Error=+0.44%)
  4740.         DEFW $004B        ; Octave  7, Note  90 - F# (1477.88Hz, Ideal=1480.00Hz, Error=-0.14%)
  4741.         DEFW $0047        ; Octave  7, Note  91 - G  (1561.14Hz, Ideal=1568.00Hz, Error=-0.44%)
  4742.         DEFW $0043        ; Octave  7, Note  92 - G# (1654.34Hz, Ideal=1661.20Hz, Error=-0.41%)
  4743.         DEFW $003F        ; Octave  7, Note  93 - A  (1759.38Hz, Ideal=1760.00Hz, Error=-0.04%)
  4744.         DEFW $003B        ; Octave  7, Note  94 - A# (1878.65Hz, Ideal=1866.40Hz, Error=+0.66%)
  4745.         DEFW $0038        ; Octave  7, Note  95 - B  (1979.30Hz, Ideal=1975.52Hz, Error=+0.19%)
  4746.  
  4747.         DEFW $0035        ; Octave  8, Note  96 - C  (2091.33Hz, Ideal=2093.04Hz, Error=-0.08%) C7
  4748.         DEFW $0032        ; Octave  8, Note  97 - C# (2216.81Hz, Ideal=2217.60Hz, Error=-0.04%)
  4749.         DEFW $002F        ; Octave  8, Note  98 - D  (2358.31Hz, Ideal=2349.28Hz, Error=+0.38%)
  4750.         DEFW $002D        ; Octave  8, Note  99 - D# (2463.13Hz, Ideal=2488.80Hz, Error=-1.03%)
  4751.         DEFW $002A        ; Octave  8, Note 100 - E  (2639.06Hz, Ideal=2637.04Hz, Error=+0.08%)
  4752.         DEFW $0028        ; Octave  8, Note 101 - F  (2771.02Hz, Ideal=2793.84Hz, Error=-0.82%)
  4753.         DEFW $0025        ; Octave  8, Note 102 - F# (2995.69Hz, Ideal=2960.00Hz, Error=+1.21%)
  4754.         DEFW $0023        ; Octave  8, Note 103 - G  (3166.88Hz, Ideal=3136.00Hz, Error=+0.98%)
  4755.         DEFW $0021        ; Octave  8, Note 104 - G# (3358.81Hz, Ideal=3322.40Hz, Error=+1.10%)
  4756.         DEFW $001F        ; Octave  8, Note 105 - A  (3575.50Hz, Ideal=3520.00Hz, Error=+1.58%)
  4757.         DEFW $001E        ; Octave  8, Note 106 - A# (3694.69Hz, Ideal=3732.80Hz, Error=-1.02%)
  4758.         DEFW $001C        ; Octave  8, Note 107 - B  (3958.59Hz, Ideal=3951.04Hz, Error=+0.19%)
  4759.  
  4760.         DEFW $001A        ; Octave  9, Note 108 - C  (4263.10Hz, Ideal=4186.08Hz, Error=+1.84%) C8
  4761.         DEFW $0019        ; Octave  9, Note 109 - C# (4433.63Hz, Ideal=4435.20Hz, Error=-0.04%)
  4762.         DEFW $0018        ; Octave  9, Note 110 - D  (4618.36Hz, Ideal=4698.56Hz, Error=-1.71%)
  4763.         DEFW $0016        ; Octave  9, Note 111 - D# (5038.21Hz, Ideal=4977.60Hz, Error=+1.22%)
  4764.         DEFW $0015        ; Octave  9, Note 112 - E  (5278.13Hz, Ideal=5274.08Hz, Error=+0.08%)
  4765.         DEFW $0014        ; Octave  9, Note 113 - F  (5542.03Hz, Ideal=5587.68Hz, Error=-0.82%)
  4766.         DEFW $0013        ; Octave  9, Note 114 - F# (5833.72Hz, Ideal=5920.00Hz, Error=-1.46%)
  4767.         DEFW $0012        ; Octave  9, Note 115 - G  (6157.81Hz, Ideal=6272.00Hz, Error=-1.82%)
  4768.         DEFW $0011        ; Octave  9, Note 116 - G# (6520.04Hz, Ideal=6644.80Hz, Error=-1.88%)
  4769.         DEFW $0010        ; Octave  9, Note 117 - A  (6927.54Hz, Ideal=7040.00Hz, Error=-1.60%)
  4770.         DEFW $000F        ; Octave  9, Note 118 - A# (7389.38Hz, Ideal=7465.60Hz, Error=-1.02%)
  4771.         DEFW $000E        ; Octave  9, Note 119 - B  (7917.19Hz, Ideal=7902.08Hz, Error=+0.19%)
  4772.  
  4773.         DEFW $000D        ; Octave 10, Note 120 - C  ( 8526.20Hz, Ideal= 8372.16Hz, Error=+1.84%) C9
  4774.         DEFW $000C        ; Octave 10, Note 121 - C# ( 9236.72Hz, Ideal= 8870.40Hz, Error=+4.13%)
  4775.         DEFW $000C        ; Octave 10, Note 122 - D  ( 9236.72Hz, Ideal= 9397.12Hz, Error=-1.71%)
  4776.         DEFW $000B        ; Octave 10, Note 123 - D# (10076.42Hz, Ideal= 9955.20Hz, Error=+1.22%)
  4777.         DEFW $000B        ; Octave 10, Note 124 - E  (10076.42Hz, Ideal=10548.16Hz, Error=-4.47%)
  4778.         DEFW $000A        ; Octave 10, Note 125 - F  (11084.06Hz, Ideal=11175.36Hz, Error=-0.82%)
  4779.         DEFW $0009        ; Octave 10, Note 126 - F# (12315.63Hz, Ideal=11840.00Hz, Error=+4.02%)
  4780.         DEFW $0009        ; Octave 10, Note 127 - G  (12315.63Hz, Ideal=12544.00Hz, Error=-1.82%)
  4781.         DEFW $0008        ; Octave 10, Note 128 - G# (13855.08Hz, Ideal=13289.60Hz, Error=+4.26%)
  4782.  
  4783. ; -------------------------
  4784. ; Play Note on MIDI Channel
  4785. ; -------------------------
  4786. ; This routine turns on a note on the MIDI channel and sets its volume, if MIDI channel is assigned to the current string.
  4787. ; Three bytes are sent, and have the following meaning:
  4788. ;   Byte 1: Channel number $00..$0F, with bits 4 and 7 set.
  4789. ;   Byte 2: Note number $00..$7F.
  4790. ;   Byte 3: Note velocity $00..$78.
  4791. ; Entry: IX=Address of the channel data block.
  4792.  
  4793. L116E:  LD   A,(IX+$01)   ; Is a MIDI channel assigned to this string?
  4794.         OR   A            ;
  4795.         RET  M            ; Return if not.
  4796.  
  4797. ;A holds the assigned channel number ($00..$0F)
  4798.  
  4799.         OR   $90          ; Set bits 4 and 7 of the channel number. A=$90..$9F.
  4800.         CALL L11A3        ; Write byte to MIDI device.
  4801.  
  4802.         LD   A,(IX+$00)   ; The note number.
  4803.         CALL L11A3        ; Write byte to MIDI device.
  4804.  
  4805.         LD   A,(IX+$04)   ; Fetch the channel's volume.
  4806.         RES  4,A          ; Ensure the 'using envelope' bit is reset so
  4807.         SLA  A            ; that A holds a value between $00 and $0F.
  4808.         SLA  A            ; Multiply by 8 to increase the range to $00..$78.
  4809.         SLA  A            ; A=Note velocity.
  4810.         CALL L11A3        ; Write byte to MIDI device.
  4811.         RET               ; [Could have saved 1 byte by using JP $11A3 (ROM 0)]
  4812.  
  4813. ; ---------------------
  4814. ; Turn MIDI Channel Off
  4815. ; ---------------------
  4816. ; This routine turns off a note on the MIDI channel, if a MIDI channel is assigned to the current string.
  4817. ; Three bytes are sent, and have the following meaning:
  4818. ;   Byte 1: Channel number $00..$0F, with bit 7 set.
  4819. ;   Byte 2: Note number $00..$7F.
  4820. ;   Byte 3: Note velocity $40.
  4821. ; Entry: IX=Address of the channel data block.
  4822.  
  4823. L118D:  LD   A,(IX+$01)   ; Is a MIDI channel assigned to this string?
  4824.         OR   A            ;
  4825.         RET  M            ; Return if not.
  4826.  
  4827. ;A holds the assigned channel number ($00..$0F)
  4828.  
  4829.         OR   $80          ; Set bit 7 of the channel number. A=$80..$8F.
  4830.         CALL L11A3        ; Write byte to MIDI device.
  4831.  
  4832.         LD   A,(IX+$00)   ; The note number.
  4833.         CALL L11A3        ; Write byte to MIDI device.
  4834.  
  4835.         LD   A,$40        ; The note velocity.
  4836.         CALL L11A3        ; Write byte to MIDI device.
  4837.         RET               ; [Could have saved 1 byte by using JP $11A3 (ROM 0)]
  4838.  
  4839. ; ------------------------
  4840. ; Send Byte to MIDI Device
  4841. ; ------------------------
  4842. ; This routine sends a byte to the MIDI port. MIDI devices communicate at 31250 baud,
  4843. ; although this routine actually generates a baud rate of 31388, which is within the 1%
  4844. ; tolerance supported by MIDI devices.
  4845. ; Entry: A=Byte to send.
  4846.  
  4847. L11A3:  LD   L,A          ; Store the byte to send.
  4848.  
  4849.         LD   BC,$FFFD     ;
  4850.         LD   A,$0E        ;
  4851.         OUT  (C),A        ; Select register 14 - I/O port.
  4852.  
  4853.         LD   BC,$BFFD     ;
  4854.         LD   A,$FA        ; Set RS232 'RXD' transmit line to 0. (Keep KEYPAD 'CTS' output line low to prevent the keypad resetting)
  4855.         OUT  (C),A        ; Send out the START bit.
  4856.  
  4857.         LD   E,$03        ; (7) Introduce delays such that the next bit is output 113 T-states from now.
  4858.  
  4859. L11B4:  DEC  E            ; (4)
  4860.         JR   NZ,L11B4     ; (12/7)
  4861.  
  4862.         NOP               ; (4)
  4863.         NOP               ; (4)
  4864.         NOP               ; (4)
  4865.         NOP               ; (4)
  4866.  
  4867.         LD   A,L          ; (4) Retrieve the byte to send.
  4868.  
  4869.         LD   D,$08        ; (7) There are 8 bits to send.
  4870.  
  4871. L11BE:  RRA               ; (4) Rotate the next bit to send into the carry.
  4872.         LD   L,A          ; (4) Store the remaining bits.
  4873.         JP   NC,L11C9     ; (10) Jump if it is a 0 bit.
  4874.  
  4875.         LD   A,$FE        ; (7) Set RS232 'RXD' transmit line to 1. (Keep KEYPAD 'CTS' output line low to prevent the keypad resetting)
  4876.         OUT  (C),A        ; (11)
  4877.         JR   L11CF        ; (12) Jump forward to process the next bit.
  4878.  
  4879. L11C9:  LD   A,$FA        ; (7) Set RS232 'RXD' transmit line to 0. (Keep KEYPAD 'CTS' output line low to prevent the keypad resetting)
  4880.         OUT  (C),A        ; (11)
  4881.         JR   L11CF        ; (12) Jump forward to process the next bit.
  4882.  
  4883. L11CF:  LD   E,$02        ; (7) Introduce delays such that the next data bit is output 113 T-states from now.
  4884.  
  4885. L11D1:  DEC  E            ; (4)
  4886.         JR   NZ,L11D1     ; (12/7)
  4887.  
  4888.         NOP               ; (4)
  4889.         ADD  A,$00        ; (7)
  4890.  
  4891.         LD   A,L          ; (4) Retrieve the remaining bits to send.
  4892.         DEC  D            ; (4) Decrement the bit counter.
  4893.         JR   NZ,L11BE     ; (12/7) Jump back if there are further bits to send.
  4894.  
  4895.         NOP               ; (4) Introduce delays such that the stop bit is output 113 T-states from now.
  4896.         NOP               ; (4)
  4897.         ADD  A,$00        ; (7)
  4898.         NOP               ; (4)
  4899.         NOP               ; (4)
  4900.  
  4901.         LD   A,$FE        ; (7) Set RS232 'RXD' transmit line to 0. (Keep KEYPAD 'CTS' output line low to prevent the keypad resetting)
  4902.         OUT  (C),A        ; (11) Send out the STOP bit.
  4903.  
  4904.         LD   E,$06        ; (7) Delay for 101 T-states (28.5us).
  4905.  
  4906. L11E7:  DEC  E            ; (4)
  4907.         JR   NZ,L11E7     ; (12/7)
  4908.  
  4909.         RET               ; (10)
  4910.  
  4911.  
  4912. ; =============================================
  4913. ; CASSETTE / RAM DISK COMMAND ROUTINES - PART 1
  4914. ; =============================================
  4915.  
  4916. ; ------------
  4917. ; SAVE Routine
  4918. ; ------------
  4919.  
  4920. L11EB:  LD   HL,FLAGS3    ; $5B66.
  4921.         SET  5,(HL)       ; Indicate SAVE.
  4922.         JR   L1205
  4923.  
  4924. ; ------------
  4925. ; LOAD Routine
  4926. ; ------------
  4927.  
  4928. L11F2:  LD   HL,FLAGS3    ; $5B66.
  4929.         SET  4,(HL)       ; Indicate LOAD.
  4930.         JR   L1205
  4931.  
  4932. ; --------------
  4933. ; VERIFY Routine
  4934. ; --------------
  4935.  
  4936. L11F9:  LD   HL,FLAGS3    ; $5B66.
  4937.         SET  7,(HL)       ; Indicate VERIFY.
  4938.         JR   L1205
  4939.  
  4940. ; -------------
  4941. ; MERGE Routine
  4942. ; -------------
  4943.  
  4944. L1200:  LD   HL,FLAGS3    ; $5B66.
  4945.         SET  6,(HL)       ; Indicate MERGE.
  4946.  
  4947. L1205:  LD   HL,FLAGS3    ; $5B66.
  4948.         RES  3,(HL)       ; Indicate using cassette.
  4949.         RST  18H          ; Get current character.
  4950.         CP   '!'          ; $21. '!'
  4951.         JP   NZ,L13BE     ; Jump ahead to handle cassette command.
  4952.  
  4953. ;RAM disk operation
  4954.  
  4955.         LD   HL,FLAGS3    ; $5B66.
  4956.         SET  3,(HL)       ; Indicate using RAM disk.
  4957.         RST  20H          ; Move on to next character.
  4958.         JP   L13BE        ; Jump ahead to handle RAM disk command.
  4959.  
  4960. L1219:  CALL L05AC        ; Produce error report.
  4961.         DB $0B          ; "C Nonsense in BASIC"
  4962.  
  4963. ; -------------------------
  4964. ; RAM Disk Command Handling
  4965. ; -------------------------
  4966. ; The information relating to the file is copied into memory in $5B66 (FLAGS3)
  4967. ; to ensure that it is available once other RAM banks are switched in.
  4968. ; This code is very similar to that in the ZX Interface 1 ROM at $08F6.
  4969. ; Entry: HL=Start address.
  4970. ;        IX=File header descriptor.
  4971.  
  4972. L121D:  LD   (HD_0D),HL   ; $5B74. Save start address.
  4973.  
  4974.         LD   A,(IX+$00)   ; Transfer header file information
  4975.         LD   (HD_00),A    ; $5B71.  from IX to HD_00 onwards.
  4976.         LD   L,(IX+$0B)   ;
  4977.         LD   H,(IX+$0C)   ;
  4978.         LD   (HD_0B),HL   ; $5B72.
  4979.         LD   L,(IX+$0D)   ;
  4980.         LD   H,(IX+$0E)   ;
  4981.         LD   (HD_11),HL   ; $5B78.
  4982.         LD   L,(IX+$0F)   ;
  4983.         LD   H,(IX+$10)   ;
  4984.         LD   (HD_0F),HL   ; $5B76.
  4985.  
  4986. ;A copy of the header information has now been copied from IX+$00 onwards to HD_00 onwards
  4987.  
  4988.         OR   A            ; Test file type.
  4989.         JR   Z,L124E      ; Jump ahead for a program file.
  4990.  
  4991.         CP   $03          ;
  4992.         JR   Z,L124E      ; Jump ahead for a CODE/SCREEN$ file.
  4993.  
  4994. ;An array type
  4995.  
  4996.         LD   A,(IX+$0E)   ;
  4997.         LD   (HD_0F),A    ; $5B76. Store array name.
  4998.  
  4999. L124E:  PUSH IX           ; IX points to file header.
  5000.         POP  HL           ; Retrieve into HL.
  5001.  
  5002.         INC  HL           ; HL points to filename.
  5003.         LD   DE,N_STR1    ; $5B67.
  5004.         LD   BC,$000A     ;
  5005.         LDIR              ; Copy the filename.
  5006.  
  5007.         LD   HL,FLAGS3    ; $5B66.
  5008.         BIT  5,(HL)       ; SAVE operation?
  5009.         JP   NZ,L1BAD     ; Jump ahead if SAVE.
  5010.  
  5011. ; Load / Verify or Merge
  5012. ; ----------------------
  5013.  
  5014.         LD   HL,HD_00     ; $5B71.
  5015.         LD   DE,SC_00     ; $5B7A.
  5016.         LD   BC,$0007     ;
  5017.         LDIR              ; Transfer requested details from HD_00 onwards into SC_00 onwards.
  5018.  
  5019.         CALL L1C2E        ; Find and load requested file header into HD_00 ($5B71).
  5020.  
  5021. ;The file exists else the call above would have produced an error "h file does not exist"
  5022.  
  5023.         LD   A,(SC_00)    ; $5B7A. Requested file type.
  5024.         LD   B,A          ;
  5025.         LD   A,(HD_00)    ; $5B71. Loaded file type.
  5026.         CP   B            ;
  5027.         JR   NZ,L1280     ; Error 'b' if file types do not match.
  5028.  
  5029.         CP   $03          ; Is it a CODE file type?
  5030.         JR   Z,L1290      ; Jump ahead to avoid MERGE program/array check.
  5031.  
  5032.         JR   C,L1284      ; Only file types 0, 1 and 2 are OK.
  5033.  
  5034. L1280:  CALL L05AC        ; Produce error report.
  5035.         DB $1D          ; "b Wrong file type"
  5036.  
  5037. L1284:  LD   A,(FLAGS3)   ; $5B66.
  5038.         BIT  6,A          ; Is it a MERGE program/array operation?
  5039.         JR   NZ,L12C5     ; Jump ahead if so.
  5040.  
  5041.         BIT  7,A          ; Is it a VERIFY program/array operation?
  5042.         JP   Z,L12DB      ; Jump ahead if LOAD.
  5043.  
  5044. ;Either a verify program/array or a load/verify CODE/SCREEN$ type file
  5045.  
  5046. L1290:  LD   A,(FLAGS3)   ; $5B66.
  5047.         BIT  6,A          ; MERGE operation?
  5048.         JR   Z,L129B      ; Jump ahead if VERIFY.
  5049.  
  5050. ;Cannot merge CODE/SCREEN$
  5051.  
  5052.         CALL L05AC        ; Produce error report.
  5053.         DB $1C          ; "a MERGE error"
  5054.  
  5055. ; ------------------------
  5056. ; RAM Disk VERIFY! Routine
  5057. ; ------------------------
  5058.  
  5059. L129B:  LD   HL,(SC_0B)   ; $5B7B. Length requested.
  5060.         LD   DE,(HD_0B)   ; $5B72. File length.
  5061.         LD   A,H          ;
  5062.         OR   L            ;
  5063.         JR   Z,L12AE      ; Jump ahead if requested length is 0, i.e. not specified.
  5064.  
  5065.         SBC  HL,DE        ; Is file length <= requested length?
  5066.         JR   NC,L12AE     ; Jump ahead if so; requested length is OK.
  5067.  
  5068. ;File was smaller than requested
  5069.  
  5070.         CALL L05AC        ; Produce error report.
  5071.         DB $1E          ; "c CODE error"
  5072.  
  5073. L12AE:  LD   HL,(SC_0D)   ; $5B7D. Fetch start address.
  5074.         LD   A,H          ;
  5075.         OR   L            ; Is length 0, i.e. not provided?
  5076.         JR   NZ,L12B8     ; Jump ahead if start address was provided.
  5077.  
  5078.         LD   HL,(HD_0D)   ; $5B74. Not provided so use file's start address.
  5079.  
  5080. L12B8:  LD   A,(HD_00)    ; $5B71. File type.
  5081.         AND  A            ; Is it a program?
  5082.         JR   NZ,L12C1     ; Jump ahead if not.
  5083.  
  5084.         LD   HL,($5C53)   ; PROG. Set start address as start of program area.
  5085.  
  5086. L12C1:  CALL L137E        ; Load DE bytes at address pointed to by HL.
  5087.                           ; [The Spectrum 128 manual states that the VERIFY keyword is not used with the RAM disk yet it clearly is,
  5088.                           ; although verifying a RAM disk file simply loads it in just as LOAD would do. To support verifying, the routine
  5089.                           ; at $1E37 (ROM 0) which loads blocks of data would need to be able to load or verify a block. The success status would
  5090.                           ; then need to be propagated back to here via routines at $137E (ROM 0), $1C4B (ROM 0) and $1E37 (ROM 0)]
  5091.         RET               ; [Could have saved 1 byte by using JP $137E (ROM 0), although could have saved a lot more by not supporting the
  5092.                           ; VERIFY keyword at all]
  5093.  
  5094. ; -----------------------
  5095. ; RAM Disk MERGE! Routine
  5096. ; -----------------------
  5097.  
  5098. L12C5:  LD   BC,(HD_0B)   ; $5B72. File length.
  5099.         PUSH BC           ; Save the length.
  5100.         INC  BC           ; Increment for terminator $80 (added later).
  5101.         RST  28H          ;
  5102.         DEFW BC_SPACES    ; $0030. Create room in the workspace for the file.
  5103.         LD   (HL),$80     ; Insert terminator.
  5104.  
  5105.         EX   DE,HL        ; HL=Start address.
  5106.         POP  DE           ; DE=File length.
  5107.         PUSH HL           ; Save start address.
  5108.         CALL L137E        ; Load DE bytes to address pointed to by HL.
  5109.         POP  HL           ; Retrieve start address.
  5110.  
  5111.         RST  28H          ;
  5112.         DEFW ME_CONTRL+$0018 ;$08CE. Delegate actual merge handling to ROM 1.
  5113.         RET               ;
  5114.  
  5115. ; ----------------------
  5116. ; RAM Disk LOAD! Routine
  5117. ; ----------------------
  5118.  
  5119. L12DB:  LD   DE,(HD_0B)   ; $5B72. File length.
  5120.         LD   HL,(SC_0D)   ; $5B7D. Requested start address.
  5121.         PUSH HL           ; Save requested start address.
  5122.         LD   A,H          ;
  5123.         OR   L            ; Was start address specified? (0 if not).
  5124.         JR   NZ,L12ED     ; Jump ahead if start address specified.
  5125.  
  5126. ;Start address was not specified
  5127.  
  5128.         INC  DE           ; Allow for variable overhead.
  5129.         INC  DE           ;
  5130.         INC  DE           ;
  5131.         EX   DE,HL        ; HL=File Length+3.
  5132.         JR   L12F6        ; Jump ahead to test if there is room.
  5133.  
  5134. ;A start address was specified
  5135.  
  5136. L12ED:  LD   HL,(SC_0B)   ; $5B7B. Requested length.
  5137.         EX   DE,HL        ; DE=Requested length. HL=File length.
  5138.         SCF               ;
  5139.         SBC  HL,DE        ; File length-Requested Length-1
  5140.         JR   C,L12FF      ; Jump if file is smaller than requested.
  5141.  
  5142. ;Test if there is room since file is bigger than requested
  5143.  
  5144. L12F6:  LD   DE,$0005     ;
  5145.         ADD  HL,DE        ;
  5146.         LD   B,H          ;
  5147.         LD   C,L          ; Space required in BC.
  5148.         RST  28H          ;
  5149.         DEFW TEST_ROOM    ; $1F05. Will automatically produce error '4' if out of memory.
  5150.  
  5151. ;Test file type
  5152.  
  5153. L12FF:  POP  HL           ; Requested start address.
  5154.         LD   A,(HD_00)    ; $5B71. Get requested file type.
  5155.  
  5156. L1303:  AND  A            ; Test file type.
  5157.         JR   Z,L1335      ; Jump if program file type.
  5158.  
  5159. ; Array type
  5160. ; ----------
  5161.  
  5162.         LD   A,H          ;
  5163.         OR   L            ; Was start address of existing array specified?
  5164.         JR   Z,L1315      ; Jump ahead if not.
  5165.  
  5166. ;Start address of existing array was specified
  5167.  
  5168.         DEC  HL           ;
  5169.         LD   B,(HL)       ;
  5170.         DEC  HL           ;
  5171.         LD   C,(HL)       ; Fetch array length.
  5172.         DEC  HL           ;
  5173.         INC  BC           ;
  5174.         INC  BC           ;
  5175.         INC  BC           ; Allow for variable header.
  5176.         RST  28H          ;
  5177.         DEFW RECLAIM_2    ; $19E8. Delete old array.
  5178.  
  5179. ;Insert new array entry into variables area
  5180.  
  5181. L1315:  LD   HL,($5C59)   ; E_LINE.
  5182.         DEC  HL           ; Point to end
  5183.         LD   BC,(HD_0B)   ; $5B72. Array length.
  5184.         PUSH BC           ; Save array length.
  5185.         INC  BC           ; Allow for variable header.
  5186.         INC  BC           ;
  5187.         INC  BC           ;
  5188.         LD   A,(SC_0F)    ; $5B7F. Get array name.
  5189.         PUSH AF           ; Save array name.
  5190.         RST  28H          ;
  5191.         DEFW MAKE_ROOM    ; $1655. Create room for new array.
  5192.         INC HL
  5193.         POP  AF           ;
  5194.         LD   (HL),A       ; Store array name.
  5195.         POP  DE           ;
  5196.         INC  HL           ;
  5197.         LD   (HL),E       ;
  5198.         INC  HL           ;
  5199.         LD   (HL),D       ; Store array length.
  5200.         INC  HL           ;
  5201.  
  5202. L1331:  CALL L137E        ; Load DE bytes to address pointed to by HL.
  5203.         RET               ; [Could have saved 1 byte by using JP $137E (ROM 0)]
  5204.  
  5205. ; Program type
  5206. ; ------------
  5207.  
  5208. L1335:  LD   HL,FLAGS3    ; $5B66.
  5209.         RES  1,(HL)       ; Signal do not auto-run BASIC program.
  5210.  
  5211.         LD   DE,($5C53)   ; PROG. Address of start of BASIC program.
  5212.         LD   HL,($5C59)   ; E_LINE. Address of end of program area.
  5213.         DEC  HL           ; Point before terminator.
  5214.         RST  28H          ;
  5215.         DEFW RECLAIM      ; $19E5. Delete current BASIC program.
  5216.  
  5217.         LD   BC,(HD_0B)   ; $5B72. Fetch file length.
  5218.         LD   HL,($5C53)   ; PROG. Address of start of BASIC program.
  5219.         RST  28H          ;
  5220.         DEFW MAKE_ROOM    ; $1655. Create room for the file.
  5221.         INC HL            ; Allow for terminator.
  5222.  
  5223.         LD   BC,(HD_0F)   ; $5B76. Length of variables.
  5224.         ADD  HL,BC        ; Determine new address of variables.
  5225.         LD   ($5C4B),HL   ; VARS.
  5226.  
  5227.         LD   A,(HD_11+1)  ; $5B79. Fetch high byte of auto-run line number.
  5228.         LD   H,A          ;
  5229.         AND  $C0          ;
  5230.         JR   NZ,L1370     ; If holds $80 then no auto-run line number specified.
  5231.  
  5232.         LD   A,(HD_11)    ; $5B78. Low byte of auto-run line number.
  5233.         LD   L,A          ;
  5234.         LD   ($5C42),HL   ; NEWPPC. Set line number to run.
  5235.         LD   (IY+$0A),$00 ; NSPPC. Statement 0.
  5236.  
  5237.         LD   HL,FLAGS3    ; $5B66.
  5238.         SET  1,(HL)       ; Signal auto-run BASIC program.
  5239.  
  5240. L1370:  LD   HL,($5C53)   ; PROG. Address of start of BASIC program.
  5241.         LD   DE,(HD_0B)   ; $5B72. Program length.
  5242.         DEC  HL           ;
  5243.         LD   ($5C57),HL   ; NXTLIN. Set the address of next line to the end of the program.
  5244.         INC  HL           ;
  5245.         JR   L1331        ; Jump back to load program bytes.
  5246.  
  5247. ; -------------------
  5248. ; RAM Disk Load Bytes
  5249. ; -------------------
  5250. ; Make a check that the requested length is not zero before proceeding to perform
  5251. ; the LOAD, MERGE or VERIFY. Note that VERIFY simply performs a LOAD.
  5252. ; Entry: HL=Destination address.
  5253. ;        DE=Length.
  5254. ;        IX=Address of catalogue entry.
  5255. ;        HD_00-HD_11 holds file header information.
  5256.  
  5257. L137E:  LD   A,D          ;
  5258.         OR   E            ;
  5259.         RET  Z            ; Return if length is zero.
  5260.  
  5261.         CALL L1C4B        ; Load bytes
  5262.         RET               ; [Could have used JP $1C4B (ROM 0) to save 1 byte]
  5263.  
  5264. ; ------------------------------
  5265. ; Get Expression from BASIC Line
  5266. ; ------------------------------
  5267. ; Returns in BC.
  5268.  
  5269. L1385:  RST  28H          ; Expect an expression on the BASIC line.
  5270.         DEFW EXPT_EXP     ; $1C8C.
  5271.         BIT  7,(IY+$01)   ; Return early if syntax checking.
  5272.         RET  Z            ;
  5273.  
  5274.         PUSH AF           ; Get the item off the calculator stack
  5275.         RST  28H          ;
  5276.         DEFW STK_FETCH    ; $2BF1.
  5277.         POP  AF           ;
  5278.         RET               ;
  5279.  
  5280. ; -----------------------
  5281. ; Check Filename and Copy
  5282. ; -----------------------
  5283. ; Called to check a filename for validity and to copy it into N_STR1 ($5B67).
  5284.  
  5285. L1393:  RST  20H          ; Advance the pointer into the BASIC line.
  5286.         CALL L1385        ; Get expression from BASIC line.
  5287.         RET  Z            ; Return if syntax checking.
  5288.  
  5289.         PUSH AF           ; [No need to save AF - see comment below]
  5290.  
  5291.         LD   A,C          ; Check for zero length.
  5292.         OR   B            ;
  5293.         JR   Z,L13BA      ; Jump if so to produce error report "f Invalid name".
  5294.  
  5295.         LD   HL,$000A     ; Check for length greater than 10.
  5296.         SBC  HL,BC        ;
  5297.         JR   C,L13BA      ; Jump if so to produce error report "f Invalid name".
  5298.  
  5299.         PUSH DE           ; Save the filename start address.
  5300.         PUSH BC           ; Save the filename length.
  5301.  
  5302.         LD   HL,N_STR1    ; $5B67. HL points to filename buffer.
  5303.         LD   B,$0A        ;
  5304.         LD   A,$20        ;
  5305.  
  5306. L13AD:  LD   (HL),A       ; Fill it with 10 spaces.
  5307.         INC  HL           ;
  5308.         DJNZ L13AD        ;
  5309.  
  5310.         POP  BC           ; Restore filename length.
  5311.         POP  HL           ; Restore filename start address.
  5312.  
  5313.         LD   DE,N_STR1    ; $5B67. DE points to where to store the filename.
  5314.         LDIR              ; Perform the copy.
  5315.  
  5316.         POP  AF           ; [No need to have saved AF as not subsequently used]
  5317.         RET               ;
  5318.  
  5319. L13BA:  CALL L05AC        ; Produce error report.
  5320.         DB $21          ; "f Invalid name"
  5321.  
  5322. ; ------------------------------------
  5323. ; Cassette / RAM Disk Command Handling
  5324. ; ------------------------------------
  5325. ; Handle SAVE, LOAD, MERGE, VERIFY commands.
  5326. ; Bit 3 of FLAGS3 indicates whether a cassette or RAM disk command.
  5327. ; This code is very similar to that in ROM 1 at $0605.
  5328.  
  5329. L13BE:  RST 28H
  5330.         DEFW EXPT_EXP     ; $1C8C. Pass the parameters of the 'name' to the calculator stack.
  5331.  
  5332.         BIT  7,(IY+$01)   ;
  5333.         JR   Z,L1407      ; Jump ahead if checking syntax.
  5334.  
  5335.         LD   BC,$0011     ; Size of save header, 17 bytes.
  5336.         LD   A,($5C74)    ; T_ADDR. Indicates which BASIC command.
  5337.         AND  A            ; Is it SAVE?
  5338.         JR   Z,L13D2      ; Jump ahead if so.
  5339.  
  5340.         LD   C,$22        ; Otherwise need 34d bytes for LOAD, MERGE and VERIFY commands.
  5341.                           ; 17 bytes for the header of the requested file, and 17 bytes for the files tested from tape.
  5342.  
  5343. L13D2:  RST  28H          ;
  5344.         DEFW BC_SPACES    ; $0030. Create space in workspace.
  5345.  
  5346.         PUSH DE           ; Get start of the created space into IX.
  5347.         POP  IX           ;
  5348.  
  5349.         LD   B,$0B        ; Clear the filename.
  5350.         LD   A,$20        ;
  5351.  
  5352. L13DC:  LD   (DE),A       ; Set all characters to spaces.
  5353.         INC  DE           ;
  5354.         DJNZ L13DC        ;
  5355.  
  5356.         LD   (IX+$01),$FF ; Indicate a null name.
  5357.         RST  28H          ; The parameters of the name are fetched.
  5358.         DEFW STK_FETCH    ; $2BF1.
  5359.  
  5360.         LD   HL,$FFF6     ; = -10.
  5361.         DEC  BC           ;
  5362.         ADD  HL,BC        ;
  5363.         INC  BC           ;
  5364.         JR   NC,L1400     ; Jump ahead if filename length within 10 characters.
  5365.  
  5366.         LD   A,($5C74)    ; T_ADDR. Indicates which BASIC command.
  5367.         AND  A            ; Is it SAVE?
  5368.         JR   NZ,L13F9     ; Jump ahead if not since LOAD, MERGE and VERIFY can have null filenames.
  5369.  
  5370.         CALL L05AC        ; Produce error report.
  5371.         DB $0E          ; "F Invalid file name"
  5372.  
  5373. ;Continue to handle the name of the program.
  5374.  
  5375. L13F9:  LD   A,B
  5376.         OR   C            ;
  5377.         JR   Z,L1407      ; Jump forward if the name has a null length.
  5378.  
  5379.         LD   BC,$000A     ; Truncate longer filenames.
  5380.  
  5381. ;The name is now transferred to the work space (second location onwards)
  5382.  
  5383. L1400:  PUSH IX           ;
  5384.         POP  HL           ; Transfer address of the workspace to HL.
  5385.         INC  HL           ; Step to the second location.
  5386.         EX   DE,HL        ;
  5387.         LDIR              ; Copy the filename.
  5388.  
  5389. ;The many different parameters, if any, that follow the command are now considered.
  5390. ;Start by handling 'xxx "name" DATA'.
  5391.  
  5392. L1407:  RST  18H          ; Get character from BASIC line.
  5393.         CP   $E4          ; Is it 'DATA'?
  5394.         JR   NZ,L145F     ; Jump if not DATA.
  5395.  
  5396. ; 'xxx "name" DATA'
  5397. ; -----------------
  5398.  
  5399.         LD   A,($5C74)    ; T_ADDR. Check the BASIC command.
  5400.         CP   $03          ; Is it MERGE?
  5401.         JP   Z,L1219      ; "C Nonsense in BASIC" if so.
  5402.  
  5403.         RST  20H          ; Get next character from BASIC line.
  5404.         RST  28H          ;
  5405.         DEFW LOOK_VARS    ; $28B2. Look in the variables area for the array.
  5406.         JR NC,L142F       ; Jump if handling an existing array.
  5407.  
  5408.         LD   HL,$0000     ; Signal 'using a new array'.
  5409.         BIT  6,(IY+$01)   ; FLAGS. Is it a string Variable?
  5410.         JR   Z,L1425      ; Jump forward if so.
  5411.  
  5412.         SET  7,C          ; Set bit 7 of the array's name.
  5413.  
  5414. L1425:  LD   A,($5C74)    ; T_ADDR.
  5415.         DEC  A            ; Give an error if trying to
  5416.         JR   Z,L1444      ; SAVE or VERIFY a new array.
  5417.  
  5418.         CALL L05AC        ; Produce error report.
  5419.         DB $01          ; "2 Variable not found"
  5420.  
  5421. ;Continue with the handling of an existing array
  5422.  
  5423. L142F:  JP   NZ,L1219     ; Jump if not an array to produce "C Nonsense in BASIC".
  5424.  
  5425.         BIT  7,(IY+$01)   ; FLAGS.
  5426.         JR   Z,L1451      ; Jump forward if checking syntax.
  5427.  
  5428.         LD   C,(HL)       ;
  5429.         INC  HL           ; Point to the 'low length' of the variable.
  5430.         LD   A,(HL)       ; The low length byte goes into
  5431.         LD   (IX+$0B),A   ; the work space.
  5432.         INC  HL           ;
  5433.         LD   A,(HL)       ; The high length byte goes into
  5434.         LD   (IX+$0C),A   ; the work space.
  5435.         INC  HL           ; Step past the length bytes.
  5436.  
  5437. ;The next part is common to both 'old' and 'new' arrays
  5438.  
  5439. L1444:  LD   (IX+$0E),C   ; Copy the array's name.
  5440.         LD   A,$01        ; Assume an array of numbers - Code $01.
  5441.         BIT  6,C          ;
  5442.         JR   Z,L144E      ; Jump if it is so.
  5443.  
  5444.         INC  A            ; Indicate it is an array of characters - Code $02.
  5445.  
  5446. L144E:  LD   (IX+$00),A   ; Save the 'type' in the first location of the header area.
  5447.  
  5448. ;The last part of the statement is examined before joining the other pathways
  5449.  
  5450. L1451:  EX   DE,HL        ; Save the pointer in DE.
  5451.         RST  20H          ;
  5452.         CP   ')'          ; $29. Is the next character a ')'?
  5453.         JR   NZ,L142F     ; Give report C if it is not.
  5454.  
  5455.         RST  20H          ; Advance to next character.
  5456.         CALL L18A1        ; Move on to the next statement if checking syntax.
  5457.         EX   DE,HL        ; Return the pointer to the HL.
  5458.                           ; (The pointer indicates the start of an existing array's contents).
  5459.         JP   L1519        ; Jump forward.
  5460.  
  5461. ; Now Consider 'SCREEN$'
  5462.  
  5463. L145F:  CP   $AA          ; Is the present code the token 'SCREEN$'?
  5464.         JR   NZ,L1482     ; Jump ahead if not.
  5465.  
  5466. ; 'xxx "name" SCREEN$'
  5467. ; --------------------
  5468.  
  5469.         LD   A,($5C74)    ; T_ADDR_lo. Check the BASIC command.
  5470.         CP   $03          ; Is it MERGE?
  5471.         JP   Z,L1219      ; Jump to "C Nonsense in BASIC" if so since it is not possible to have 'MERGE name SCREEN$'.
  5472.  
  5473.         RST  20H          ; Advance pointer into BASIC line.
  5474.         CALL L18A1        ; Move on to the next statement if checking syntax.
  5475.  
  5476.         LD   (IX+$0B),$00 ; Length of the block.
  5477.         LD   (IX+$0C),$1B ; The display area and the attribute area occupy $1800 locations.
  5478.  
  5479.         LD   HL,$4000     ; Start of the block, beginning of the display file $4000.
  5480.         LD   (IX+$0D),L   ;
  5481.         LD   (IX+$0E),H   ; Store in the workspace.
  5482.         JR   L14CF        ; Jump forward.
  5483.  
  5484. ; Now consider 'CODE'
  5485.  
  5486. L1482:  CP   $AF          ; Is the present code the token 'CODE'?
  5487.         JR   NZ,L14D5     ; Jump ahead if not.
  5488.  
  5489. ; 'xxx "name" CODE'
  5490. ; -----------------
  5491.  
  5492.         LD   A,($5C74)    ; T_ADDR_lo. Check the BASIC command.
  5493.         CP   $03          ; Is it MERGE?
  5494.         JP   Z,L1219      ; Jump to "C Nonsense in BASIC" if so since it is not possible to have 'MERGE name CODE'.
  5495.  
  5496.         RST  20H          ; Advance pointer into BASIC line.
  5497.         RST  28H          ;
  5498.         DEFW PR_ST_END    ; $2048.
  5499.         JR   NZ,L14A0     ; Jump forward if the statement has not finished
  5500.  
  5501.         LD   A,($5C74)    ; T_ADDR_lo.
  5502.         AND  A            ; It is not possible to have 'SAVE name CODE' by itself.
  5503.         JP   Z,L1219      ; Jump if so to produce "C Nonsense in BASIC".
  5504.  
  5505.         RST  28H          ;
  5506.         DEFW USE_ZERO     ; $1CE6. Put a zero on the calculator stack - for the 'start'.
  5507.         JR   L14AF        ; Jump forward.
  5508.  
  5509. ;Look for a 'starting address'
  5510.  
  5511. L14A0:  RST  28H          ;
  5512.         DEFW EXPT_1NUM    ; $1C82. Fetch the first number.
  5513.         RST  18H          ;
  5514.         CP   ','          ; $2C. Is the present character a ','?
  5515.         JR   Z,L14B4      ; Jump if it is - the number was a 'starting address'
  5516.  
  5517.         LD   A,($5C74)    ; T_ADDR_lo.
  5518.         AND  A            ; Refuse 'SAVE name CODE' that does not have a 'start' and a 'length'.
  5519.         JP   Z,L1219      ; Jump if so to produce "C Nonsense in BASIC".
  5520.  
  5521. L14AF:  RST  28H          ;
  5522.         DEFW USE_ZERO     ; $1CE6. Put a zero on the calculator stack - for the 'length'.
  5523.         JR   L14B8        ; Jump forward.
  5524.  
  5525. ;Fetch the 'length' as it was specified
  5526.  
  5527. L14B4:  RST  20H          ; Advance to next character.
  5528.         RST  28H          ;
  5529.         DEFW EXPT_1NUM    ; $1C82. Fetch the 'length'.
  5530.  
  5531. ;The parameters are now stored in the header area of the work space
  5532.  
  5533. L14B8:  CALL L18A1        ; But move on to the next statement now if checking syntax.
  5534.         RST  28H          ;
  5535.         DEFW FIND_INT2    ; $1E99. Compress the 'length' into BC.
  5536.         LD   (IX+$0B),C   ; Store the length of the CODE block.
  5537.         LD   (IX+$0C),B   ;
  5538.         RST  28H          ;
  5539.         DEFW FIND_INT2    ; $1E99. Compress the 'starting address' into BC.
  5540.         LD   (IX+$0D),C   ; Store the start address of the CODE block.
  5541.         LD   (IX+$0E),B   ;
  5542.         LD   H,B          ; Transfer start address pointer to HL.
  5543.         LD   L,C          ;
  5544.  
  5545. ;'SCREEN$' and 'CODE' are both of type 3
  5546.  
  5547. L14CF:  LD   (IX+$00),$03 ; Store file type = $03 (CODE).
  5548.         JR   L1519        ; Rejoin the other pathways.
  5549.  
  5550. ; 'xxx "name"' / 'SAVE "name" LINE'
  5551. ; ---------------------------------
  5552.  
  5553. ;Now consider 'LINE' and 'no further parameters'
  5554.  
  5555. L14D5:  CP   $CA          ; Is the present code the token 'LINE'?
  5556.         JR   Z,L14E2      ; Jump ahead if so.
  5557.  
  5558.         CALL L18A1        ; Move on to the next statement if checking syntax.
  5559.         LD   (IX+$0E),$80 ; Indicate no LINE number.
  5560.         JR   L14F9        ; Jump forward.
  5561.  
  5562. ;Fetch the 'line number' that must follow 'LINE'
  5563.  
  5564. L14E2:  LD   A,($5C74)    ; T_ADDR_lo. Only allow 'SAVE name LINE number'.
  5565.         AND  A            ; Is it SAVE?
  5566.         JP   NZ,L1219     ; Produce "C Nonsense in BASIC" if not.
  5567.  
  5568.         RST  20H          ; Advance pointer into BASIC line.
  5569.         RST  28H          ; Get LINE number onto calculator stack
  5570.         DEFW EXPT_1NUM    ; $1C82. Pass the number to the calculator stack.
  5571.         CALL L18A1        ; Move on to the next statement if checking syntax.
  5572.         RST  28H          ; Retrieve LINE number from calculator stack
  5573.         DEFW FIND_INT2    ; $1E99. Compress the 'line number' into BC.
  5574.         LD   (IX+$0D),C   ; Store the LINE number.
  5575.         LD   (IX+$0E),B   ;
  5576.  
  5577. ;'LINE' and 'no further parameters' are both of type 0
  5578.  
  5579. L14F9:  LD   (IX+$00),$00 ; Store file type = $00 (program).
  5580.         LD   HL,($5C59)   ; E_LINE. The pointer to the end of the variables area.
  5581.         LD   DE,($5C53)   ; PROG. The pointer to the start of the BASIC program.
  5582.         SCF               ;
  5583.         SBC  HL,DE        ; Perform the subtraction to find the length of the 'program + variables'.
  5584.         LD   (IX+$0B),L   ;
  5585.         LD   (IX+$0C),H   ; Store the length.
  5586.  
  5587.         LD   HL,($5C4B)   ; VARS. Repeat the operation but this
  5588.         SBC  HL,DE        ; time storing the length of the
  5589.         LD   (IX+$0F),L   ; 'program' only.
  5590.         LD   (IX+$10),H   ;
  5591.         EX   DE,HL        ; Transfer pointer to HL.
  5592.  
  5593. ;In all cases the header information has now been prepared:
  5594. ;- The location 'IX+00' holds the type number.
  5595. ;- Locations 'IX+01 to IX+0A' holds the name ($FF in 'IX+01' if null).
  5596. ;- Locations 'IX+0B & IX+0C' hold the number of bytes that are to be found in the 'data block'.
  5597. ;- Locations 'IX+0D to IX+10' hold a variety of parameters whose exact interpretation depends on the 'type'.
  5598.  
  5599. ;The routine continues with the first task being to separate SAVE from LOAD, VERIFY and MERGE.
  5600.  
  5601. L1519:  LD   A,(FLAGS3)   ; $5B66.
  5602.         BIT  3,A          ; Using RAM disk?
  5603.         JP   NZ,L121D     ; Jump if the operation is on the RAM disk.
  5604.  
  5605.         LD   A,($5C74)    ; T_ADDR_lo. Get the BASIC command.
  5606.         AND  A            ; Is it SAVE?
  5607.         JR   NZ,L152B     ; Jump ahead if not.
  5608.  
  5609.         RST  28H          ;
  5610.         DEFW SA_CONTROL   ; $0970. Run the save routine in ROM 1.
  5611.         RET               ;
  5612.  
  5613. ;In the case of a LOAD, VERIFY or MERGE command the first seventeen bytes of the 'header area'
  5614. ;in the work space hold the prepared information, as detailed above;
  5615. ;and it is now time to fetch a 'header' from the tape.
  5616.  
  5617. L152B:  RST  28H          ;
  5618.         DEFW SA_ALL+$0007 ; $0761. Run the load/merge/verify routine in ROM 1.
  5619.         RET               ;
  5620.  
  5621.  
  5622. ; ========================
  5623. ; EDITOR ROUTINES - PART 1
  5624. ; ========================
  5625.  
  5626. ; ----------------------------------------------
  5627. ; Relist the BASIC Program from the Current Line
  5628. ; ----------------------------------------------
  5629. ; This routine lists the BASIC program from the current line number. It initially shows the last line displayed but rows may subsequently
  5630. ; be scrolled up until the required BASIC line has been found. The structure of the ROM program only supports listing BASIC lines that are
  5631. ; 20 rows or less; larger lines are shown truncated to 20 rows.
  5632.  
  5633. L152F:  LD   HL,$EEF5     ; Flags.
  5634.         RES  0,(HL)       ; Signal this is not the current line.
  5635.         SET  1,(HL)       ; Signal not yet located the current line.
  5636.  
  5637. ;A loop is entered to display a screenful of program listing. If the current line number is not found in the lines displayed then all
  5638. ;lines are scrolled up and the listing reproduced. This procedure repeats until the current line number has been found and displayed.
  5639.  
  5640. L1536:  LD   HL,($5C49)   ; E_PPC. Fetch current line number.
  5641.         LD   A,H          ;
  5642.         OR   L            ; Is there a currently selected line?
  5643.         JR   NZ,L1540     ; Jump ahead if so.
  5644.  
  5645.         LD   ($EC06),HL   ; Set to $0000 to indicate no editable characters before the cursor.
  5646.  
  5647. L1540:  LD   A,($F9DB)    ; Fetch the number of rows of the BASIC line that are in the Above-Screen Line Edit Buffer,
  5648.         PUSH AF           ; i.e. that are off the top of the screen.
  5649.  
  5650.         LD   HL,($FC9A)   ; Line number of the BASIC line at the top of the screen (or 0 for the first line).
  5651.         CALL L334A        ; Find closest line number (or $0000 if no subsequent line exists).
  5652.         LD   ($F9D7),HL   ; Store the line number of the BASIC line being edited in the buffer.
  5653.  
  5654.         CALL L3222        ; Set default Above-Screen Line Edit Buffer settings.
  5655.         CALL L30D6        ; Set default Below-Screen Line Edit Buffer settings.
  5656.  
  5657.         POP  AF           ; A=Number of rows of the BASIC line that are in the Above-Screen Line Edit Buffer.
  5658.  
  5659. L1554:  OR   A            ; Are there any rows off the top of the screen?
  5660.         JR   Z,L1563      ; Jump ahead if not.
  5661.  
  5662. ;The current settings indicate that the top BASIC line straggles into the Above-Screen Line Edit Buffer. It is therefore necessary to insert the current
  5663. ;BASIC line into the Below-Screen Line Edit Buffer and then shift the appropriate number of rows into the Above-Screen Line Edit Buffer.
  5664.  
  5665.         PUSH AF           ; Save the number of rows off the top of the screen.
  5666.         CALL L30DF        ; Copy a BASIC line from the program area into the Below-Screen Line Edit Buffer.
  5667.         EX   DE,HL        ; DE=Address of the Below-Screen Line Edit Buffer.
  5668.         CALL L326A        ; Shift up a row into the Above-Screen Line Edit Buffer.
  5669.         POP  AF           ; Retrieve the number of rows off the top of the screen.
  5670.         DEC  A            ; Decrement the number of rows.
  5671.         JR   L1554        ; Jump back to shift up another row if required.
  5672.  
  5673. ;Either there the top BASI Cline does not straggle off the top of the the screen or the appropriate number of rows have been copied into the
  5674. ;Above-Screen Line Edit Buffer. In the latter case, the Below-Screen Line Edit Buffer contains the remaining rows of the BASIC line and which
  5675. ;be copied into the top of the Screen Line Edit Buffer.
  5676.  
  5677. L1563:  LD   C,$00        ; C=Row 0.
  5678.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the first row, as specified in C.
  5679.  
  5680.         LD   B,C          ; B=Row 0.
  5681.         LD   A,($EC15)    ; The number of editing rows on screen.
  5682.         LD   C,A          ; C=Number of editing rows on screen.
  5683.         PUSH BC           ; B=Row number, C=Number of editing rows on screen.
  5684.         PUSH DE           ; DE=Start address in Screen Line Edit Buffer of the first row.
  5685.  
  5686. ;Enter a loop to copy BASIC line rows into the Screen Line Edit Buffer. The Below-Screen Line Edit Buffer is used as a temporary store for holding each BASIC line
  5687. ;as it is copied into the Screen Line Edit Buffer. If the top BASIC line straggles above the screen then this loop is entered with the remains of the line
  5688. ;already in the Below-Screen Line Edit Buffer.
  5689.  
  5690. L156F:  CALL L30DF        ; Shift up all rows of the BASIC line in the Below-Screen Line Edit Buffer, or if empty then copy a BASIC line from the program area into it.
  5691.                           ; If no BASIC line available then empty the first row of the Below-Screen Line Edit Buffer.
  5692.  
  5693.         LD   A,($EEF5)    ; Listing flags.
  5694.         BIT  1,A          ; Has the current line been previously found?
  5695.         JR   Z,L1596      ; Jump if so.
  5696.  
  5697. ;The current line has not yet been found so examine the current row in case it is the current line
  5698.  
  5699.         PUSH DE           ; DE=Start address in Screen Line Edit Buffer of the current row.
  5700.         PUSH HL           ; HL=Address of the first row in the Below-Screen Line Edit Buffer.
  5701.  
  5702.         LD   DE,$0020     ;
  5703.         ADD  HL,DE        ; Point to the flag byte for the first row.
  5704.         BIT  0,(HL)       ; Is it the first row of a BASIC line?
  5705.         JR   Z,L1594      ; Jump if not.
  5706.  
  5707. ;The Below-Screen Line Edit Buffer contains a complete BASIC line so determine whether this is the current line
  5708.  
  5709.         INC  HL           ;
  5710.         LD   D,(HL)       ; Get line number into DE.
  5711.         INC  HL           ;
  5712.         LD   E,(HL)       ;
  5713.         OR   A            ;
  5714.         LD   HL,($5C49)   ; E_PPC. Current line number.
  5715.         SBC  HL,DE        ;
  5716.         JR   NZ,L1594     ; Jump ahead unless this is the current line.
  5717.  
  5718.         LD   HL,$EEF5     ;
  5719.         SET  0,(HL)       ; Signal this is the current line.
  5720.  
  5721. L1594:  POP  HL           ; HL=Address of the current row in the Below-Screen Line Edit Buffer.
  5722.         POP  DE           ; DE=Start address in Screen Line Edit Buffer of the current row.
  5723.  
  5724. ;Copy the row of the BASIC line from the Below-Screen Line Edit Buffer into the Screen Line Edit Buffer
  5725.  
  5726. L1596:  PUSH BC           ; B=Row number, C=Number of editing rows on screen.
  5727.         PUSH HL           ; HL=Address of the current row in the Below-Screen Line Edit Buffer.
  5728.         LD   BC,$0023     ;
  5729.         LDIR              ; Copy the first row of the BASIC line in the Below-Screen Line Edit Buffer into the next row of the Screen Line Edit Buffer.
  5730.         POP  HL           ; HL=Address of the current row in the Below-Screen Line Edit Buffer.
  5731.         POP  BC           ; B=Row number, C=Number of editing rows on screen.
  5732.  
  5733.         PUSH DE           ; DE=Start address in Screen Line Edit Buffer of the next row.
  5734.         PUSH BC           ; B=Row number, C=Number of editing rows on screen.
  5735.         EX   DE,HL        ; DE=Address of the current row in the Below-Screen Line Edit Buffer.
  5736.  
  5737.         LD   HL,$EEF5     ; Flags.
  5738.         BIT  0,(HL)       ; Is this the current line?
  5739.         JR   Z,L15D3      ; Jump if not.
  5740.  
  5741. ;This is the current line so scan across the BASIC line to locate the cursor column position
  5742.  
  5743.         LD   B,$00        ; Column 0.
  5744.  
  5745. L15AB:  LD   HL,($EC06)   ; HL=Count of the number of editable characters in the BASIC line up to the cursor within the Screen Line Edit Buffer.
  5746.         LD   A,H          ;
  5747.         OR   L            ; Are there any editable characters in this row prior to the cursor?
  5748.         JR   Z,L15C0      ; Jump if there are none, i.e. cursor at start of the row.
  5749.  
  5750. ;There are editable characters on this row prior to the cursor
  5751.  
  5752. ; [*BUG* - Entering '  10 REM' or '0010 REM' will insert the line into the program area but instead of placing the cursor on the following row it is placed after the following
  5753. ;          BASIC line, or if the line inserted was the last in the program then the cursor is placed on row 20. The bug occurs due to the leading spaces or zeros, and hence will apply
  5754. ;          to every BASIC command. When the line is inserted into the Screen Line Edit Buffer, the leading spaces are discarded and hence the line length is shorter than that typed
  5755. ;          in. However, it is the typed in line length that is used when parsing the BASIC line in the Screen Line Edit Buffer and as a result this causes an
  5756. ;          attempt to find the remaining characters on the following row of the Screen Line Edit Buffer. If another BASIC line is on the following Screen Line Edit Buffer
  5757. ;          row then the search completes and the cursor is placed on the row after this BASIC line. If there is not a BASIC line on the following
  5758. ;          row then the search continues on the next row. Since this will also be empty, the search advances onto the next row, and then the next, and so
  5759. ;          on until row 20 is reached. To fix the bug, the typed in character count until the cursor (held in $EC06) ideally needs to be adjusted to match the actual number of characters stored
  5760. ;          in the Screen Line Edit Buffer. However, this is not a trivial change to implement. A simpler solution to fix the bug is to intercept when a move to the next row is made and
  5761. ;          to determine whether the BASIC line actually continues on this row. Credit: Paul Farrow]
  5762.  
  5763. ; [To fix the bug, the POP HL and JR NC,$15CB (ROM 0) instructions following the call to $2E41 (ROM 0) should be replaced with the following. Credit: Paul Farrow.
  5764. ;
  5765. ;       PUSH DE           ; DE=Address of the start of the row of the BASIC line in the Screen Line Edit Buffer.
  5766. ;       PUSH AF           ; Save the flags.
  5767. ;
  5768. ;       LD   HL,$0020     ;
  5769. ;       ADD  HL,DE        ;
  5770. ;       EX   DE,HL        ; DE=Address of the flag byte for the row in the Screen Line Edit Buffer.
  5771. ;
  5772. ;       POP  AF           ; Restore the flags.
  5773. ;       JR   C,CHAR_FOUND ; Jump if editable column found.
  5774. ;
  5775. ;       LD   A,(DE)       ; Fetch the flag byte.
  5776. ;       BIT  1,A          ; Does the BASIC line span onto the next row?
  5777. ;       JR   NZ,SPANS_ROW ; Jump if it does.
  5778. ;
  5779. ;       POP  DE           ; DE=Address of the start of the BASIC row in the Screen Line Edit Buffer.
  5780. ;       POP  HL
  5781. ;       LD   HL,$0000     ; Signal no editable characters left on the row.
  5782. ;       LD   ($EC06),HL   ;
  5783. ;       JP   $15C0 (ROM 0) ; Jump since all characters on the row have been scanned through.
  5784. ;
  5785. ;SPANS_ROW:
  5786. ;       POP  DE           ; DE=Address of the start of the BASIC row in the Screen Line Edit Buffer.
  5787. ;       POP  HL           ;
  5788. ;       JP   $15CB (ROM 0) ; Jump if no editable columns left on the row.
  5789. ;
  5790. ;CHAR_FOUND:
  5791. ;       POP  DE           ; DE=Address of the start of the BASIC row in the Screen Line Edit Buffer.
  5792. ;       POP  HL           ; ]
  5793.  
  5794.         PUSH HL           ;
  5795.         CALL L2E41        ; Find editable position on this row from the previous column to the right, returning column number in B.
  5796.         POP  HL           ;
  5797.         JR   NC,L15CB     ; Jump if no editable character found on this row, i.e. there must be more characters on the next row.
  5798.  
  5799. ;An editable character was found to the right on the current row
  5800.  
  5801.         DEC  HL           ; Decrement the count of characters prior to the cursor.
  5802.         INC  B            ; Advance to next column.
  5803.         LD   ($EC06),HL   ; Update the count of the number of editable characters up to the cursor.
  5804.         JR   L15AB        ; Jump back to test next column.
  5805.  
  5806. ;Column position of cursor located, find the closest editable character
  5807.  
  5808. L15C0:  CALL L2E41        ; Find editable position on this row from the previous column to the right, returning column number in B.
  5809.         CALL NC,L2E63     ; If no editable character found then find editable position to the left, returning column number in B.
  5810.  
  5811.         LD   HL,$EEF5     ; Flags.
  5812.         LD   (HL),$00     ; Signal 'not the current line', 'current line has previously been found' and 'update display file enabled'.
  5813.  
  5814. ;Store the current cursor position
  5815.  
  5816. L15CB:  LD   A,B          ; A=Column number. This will be the preferred column number.
  5817.         POP  BC           ; B=Row number, C=Number of editing rows on screen.
  5818.         PUSH BC           ;
  5819.         LD   C,B          ; C=Row number.
  5820.         LD   B,A          ; B=Column number.
  5821.         CALL L2A11        ; Store this as the current cursor editing position.
  5822.  
  5823. ;Move to next row
  5824.  
  5825. L15D3:  POP  BC           ; B=Row number, C=Number of editing rows on screen.
  5826.         POP  DE           ; DE=Start address in Screen Line Edit Buffer of the next row.
  5827.         LD   A,C          ; A=Number of editing rows on screen.
  5828.         INC  B            ; Next row.
  5829.         CP   B            ; Reached the bottom screen row?
  5830.         JR   NC,L156F     ; Jump back if not to display the next row.
  5831.  
  5832. ;The bottom screen row has been exceeded
  5833.  
  5834.         LD   A,($EEF5)    ; Listing flags.
  5835.         BIT  1,A          ; Has the current line been previously found?
  5836.         JR   Z,L1602      ; Jump if so.
  5837.  
  5838. ;Current line has not yet been found
  5839.  
  5840.         BIT  0,A          ; Is this the current line?
  5841.         JR   NZ,L1602     ; Jump if so.
  5842.  
  5843. ;This is not the current line
  5844.  
  5845.         LD   HL,($5C49)   ; E_PPC. Current line number.
  5846.         LD   A,H          ;
  5847.         OR   L            ;
  5848.         JR   Z,L15F4      ; Jump if there is no current line number.
  5849.  
  5850.         LD   ($FC9A),HL   ; Store it as the line number at top of the screen.
  5851.  
  5852.         CALL L3222        ; Set default Above-Screen Line Edit Buffer settings to clear the count of the number of rows it contains.
  5853.         JR   L15FD        ; Jump forward.
  5854.  
  5855. ;There is no current line number
  5856.  
  5857. L15F4:  LD   ($FC9A),HL   ; Set the line number at top of the screen to $0000, i.e. first available.
  5858.         CALL L3352        ; Create line number representation in the Keyword Construction Buffer of the next BASIC line.
  5859.         LD   ($5C49),HL   ; E_PPC. Current line number is the first in the BASIC program.
  5860.  
  5861. L15FD:  POP  DE           ; DE=Start address in Screen Line Edit Buffer of the first row.
  5862.         POP  BC           ; B=Row number, C=Number of editing rows on screen.
  5863.         JP   L1536        ; Jump back to continue listing the program until the current line is found.
  5864.  
  5865. ;The bottom line is the current line
  5866.  
  5867. L1602:  POP  DE           ; DE=Start address in Screen Line Edit Buffer of the first row.
  5868.         POP  BC           ; B=Row number, C=Number of editing rows on screen.
  5869.         CP   A            ; Set the zero flag if current line has yet to be found, hence signal do not update cursor position settings.
  5870.  
  5871. ; ----------------------------------------------------------
  5872. ; Print All Screen Line Edit Buffer Rows to the Display File
  5873. ; ----------------------------------------------------------
  5874. ; Print all rows of the edit buffer to the display file, and updating the cursor position settings if required.
  5875. ; Entry: Zero flag reset if update of cursor position settings required.
  5876. ;        B=Row number.
  5877. ;        C=Number of editing rows on screen.
  5878.  
  5879. L1605:  PUSH AF           ; Save the zero flag.
  5880.  
  5881.         LD   A,C          ; Save the number of editing rows on screen.
  5882.         LD   C,B          ; C=Row number.
  5883.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of row held in C
  5884.         EX   DE,HL        ; and transfer into HL.
  5885.  
  5886. L160C:  PUSH AF           ; A=Number of editing rows on screen.
  5887.         CALL L3604        ; Print a row of the edit buffer to the screen.
  5888.         POP  AF           ;
  5889.  
  5890.         LD   DE,$0023     ;
  5891.         ADD  HL,DE        ; Point to the start of the next row.
  5892.  
  5893. L1615:  INC  C            ; Advance to the next row.
  5894.         CP   C            ; All rows printed?
  5895.         JR   NC,L160C     ; Jump back if not to print next row.
  5896.  
  5897. ;All rows printed
  5898.  
  5899.         POP  AF           ; Retrieve the zero flag.
  5900.         RET  Z            ; Return if 'not the current line' and 'current line has previously been found'.
  5901.  
  5902. ;Find the new cursor column position
  5903.  
  5904.         CALL L2A07        ; Get current cursor position (C=row, B=column, A=preferred column).
  5905.  
  5906. L161E:  CALL L2B78        ; Find next Screen Line Edit Buffer editable position to right, moving to next row if necessary. Returns column number in B.
  5907.  
  5908.         LD   HL,($EC06)   ; Fetch the number of editable characters on this row prior to the cursor.
  5909.         DEC  HL           ; Decrement the count.
  5910.         LD   A,H          ; Are there any characters?
  5911.         OR   L            ;
  5912.         LD   ($EC06),HL   ; Store the new count.
  5913.         JR   NZ,L161E     ; Jump if there are some characters prior to the cursor.
  5914.  
  5915.         JP   L2A11        ; Store cursor editing position, with preferred column of 0.
  5916.  
  5917.         RET               ; [Redundant byte]
  5918.  
  5919. ; ---------------------
  5920. ; Clear Editing Display
  5921. ; ---------------------
  5922.  
  5923. L1630:  LD   B,$00        ; Top row of editing area.
  5924.         LD   A,($EC15)    ; The number of editing rows on screen.
  5925.         LD   D,A          ; D=Number of rows in editing area.
  5926.         JP   L3B5E        ; Clear specified display rows.
  5927.  
  5928. ; -----------------------------------------------------------------
  5929. ; Shift All Edit Buffer Rows Up and Update Display File if Required
  5930. ; -----------------------------------------------------------------
  5931. ; This routine shifts all edit buffer rows up, updating the display file if required.
  5932. ; Entry: HL=Address of the 'Bottom Row Scroll Threshold' within the editing area information.
  5933. ; Exit : Carry flag set if edit buffer rows were shifted.
  5934.  
  5935. L1639:  LD   B,$00        ; Row number to start shifting from.
  5936.         PUSH HL           ; Save the address of the 'Bottom Row Scroll Threshold' within the editing area information.
  5937.  
  5938. ;Attempt to shift a row into the Above-Screen Line Edit Buffer
  5939.  
  5940.         LD   C,B          ; Find the address of row 0.
  5941.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  5942.         CALL L326A        ; Attempt to shift the top row of the Screen Line Edit Buffer into the Above-Screen Line Edit Buffer.
  5943.  
  5944.         POP  HL           ; Retrieve the address of the 'Bottom Row Scroll Threshold' within the editing area information.
  5945.         RET  NC           ; Return if the Above-Screen Line Edit Buffer is full, i.e. no edit buffer rows shifted.
  5946.  
  5947. ;A change to the number of rows in the Above-Screen Line Edit Buffer occurred
  5948.  
  5949.         CALL L30DF        ; Shift up rows of the BASIC line in Below-Screen Line Edit Buffer, inserting the next line BASIC line if the buffer becomes empty.
  5950.                           ; Returns with HL holding the address of the first row in the Below-Screen Line Edit Buffer.
  5951.  
  5952. ; Shift All Screen Line Edit Buffer Rows Up and Update Display File if Required
  5953. ; -----------------------------------------------------------------------------
  5954.  
  5955. L1648:  PUSH BC           ; B=Row counter.
  5956.         PUSH HL           ; HL=Address of first row in the Below-Screen Line Edit Buffer.
  5957.  
  5958.         LD   HL,$0023     ; DE=Address of the current row in the Screen Line Edit Buffer.
  5959.         ADD  HL,DE        ; HL=Address of the next row in the Screen Line Edit Buffer.
  5960.  
  5961.         LD   A,($EC15)    ;
  5962.         LD   C,A          ; C=Number of editing rows on screen.
  5963.         CP   B            ; Any rows to shift?
  5964.         JR   Z,L1663      ; Jump if not.
  5965.  
  5966. ;Shift all Screen Line Edit Buffer rows up
  5967.  
  5968.         PUSH BC           ; C=Number of editing rows on screen.
  5969.  
  5970. L1656:  PUSH BC           ; C=Number of editing rows on screen.
  5971.         LD   BC,$0023     ; DE=Current Screen Line Edit Buffer row, HL=Next Screen Line Edit Buffer row.
  5972.         LDIR              ; Shift one row of the Screen Line Edit Buffer up.
  5973.         POP  BC           ; C=Number of editing rows on screen.
  5974.  
  5975.         LD   A,C          ; Fetch the number of editing rows on screen.
  5976.         INC  B            ; Next row.
  5977.         CP   B            ; All rows shifted?
  5978.         JR   NZ,L1656     ; Repeat for all edit buffer rows to shift.
  5979.  
  5980. ;All Screen Line Edit Buffer rows have been shifted up
  5981.  
  5982.         POP  BC           ; C=Number of editing rows on screen, B=Row number, i.e. 0.
  5983.  
  5984. L1663:  POP  HL           ; HL=Address of the first row in the Below-Screen Line Edit Buffer.
  5985.  
  5986. L1664:  CALL L3618        ; Shift up all edit rows in the display file if updating required.
  5987.  
  5988.         LD   BC,$0023     ; HL=Address of the first row in the Below-Screen Line Edit Buffer, DE=Address of last row in Screen Line Edit Buffer.
  5989.         LDIR              ; Copy the first row of the Below-Screen Line Edit Buffer into the last row of the Screen Line Edit Buffer.
  5990.  
  5991.         SCF               ; Signal that edit buffer rows were shifted.
  5992.         POP  BC           ; B=Row counter.
  5993.         RET               ;
  5994.  
  5995. ; -------------------------------------------------------------------
  5996. ; Shift All Edit Buffer Rows Down and Update Display File if Required
  5997. ; -------------------------------------------------------------------
  5998. ; This routine shifts all edit buffer rows down, updating the display file if required.
  5999. ; Exit : Carry flag set if edit buffer rows were shifted.
  6000. ;        B=Last row number to shift.
  6001.  
  6002. ;Shift all rows in the Above-Screen Line Edit Buffer, shifting in a new BASIC line if applicable
  6003.  
  6004. L166F:  LD   B,$00        ; Last row number to shift.
  6005.         CALL L322B        ; Attempt to shift down the Above-Screen Line Edit Buffer, loading in a new BASIC line if it is empty.
  6006.         RET  NC           ; Return if Above-Screen Line Edit Buffer is empty, i.e. no edit buffer rows were shifted.
  6007.  
  6008. ;Entry point from routine at $2ED3 (ROM 0) to insert a blank row
  6009.  
  6010. L1675:  PUSH BC           ; B=Last row number to shift.
  6011.         PUSH HL           ; HL=Address of next row to use within the Above-Screen Line Edit Buffer.
  6012.  
  6013. ;Shift all rows in the Below-Screen Line Edit Buffer down, shifting in a new BASIC line if applicable
  6014.  
  6015.         LD   A,($EC15)    ; A=Number of editing rows on screen.
  6016.         LD   C,A          ; C=Number of editing rows on screen.
  6017.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the last editing row.
  6018.  
  6019.         CALL L311E        ; Shift down all rows in the Below-Screen Line Edit Buffer, or empty the buffer a row does not straggle off the bottom of the screen.
  6020.         JR   NC,L16A9     ; Jump if the Below-Screen Line Edit Buffer is full.
  6021.  
  6022.         DEC  DE           ; DE=Address of the last flag byte of the penultimate editing row in the Screen Line Edit Buffer.
  6023.         LD   HL,$0023     ; Length of an edit buffer row.
  6024.         ADD  HL,DE        ; HL=Address of the last flag byte of the last editing row in the Screen Line Edit Buffer.
  6025.         EX   DE,HL        ; DE=Address of last flag byte of last editing row in Screen Line Edit Buffer, HL=Address of last flag byte of penultimate editing row in Screen Line Edit Buffer.
  6026.  
  6027.         PUSH BC           ; C=Number of editing rows on screen, B=Last row number to shift.
  6028.         LD   A,B          ;
  6029.         CP   C            ; Any rows to shift?
  6030.         JR   Z,L169A      ; Jump if not.
  6031.  
  6032. L168E:  PUSH BC           ; C=Row number to shift, B=Last row number to shift.
  6033.         LD   BC,$0023     ;
  6034.         LDDR              ; Copy one row of the Screen Line Edit Buffer down.
  6035.         POP  BC           ; C=Number of editing rows on screen, B=Row shift counter.
  6036.  
  6037. L1695:  LD   A,B          ; A=Row shift counter.
  6038.         DEC  C            ;
  6039.         CP   C            ;
  6040.         JR   C,L168E      ; Repeat for all edit buffer rows to shift.
  6041.  
  6042. ;All Screen Line Edit Buffer rows have been shifted down
  6043.  
  6044. L169A:  EX   DE,HL        ; HL=Address of last flag byte of first editing row in Screen Line Edit Buffer, DE=Address of byte before start of first editing row in Screen Line Edit Buffer.
  6045.         INC  DE           ; DE=Start of first row in Screen Line Edit Buffer.
  6046.  
  6047.         POP  BC           ; C=Number of editing rows on screen, B=Last row number to shift.
  6048.         POP  HL           ; HL=Address of next row to use within the Above-Screen Line Edit Buffer.
  6049.  
  6050.         CALL L362C        ; Shift down all edit rows in the display file if updating required.
  6051.  
  6052.         LD   BC,$0023     ;
  6053.         LDIR              ; Copy the next row of the Above-Screen Line Edit Buffer into the first row of the Screen Line Edit Buffer.
  6054.  
  6055.         SCF               ; Signal Below-Screen Line Edit Buffer is not full.
  6056.         POP  BC           ; B=Last row number to shift.
  6057.         RET               ;
  6058.  
  6059. ;The Below-Screen Line Edit Buffer is full
  6060.  
  6061. L16A9:  POP  HL           ; Restore registers.
  6062.         POP  BC           ; B=Last row number to shift.
  6063.         RET               ;
  6064.  
  6065. ; ---------------------------------------------------------
  6066. ; Insert Character into Edit Buffer Row, Shifting Row Right
  6067. ; ---------------------------------------------------------
  6068. ; This routine shifts a byte into an edit buffer row, shifting all existing
  6069. ; characters right until either the end of the row is reached or the specified
  6070. ; end column is reached.
  6071. ; Entry: DE=Start address of an edit buffer row.
  6072. ;        A=Character to shift into left of row.
  6073. ;        B=Column to start shifting at.
  6074. ; Exit : A=Byte shifted out from last column.
  6075. ;        HL=Points byte after row (i.e. flag byte).
  6076. ;        Zero flag set if the character shifted out was a null ($00).
  6077.  
  6078. L16AC:  PUSH DE           ; Save DE.
  6079.  
  6080.         LD   H,$00        ;
  6081.         LD   L,B          ; HL=Start column number.
  6082.  
  6083. L16B0:  ADD  HL,DE        ; HL=Address of the starting column.
  6084.         LD   D,A          ; Store the character to shift in.
  6085.         LD   A,B          ; A=Start column number.
  6086.  
  6087. ;Shift all bytes in the row to the right.
  6088.  
  6089. L16B3:  LD   E,(HL)       ; Fetch a character from the row.
  6090.         LD   (HL),D       ; Replace it with the character to shift in.
  6091.         LD   D,E          ; Store the old character for use next time.
  6092.  
  6093.         INC  HL           ; Point to the next column.
  6094.         INC  A            ;
  6095.         CP   $20          ; End of row reached?
  6096.         JR   C,L16B3      ; Jump if not to shift the next character.
  6097.  
  6098.         LD   A,E          ; A=Character that was shifted out.
  6099.         CP   $00          ; Return with zero flag set if the character was $00.
  6100.  
  6101.         POP  DE           ; Restore DE
  6102.         RET               ;
  6103.  
  6104. ; --------------------------------------------------------
  6105. ; Insert Character into Edit Buffer Row, Shifting Row Left
  6106. ; --------------------------------------------------------
  6107. ; This routine shifts a byte into an edit buffer row, shifting all existing
  6108. ; characters left until either the beginning of the row is reached or the specified
  6109. ; end column is reached.
  6110. ; Entry: DE=Start address of an edit buffer row.
  6111. ;        A=Character to shift into right of row.
  6112. ;        B=Column to stop shifting at.
  6113. ; Exit : A=Byte shifted out.
  6114. ;        HL=Points byte before row.
  6115. ;        Zero flag set if the character shifted out was a null ($00).
  6116.  
  6117. L16C1:  PUSH DE           ; Save DE.
  6118.  
  6119.         LD   HL,$0020     ; 32 columns.
  6120.  
  6121. L16C5:  ADD  HL,DE        ; Point to the flag byte for this row.
  6122.         PUSH HL           ; Save it.
  6123.  
  6124.         LD   D,A          ; Store the character to shift in.
  6125.         LD   A,$1F        ; Maximum of 31 shifts.
  6126.         JR   L16D3        ; Jump ahead to start shifting.
  6127.  
  6128. L16CC:  LD   E,(HL)       ; Fetch a character from the row.
  6129.         LD   (HL),D       ; Replace it with the character to shift in.
  6130.         LD   D,E          ; Store the old character for use next time.
  6131.         CP   B            ; End column reached?
  6132.         JR   Z,L16D6      ; Jump if so to exit.
  6133.  
  6134.         DEC  A            ; Decrement column counter.
  6135.  
  6136. L16D3:  DEC  HL           ; Point back a column.
  6137.         JR   L16CC        ; Loop back to shift the next character.
  6138.  
  6139. L16D6:  LD   A,E          ; A=Character that was shifted out.
  6140.         CP   $00          ; Return with zero flag set if the character was $00.
  6141.  
  6142.         POP  HL           ; Fetch address of next flag byte for the row.
  6143.         POP  DE           ; Restore DE.
  6144.         RET               ;
  6145.  
  6146.  
  6147. ; =======================================================
  6148. ; BASIC LINE AND COMMAND INTERPRETATION ROUTINES - PART 1
  6149. ; =======================================================
  6150.  
  6151. ; -----------------------
  6152. ; The Syntax Offset Table
  6153. ; -----------------------
  6154. ; Similar in construction to the table in ROM 1 at $1A48.
  6155.  
  6156. L16DC:  DB $B1          ; DEF FN    -> $178D (ROM 0)
  6157.         DB $C9          ; CAT       -> $17A6 (ROM 0)
  6158.         DB $BC          ; FORMAT    -> $179A (ROM 0)
  6159.         DB $BE          ; MOVE      -> $179D (ROM 0)
  6160.         DB $C3          ; ERASE     -> $17A3 (ROM 0)
  6161.         DB $AF          ; OPEN #    -> $1790 (ROM 0)
  6162.         DB $B4          ; CLOSE #   -> $1796 (ROM 0)
  6163.         DB $93          ; MERGE     -> $1776 (ROM 0)
  6164.         DB $91          ; VERIFY    -> $1775 (ROM 0)
  6165.         DB $92          ; BEEP      -> $1777 (ROM 0)
  6166.         DB $95          ; CIRCLE    -> $177B (ROM 0)
  6167.         DB $98          ; INK       -> $177F (ROM 0)
  6168.         DB $98          ; PAPER     -> $1780 (ROM 0)
  6169.         DB $98          ; FLASH     -> $1781 (ROM 0)
  6170.         DB $98          ; BRIGHT    -> $1782 (ROM 0)
  6171.         DB $98          ; INVERSE   -> $1783 (ROM 0)
  6172.         DB $98          ; OVER      -> $1784 (ROM 0)
  6173.         DB $98          ; OUT       -> $1785 (ROM 0)
  6174.         DB $7F          ; LPRINT    -> $176D (ROM 0)
  6175.         DB $81          ; LLIST     -> $1770 (ROM 0)
  6176.         DB $2E          ; STOP      -> $171E (ROM 0)
  6177.         DB $6C          ; READ      -> $175D (ROM 0)
  6178.         DB $6E          ; DATA      -> $1760 (ROM 0)
  6179.         DB $70          ; RESTORE   -> $1763 (ROM 0)
  6180.         DB $48          ; NEW       -> $173C (ROM 0)
  6181.         DB $94          ; BORDER    -> $1789 (ROM 0)
  6182.         DB $56          ; CONTINUE  -> $174C (ROM 0)
  6183.         DB $3F          ; DIM       -> $1736 (ROM 0)
  6184.         DB $41          ; REM       -> $1739 (ROM 0)
  6185.         DB $2B          ; FOR       -> $1724 (ROM 0)
  6186.         DB $17          ; GO TO     -> $1711 (ROM 0)
  6187.         DB $1F          ; GO SUB    -> $171A (ROM 0)
  6188.         DB $37          ; INPUT     -> $1733 (ROM 0)
  6189.         DB $77          ; LOAD      -> $1774 (ROM 0)
  6190.         DB $44          ; LIST      -> $1742 (ROM 0)
  6191.         DB $0F          ; LET       -> $170E (ROM 0)
  6192.         DB $59          ; PAUSE     -> $1759 (ROM 0)
  6193.         DB $2B          ; NEXT      -> $172C (ROM 0)
  6194.         DB $43          ; POKE      -> $1745 (ROM 0)
  6195.         DB $2D          ; PRINT     -> $1730 (ROM 0)
  6196.         DB $51          ; PLOT      -> $1755 (ROM 0)
  6197.         DB $3A          ; RUN       -> $173F (ROM 0)
  6198.         DB $6D          ; SAVE      -> $1773 (ROM 0)
  6199.         DB $42          ; RANDOMIZE -> $1749 (ROM 0)
  6200.         DB $0D          ; IF        -> $1715 (ROM 0)  [No instruction fetch at $1708 hence ZX Interface 1 will not be paged in by this ROM. Credit: Paul Farrow].
  6201.         DB $49          ; CLS       -> $1752 (ROM 0)
  6202.         DB $5C          ; DRAW      -> $1766 (ROM 0)
  6203.         DB $44          ; CLEAR     -> $174F (ROM 0)
  6204.         DB $15          ; RETURN    -> $1721 (ROM 0)
  6205.         DB $5D          ; COPY      -> $176A (ROM 0)
  6206.  
  6207. ; --------------------------
  6208. ; The Syntax Parameter Table
  6209. ; --------------------------
  6210. ; Similar to the parameter table in ROM 1 at $1A7A.
  6211.  
  6212. L170E:  DB $01          ; CLASS-01    LET
  6213.         DB '='          ; $3D. '='
  6214.         DB $02          ; CLASS-02
  6215.  
  6216. L1711:  DB $06          ; CLASS-06    GO TO
  6217.         DB $00          ; CLASS-00
  6218.         DEFW GO_TO        ; $1E67. GO TO routine in ROM 1.
  6219.  
  6220. L1715:  DB $06          ; CLASS-06    IF
  6221.         DB $CB          ; 'THEN'
  6222.         DB $0E          ; CLASS-0E
  6223.         DEFW L1967        ; New IF routine in ROM 0.
  6224.  
  6225. L171A:  DB $06          ; CLASS-06    GO SUB
  6226.         DB $0C          ; CLASS-0C
  6227.         DEFW L1A53        ; New GO SUB routine in ROM 0.
  6228.  
  6229. L171E:  DB $00          ; CLASS-00    STOP
  6230.         DEFW STOP         ; $1CEE. STOP routine in ROM 1.
  6231.  
  6232. L1721:  DB $0C          ; CLASS-0C    RETURN
  6233.         DEFW L1A6F        ; New RETURN routine in ROM 0.
  6234.  
  6235. L1724:  DB $04          ; CLASS-04    FOR
  6236.         DB '='          ; $3D. '='
  6237.         DB $06          ; CLASS-06
  6238.         DB $CC          ; 'TO'
  6239.         DB $06          ; CLASS-06
  6240.         DB $0E          ; CLASS-0E
  6241.         DEFW L1981        ; New FOR routine in ROM 0.
  6242.  
  6243. L172C:  DB $04          ; CLASS-04    NEXT
  6244.         DB $00          ; CLASS-00
  6245.         DEFW NEXT         ; $1DAB. NEXT routine in ROM 1.
  6246.  
  6247. L1730:  DB $0E          ; CLASS-0E    PRINT
  6248.         DEFW L2178        ; New PRINT routine in ROM 0.
  6249.  
  6250. L1733:  DB $0E          ; CLASS-0E    INPUT
  6251.         DEFW L218C        ; New INPUT routine in ROM 0.
  6252.  
  6253. L1736:  DB $0E          ; CLASS-0E    DIM
  6254.         DEFW L21D5        ; New DIM routine in ROM 0.
  6255.  
  6256. L1739:  DB $0E          ; CLASS-0E    REM
  6257.         DEFW L1862        ; New REM routine in ROM 0.
  6258.  
  6259. L173C:  DB $0C          ; CLASS-0C    NEW
  6260.         DEFW L21AA        ; New NEW routine in ROM 0.
  6261.  
  6262. L173F:  DB $0D          ; CLASS-0D    RUN
  6263.         DEFW L1A02        ; New RUN routine in ROM 0.
  6264.  
  6265. L1742:  DB $0E          ; CLASS-0E    LIST
  6266.         DEFW L1B75        ; New LIST routine in ROM 0.
  6267.  
  6268. L1745:  DB $08          ; CLASS-08    POKE
  6269.         DB $00          ; CLASS-00
  6270.         DEFW POKE         ; $1E80. POKE routine in ROM 1.
  6271.  
  6272. L1749:  DB $03          ; CLASS-03    RANDOMIZE
  6273.         DEFW RANDOMIZE    ; $1E4F. RANDOMIZE routine in ROM 1.
  6274.  
  6275. L174C:  DB $00          ; CLASS-00    CONTINUE
  6276.         DEFW CONTINUE     ; $1E5F. CONTINUE routine in ROM 1.
  6277.  
  6278. L174F:  DB $0D          ; CLASS-0D    CLEAR
  6279.         DEFW L1A0D        ; New CLEAR routine in ROM 0.
  6280.  
  6281. L1752:  DB $00          ; CLASS-00    CLS
  6282.         DEFW CLS          ; $0D6B. CLS routine in ROM 1.
  6283.  
  6284. L1755:  DB $09          ; CLASS-09    PLOT
  6285.         DB $00          ; CLASS-00
  6286.         DEFW PLOT         ; $22DC. PLOT routine in ROM 1
  6287.  
  6288. L1759:  DB $06          ; CLASS-06    PAUSE
  6289.         DB $00          ; CLASS-00
  6290.         DEFW PAUSE        ; $1F3A. PAUSE routine in ROM 1.
  6291.  
  6292. L175D:  DB $0E          ; CLASS-0E    READ
  6293.         DEFW L19AB        ; New READ routine in ROM 0.
  6294.  
  6295. L1760:  DB $0E          ; CLASS-0E    DATA
  6296.         DEFW L19EB        ; New DATA routine in ROM 0.
  6297.  
  6298. L1763:  DB $03          ; CLASS-03    RESTORE
  6299.         DEFW RESTORE      ; $1E42. RESTORE routine in ROM 1.
  6300.  
  6301. L1766:  DB $09          ; CLASS-09    DRAW
  6302.         DB $0E          ; CLASS-0E
  6303.         DEFW L21BE        ; New DRAW routine in ROM 0.
  6304.  
  6305. L176A:  DB $0C          ; CLASS-0C    COPY
  6306.         DEFW L21A7        ; New COPY routine in ROM 0.
  6307.  
  6308. L176D:  DB $0E          ; CLASS-0E    LPRINT
  6309.         DEFW L2174        ; New LPRINT routine in ROM 0.
  6310.  
  6311. L1770:  DB $0E          ; CLASS-0E    LLIST
  6312.         DEFW L1B71        ; New LLIST routine in ROM 0.
  6313.  
  6314. L1773:  DB $0B          ; CLASS-0B    SAVE
  6315.  
  6316. L1774:  DB $0B          ; CLASS-0B    LOAD
  6317.  
  6318. L1775:  DB $0B          ; CLASS-0B    VERIFY
  6319.  
  6320. L1776:  DB $0B          ; CLASS-0B    MERGE
  6321.  
  6322. L1777:  DB $08          ; CLASS-08    BEEP
  6323.         DB $00          ; CLASS-00
  6324.         DEFW BEEP         ; $03F8. BEEP routine in ROM 1.
  6325.  
  6326. L177B:  DB $09          ; CLASS-09    CIRCLE
  6327.         DB $0E          ; CLASS-0E
  6328.         DEFW L21AE        ; New CIRCLE routine in ROM 0.
  6329.  
  6330. L177F:  DB $07          ; CLASS-07    INK
  6331.  
  6332. L1780:  DB $07          ; CLASS-07    PAPER
  6333.  
  6334. L1781:  DB $07          ; CLASS-07    FLASH
  6335.  
  6336. L1782:  DB $07          ; CLASS-07    BRIGHT
  6337.  
  6338. L1783:  DB $07          ; CLASS-07    INVERSE
  6339.  
  6340. L1784:  DB $07          ; CLASS-07    OVER
  6341.  
  6342. L1785:  DB $08          ; CLASS-08    OUT
  6343.         DB $00          ; CLASS-00
  6344.         DEFW COUT         ; $1E7A. OUT routine in ROM 1.
  6345.  
  6346. L1789:  DB $06          ; CLASS-06    BORDER
  6347.         DB $00          ; CLASS-00
  6348.         DEFW BORDER       ; $2294. BORDER routine in ROM 1.
  6349.  
  6350. L178D:  DB $0E          ; CLASS-0E    DEF FN
  6351.         DEFW L1A8C        ; New DEF FN routine in ROM 0.
  6352.  
  6353. L1790:  DB $06          ; CLASS-06    OPEN #
  6354.         DB ','          ; $2C. ','
  6355.         DB $0A          ; CLASS-0A
  6356.         DB $00          ; CLASS-00
  6357.         DEFW OPEN         ; $1736. OPEN # routine in ROM 1.
  6358.  
  6359. L1796:  DB $06          ; CLASS-06    CLOSE #
  6360.         DB $00          ; CLASS-00
  6361.         DEFW CLOSE        ; $16E5. CLOSE # routine in ROM 1.
  6362.  
  6363. L179A:  DB $0E          ; CLASS-0E    FORMAT
  6364.         DEFW L0641        ; FORMAT routine in ROM 0.
  6365.  
  6366. L179D:  DB $0A          ; CLASS-0A    MOVE
  6367.         DB ','          ; $2C. ','
  6368.         DB $0A          ; CLASS-0A
  6369.         DB $0C          ; CLASS-0C
  6370.         DEFW L1AF0        ; Just execute a RET.
  6371.  
  6372. L17A3:  DB $0E          ; CLASS-0E    ERASE
  6373.         DEFW L1C0C        ; New ERASE routine in ROM 0.
  6374.  
  6375. L17A6:  DB $0E          ; CLASS-0E    CAT
  6376.         DEFW L1BE5        ; New CAT routine in ROM 0.
  6377.  
  6378. L17A9:  DB $0C          ; CLASS-0C    SPECTRUM
  6379.         DEFW L1B2B        ; SPECTRUM routine in ROM 0.
  6380.  
  6381. L17AC:  DB $0E          ; CLASS-0E    PLAY
  6382.         DEFW L2317        ; PLAY routine in ROM 0.
  6383.  
  6384. ; (From Logan & O'Hara's 48K ROM disassembly):
  6385. ; The requirements for the different command classes are as follows:
  6386. ; CLASS-00 - No further operands.
  6387. ; CLASS-01 - Used in LET. A variable is required.
  6388. ; CLASS-02 - Used in LET. An expression, numeric or string, must follow.
  6389. ; CLASS-03 - A numeric expression may follow. Zero to be used in case of default.
  6390. ; CLASS-04 - A single character variable must follow.
  6391. ; CLASS-05 - A set of items may be given.
  6392. ; CLASS-06 - A numeric expression must follow.
  6393. ; CLASS-07 - Handles colour items.
  6394. ; CLASS-08 - Two numeric expressions, separated by a comma, must follow.
  6395. ; CLASS-09 - As for CLASS-08 but colour items may precede the expressions.
  6396. ; CLASS-0A - A string expression must follow.
  6397. ; CLASS-0B - Handles cassette/RAM disk routines.
  6398.  
  6399. ; In addition the 128 adds the following classes:
  6400. ; CLASS-0C - Like class 00 but calling ROM 0. (Used by SPECTRUM, MOVE, COPY, NEW, GO SUB, RETURN)
  6401. ; CLASS-0D - Like class 06 but calling ROM 0. (Used by CLEAR, RUN)
  6402. ; CLASS-0E - Handled in ROM 0. (Used by PLAY, ERASE, CAT, FORMAT, CIRCLE, LPRINT, LLIST, DRAW, DATA, READ, LIST, DIM, INPUT, PRINT, FOR, IF)
  6403.  
  6404. ; ------------------------------------------
  6405. ; The 'Main Parser' Of the BASIC Interpreter
  6406. ; ------------------------------------------
  6407. ; The parsing routine of the BASIC interpreter is entered at $17AF (ROM 0) when syntax is being checked,
  6408. ; and at $1838 (ROM 0) when a BASIC program of one or more statements is to be executed.
  6409. ; This code is similar to that in ROM 1 at $1B17.
  6410.  
  6411. L17AF:  RES  7,(IY+$01)   ; FLAGS. Signal 'syntax checking'.
  6412.         RST  28H          ;
  6413.         DEFW E_LINE_NO    ; $19FB. CH-ADD is made to point to the first code after any line number
  6414.         XOR  A            ;
  6415.         LD   ($5C47),A    ; SUBPPC. Set to $00.
  6416.         DEC  A            ;
  6417.         LD   ($5C3A),A    ; ERR_NR. Set to $FF.
  6418.         JR   L17C1        ; Jump forward to consider the first statement of the line.
  6419.  
  6420. ; ------------------
  6421. ; The Statement Loop
  6422. ; ------------------
  6423. ; Each statement is considered in turn until the end of the line is reached.
  6424.  
  6425. L17C0:  RST  20H          ; Advance CH-ADD along the line.
  6426.  
  6427. L17C1:  RST  28H          ;
  6428.         DEFW SET_WORK     ; $16BF. The work space is cleared.
  6429.         INC  (IY+$0D)     ; SUBPPC. Increase SUBPPC on each passage around the loop.
  6430.         JP   M,L1912      ; Only '127' statements are allowed in a single line. Jump to report "C Nonsense in BASIC".
  6431.  
  6432.         RST  18H          ; Fetch a character.
  6433.         LD   B,$00        ; Clear the register for later.
  6434.         CP   $0D          ; Is the character a 'carriage return'?
  6435.         JP   Z,L1863      ; jump if it is.
  6436.  
  6437.         CP   ':'          ; $3A. Go around the loop again if it is a ':'.
  6438.         JR   Z,L17C0      ;
  6439.  
  6440. ;A statement has been identified so, first, its initial command is considered
  6441.  
  6442.         LD   HL,L1821     ; Pre-load the machine stack with the return address.
  6443.         PUSH HL           ;
  6444.  
  6445.         LD   C,A          ; Save the command temporarily
  6446.         RST  20H          ; in the C register whilst CH-ADD is advanced again.
  6447.         LD   A,C          ;
  6448.         SUB  $CE          ; Reduce the command's code by $CE giving the range indexed from $00.
  6449.         JR   NC,L17F4     ; Jump for DEF FN and above.
  6450.  
  6451.         ADD  A,$CE        ;
  6452.         LD   HL,L17A9     ;
  6453.         CP   $A3          ; Is it 'SPECTRUM'?
  6454.         JR   Z,L1800      ; Jump if so into the scanning loop with this address.
  6455.  
  6456.         LD   HL,L17AC     ;
  6457.         CP   $A4          ; Is it 'PLAY'?
  6458.         JR   Z,L1800      ; Jump if so into the scanning loop with this address.
  6459.  
  6460.         JP   L1912        ; Produce error report "C Nonsense in BASIC".
  6461.  
  6462. L17F4:  LD   C,A          ; Move the command code to BC (B holds $00).
  6463.         LD   HL,L16DC     ; The base address of the syntax offset table.
  6464.         ADD  HL,BC        ;
  6465.         LD   C,(HL)       ;
  6466.         ADD  HL,BC        ; Find address for the command's entries in the parameter table.
  6467.         JR   L1800        ; Jump forward into the scanning loop with this address.
  6468.  
  6469. ;Each of the command class routines applicable to the present command are executed in turn.
  6470. ;Any required separators are also considered.
  6471.  
  6472. L17FD:  LD   HL,($5C74)   ; T_ADDR. The temporary pointer to the entries in the parameter table.
  6473.  
  6474. L1800:  LD   A,(HL)       ; Fetch each entry in turn.
  6475.         INC  HL           ; Update the pointer to the entries for the next pass.
  6476.         LD   ($5C74),HL   ; T_ADDR.
  6477.  
  6478.         LD   BC,L17FD     ; Pre-load the machine stack with the return address.
  6479.         PUSH BC           ;
  6480.  
  6481.         LD   C,A          ; Copy the entry to the C register for later.
  6482.         CP   $20          ;
  6483.         JR   NC,L181A     ; Jump forward if the entry is a 'separator'.
  6484.  
  6485.         LD   HL,L18B5     ; The base address of the 'command class' table.
  6486.         LD   B,$00        ;
  6487.         ADD  HL,BC        ; Index into the table.
  6488.         LD   C,(HL)       ;
  6489.         ADD  HL,BC        ; HL=base + code + (base + code).
  6490.         PUSH HL           ; HL=The starting address of the required command class routine.
  6491.  
  6492.         RST  18H          ; Before making an indirect jump to the command class routine pass the command code
  6493.         DEC  B            ; to the A register and set the B register to $FF.
  6494.         RET               ; Return to the stacked address.
  6495.  
  6496. ; --------------------------
  6497. ; The 'Separator' Subroutine
  6498. ; --------------------------
  6499. ; The report 'Nonsense in BASIC is given if the required separator is not present.
  6500. ; But note that when syntax is being checked the actual report does not appear on the screen - only the 'error marker'.
  6501. ; This code is similar to that in ROM 1 at $1B6F.
  6502.  
  6503. L181A:  RST  18H          ; The current character is
  6504.         CP   C            ; fetched and compared to the entry in the parameter table.
  6505.         JP   NZ,L1912     ; Give the error report if there is not a match.
  6506.  
  6507.         RST  20H          ; Step past a correct character
  6508.         RET               ; and return.
  6509.  
  6510. ; ---------------------------------
  6511. ; The 'Statement Return' Subroutine
  6512. ; ---------------------------------
  6513. ; After the correct interpretation of a statement, a return is made to this entry point.
  6514. ; This code is similar to that in ROM 1 at $1B76.
  6515.  
  6516. L1821:  CALL L05D6        ; Check for BREAK
  6517.         JR   C,L182A      ; [This code is redundant since the BREAK key check routine at $05D6 (ROM 0)
  6518.                           ;  will automatically produce the error report code if BREAK is being pressed
  6519.                           ;  and so 6 bytes could have been saved here. Credit: Paul Farrow].
  6520.  
  6521.         CALL L05AC        ; Produce error report.
  6522.         DB $14          ; "L Break into program"
  6523.  
  6524. L182A:  BIT  7,(IY+$0A)   ; NSPPC - statement number in line to be jumped to
  6525.         JP   NZ,L18A8     ; Jump forward if there is not a 'jump' to be made.
  6526.  
  6527.         LD   HL,($5C42)   ; NEWPPC, line number to be jumped to.
  6528.         BIT  7,H          ;
  6529.         JR   Z,L184C      ; Jump forward unless dealing with a further statement in the editing area.
  6530.  
  6531. ; --------------------------
  6532. ; The 'Line Run' Entry Point
  6533. ; --------------------------
  6534. ; This entry point is used wherever a line in the editing area is to be 'run'.
  6535. ; In such a case the syntax/run flag (bit 7 of FLAGS) will be set.
  6536. ; The entry point is also used in the syntax checking of a line in the editing area
  6537. ; that has more than one statement (bit 7 of FLAGS will be reset).
  6538. ; This code is similar to that in ROM 1 at $1B8A.
  6539.  
  6540. L1838:  LD   HL,$FFFE     ; A line in the editing area is considered as line '-2'.
  6541.         LD   ($5C45),HL   ; PPC.
  6542.         LD   HL,($5C61)   ; WORKSP. Make HL point to the end marker of the editing area.
  6543.         DEC  HL           ;
  6544.         LD   DE,($5C59)   ; E_LINE. Make DE point to the location before the end marker of the editing area.
  6545.         DEC  DE           ;
  6546.         LD   A,($5C44)    ; NSPPC. Fetch the number of the next statement to be handled.
  6547.         JR   L1882        ; Jump forward.
  6548.  
  6549. ; -------------------------
  6550. ; The 'Line New' Subroutine
  6551. ; -------------------------
  6552. ; There has been a jump in the program and the starting address of the new line has to be found.
  6553. ; This code is similar to that in ROM 1 at 1B9E.
  6554.  
  6555. L184C:  RST  28H          ;
  6556.         DEFW LINE_ADDR    ; $196E. The starting address of the line, or the 'first line after' is found.
  6557.         LD   A,($5C44)    ; NSPPC. Collect the statement number.
  6558.         JR   Z,L1870      ; Jump forward if the required line was found.
  6559.  
  6560.         AND  A            ; Check the validity of the statement number - must be zero.
  6561.         JR   NZ,L189D     ; Jump if not to produce error report "N Statement lost".
  6562.  
  6563.         LD   B,A          ; Also check that the 'first
  6564.         LD   A,(HL)       ; line after' is not after the
  6565.         AND  $C0          ; actual 'end of program'.
  6566.         LD   A,B          ;
  6567.         JR   Z,L1870      ; Jump forward with valid addresses; otherwise signal the error 'OK'.
  6568.  
  6569.         CALL L05AC        ; Produce error report.
  6570.         DB $FF          ; "0 OK"
  6571.  
  6572. ; -----------
  6573. ; REM Routine
  6574. ; -----------
  6575. ; The return address to STMT-RET is dropped which has the effect of forcing the rest of the
  6576. ; line to be ignored.
  6577. ; This code is similar to that in ROM 1 at $1BB2.
  6578.  
  6579. L1862:  POP  BC           ; Drop the statement return address.
  6580.  
  6581. ; ----------------------
  6582. ; The 'Line End' Routine
  6583. ; ----------------------
  6584. ; If checking syntax a simple return is made but when 'running' the address held by NXTLIN
  6585. ; has to be checked before it can be used.
  6586. ; This code is similar to that in ROM 1 at $1BB3.
  6587.  
  6588. L1863:  BIT  7,(IY+$01)   ;
  6589.         RET  Z            ; Return if syntax is being checked.
  6590.  
  6591.         LD   HL,($5C55)   ; NXTLIN.
  6592.         LD   A,$C0        ; Return if the address is after the end of the program - the 'run' is finished.
  6593.         AND  (HL)         ;
  6594.         RET  NZ           ;
  6595.  
  6596.         XOR  A            ; Signal 'statement zero' before proceeding.
  6597.  
  6598. ; ----------------------
  6599. ; The 'Line Use' Routine
  6600. ; ----------------------
  6601. ; This  routine has three functions:
  6602. ;  i.  Change statement zero to statement '1'.
  6603. ;  ii.  Find the number of the new line and enter it into PPC.
  6604. ;  iii. Form the address of the start of the line after.
  6605. ; This code is similar to that in ROM 1 at $1BBF.
  6606.  
  6607. L1870:  CP   $01          ; Statement zero becomes statement 1.
  6608.         ADC  A,$00        ;
  6609.         LD   D,(HL)       ; The line number of the line to be used is collected and
  6610.         INC  HL           ; passed to PPC.
  6611.         LD   E,(HL)       ;
  6612.         LD   ($5C45),DE   ; PPC.
  6613.         INC  HL           ;
  6614.         LD   E,(HL)       ; Now find the 'length' of the line.
  6615.         INC  HL           ;
  6616.         LD   D,(HL)       ;
  6617.         EX   DE,HL        ; Switch over the values.
  6618.         ADD  HL,DE        ; Form the address of the start of the line after in HL and the
  6619.         INC  HL           ; location before the 'next' line's first character in DE.
  6620.  
  6621. ; -----------------------
  6622. ; The 'Next Line' Routine
  6623. ; -----------------------
  6624. ; On entry the HL register pair points to the location after the end of the 'next' line
  6625. ; to be handled and the DE register pair to the location before the first character of the line.
  6626. ; This applies to lines in the program area and also to a line in the editing area - where the
  6627. ; next line will be the same line again whilst there are still statements to be interpreted.
  6628. ; This code is similar to that in ROM 1 at $1BD1.
  6629.  
  6630. L1882:  LD   ($5C55),HL   ; NXTLIN. Set NXTLIN for use once the current line has been completed.
  6631.         EX   DE,HL        ;
  6632.         LD   ($5C5D),HL   ; CH_ADD. CH_ADD points to the location before the first character to be considered.
  6633.         LD   D,A          ; The statement number is fetched.
  6634.         LD   E,$00        ; The E register is cleared in case the 'Each Statement' routine is used.
  6635.         LD   (IY+$0A),$FF ; NSPPC. Signal 'no jump'.
  6636.         DEC  D            ;
  6637.         LD   (IY+$0D),D   ; SUB_PPC. Statement number-1.
  6638.         JP   Z,L17C0      ; Jump if the first statement.
  6639.  
  6640.         INC  D            ; For later statements the 'starting address' has to be found.
  6641.         RST  28H          ;
  6642.         DEFW EACH_STMT    ; $198B.
  6643.         JR   Z,L18A8      ; Jump forward unless the statement does not exist.
  6644.  
  6645. L189D:  CALL L05AC        ; Produce error report.
  6646.         DB $16          ; "N Statement lost"
  6647.  
  6648. ; --------------------------
  6649. ; The 'CHECK-END' Subroutine
  6650. ; --------------------------
  6651. ; This is called when the syntax of the edit-line is being checked. The purpose of the routine is to
  6652. ; give an error report if the end of a statement has not been reached and to move on to the next
  6653. ; statement if the syntax is correct.
  6654. ; The routine is the equivalent of routine CHECK_END in ROM 1 at $1BEE.
  6655.  
  6656. L18A1:  BIT  7,(IY+$01)   ; Very like CHECK-END at 1BEE in ROM 1
  6657.         RET  NZ           ; Return unless checking syntax.
  6658.  
  6659.         POP  BC           ; Drop scan loop and statement return addresses.
  6660.         POP  BC           ;
  6661.  
  6662. ; -----------------------
  6663. ; The 'STMT-NEXT' Routine
  6664. ; -----------------------
  6665. ; If the present character is a 'carriage return' then the 'next statement' is on the 'next line',
  6666. ; if ':' it is on the same line; but if any other character is found then there is an error in syntax.
  6667. ; The routine is the equivalent of routine STMT_NEXT in ROM 1 at $1BF4.
  6668.  
  6669. L18A8:  RST  18H          ; Fetch the present character.
  6670.         CP   $0D          ; Consider the 'next line' if
  6671.         JR   Z,L1863      ; it is a 'carriage return'.
  6672.  
  6673.         CP   ':'          ; $3A. Consider the 'next statement'
  6674.         JP   Z,L17C0      ; if it is a ':'.
  6675.  
  6676.         JP   L1912        ; Otherwise there has been a syntax error so produce "C Nonsense in BASIC".
  6677.  
  6678. ; -------------------------
  6679. ; The 'Command Class' Table
  6680. ; -------------------------
  6681.  
  6682. L18B5:  DB L18D9-$      ; CLASS-00 -> L18D9 = $24
  6683.         DB L18F9-$      ; CLASS-01 -> L18F9 = $43
  6684.         DB L18FD-$      ; CLASS-02 -> L18FD = $46
  6685.         DB L18D6-$      ; CLASS-03 -> L18D6 = $1E
  6686.         DB L1905-$      ; CLASS-04 -> L1905 = $4C
  6687.         DB L18DA-$      ; CLASS-05 -> L18DA = $20
  6688.         DB L190E-$      ; CLASS-06 -> L190E = $53
  6689.         DB L191A-$      ; CLASS-07 -> L191A = $5E
  6690.         DB L190A-$      ; CLASS-08 -> L190A = $4D
  6691.         DB L1944-$      ; CLASS-09 -> L1944 = $86
  6692.         DB L1916-$      ; CLASS-0A -> L1916 = $57
  6693.         DB L1948-$      ; CLASS-0B -> L1948 = $88
  6694.         DB L18C7-$      ; CLASS-0C -> L18C7 = $06
  6695.         DB L18C4-$      ; CLASS-0D -> L18C4 = $02
  6696.         DB L18C8-$      ; CLASS-0E -> L18C8 = $05
  6697.  
  6698. ; -----------------------------------
  6699. ; The 'Command Classes - 0C, 0D & 0E'
  6700. ; -----------------------------------
  6701. ; For commands of class-0D a numeric expression must follow.
  6702.  
  6703. L18C4:  RST  28H          ; Code 0D enters here.
  6704.         DEFW FETCH_NUM    ; $1CDE.
  6705.  
  6706. ;The commands of class-0C must not have any operands. e.g. SPECTRUM.
  6707.  
  6708. L18C7:  CP   A            ; Code 0C enters here. Set zero flag.
  6709.  
  6710. ;The commands of class-0E may be followed by a set of items. e.g. PLAY.
  6711.  
  6712. L18C8:  POP  BC           ; Code 0E enters here.
  6713.                           ; Retrieve return address.
  6714.         CALL Z,L18A1      ; If handling commands of classes 0C & 0D and syntax is being
  6715.                           ; checked move on now to consider the next statement.
  6716.         EX   DE,HL        ; Save the line pointer in DE.
  6717.  
  6718. ; After the command class entries and the separator entries in the parameter table have
  6719. ; been considered the jump to the appropriate command routine is made.
  6720. ; The routine is similar to JUMP-C-R in ROM 1 at $1C16.
  6721.  
  6722.         LD   HL,($5C74)   ; T_ADDR.
  6723.         LD   C,(HL)       ; Fetch the pointer to the entries in the parameter table
  6724.         INC  HL           ; and fetch the address of the
  6725.         LD   B,(HL)       ; required command routine.
  6726.         EX   DE,HL        ; Exchange the pointers back.
  6727.         PUSH BC           ; Make an indirect jump to the command routine.
  6728.         RET               ;
  6729.  
  6730. ; -----------------------------------
  6731. ; The 'Command Classes - 00, 03 & 05'
  6732. ; -----------------------------------
  6733. ; These routines are the equivalent of the routines in ROM 1 starting at $1C0D.
  6734.  
  6735. ; The commands of class-03 may, or may not, be followed by a number. e.g. RUN & RUN 200.
  6736.  
  6737. L18D6:  RST  28H          ; Code 03 enters here.
  6738.         DEFW FETCH_NUM    ; $1CDE. A number is fetched but zero is used in cases of default.
  6739.  
  6740. ;The commands of class-00 must not have any operands. e.g. COPY & CONTINUE.
  6741.  
  6742. L18D9:  CP   A            ; Code 00 enters here. Set the zero flag.
  6743.  
  6744. ;The commands of class-05 may be followed by a set of items. e.g. PRINT & PRINT "222".
  6745.  
  6746. L18DA:  POP  BC           ; Code 05 enters here. Drop return address.
  6747.         CALL Z,L18A1      ; If handling commands of classes 00 & 03 and syntax is being
  6748.                           ; checked move on now to consider the next statement.
  6749.         EX   DE,HL        ; Save the line pointer in DE.
  6750.  
  6751.         LD   HL,($5C74)   ; T_ADDR. Fetch the pointer to the entries in the parameter table.
  6752.         LD   C,(HL)       ;
  6753.         INC  HL           ;
  6754.         LD   B,(HL)       ; Fetch the address of the required command routine.
  6755.         EX   DE,HL        ; Exchange the pointers back.
  6756.         PUSH HL           ; Save command routine address.
  6757.  
  6758.         LD   HL,L18F8     ; The address to return to (the RET below).
  6759.         LD   (RETADDR),HL ; $5B5A. Store the return address.
  6760.         LD   HL,YOUNGER   ; $5B14. Paging subroutine.
  6761.         EX   (SP),HL      ; Replace the return address with the address of the YOUNGER routine.
  6762.         PUSH HL           ; Save the original top stack item.
  6763.         LD   H,B          ;
  6764.         LD   L,C          ; HL=Address of command routine.
  6765.         EX   (SP),HL      ; Put onto the stack so that an indirect jump will be made to it.
  6766.         JP   SWAP         ; $5B00. Switch to other ROM and 'return' to the command routine.
  6767.  
  6768. ;Comes here after ROM 1 has been paged in, the command routine called, ROM 0 paged back in.
  6769.  
  6770. L18F8:  RET               ; Simply make a return.
  6771.  
  6772. ; ------------------------
  6773. ; The 'Command Class - 01'
  6774. ; ------------------------
  6775. ; Command class 01 is concerned with the identification of the variable in a LET, READ or INPUT statement.
  6776.  
  6777. L18F9:  RST  28H          ; Delegate handling to ROM 1.
  6778.         DEFW CLASS_01     ; $1C1F.
  6779.         RET               ;
  6780.  
  6781. ; ------------------------
  6782. ; The 'Command Class - 02'
  6783. ; ------------------------
  6784. ; Command class 02 is concerned with the actual calculation of the value to be assigned in a LET statement.
  6785.  
  6786. L18FD:  POP  BC           ; Code 02 enters here. Delegate handling to ROM 1.
  6787.         RST  28H          ;
  6788.         DEFW VAL_FET_1    ; $1C56. "... used by LET, READ and INPUT statements to
  6789.                           ;         first evaluate and then assign values to the
  6790.                           ;         previously designated variable" (Logan/O'Hara)
  6791.         CALL L18A1        ; Move on to the next statement if checking syntax
  6792.         RET               ; else return here.
  6793.  
  6794. ; ------------------------
  6795. ; The 'Command Class - 04'
  6796. ; ------------------------
  6797. ; The command class 04 entry point is used by FOR & NEXT statements.
  6798.  
  6799. L1905:  RST  28H          ; Code 04 enters here. Delegate handling to ROM 1.
  6800.         DEFW CLASS_04     ; $1C6C.
  6801.         RET               ;
  6802.  
  6803. ; ------------------------
  6804. ; The 'Command Class - 08'
  6805. ; ------------------------
  6806. ; Command class 08 allows for two numeric expressions, separated by a comma, to be evaluated.
  6807.  
  6808. L1909:  RST  20H          ; [Redundant byte]
  6809.  
  6810. L190A:  RST  28H          ; Delegate handling to ROM 1.
  6811.         DEFW EXPT_2NUM    ; $1C7A.
  6812.         RET               ;
  6813.  
  6814. ; ------------------------
  6815. ; The 'Command Class - 06'
  6816. ; ------------------------
  6817. ; Command class 06 allows for a single numeric expression to be evaluated.
  6818.  
  6819. L190E:  RST  28H          ; Code 06 enters here. Delegate handling to ROM 1.
  6820.         DEFW EXPT_1NUM    ; $1C82.
  6821.         RET               ;
  6822.  
  6823. ; ----------------------------
  6824. ; Report C - Nonsense in BASIC
  6825. ; ----------------------------
  6826.  
  6827. L1912:  CALL L05AC        ; Produce error report. [Could have saved 4 bytes by using the identical routine at $1219 (ROM 0) instead]
  6828.         DB $0B          ; "C Nonsense in BASIC"
  6829.  
  6830. ; ------------------------
  6831. ; The 'Command Class - 0A'
  6832. ; ------------------------
  6833. ; Command class 0A allows for a single string expression to be evaluated.
  6834.  
  6835. L1916:  RST  28H          ; Code 0A enters here. Delegate handling to ROM 1.
  6836.         DEFW EXPT_EXP     ; $1C8C.
  6837.         RET               ;
  6838.  
  6839. ; ------------------------
  6840. ; The 'Command Class - 07'
  6841. ; ------------------------
  6842. ; Command class 07 is the command routine for the six colour item commands.
  6843. ; Makes the current temporary colours permanent.
  6844.  
  6845. L191A:  BIT  7,(IY+$01)   ; The syntax/run flag is read.
  6846.         RES  0,(IY+$02)   ; TV_FLAG. Signal 'main screen'.
  6847.         JR   Z,L1927      ; Jump ahead if syntax checking.
  6848.  
  6849.         RST  28H          ; Only during a 'run' call TEMPS to ensure the temporary
  6850.         DEFW TEMPS        ; $0D4D.   colours are the main screen colours.
  6851.  
  6852. L1927:  POP  AF           ; Drop the return address.
  6853.         LD   A,($5C74)    ; T_ADDR.
  6854.         SUB  (L177F & $00FF)+$28 ; Reduce to range $D9-$DE which are the token codes for INK to OVER.
  6855.         RST  28H          ;
  6856.         DEFW CO_TEMP_4    ; $21FC. Change the temporary colours as directed by the BASIC statement.
  6857.         CALL L18A1        ; Move on to the next statement if checking syntax.
  6858.  
  6859.         LD   HL,($5C8F)   ; ATTR_T. Now the temporary colour
  6860.         LD   ($5C8D),HL   ; ATTR_P.   values are made permanent
  6861.         LD   HL,$5C91     ; P_FLAG.
  6862.         LD   A,(HL)       ; Value of P_FLAG also has to be considered.
  6863.  
  6864. ;The following instructions cleverly copy the even bits of the supplied byte to the odd bits.
  6865. ;In effect making the permanent bits the same as the temporary ones.
  6866.  
  6867.         RLCA              ; Move the mask leftwards.
  6868.         XOR  (HL)         ; Impress onto the mask
  6869.         AND  $AA          ; only the even bits of the
  6870.         XOR  (HL)         ; other byte.
  6871.         LD   (HL),A       ; Restore the result.
  6872.         RET               ;
  6873.  
  6874. ; ------------------------
  6875. ; The 'Command Class - 09'
  6876. ; ------------------------
  6877. ; This routine is used by PLOT, DRAW & CIRCLE statements in order to specify the default conditions
  6878. ; of 'FLASH 8; BRIGHT 8; PAPER 8;' that are set up before any embedded colour items are considered.
  6879.  
  6880. L1944:  RST  28H          ; Code 09 enters here. Delegate handling to ROM 1.
  6881.         DEFW CLASS_09     ; $1CBE.
  6882.         RET
  6883.  
  6884. ; ------------------------
  6885. ; The 'Command Class - 0B'
  6886. ; ------------------------
  6887. ; This routine is used by SAVE, LOAD, VERIFY & MERGE statements.
  6888.  
  6889. L1948:  POP  AF           ; Drop the return address.
  6890.  
  6891.         LD   A,(FLAGS3)   ; $5B66.
  6892.         AND  $0F          ; Clear LOAD/SAVE/VERIFY/MERGE indication bits.
  6893.         LD   (FLAGS3),A   ; $5B66.
  6894.  
  6895.         LD   A,($5C74)    ; T_ADDR-lo.
  6896.         SUB  1+(L1773 & $00FF) ; Correct by $74 so that SAVE = $00, LOAD = $01, VERIFY = $02, MERGE = $03.
  6897.         LD   ($5C74),A    ; T_ADDR-lo.
  6898.         JP   Z,L11EB      ; Jump to handle SAVE.
  6899.  
  6900.         DEC  A            ;
  6901.         JP   Z,L11F2      ; Jump to handle LOAD.
  6902.  
  6903.         DEC  A            ;
  6904.         JP   Z,L11F9      ; Jump to handle VERIFY.
  6905.  
  6906.         JP   L1200        ; Jump to handle MERGE.
  6907.  
  6908. ; ----------
  6909. ; IF Routine
  6910. ; ----------
  6911. ; On entry the value of the expression between the IF and the THEN is the
  6912. ; 'last value' on the calculator stack. If this is logically true then the next
  6913. ; statement is considered; otherwise the line is considered to have been finished.
  6914.  
  6915. L1967:  POP  BC           ; Drop the return address.
  6916.         BIT  7,(IY+$01)   ;
  6917.         JR   Z,L197E      ; Jump forward if checking syntax.
  6918.  
  6919. ;Now 'delete' the last value on the calculator stack
  6920.  
  6921. L196E:  LD   HL,($5C65)   ; STKEND.
  6922.         LD   DE,$FFFB     ; -5
  6923.         ADD  HL,DE        ; The present 'last value' is deleted.
  6924.         LD   ($5C65),HL   ; STKEND. HL point to the first byte of the value.
  6925.         RST  28H          ;
  6926.         DEFW TEST_ZERO    ; $34E9. Is the value zero?
  6927.         JP   C,L1863      ; If the value was 'FALSE' jump to the next line.
  6928.  
  6929. L197E:  JP   L17C1        ; But if 'TRUE' jump to the next statement (after the THEN).
  6930.  
  6931. ; -----------
  6932. ; FOR Routine
  6933. ; -----------
  6934. ; This command routine is entered with the VALUE and the LIMIT of the FOR statement already
  6935. ; on the top of the calculator stack.
  6936.  
  6937. L1981:  CP   $CD          ; Jump forward unless a 'STEP' is given.
  6938.         JR   NZ,L198E     ;
  6939.  
  6940.         RST  20H          ; Advance pointer
  6941.         CALL L190E        ; Indirectly call EXPT_1NUM in ROM 1 to get the value of the STEP.
  6942.         CALL L18A1        ; Move on to the next statement if checking syntax.
  6943.         JR   L19A6        ; Otherwise jump forward.
  6944.  
  6945. ;There has not been a STEP supplied so the value '1' is to be used.
  6946.  
  6947. L198E:  CALL L18A1        ; Move on to the next statement if checking syntax.
  6948.         LD   HL,($5C65)   ; STKEND.
  6949.         LD   (HL),$00     ;
  6950.         INC  HL           ;
  6951.         LD   (HL),$00     ;
  6952.         INC  HL           ;
  6953.         LD   (HL),$01     ;
  6954.         INC  HL           ;
  6955.         LD   (HL),$00     ;
  6956.         INC  HL           ;
  6957.         LD   (HL),$00     ; Place a value of 1 on the calculator stack.
  6958.         INC  HL           ;
  6959.         LD   ($5C65),HL   ; STKEND.
  6960.  
  6961. ;The three values on the calculator stack are the VALUE (v), the LIMIT (l) and the STEP (s).
  6962. ;These values now have to be manipulated. Delegate handling to ROM 1.
  6963.  
  6964. L19A6:  RST  28H          ;
  6965.         DEFW F_REORDER    ; $1D16.
  6966.         RET               ;
  6967.  
  6968. ; ------------
  6969. ; READ Routine
  6970. ; ------------
  6971.  
  6972. L19AA:  RST  20H          ; Come here on each pass, after the first, to move along the READ statement.
  6973.  
  6974. L19AB:  CALL L18F9        ; Indirectly call CLASS_01 in ROM 1 to consider whether the variable has
  6975.                           ; been used before, and find the existing entry if it has.
  6976.         BIT  7,(IY+$01)   ;
  6977.         JR   Z,L19E2      ; Jump forward if checking syntax.
  6978.  
  6979.         RST  18H          ; Save the current pointer CH_ADD in X_PTR.
  6980.         LD   ($5C5F),HL   ; X_PTR.
  6981.  
  6982.         LD   HL,($5C57)   ; DATADD.
  6983.         LD   A,(HL)       ; Fetch the current DATA list pointer
  6984.         CP   $2C          ; and jump forward unless a new
  6985.         JR   Z,L19CB      ; DATA statement has to be found.
  6986.  
  6987.         LD   E,$E4        ; The search is for 'DATA'.
  6988.         RST  28H          ;
  6989.         DEFW LOOK_PROG    ; $1D86.
  6990.         JR   NC,L19CB     ; Jump forward if the search is successful.
  6991.  
  6992.         CALL L05AC        ; Produce error report.
  6993.         DB $0D          ; "E Out of Data"
  6994.  
  6995. ; Pick up a value from the DATA list.
  6996.  
  6997. L19CB:  INC  HL           ; Advance the pointer along the DATA list.
  6998.         LD   ($5C5D),HL   ; CH_ADD.
  6999.         LD   A,(HL)       ;
  7000.         RST  28H          ;
  7001.         DEFW VAL_FET_1    ; $1C56. Fetch the value and assign it to the variable.
  7002.         RST  18H          ;
  7003.  
  7004.         LD   ($5C57),HL   ; DATADD.
  7005.         LD   HL,($5C5F)   ; X_PTR. Fetch the current value of CH_ADD and store it in DATADD.
  7006.  
  7007.         LD   (IY+$26),$00 ; X_PTR_hi. Clear X_PTR.
  7008.         LD   ($5C5D),HL   ; CH_ADD. Make CH-ADD once again point to the READ statement.
  7009.         LD   A,(HL)       ;
  7010.  
  7011. L19E2:  RST  18H          ; GET the present character
  7012.         CP   ','          ; $2C. Check if it is a ','.
  7013.  
  7014. L19E5:  JR   Z,L19AA      ; If it is then jump back as there are further items.
  7015.  
  7016.         CALL L18A1        ; Return if checking syntax
  7017.         RET               ; or here if not checking syntax.
  7018.  
  7019. ; ------------
  7020. ; DATA Routine
  7021. ; ------------
  7022. ; During syntax checking a DATA statement is checked to ensure that it contains a series
  7023. ; of valid expressions, separated by commas. But in 'run-time' the statement is passed by.
  7024.  
  7025. L19EB:  BIT  7,(IY+$01)   ; Jump forward unless checking syntax.
  7026.         JR   NZ,L19FC     ;
  7027.  
  7028. ;A loop is now entered to deal with each expression in the DATA statement.
  7029.  
  7030. L19F1:  RST  28H          ;
  7031.         DEFW SCANNING     ; $24FB. Scan the next expression.
  7032.         CP   ','          ; $2C. Check for the correct separator ','.
  7033.         CALL NZ,L18A1     ; but move on to the next statement if not matched.
  7034.         RST  20H          ; Whilst there are still expressions to be checked
  7035.         JR   L19F1        ; go around again.
  7036.  
  7037. ;The DATA statement has to be passed-by in 'run-time'.
  7038.  
  7039. L19FC:  LD   A,$E4        ; It is a 'DATA' statement that is to be passed-by.
  7040.  
  7041. ;On entry the A register will hold either the token 'DATA' or the token 'DEF FN'
  7042. ;depending on the type of statement that is being 'passed-by'.
  7043.  
  7044. L19FE:  RST  28H          ;
  7045.         DEFW PASS_BY      ; $1E39. Delegate handling to ROM 1.
  7046.         RET
  7047.  
  7048. ; -----------
  7049. ; RUN Routine
  7050. ; -----------
  7051. ; The parameter of the RUN command is passed to NEWPPC by calling the GO TO command routine.
  7052. ; The operations of 'RESTORE 0' and 'CLEAR 0' are then performed before a return is made.
  7053.  
  7054. L1A02:  RST  28H
  7055.         DEFW GO_TO        ; $1E67.
  7056.  
  7057.         LD BC,$0000       ; Now perform a 'RESTORE 0'.
  7058.         RST  28H
  7059.         DEFW REST_RUN     ; $1E45.
  7060.         JR   L1A10        ; Exit via the CLEAR command routine.
  7061.  
  7062. ; -------------
  7063. ; CLEAR Routine
  7064. ; -------------
  7065. ; This routine allows for the variables area to be cleared, the display area cleared
  7066. ; and RAMTOP moved. In consequence of the last operation the machine stack is rebuilt
  7067. ; thereby having the effect of also clearing the GO SUB stack.
  7068.  
  7069. L1A0D:  RST  28H          ;
  7070.         DEFW FIND_INT2    ; $1E99. Fetch the operand - using zero by default.
  7071.  
  7072. L1A10:  LD   A,B          ; Jump forward if the operand is
  7073.         OR   C            ; other than zero. When called
  7074.         JR   NZ,L1A18     ; from RUN there is no jump.
  7075.  
  7076.         LD   BC,($5CB2)   ; RAMTOP. Use RAMTOP if the parameter is 0.
  7077.  
  7078. L1A18:  PUSH BC           ; BC = Address to clear to. Save it.
  7079.         LD   DE,($5C4B)   ; VARS.
  7080.         LD   HL,($5C59)   ; E LINE.
  7081.         DEC  HL           ;
  7082.         RST  28H          ; Delete the variables area.
  7083.         DEFW RECLAIM      ; $19E5.
  7084.         RST  28H          ; Clear the screen
  7085.         DEFW CLS          ; $0D6B.
  7086.  
  7087. ;The value in the BC register pair which will be used as RAMTOP is tested to ensure it
  7088. ;is neither too low nor too high.
  7089.  
  7090.         LD   HL,($5C65)   ; STKEND. The current value of STKEND
  7091.         LD   DE,$0032     ; is increased by 50 before
  7092.         ADD  HL,DE        ; being tested. This forms the
  7093.         POP  DE           ; ADE = address to clear to lower limit.
  7094.         SBC  HL,DE        ;
  7095.         JR   NC,L1A3B     ; Ramtop no good.
  7096.  
  7097.         LD   HL,($5CB4)   ; P_RAMT. For the upper test the value
  7098.         AND  A            ; for RAMTOP is tested against P_RAMT.
  7099.         SBC  HL,DE        ;
  7100.         JR   NC,L1A3F     ; Jump forward if acceptable.
  7101.  
  7102. L1A3B:  CALL L05AC        ; Produce error report.
  7103.         DB $15          ; "M Ramtop no good"
  7104.  
  7105. L1A3F:  LD   ($5CB2),DE   ; RAMTOP.
  7106.         POP  DE           ; Retrieve interpreter return address from stack
  7107.         POP  HL           ; Retrieve 'error address' from stack
  7108.         POP  BC           ; Retrieve the GO SUB stack end marker.
  7109.                           ; [*BUG* - It is assumed that the top of the GO SUB stack will be empty and hence only
  7110.                           ; contain the end marker. This will not be the case if CLEAR is used within a subroutine,
  7111.                           ; in which case BC will now hold the calling line number and this will be stacked in place
  7112.                           ; of the end marker. When a RETURN command is encountered, the GO SUB stack appears to contain
  7113.                           ; an entry since the end marker was not the top item. An attempt to return is therefore made.
  7114.                           ; The CLEAR command handler within the 48K Spectrum ROM does not make any assumption about
  7115.                           ; the contents of the GO SUB stack and instead always re-inserts the end marker. The bug could
  7116.                           ; be fixed by inserting the line LD BC,$3E00 after the POP BC. Credit: Ian Collier (+3), Paul Farrow (128)]
  7117.         LD   SP,($5CB2)   ; RAMTOP.
  7118.         INC  SP           ;
  7119.         PUSH BC           ; Stack the GO SUB stack end marker.
  7120.         PUSH HL           ; Stack 'error address'.
  7121.         LD   ($5C3D),SP   ; ERR_SP.
  7122.         PUSH DE           ; Stack the interpreter return address.
  7123.         RET
  7124.  
  7125. ; --------------
  7126. ; GO SUB Routine
  7127. ; --------------
  7128. ; The present value of PPC and the incremented value of SUBPPC are stored on the GO SUB stack.
  7129.  
  7130. L1A53:  POP  DE           ; Save the return address.
  7131.         LD   H,(IY+$0D)   ; SUBPPC. Fetch the statement number and increment it.
  7132.         INC  H            ;
  7133.         EX   (SP),HL      ; Exchange the 'error address' with the statement number.
  7134.         INC  SP           ; Reclaim the use of a location.
  7135.  
  7136.         LD   BC,($5C45)   ; PPC.
  7137.         PUSH BC           ; Next save the present line number.
  7138.         PUSH HL           ; Return the 'error address' to the machine stack
  7139.         LD   ($5C3D),SP   ; ERR-SP.  and reset ERR-SP to point to it.
  7140.         PUSH DE           ; Stack the return address.
  7141.  
  7142.         RST  28H          ;
  7143.         DEFW GO_TO        ; $1E67. Now set NEWPPC & NSPPC to the required values.
  7144.  
  7145.         LD   BC,$0014     ; But before making the jump make a test for room.
  7146.         RST  28H          ;
  7147.         DEFW TEST_ROOM    ; $1F05. Will automatically produce error '4' if out of memory.
  7148.         RET
  7149.  
  7150. ; --------------
  7151. ; RETURN Routine
  7152. ; --------------
  7153. ; The line number and the statement number that are to be made the object of a 'return'
  7154. ; are fetched from the GO SUB stack.
  7155.  
  7156. L1A6F:  POP  BC           ; Fetch the return address.
  7157.         POP  HL           ; Fetch the 'error address'.
  7158.         POP  DE           ; Fetch the last entry on the GO SUB stack.
  7159.         LD   A,D          ; The entry is tested to see if
  7160.         CP   $3E          ; it is the GO SUB stack end marker.
  7161.         JR   Z,L1A86      ; Jump if it is.
  7162.  
  7163.         DEC  SP           ; The full entry uses three locations only.
  7164.         EX   (SP),HL      ; Exchange the statement number with the 'error address'.
  7165.         EX   DE,HL        ; Move the statement number.
  7166.         LD   ($5C3D),SP   ; ERR_SP. Reset the error pointer.
  7167.         PUSH BC           ; Replace the return address.
  7168.         LD   ($5C42),HL   ; NEWPPC. Enter the line number.
  7169.         LD   (IY+$0A),D   ; NSPPC.  Enter the statement number.
  7170.         RET               ;
  7171.  
  7172. L1A86:  PUSH DE           ; Replace the end marker and
  7173.         PUSH HL           ; the 'error address'.
  7174.  
  7175.         CALL L05AC        ; Produce error report.
  7176.         DB $06          ; "7 RETURN without GO SUB"
  7177.  
  7178. ; --------------
  7179. ; DEF FN Routine
  7180. ; --------------
  7181. ; During syntax checking a DEF FN statement is checked to ensure that it has the correct form.
  7182. ; Space is also made available for the result of evaluating the function.
  7183. ; But in 'run-time' a DEF FN statement is passed-by.
  7184.  
  7185. L1A8C:  BIT  7,(IY+$01)
  7186.         JR   Z,L1A97      ; Jump forward if checking syntax.
  7187.  
  7188.         LD   A,$CE        ; Otherwise bass-by the
  7189.         JP   L19FE        ; 'DEF FN' statement.
  7190.  
  7191. ;First consider the variable of the function.
  7192.  
  7193. L1A97:  SET  6,(IY+$01)   ; Signal 'a numeric variable'.
  7194.         RST  28H          ;
  7195.         DEFW ALPHA        ; $2C8D. Check that the present code is a letter.
  7196.         JR   NC,L1AB6     ; Jump forward if not.
  7197.  
  7198.         RST  20H          ; Fetch the next character.
  7199.         CP   '$'          ; $24.
  7200.         JR   NZ,L1AAA     ; Jump forward unless it is a '$'.
  7201.  
  7202.         RES  6,(IY+$01)   ; Change bit 6 as it is a string variable.
  7203.         RST  20H          ; Fetch the next character.
  7204.  
  7205. L1AAA:  CP   '('          ; $28. A '(' must follow the variable's name.
  7206.         JR   NZ,L1AEA     ; Jump forward if not.
  7207.  
  7208.         RST  20H          ; Fetch the next character
  7209.         CP   ')'          ; $29. Jump forward if it is a ')'
  7210.         JR   Z,L1AD3      ; as there are no parameters of the function.
  7211.  
  7212. ;A loop is now entered to deal with each parameter in turn.
  7213.  
  7214. L1AB3:  RST  28H          ;
  7215.         DEFW ALPHA        ; $2C8D.
  7216.  
  7217. L1AB6:  JP   NC,L1912     ; The present code must be a letter.
  7218.  
  7219.         EX   DE,HL        ; Save the pointer in DE.
  7220.         RST  20H          ; Fetch the next character.
  7221.         CP   '$'          ; $24.
  7222.         JR   NZ,L1AC1     ; Jump forward unless it is a '$'.
  7223.  
  7224.         EX   DE,HL        ; Otherwise save the new pointer in DE instead.
  7225.         RST  20H          ; Fetch the next character.
  7226.  
  7227. L1AC1:  EX   DE,HL        ; Move the pointer to the last character of the name to HL.
  7228.         LD   BC,$0006     ; Now make six locations after that last character.
  7229.         RST  28H          ;
  7230.         DEFW MAKE_ROOM    ; $1655.
  7231.         INC  HL           ;
  7232.         INC  HL           ;
  7233.         LD   (HL),$0E     ; Enter a 'number marker' into the first of the new locations.
  7234.         CP   ','          ; $2C. If the present character is a ',' then jump back as
  7235.         JR   NZ,L1AD3     ; there should be a further parameter.
  7236.  
  7237.         RST  20H          ;
  7238.         JR   L1AB3        ; Otherwise jump out of the loop.
  7239.  
  7240. ;Next the definition of the function is considered.
  7241.  
  7242. L1AD3:  CP   ')'          ; $29. Check that the ')' does exist.
  7243.         JR   NZ,L1AEA     ; Jump if not.
  7244.  
  7245.         RST  20H          ; The next character is fetched.
  7246.         CP   '='          ; $3D. It must be an '='.
  7247.         JR   NZ,L1AEA     ; Jump if not.
  7248.  
  7249.         RST  20H          ; Fetch the next character.
  7250.         LD   A,($5C3B)    ; FLAGS.
  7251.         PUSH AF           ; Save the nature (numeric or string) of the variable
  7252.         RST  28H          ;
  7253.         DEFW SCANNING     ; $24FB. Now consider the definition as an expression.
  7254.         POP  AF           ; Fetch the nature of the variable.
  7255.  
  7256.         XOR  (IY+$01)     ; FLAGS. Check that it is of the same type
  7257.         AND  $40          ; as found for the definition.
  7258.  
  7259. L1AEA:  JP   NZ,L1912     ; Give an error report if required.
  7260.  
  7261.         CALL L18A1        ; Move on to consider the next statement in the line.
  7262.  
  7263. ; ------------
  7264. ; MOVE Routine
  7265. ; ------------
  7266.  
  7267. L1AF0:  RET               ; Simply return.
  7268.  
  7269.  
  7270. ; ======================
  7271. ; MENU ROUTINES - PART 1
  7272. ; ======================
  7273.  
  7274. ; ---------------
  7275. ; Run Tape Loader
  7276. ; ---------------
  7277. ; Used by Main Menu - Tape Loader option.
  7278.  
  7279. L1AF1:  LD   HL,$EC0E     ; Fetch mode.
  7280.         LD   (HL),$FF     ; Set Tape Loader mode.
  7281.         CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  7282.  
  7283.         RST  28H          ;
  7284.         DEFW SET_MIN      ; $16B0. Clear out editing area.
  7285.  
  7286.         LD   HL,($5C59)   ; E_LINE.
  7287.         LD   BC,$0003     ; Create 3 bytes of space for the LOAD "" command.
  7288.         RST  28H          ;
  7289.         DEFW MAKE_ROOM    ; $1655.
  7290.  
  7291.         LD   HL,L1B6E     ; Address of command bytes for LOAD "".
  7292.         LD   DE,($5C59)   ; E_LINE.
  7293.         LD   BC,$0003     ;
  7294.         LDIR              ; Copy LOAD "" into the line editing area.
  7295.  
  7296. L1B11           CALL L026B        ; Parse and execute the BASIC line.
  7297.                           ; [Will not return here but will exit via the error handler routine]
  7298.  
  7299. ; -----------------------
  7300. ; List Program to Printer
  7301. ; -----------------------
  7302. ; Used by Edit Menu - Print option.
  7303.  
  7304. L1B14:  CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  7305.         RST  28H          ;
  7306.         DEFW SET_MIN      ; $16B0. Clear out editing area.
  7307.  
  7308.         LD   HL,($5C59)   ; E_LINE.
  7309.         LD   BC,$0001     ; Create 1 byte of space.
  7310.         RST  28H          ;
  7311.         DEFW MAKE_ROOM    ; $1655.
  7312.  
  7313.         LD   HL,($5C59)   ; E_LINE.
  7314.         LD   (HL),$E1     ; Copy LLIST into the line editing area.
  7315.  
  7316.         CALL L026B        ; Parse and execute the BASIC line.
  7317.                           ; [Will not return here but will exit via the error handler routine]
  7318.  
  7319.  
  7320. ; =======================================================
  7321. ; BASIC LINE AND COMMAND INTERPRETATION ROUTINES - PART 2
  7322. ; =======================================================
  7323.  
  7324. ; ----------------
  7325. ; SPECTRUM Routine
  7326. ; ----------------
  7327. ; Return to 48K BASIC Mode. This routine will force caps lock is off.
  7328.  
  7329. L1B2B:  CALL L1B53        ; Overwrite 'P' channel data to use the ZX Printer.
  7330.  
  7331.         LD   SP,($5C3D)   ; ERR_SP. Purge the stack.
  7332.         POP  HL           ; Remove error handler address.
  7333.  
  7334.         LD   HL,MAIN_4    ; $1303. The main execution loop within ROM 1.
  7335.         PUSH HL           ;
  7336.  
  7337.         LD   HL,0X13;3    ; $0003. Address of a $FF byte within ROM 1, used to generate error report "0 OK".
  7338.         PUSH HL           ;
  7339.         LD   HL,ERROR_1   ; $0008. The address of the error handler within ROM 1.
  7340.         PUSH HL           ;
  7341.  
  7342. ; [*BUG* - Although the channel 'P' information has been reconfigured to use the ZX Printer, the ZX printer buffer and
  7343. ; associated system variables still need to be cleared. Failure to do so means that the first use of the ZX Printer will
  7344. ; cause garbage to the printed, i.e. the paging routines and new system variables still present in the ZX Printer buffer.
  7345. ; Subsequently printer output will then be ok since the ZX Printer buffer and system variables will be cleared.
  7346. ; Worse still, there is the possibility that new data to be printed will be inserted beyond the ZX Printer buffer since
  7347. ; ROM 1 does not trap whether the ZX Printer system variable PR_POSN and PR_CC hold invalid values. The bug can be fixed
  7348. ; by inserting the following instructions, which cause the ZX Printer buffer to be cleared immediately after switching to
  7349. ; ROM 1 and before the error report "0 OK" is produced. Credit: Paul Farrow and Andrew Owen.
  7350. ;
  7351. ;       LD   HL,CLEAR_PRB ; Address of the routine in ROM 1 to clear the ZX Printer buffer and associated system variables.
  7352. ;       PUSH HL           ;
  7353. ;       SET  1,(IY+$01)   ; FLAGS. Signal the printer is in use.]
  7354.  
  7355.         LD   A,$20        ; Force 48K mode.
  7356.         LD   (BANK_M),A   ; $5B5C.
  7357.         JP   SWAP         ; $5B00. Swap to ROM 1 and return via a RST $08 / DB $FF.
  7358.  
  7359.  
  7360. ; ======================
  7361. ; MENU ROUTINES - PART 2
  7362. ; ======================
  7363.  
  7364. ; ---------------------------
  7365. ; Main Menu - 48 BASIC Option
  7366. ; ---------------------------
  7367.  
  7368. L1B47:  LD   HL,$0000     ; Stack a $0000 address to return to.
  7369.         PUSH HL           ;
  7370.  
  7371.         LD   A,$20        ; Force 48 mode.
  7372.         LD   (BANK_M),A   ; $5B5C
  7373.         JP   SWAP         ; $5B00. Swap to ROM 1, return to $0000.
  7374.  
  7375. ; --------------------
  7376. ; Set 'P' Channel Data
  7377. ; --------------------
  7378. ; This routine overwrites the 'P' channel data with the 'S' channel data, i.e. the default values when using the ZX Printer.
  7379.  
  7380. L1B53:  LD   HL,($5C4F)   ; CHANS.
  7381.         LD   DE,$0005     ;
  7382.         ADD  HL,DE        ; HL=Address 'S' channel data.
  7383.         LD   DE,$000A     ;
  7384.         EX   DE,HL        ; HL=$000A, DE=Address 'S' channel data.
  7385.         ADD  HL,DE        ; HL=Address 'P' channel data.
  7386.         EX   DE,HL        ; DE=Address 'P' channel data, HL=Address 'S' channel data.
  7387.         LD   BC,$0004     ;
  7388.         LDIR              ; Copy the 'S' channel data over the 'P' channel data.
  7389.         RES  3,(IY+$30)   ; FLAGS2. Signal caps lock unset. [Not really necessary for switching back to 48 BASIC mode]
  7390.         RES  4,(IY+$01)   ; FLAGS. Signal not 128K mode.
  7391.         RET               ;
  7392.  
  7393. ; ---------------------
  7394. ; LOAD "" Command Bytes
  7395. ; ---------------------
  7396. ; Used by the Tape Loader routine.
  7397.  
  7398. L1B6E:  DB $EF, $22, $22  ; LOAD ""
  7399.  
  7400.  
  7401. ; =======================================================
  7402. ; BASIC LINE AND COMMAND INTERPRETATION ROUTINES - PART 3
  7403. ; =======================================================
  7404.  
  7405. ; -------------
  7406. ; LLIST Routine
  7407. ; -------------
  7408.  
  7409. L1B71:  LD   A,$03        ; Printer channel.
  7410.         JR   L1B77        ; Jump ahead to join LIST.
  7411.  
  7412. ; ------------
  7413. ; LIST Routine
  7414. ; ------------
  7415.  
  7416. L1B75:  LD   A,$02        ; Main screen channel.
  7417.  
  7418. L1B77:  LD   (IY+$02),$00 ; TV_FLAG. Signal 'an ordinary listing in the main part of the screen'.
  7419.         RST  28H          ;
  7420.         DEFW SYNTAX_Z     ; $2530.
  7421.         JR   Z,L1B83      ; Do not open the channel if checking syntax.
  7422.  
  7423.         RST  28H          ;
  7424.         DEFW CHAN_OPEN    ; $1601. Open the channel.
  7425.  
  7426. L1B83:  RST  28H          ;
  7427.         DEFW GET_CHAR     ; $0018. [Could just do RST $18]
  7428.         RST  28H          ;
  7429.         DEFW STR_ALTER    ; $2070. See if the stream is to be changed.
  7430.         JR   C,L1BA3      ; Jump forward if unchanged.
  7431.  
  7432.         RST  28H
  7433.         DEFW GET_CHAR     ; $0018. Get current character.
  7434.         CP   $3B          ; Is it a ';'?
  7435.         JR   Z,L1B96      ; Jump if it is.
  7436.  
  7437.         CP   ','          ; $2C. Is it a ','?
  7438.         JR   NZ,L1B9E     ; Jump if it is not.
  7439.  
  7440. L1B96:  RST  28H          ;
  7441.         DEFW NEXT_CHAR    ; $0020. Get the next character.
  7442.         CALL L190E        ; Indirectly call EXPT-1NUM in ROM 1 to check that
  7443.                           ; a numeric expression follows, e.g. LIST #5,20.
  7444.         JR   L1BA6        ; Jump forward with it.
  7445.  
  7446. L1B9E:  RST  28H          ;
  7447.         DEFW USE_ZERO     ; $1CE6. Otherwise use zero and
  7448.         JR   L1BA6        ; jump forward.
  7449.  
  7450. ;Come here if the stream was unaltered.
  7451.  
  7452. L1BA3:  RST  28H          ;
  7453.         DEFW FETCH_NUM    ; $1CDE. Fetch any line or use zero if none supplied.
  7454.  
  7455. L1BA6:  CALL L18A1        ; If checking the syntax of the edit-line move on to the next statement.
  7456.         RST  28H          ;
  7457.         DEFW LIST_5+3     ; $1825. Delegate handling to ROM 1.
  7458.         RET
  7459.  
  7460. ; ----------------------
  7461. ; RAM Disk SAVE! Routine
  7462. ; ----------------------
  7463.  
  7464. L1BAD:  LD   (OLDSP),SP   ; $5B81. Save SP.
  7465.         LD   SP,TSTACK    ; $5BFF. Use temporary stack.
  7466.  
  7467.         CALL L1C97        ; Create new catalogue entry.
  7468.  
  7469.         LD   BC,(HD_0B)   ; $5B72. get the length of the file.
  7470.         LD   HL,$FFF7     ; -9 (9 is the length of the file header).
  7471.         OR   $FF          ; Extend the negative number into the high byte.
  7472.         SBC  HL,BC        ; AHL=-(length of file + 9).
  7473.         CALL L1CF3        ; Check for space in RAM disk (produce "4 Out of memory" if no room).
  7474.  
  7475.         LD   BC,$0009     ; File header length.
  7476.         LD   HL,HD_00     ; $5B71. Address of file header.
  7477.         CALL L1DAC        ; Store file header to RAM disk.
  7478.  
  7479.         LD   HL,(HD_0D)   ; $5B74. Start address of file data.
  7480.         LD   BC,(HD_0B)   ; $5B72. Length of file data.
  7481.         CALL L1DAC        ; Store bytes to RAM disk.
  7482.         CALL L1D56        ; Update catalogue entry (leaves logical RAM bank 4 paged in).
  7483.  
  7484.         LD   A,$05        ; Page in logical RAM bank 5 (physical RAM bank 0).
  7485.         CALL L1C64        ;
  7486.  
  7487.         LD   SP,(OLDSP)   ; $5B81. Use original stack.
  7488.         RET               ;
  7489.  
  7490. ; ------------
  7491. ; CAT! Routine
  7492. ; ------------
  7493.  
  7494. L1BE5:  RST  28H          ; Get the current character.
  7495.         DEFW GET_CHAR     ; $0018. [Could just do RST $18 here]
  7496.         CP   '!'          ; $21. Is it '!'?
  7497.         JP   NZ,L1912     ; Jump to "C Nonsense in BASIC" if not.
  7498.  
  7499.         RST  28H          ; Get the next character.
  7500.         DEFW NEXT_CHAR    ; $0020. [Could just do RST $20 here]
  7501.         CALL L18A1        ; Check for end of statement.
  7502.  
  7503.         LD   A,$02        ; Select main screen.
  7504.         RST  28H          ;
  7505.         DEFW CHAN_OPEN    ; $1601.
  7506.  
  7507.         LD   (OLDSP),SP   ; $5B81. Store SP.
  7508.         LD   SP,TSTACK    ; $5BFF. Use temporary stack.
  7509.  
  7510.         CALL L20D2        ; Print out the catalogue.
  7511.  
  7512.         LD   A,$05        ; Page in logical RAM bank 5 (physical RAM bank 0).
  7513.         CALL L1C64        ;
  7514.  
  7515.         LD   SP,(OLDSP)   ; $5B81. Use original stack.
  7516.         RET               ;
  7517.  
  7518. ; --------------
  7519. ; ERASE! Routine
  7520. ; --------------
  7521.  
  7522. L1C0C:  RST  28H          ; Get character from BASIC line.
  7523.         DEFW GET_CHAR     ; $0018.
  7524.         CP   '!'          ; $21. Is it '!'?
  7525.         JP   NZ,L1912     ; Jump to "C Nonsense in BASIC" if not.
  7526.  
  7527.         CALL L1393        ; Get the filename into N_STR1.
  7528.         CALL L18A1        ; Make sure we've reached the end of the BASIC statement.
  7529.  
  7530.         LD   (OLDSP),SP   ; $5B81. Store SP.
  7531.         LD   SP,TSTACK    ; $5BFF. Use temporary stack.
  7532.  
  7533.         CALL L1F5F        ; Do the actual erasing (leaves logical RAM bank 4 paged in).
  7534.  
  7535.         LD   A,$05        ; Restore RAM configuration.
  7536.         CALL L1C64        ; Page in logical RAM bank 5 (physical RAM bank 0).
  7537.  
  7538.         LD   SP,(OLDSP)   ; $5B81. Use original stack.
  7539.         RET               ;
  7540.  
  7541.  
  7542. ; ==================================
  7543. ; RAM DISK COMMAND ROUTINES - PART 2
  7544. ; ==================================
  7545.  
  7546. ; -------------------------
  7547. ; Load Header from RAM Disk
  7548. ; -------------------------
  7549.  
  7550. L1C2E:  LD   (OLDSP),SP   ; $5B81. Store SP.
  7551.         LD   SP,TSTACK    ; $5BFF. Use temporary stack.
  7552.  
  7553.         CALL L1D35        ; Find file (return details pointed to by IX). Leaves logical RAM bank 4 paged in.
  7554.  
  7555. ;The file exists else the call above would have produced an error "h file does not exist"
  7556.  
  7557.         LD   HL,HD_00     ; $5B71. Load 9 header bytes.
  7558.         LD   BC,$0009     ;
  7559.         CALL L1E37        ; Load bytes from RAM disk.
  7560.  
  7561.         LD   A,$05        ; Restore RAM configuration.
  7562.         CALL L1C64        ; Page in logical RAM bank 5 (physical RAM bank 0).
  7563.  
  7564.         LD   SP,(OLDSP)   ; $5B81. Use original stack.
  7565.         RET               ;
  7566.  
  7567. ; ------------------
  7568. ; Load from RAM Disk
  7569. ; ------------------
  7570. ; Used by LOAD, VERIFY and MERGE. Note that VERIFY will simply perform a LOAD.
  7571. ; Entry: HL=Destination address.
  7572. ;        DE=Length (will be greater than zero).
  7573. ;        IX=File descriptor.
  7574. ;        IX=Address of catalogue entry (IX+$10-IX+$12 points to the address of the file's data, past its header).
  7575. ;        HD_00-HD_11 holds file header information.
  7576.  
  7577. L1C4B:  LD   (OLDSP),SP   ; $5B81. Store SP
  7578.         LD   SP,TSTACK    ; $5BFF. Use temporary stack.
  7579.  
  7580.         LD   B,D          ;
  7581.         LD   C,E          ; BC=Length.
  7582.         CALL L1E37        ; Load bytes from RAM disk.
  7583.         CALL L1D56        ; Update catalogue entry (leaves logical RAM bank 4 paged in).
  7584.  
  7585.         LD   A,$05        ; Restore RAM configuration.
  7586.         CALL L1C64        ; Page in logical RAM bank 5 (physical RAM bank 0).
  7587.  
  7588.         LD   SP,(OLDSP)   ; $5B81. Use original stack.
  7589.         RET               ;
  7590.  
  7591.  
  7592. ; ========================
  7593. ; PAGING ROUTINES - PART 1
  7594. ; ========================
  7595.  
  7596. ; ---------------------
  7597. ; Page Logical RAM Bank
  7598. ; ---------------------
  7599. ; This routine converts between logical and physical RAM banks and pages the
  7600. ; selected bank in.
  7601. ; Entry: A=Logical RAM bank.
  7602.  
  7603. L1C64:  PUSH HL           ; Save BC and HL.
  7604.         PUSH BC           ;
  7605.  
  7606.         LD   HL,L1C81     ; Physical banks used by RAM disk.
  7607.         LD   B,$00        ;
  7608.         LD   C,A          ; BC=Logical RAM bank.
  7609.         ADD  HL,BC        ; Point to table entry.
  7610.         LD   C,(HL)       ; Look up physical page.
  7611.  
  7612.         DI                ; Disable interrupts whilst paging.
  7613.         LD   A,(BANK_M)   ; $5B5C. Fetch the current configuration.
  7614.         AND  $F8          ; Mask off current RAM bank.
  7615.         OR   C            ; Include new RAM bank.
  7616.         LD   (BANK_M),A   ; $5B5C. Store the new configuration.
  7617.         LD   BC,$7FFD     ;
  7618.         OUT  (C),A        ; Perform the page.
  7619.         EI                ; Re-enable interrupts.
  7620.  
  7621.         POP  BC           ; Restore BC and HL.
  7622.         POP  HL           ;
  7623.         RET               ;
  7624.  
  7625. ; -------------------------------
  7626. ; Physical RAM Bank Mapping Table
  7627. ; -------------------------------
  7628.  
  7629. L1C81:  DB $01          ; Logical bank $00.
  7630.         DB $03          ; Logical bank $01.
  7631.         DB $04          ; Logical bank $02.
  7632.         DB $06          ; Logical bank $03.
  7633.         DB $07          ; Logical bank $04.
  7634.         DB $00          ; Logical bank $05.
  7635.  
  7636.  
  7637. ; ==================================
  7638. ; RAM DISK COMMAND ROUTINES - PART 3
  7639. ; ==================================
  7640.  
  7641. ; -----------------
  7642. ; Compare Filenames
  7643. ; -----------------
  7644. ; Compare filenames at N_STR1 and IX.
  7645. ; Exit: Zero flag set if filenames match.
  7646. ;       Carry flag set if filename at DE is alphabetically lower than filename at IX.
  7647.  
  7648. L1C87:  LD   DE,N_STR1    ; $5B67.
  7649.  
  7650. ; Compare filenames at DE and IX
  7651.  
  7652. L1C8A:  PUSH IX           ;
  7653.         POP  HL           ;
  7654.         LD   B,$0A        ; Maximum of 10 characters.
  7655.  
  7656. L1C8F:  LD   A,(DE)       ;
  7657.         INC  DE           ;
  7658.         CP   (HL)         ; compare each character.
  7659.         INC  HL           ;
  7660.         RET  NZ           ; Return if characters are different.
  7661.  
  7662.         DJNZ L1C8F        ; Repeat for all characters of the filename.
  7663.  
  7664.         RET               ;
  7665.  
  7666. ; --------------------------
  7667. ; Create New Catalogue Entry
  7668. ; --------------------------
  7669. ; Add a catalogue entry with filename contained in N_STR1.
  7670. ; Exit: HL=Address of next free catalogue entry.
  7671. ;       IX=Address of newly created catalogue entry.
  7672.  
  7673. L1C97:  CALL L1D12        ; Find entry in RAM disk area, returning IX pointing to catalogue entry (leaves logical RAM bank 4 paged in).
  7674.         JR   Z,L1CA0      ; Jump ahead if does not exist.
  7675.  
  7676.         CALL L05AC        ; Produce error report.
  7677.         DB $20          ; "e File already exists"
  7678.  
  7679. L1CA0:  PUSH IX           ;
  7680.         LD   BC,$3FEC     ; 16384-20 (maximum size of RAM disk catalogue).
  7681.         ADD  IX,BC        ; IX grows downwards as new RAM disk catalogue entries added.
  7682.                           ; If adding the maximum size to IX does not result in the carry flag being set
  7683.                           ; then the catalogue is full, so issue an error report "4 Out of Memory".
  7684.         POP  IX           ;
  7685.         JR   NC,L1D0E     ; Jump if out of memory.
  7686.  
  7687.         LD   HL,$FFEC     ; -20 (20 bytes is the size of a RAM disk catalogue entry).
  7688.         LD   A,$FF        ; Extend the negative number into the high byte.
  7689.         CALL L1CF3        ; Ensure space in RAM disk area.
  7690.         LD   HL,FLAGS3    ; $5B66.
  7691.         SET  2,(HL)       ; Signal editing RAM disk catalogue.
  7692.         PUSH IX           ;
  7693.         POP  DE           ; DE=Address of new catalogue entry.
  7694.         LD   HL,N_STR1    ; $5B67. Filename.
  7695.  
  7696. L1CBE:  LD   BC,$000A     ; 10 characters in the filename.
  7697.         LDIR              ; Copy the filename.
  7698.  
  7699.         SET  0,(IX+$13)   ; Indicate catalogue entry requires updating.
  7700.  
  7701.         LD   A,(IX+$0A)   ; Set the file access address to be the
  7702.         LD   (IX+$10),A   ; start address of the file.
  7703.         LD   A,(IX+$0B)   ;
  7704.         LD   (IX+$11),A   ;
  7705.         LD   A,(IX+$0C)   ;
  7706.         LD   (IX+$12),A   ;
  7707.  
  7708.         XOR  A            ; Set the fill length to zero.
  7709.         LD   (IX+$0D),A   ;
  7710.         LD   (IX+$0E),A   ;
  7711.         LD   (IX+$0F),A   ;
  7712.  
  7713.         LD   A,$05        ;
  7714.         CALL L1C64        ; Logical RAM bank 5 (physical RAM bank 0).
  7715.  
  7716.         PUSH IX           ;
  7717.         POP  HL           ; HL=Address of new catalogue entry.
  7718.         LD   BC,$FFEC     ; -20 (20 bytes is the size of a catalogue entry).
  7719.         ADD  HL,BC        ;
  7720.         LD   (SFNEXT),HL  ; $5B83. Store address of next free catalogue entry.
  7721.         RET               ;
  7722.  
  7723. ; --------------------------
  7724. ; Adjust RAM Disk Free Space
  7725. ; --------------------------
  7726. ; Adjust the count of free bytes within the RAM disk.
  7727. ; The routine can produce "4 Out of memory" when adding.
  7728. ; Entry: AHL=Size adjustment (negative when a file added, positive when a file deleted).
  7729. ;        A=Bit 7 set for adding data, else deleting data.
  7730.  
  7731. L1CF3:  LD   DE,(SFSPACE) ; $5B85.
  7732.         EX   AF,AF'       ; A'HL=Requested space.
  7733.  
  7734.         LD   A,(SFSPACE+2) ; $5B87. ADE=Free space on RAM disk.
  7735.         LD   C,A          ; CDE=Free space.
  7736.  
  7737.         EX   AF,AF'       ; AHL=Requested space.
  7738.        BIT  7,A          ; A negative adjustment, i.e. adding data?
  7739.        JR   NZ,L1D0A     ; Jump ahead if so.
  7740.  
  7741. ;Deleting data
  7742.  
  7743.        ADD  HL,DE        ;
  7744.        ADC  A,C          ; AHL=Free space left.
  7745.  
  7746. L1D03:  LD   (SFSPACE),HL ; $5B85. Store free space.
  7747.        LD   (SFSPACE+2),A ; $5B87.
  7748.        RET               ;
  7749.  
  7750. ;Adding data
  7751.  
  7752. L1D0A:  ADD  HL,DE        ;
  7753.        ADC  A,C          ;
  7754.        JR   C,L1D03      ; Jump back to store free space if space left.
  7755.  
  7756. L1D0E:  CALL L05AC        ; Produce error report.
  7757.        DB 03           ; "4 Out of memory"
  7758.  
  7759. ; ---------------------------------
  7760. ; Find Catalogue Entry for Filename
  7761. ; ---------------------------------
  7762. ; Entry: Filename stored at N_STR1 ($5B67).
  7763. ; Exit : Zero flag set if file does not exist.
  7764. ;        If file exists, IX points to catalogue entry.
  7765. ;        Always leaves logical RAM bank 4 paged in.
  7766.  
  7767. L1D12:  LD   A,$04        ; Page in logical RAM bank 4 (physical RAM bank 7).
  7768.        CALL L1C64        ;
  7769.  
  7770.        LD   IX,$EBEC     ; Point to first catalogue entry.
  7771.  
  7772. L1D1B:  LD   DE,(SFNEXT)  ; $5B83. Pointer to last catalogue entry.
  7773.        OR   A            ; Clear carry flag.
  7774.        PUSH IX           ;
  7775.        POP  HL           ; HL=First catalogue entry.
  7776.        SBC  HL,DE        ;
  7777.        RET  Z            ; Return with zero flag set if end of catalogue reached
  7778.                          ; and hence filename not found.
  7779.  
  7780.        CALL L1C87        ; Test filename match with N_STR1 ($5B67).
  7781.        JR   NZ,L1D2E     ; Jump ahead if names did not match.
  7782.  
  7783.        OR   $FF          ; Reset zero flag to indicate filename exists.
  7784.        RET               ;
  7785.  
  7786. L1D2E:  LD   BC,$FFEC     ; -20 bytes (20 bytes is the size of a catalogue entry).
  7787.        ADD  IX,BC        ; Point to the next directory entry.
  7788.        JR   L1D1B        ; Test the next name.
  7789.  
  7790. ; ------------------
  7791. ; Find RAM Disk File
  7792. ; ------------------
  7793. ; Find a file in the RAM disk matching name held in N_STR1,
  7794. ; and return with IX pointing to the catalogue entry.
  7795.  
  7796. L1D35:  CALL L1D12        ; Find entry in RAM disk area, returning IX pointing to catalogue entry (leaves logical RAM bank 4 paged in).
  7797.        JR   NZ,L1D3E     ; Jump ahead if it exists.
  7798.  
  7799.        CALL L05AC        ; Produce error report.
  7800.        DB $23          ; "h File does not exist"
  7801.  
  7802. L1D3E:  LD   A,(IX+$0A)   ; Take the current start address (bank + location)
  7803.        LD   (IX+$10),A   ; and store it as the current working address.
  7804.        LD   A,(IX+$0B)   ;
  7805.        LD   (IX+$11),A   ;
  7806.        LD   A,(IX+$0C)   ;
  7807.        LD   (IX+$12),A   ;
  7808.  
  7809.        LD   A,$05        ; Page in logical RAM bank 5 (physical RAM bank 0).
  7810.        CALL L1C64        ;
  7811.        RET               ; [Could have saved 1 byte by using JP $1C64 (ROM 0)]
  7812.  
  7813. ; ----------------------
  7814. ; Update Catalogue Entry
  7815. ; ----------------------
  7816. ; Entry: IX=Address of catalogue entry (IX+$10-IX+$12 points to end of the file).
  7817. ; Exits with logical RAM bank 4 paged in.
  7818.  
  7819. L1D56:  LD   A,$04        ; Page in logical RAM bank 4 (physical RAM bank 7).
  7820.        CALL L1C64        ;
  7821.  
  7822.        BIT  0,(IX+$13)   ;
  7823.        RET  Z            ; Ignore if catalogue entry does not require updating.
  7824.  
  7825.        RES  0,(IX+$13)   ; Indicate catalogue entry updated.
  7826.  
  7827.        LD   HL,FLAGS3    ; $5B66.
  7828.        RES  2,(HL)       ; Signal not editing RAM disk catalogue.
  7829.  
  7830.        LD   L,(IX+$10)   ; Points to end address within logical RAM bank.
  7831.        LD   H,(IX+$11)   ;
  7832.        LD   A,(IX+$12)   ; Points to end logical RAM bank.
  7833.  
  7834.        LD   E,(IX+$0A)   ; Start address within logical RAM bank.
  7835.        LD   D,(IX+$0B)   ;
  7836.        LD   B,(IX+$0C)   ; Start logical RAM bank.
  7837.        OR   A            ; Clear carry flag.
  7838.        SBC  HL,DE        ; HL=End address-Start address. Maximum difference fits within 14 bits.
  7839.  
  7840.        SBC  A,B          ; A=End logical RAM bank-Start logical RAM bank - 1 if addresses overlap.
  7841.        RL   H            ;
  7842.        RL   H            ; Work out how many full banks of 16K are being used.
  7843.        SRA  A            ; Place this in the upper two bits of H.
  7844.        RR   H            ;
  7845.        SRA  A            ;
  7846.        RR   H            ; HL=Total length.
  7847.  
  7848.        LD   (IX+$0D),L   ; Length within logical RAM bank.
  7849.        LD   (IX+$0E),H   ;
  7850.        LD   (IX+$0F),A   ;
  7851.  
  7852. ;Copy the end address of the previous entry into the new entry
  7853.  
  7854.        LD   L,(IX+$10)   ; End address within logical RAM bank.
  7855.        LD   H,(IX+$11)   ;
  7856.        LD   A,(IX+$12)   ; End logical RAM bank.
  7857.        LD   BC,$FFEC     ; -20 bytes (20 bytes is the size of a catalogue entry).
  7858.        ADD  IX,BC        ; Address of next catalogue entry.
  7859.        LD   (IX+$0A),L   ; Start address within logical RAM bank.
  7860.        LD   (IX+$0B),H   ;
  7861.        LD   (IX+$0C),A   ; Start logical RAM bank.
  7862.        RET               ;
  7863.  
  7864. ; ----------------------
  7865. ; Save Bytes to RAM Disk
  7866. ; ----------------------
  7867. ; Entry: IX=Address of catalogue entry.
  7868. ;        HL=Source address in conventional RAM.
  7869. ;        BC=Length.
  7870. ; Advances IX+$10-IX+$12 as bytes are saved so that always points to next location to fill,
  7871. ; eventually pointing to the end of the file.
  7872.  
  7873. L1DAC:  LD   A,B          ; Check whether a data length of zero was requested.
  7874.        OR   C            ;
  7875.        RET  Z            ; Ignore if so since all bytes already saved.
  7876.  
  7877.        PUSH HL           ; Save the source address.
  7878.        LD   DE,$C000     ; DE=The start of the upper RAM bank.
  7879.        EX   DE,HL        ; HL=The start of the RAM bank. DE=Source address.
  7880.        SBC  HL,DE        ; HL=RAM bank start - Source address.
  7881.        JR   Z,L1DD5      ; Jump ahead if saving bytes from $C000.
  7882.  
  7883.        JR   C,L1DD5      ; Jump ahead if saving bytes from an address above $C000.
  7884.  
  7885. ;Source is below $C000
  7886.  
  7887.        PUSH HL           ; HL=Distance below $C000 (RAM bank start - Source address).
  7888.        SBC  HL,BC        ;
  7889.        JR   NC,L1DCC     ; Jump if requested bytes are all below $C000.
  7890.  
  7891. ;Source spans across $C000
  7892.  
  7893.        LD   H,B          ;
  7894.        LD   L,C          ; HL=Requested length.
  7895.        POP  BC           ; BC=Distance below $C000.
  7896.        OR   A            ;
  7897.        SBC  HL,BC        ; HL=Bytes occupying upper RAM bank.
  7898.        EX   (SP),HL      ; Stack it. HL=Source address.
  7899.        LD   DE,$C000     ; Start of upper RAM bank.
  7900.        PUSH DE           ;
  7901.        JR   L1DF4        ; Jump forward.
  7902.  
  7903. ;Source fits completely below upper RAM bank (less than $C000)
  7904.  
  7905. L1DCC:  POP  HL           ; Forget the 'distance below $C000' count.
  7906.        POP  HL           ; HL=Source address.
  7907.        LD   DE,$0000     ; Remaining bytes to transfer.
  7908.        PUSH DE           ;
  7909.        PUSH DE           ; Stack dummy Start of upper RAM bank.
  7910.        JR   L1DF4        ; Jump forward.
  7911.  
  7912. ;Source fits completely within upper RAM bank (greater than or equal $C000)
  7913.  
  7914. L1DD5:  LD   H,B          ;
  7915.        LD   L,C          ; HL=Requested length.
  7916.        LD   DE,$0020     ; DE=Length of buffer.
  7917.        OR   A            ;
  7918.        SBC  HL,DE        ; HL=Requested length-Length of buffer = Buffer overspill.
  7919.        JR   C,L1DE4      ; Jump if requested length will fit within the buffer.
  7920.  
  7921. ;Source spans transfer buffer
  7922.  
  7923.        EX   (SP),HL      ; Stack buffer overspill. HL=$0000.
  7924.        LD   B,D          ;
  7925.        LD   C,E          ; BC=Buffer length.
  7926.        JR   L1DE9        ; Jump forward.
  7927.  
  7928. ;Source fits completely within transfer buffer
  7929.  
  7930. L1DE4:  POP  HL           ; HL=Destination address.
  7931.        LD   DE,$0000     ; Remaining bytes to transfer.
  7932.        PUSH DE           ; Stack 'transfer buffer in use' flag.
  7933.  
  7934. ;Transfer a block
  7935.  
  7936. L1DE9:  PUSH BC           ; Stack the length.
  7937.        LD   DE,STRIP1    ; $5B98. Transfer buffer.
  7938.        LDIR              ; Transfer bytes.
  7939.        POP  BC           ; BC=Length.
  7940.        PUSH HL           ; HL=New source address.
  7941.        LD   HL,STRIP1    ; $5B98. Transfer buffer.
  7942.  
  7943. L1DF4:  LD   A,$04        ; Page in logical RAM bank 4 (physical RAM bank 7).
  7944.        CALL L1C64        ;
  7945.  
  7946.        LD   E,(IX+$10)   ;
  7947.        LD   D,(IX+$11)   ; Fetch the address from the current logical RAM bank.
  7948.        LD   A,(IX+$12)   ; Logical RAM bank.
  7949.        CALL L1C64        ; Page in appropriate logical RAM bank.
  7950.  
  7951. L1E05:  LDI               ; Transfer a byte from the file to the required RAM disk location or transfer buffer.
  7952.        LD   A,D          ;
  7953.        OR   E            ; Has DE been incremented to $0000?
  7954.        JR   Z,L1E24      ; Jump if end of RAM bank reached.
  7955.  
  7956. L1E0B:  LD   A,B          ;
  7957.        OR   C            ;
  7958.        JP   NZ,L1E05     ; Repeat until all bytes transferred.
  7959.  
  7960.        LD   A,$04        ; Page in logical RAM bank 4 (physical RAM bank 7).
  7961.        CALL L1C64        ;
  7962.  
  7963.        LD   (IX+$10),E   ;
  7964.        LD   (IX+$11),D   ; Store the next RAM bank source address.
  7965.  
  7966.        LD   A,$05        ; Page in logical RAM bank 5 (physical RAM bank 0).
  7967.        CALL L1C64        ;
  7968.  
  7969.        POP  HL           ; HL=Source address.
  7970.        POP  BC           ; BC=Length.
  7971.        JR   L1DAC        ; Re-enter this routine to transfer another block.
  7972.  
  7973. ;The end of a RAM bank has been reached so switch to the next bank
  7974.  
  7975. L1E24:  LD   A,$04        ; Page in logical RAM bank 4 (physical RAM bank 7).
  7976.        CALL L1C64        ;
  7977.  
  7978.        INC  (IX+$12)     ; Increment to the new logical RAM bank.
  7979.        LD   A,(IX+$12)   ; Fetch the new logical RAM bank.
  7980.        LD   DE,$C000     ; The start of the RAM disk
  7981.        CALL L1C64        ; Page in next RAM bank.
  7982.        JR   L1E0B        ; Jump back to transfer another block.
  7983.  
  7984. ; ------------------------
  7985. ; Load Bytes from RAM Disk
  7986. ; ------------------------
  7987. ; Used for loading file header and data.
  7988. ; Entry: IX=RAM disk catalogue entry address. IX+$10-IX+$12 points to the next address to fetch from the file.
  7989. ;        HL=Destination address.
  7990. ;        BC=Requested length.
  7991.  
  7992. L1E37:  LD   A,B          ; Check whether a data length of zero was requested.
  7993.        OR   C            ;
  7994.        RET  Z            ; Ignore if so since all bytes already loaded.
  7995.  
  7996.        PUSH HL           ; Save the destination address.
  7997.        LD   DE,$C000     ; DE=The start of the upper RAM bank.
  7998.        EX   DE,HL        ; HL=The start of the RAM bank. DE=Destination address.
  7999.        SBC  HL,DE        ; HL=RAM bank start - Destination address.
  8000.        JR   Z,L1E67      ; Jump if destination is $C000.
  8001.        JR   C,L1E67      ; Jump if destination is above $C000.
  8002.  
  8003. ;Destination is below $C000
  8004.  
  8005. L1E45:  PUSH HL           ; HL=Distance below $C000 (RAM bank start - Destination address).
  8006.        SBC  HL,BC        ;
  8007.        JR   NC,L1E5C     ; Jump if requested bytes all fit below $C000.
  8008.  
  8009. ;Code will span across $C000
  8010.  
  8011.        LD   H,B          ;
  8012.        LD   L,C          ; HL=Requested length.
  8013.        POP  BC           ; BC=Distance below $C000.
  8014.        OR   A            ;
  8015.        SBC  HL,BC        ; HL=Bytes destined for upper RAM bank.
  8016.        EX   (SP),HL      ; Stack it. HL=Destination address.
  8017.        LD   DE,$0000     ; Remaining bytes to transfer.
  8018.        PUSH DE           ;
  8019.        LD   DE,$C000     ; Start of upper RAM bank.
  8020.        PUSH DE           ;
  8021.        EX   DE,HL        ; HL=Start of upper RAM bank.
  8022.        JR   L1E80        ; Jump forward.
  8023.  
  8024. ;Code fits completely below upper RAM bank (less than $C000)
  8025.  
  8026. L1E5C:  POP  HL           ; Forget the 'distance below $C000' count.
  8027.        POP  HL           ; HL=Destination address.
  8028.        LD   DE,$0000     ; Remaining bytes to transfer.
  8029.        PUSH DE           ;
  8030.        PUSH DE           ; Stack dummy Start of upper RAM bank.
  8031.        PUSH DE           ;
  8032.        EX   DE,HL        ; HL=$0000, DE=Destination address.
  8033.        JR   L1E80        ; Jump forward.
  8034.  
  8035. ;Code destined for upper RAM bank (greater than or equal to $C000)
  8036.  
  8037. L1E67:  LD   H,B          ;
  8038.        LD   L,C          ; HL=Requested length.
  8039.        LD   DE,$0020     ; DE=Length of buffer.
  8040.        OR   A            ;
  8041.        SBC  HL,DE        ; HL=Requested length-Length of buffer = Buffer overspill.
  8042.        JR   C,L1E76      ; Jump if requested length will fit within the buffer.
  8043.  
  8044. ;Code will span transfer buffer
  8045.  
  8046.        EX   (SP),HL      ; Stack buffer overspill. HL=$0000.
  8047.        LD   B,D          ;
  8048.        LD   C,E          ; BC=Buffer length.
  8049.        JR   L1E7B        ; Jump forward.
  8050.  
  8051. ;Code will all fit within transfer buffer
  8052.  
  8053. L1E76:  POP  HL           ; HL=Destination address.
  8054.        LD   DE,$0000     ; Remaining bytes to transfer.
  8055.        PUSH DE           ; Stack 'transfer buffer in use' flag.
  8056.  
  8057. L1E7B:  PUSH BC           ; Stack the length.
  8058.        PUSH HL           ; Stack destination address.
  8059.        LD   DE,STRIP1    ; $5B98. Transfer buffer.
  8060.  
  8061. ;Transfer a block
  8062.  
  8063. L1E80:  LD   A,$04        ; Page in logical RAM bank 4 (physical RAM bank 7).
  8064.        CALL L1C64        ;
  8065.  
  8066.        LD   L,(IX+$10)   ; RAM bank address.
  8067.        LD   H,(IX+$11)   ;
  8068.        LD   A,(IX+$12)   ; Logical RAM bank.
  8069.        CALL L1C64        ; Page in appropriate logical RAM bank.
  8070.  
  8071. ;Enter a loop to transfer BC bytes, either to required destination or to the transfer buffer
  8072.  
  8073. L1E91:  LDI               ; Transfer a byte from the file to the required location or transfer buffer.
  8074.        LD   A,H          ;
  8075.        OR   L            ; Has HL been incremented to $0000?
  8076.        JR   Z,L1EBC      ; Jump if end of RAM bank reached.
  8077.  
  8078. L1E97:  LD   A,B          ;
  8079.        OR   C            ;
  8080.        JP   NZ,L1E91     ; Repeat until all bytes transferred.
  8081.  
  8082.        LD   A,$04        ; Page in logical RAM bank 4 (physical RAM bank 7).
  8083.        CALL L1C64        ;
  8084.  
  8085.        LD   (IX+$10),L   ;
  8086.        LD   (IX+$11),H   ; Store the next RAM bank destination address.
  8087.  
  8088.        LD   A,$05        ; Page in logical RAM bank 5 (physical RAM bank 0).
  8089.        CALL L1C64        ;
  8090.  
  8091.        POP  DE           ; DE=Destination address.
  8092.        POP  BC           ; BC=Length.
  8093.  
  8094.        LD   HL,STRIP1    ; $5B98. Transfer buffer.
  8095.        LD   A,B          ;
  8096.        OR   C            ; All bytes transferred?
  8097.        JR   Z,L1EB7      ; Jump forward if so.
  8098.  
  8099.        LDIR              ; Transfer code in buffer to the required address.
  8100.  
  8101. L1EB7:  EX   DE,HL        ; HL=New destination address.
  8102.        POP  BC           ; BC=Remaining bytes to transfer.
  8103.        JP   L1E37        ; Re-enter this routine to transfer another block.
  8104.  
  8105. ;The end of a RAM bank has been reached so switch to the next bank
  8106.  
  8107. L1EBC:  LD   A,$04        ; Page in logical RAM bank 4 (physical RAM bank 7).
  8108.        CALL L1C64        ;
  8109.  
  8110.        INC  (IX+$12)     ; Increment to the new logical RAM bank.
  8111.        LD   A,(IX+$12)   ; Fetch the new logical RAM bank.
  8112.        LD   HL,$C000     ; The start of the RAM disk.
  8113.        CALL L1C64        ; Page in next logical RAM bank.
  8114.        JR   L1E97        ; Jump back to transfer another block.
  8115.  
  8116. ; -------------------------------------------------
  8117. ; Transfer Bytes to RAM Bank 4 - Vector Table Entry
  8118. ; -------------------------------------------------
  8119. ; This routine can be used to transfer bytes from the current RAM bank into logical RAM bank 4.
  8120. ; It is not used in this ROM and is a remnant of the original Spanish Spectrum 128 ROM 0.
  8121. ; Entry: HL=Source address in conventional RAM.
  8122. ;        DE=Destination address in logical RAM bank 4 (physical RAM bank 7).
  8123. ;        BC=Number of bytes to save.
  8124.  
  8125. L1ECF:  PUSH AF           ; Save AF.
  8126.  
  8127.        LD   A,(BANK_M)   ; $5B5C. Fetch current physical RAM bank configuration.
  8128.        PUSH AF           ; Save it.
  8129.        PUSH HL           ; Save source address.
  8130.        PUSH DE           ; Save destination address.
  8131.        PUSH BC           ; Save length.
  8132.  
  8133.        LD   IX,N_STR1+3  ; $5B6A.
  8134.  
  8135.        LD   (IX+$10),E   ; Store destination address as the current address pointer.
  8136.        LD   (IX+$11),D   ;
  8137.        LD   (IX+$12),$04 ; Destination is in logical RAM bank 4 (physical RAM bank 7).
  8138.  
  8139.        CALL L1DAC        ; Store bytes to RAM disk.
  8140.  
  8141. ;Entered here by load vector routine
  8142.  
  8143. L1EE8:  LD   A,$05        ; Page in logical RAM bank 5 (physical RAM bank 0).
  8144.        CALL L1C64        ;
  8145.  
  8146.        POP  BC           ; Get length.
  8147.        POP  DE           ; Get destination address.
  8148.        POP  HL           ; Get source address.
  8149.  
  8150.        ADD  HL,BC        ; HL=Address after end of source.
  8151.        EX   DE,HL        ; DE=Address after end of source. HL=Destination address.
  8152.        ADD  HL,BC        ; HL=Address after end of destination.
  8153.        EX   DE,HL        ; HL=Address after end of source. DE=Address after end of destination.
  8154.  
  8155.        POP  AF           ; Get original RAM bank configuration.
  8156.        LD   BC,$7FFD     ;
  8157.        DI                ; Disable interrupts whilst paging.
  8158.        OUT  (C),A        ;
  8159.        LD   (BANK_M),A   ; $5B5C.
  8160.        EI                ; Re-enable interrupts.
  8161.  
  8162.        LD   BC,$0000     ; Signal all bytes loaded/saved.
  8163.        POP  AF           ; Restore AF.
  8164.        RET               ;
  8165.  
  8166. ; ---------------------------------------------------
  8167. ; Transfer Bytes from RAM Bank 4 - Vector Table Entry
  8168. ; ---------------------------------------------------
  8169. ; This routine can be used to transfer bytes from logical RAM bank 4 into the current RAM bank.
  8170. ; It is not used in this ROM and is a remnant of the original Spanish Spectrum 128 ROM 0.
  8171. ; Entry: HL=Source address in logical RAM bank 4 (physical RAM bank 7).
  8172. ;        DE=Destination address in current RAM bank.
  8173. ;        BC=Number of bytes to load.
  8174.  
  8175. L1F04:  PUSH AF           ; Save AF.
  8176.  
  8177.        LD   A,(BANK_M)   ; $5B5C. Fetch current physical RAM bank configuration.
  8178.        PUSH AF           ; Save it.
  8179.        PUSH HL           ; Save source address.
  8180.        PUSH DE           ; Save destination address.
  8181.        PUSH BC           ; Save length.
  8182.  
  8183.        LD   IX,N_STR1+3  ; $5B6A.
  8184.  
  8185.        LD   (IX+$10),L   ; Store source address as the current address pointer.
  8186.        LD   (IX+$11),H   ;
  8187.        LD   (IX+$12),$04 ; Source is in logical RAM bank 4 (physical RAM bank 7).
  8188.  
  8189.        EX   DE,HL        ; HL=Destination address.
  8190.        CALL L1E37        ; Load bytes from RAM disk.
  8191.        JR   L1EE8        ; Join the save vector routine above.
  8192.  
  8193.  
  8194. ; ========================
  8195. ; PAGING ROUTINES - PART 2
  8196. ; ========================
  8197.  
  8198. ; ----------------------------
  8199. ; Use Normal RAM Configuration
  8200. ; ----------------------------
  8201. ; Page in physical RAM bank 0, use normal stack and stack TARGET address.
  8202. ; Entry: HL=TARGET address.
  8203.  
  8204. L1F20:  EX   AF,AF'       ; Save AF.
  8205.  
  8206.         LD   A,$00        ; Physical RAM bank 0.
  8207.         DI                ; Disable interrupts whilst paging.
  8208.         CALL L1F3A        ; Page in physical RAM bank 0.
  8209.         POP  AF           ; AF=Address on stack when CALLed.
  8210.         LD   (TARGET),HL  ; $5B58. Store HL.
  8211.         LD   HL,(OLDSP)   ; $5B81. Fetch the old stack.
  8212.         LD   (OLDSP),SP   ; $5B81. Save the current stack.
  8213.         LD   SP,HL        ; Use the old stack.
  8214.         EI                ; Re-enable interrupts.
  8215.         LD   HL,(TARGET)  ; $5B58. Restore HL.
  8216.         PUSH AF           ; Re-stack the return address.
  8217.  
  8218.         EX   AF,AF'       ; Get AF back.
  8219.        RET               ;
  8220.  
  8221. ; ---------------
  8222. ; Select RAM Bank
  8223. ; ---------------
  8224. ; Used twice by the ROM to select either physical RAM bank 0 or physical RAM bank 7.
  8225. ; However, it could in theory also be used to set other paging settings.
  8226. ; Entry: A=RAM bank number.
  8227.  
  8228. L1F3A:  PUSH BC           ; Save BC
  8229.        LD   BC,$7FFD     ;
  8230.        OUT  (C),A        ; Perform requested paging.
  8231.        LD   (BANK_M),A   ; $5B5C.
  8232.        POP  BC           ; Restore BC.
  8233.        RET               ;
  8234.  
  8235. ; -------------------------------
  8236. ; Use Workspace RAM Configuration
  8237. ; -------------------------------
  8238. ; Page in physical RAM bank 7, use workspace stack and stack TARGET address.
  8239. ; Entry: HL=TARGET address.
  8240.  
  8241. L1F45:  EX   AF,AF'       ; Save A.
  8242.  
  8243.         DI                ; Disable interrupts whilst paging.
  8244.  
  8245.         POP  AF           ; Fetch return address.
  8246.         LD   (TARGET),HL  ; $5B58. Store HL.
  8247.  
  8248.         LD   HL,(OLDSP)   ; $5B81. Fetch the old stack.
  8249.         LD   (OLDSP),SP   ; $5B81. Save the current stack.
  8250.         LD   SP,HL        ; Use the old stack.
  8251.  
  8252.         LD   HL,(TARGET)  ; $5B58. Restore HL.
  8253.         PUSH AF           ; Stack return address.
  8254.  
  8255.         LD   A,$07        ; RAM bank 7.
  8256.         CALL L1F3A        ; Page in RAM bank 7.
  8257.         EI                ; Re-enable interrupts.
  8258.  
  8259.         EX   AF,AF'       ; Restore A.
  8260.        RET               ;
  8261.  
  8262.  
  8263. ; ==================================
  8264. ; RAM DISK COMMAND ROUTINES - PART 4
  8265. ; ==================================
  8266.  
  8267. ; ---------------------
  8268. ; Erase a RAM Disk File
  8269. ; ---------------------
  8270. ; N_STR1 contains the name of the file to erase.
  8271.  
  8272. L1F5F:  CALL L1D12        ; Find entry in RAM disk area, returning IX pointing to catalogue entry (leaves logical RAM bank 4 paged in).
  8273.        JR   NZ,L1F68     ; Jump ahead if it was found. [Could have saved 3 bytes by using JP Z,$1D3E (ROM 0)]
  8274.  
  8275.        CALL L05AC        ; Produce error report.
  8276.        DB $23          ; "h File does not exist"
  8277.  
  8278. L1F68:  LD   L,(IX+$0D)   ; AHL=Length of file.
  8279.        LD   H,(IX+$0E)   ;
  8280.        LD   A,(IX+$0F)   ; Bit 7 of A will be 0 indicating to delete rather than add.
  8281.        CALL L1CF3        ; Free up this amount of space.
  8282.  
  8283.        PUSH IY           ; Preserve current value of IY.
  8284.  
  8285.        LD   IY,(SFNEXT)  ; $5B83. IY points to next free catalogue entry.
  8286.        LD   BC,$FFEC     ; BC=-20 (20 bytes is the size of a catalogue entry).
  8287.        ADD  IX,BC        ; IX points to the next catalogue entry
  8288.  
  8289.        LD   L,(IY+$0A)   ; AHL=First spare byte in RAM disk file area.
  8290.        LD   H,(IY+$0B)   ;
  8291.        LD   A,(IY+$0C)   ;
  8292.  
  8293.        POP  IY           ; Restore IY to normal value.
  8294.  
  8295.        LD   E,(IX+$0A)   ; BDE=Start of address of next RAM disk file entry.
  8296.        LD   D,(IX+$0B)   ;
  8297.        LD   B,(IX+$0C)   ;
  8298.        OR   A            ;
  8299.        SBC  HL,DE        ;
  8300.        SBC  A,B          ;
  8301.        RL   H            ;
  8302.        RL   H            ;
  8303.        SRA  A            ;
  8304.        RR   H            ;
  8305.        SRA  A            ;
  8306.        RR   H            ; HL=Length of all files to be moved.
  8307.  
  8308.        LD   BC,$0014     ; 20 bytes is the size of a catalogue entry.
  8309.        ADD  IX,BC        ; IX=Catalogue entry to delete.
  8310.  
  8311.        LD   (IX+$10),L   ; Store file length in the 'deleted' catalogue entry.
  8312.        LD   (IX+$11),H   ;
  8313.        LD   (IX+$12),A   ;
  8314.  
  8315.        LD   BC,$FFEC     ; -20 (20 bytes is the size of a catalogue entry).
  8316.        ADD  IX,BC        ; IX=Next catalogue entry.
  8317.  
  8318.        LD   L,(IX+$0A)   ; DHL=Start address of next RAM disk file entry.
  8319.        LD   H,(IX+$0B)   ;
  8320.        LD   D,(IX+$0C)   ;
  8321.  
  8322.        LD   BC,$0014     ; 20 bytes is the size of a catalogue entry.
  8323.        ADD  IX,BC        ; IX points to catalogue entry to delete.
  8324.  
  8325.        LD   A,D          ; Page in logical RAM bank for start address of entry to delete.
  8326.        CALL L1C64        ;
  8327.  
  8328.        LD   A,(BANK_M)   ; $5B5C.
  8329.        LD   E,A          ; Save current RAM bank configuration in E.
  8330.        LD   BC,$7FFD     ; Select physical RAM bank 7.
  8331.        LD   A,$07        ;
  8332.        DI                ; Disable interrupts whilst performing paging operations.
  8333.        OUT  (C),A        ; Page in selected RAM bank.
  8334.        EXX               ; DHL'=Start address of next RAM disk file entry.
  8335.  
  8336.         LD   L,(IX+$0A)   ; DHL=Start of address of RAM disk file entry to delete.
  8337.         LD   H,(IX+$0B)   ;
  8338.         LD   D,(IX+$0C)   ;
  8339.  
  8340.         LD   A,D          ;
  8341.         CALL L1C64        ; Page in logical RAM bank for file entry (will update BANK_M).
  8342.  
  8343.         LD   A,(BANK_M)   ; $5B5C.
  8344.         LD   E,A          ; Get RAM bank configuration for the file in E.
  8345.         LD   BC,$7FFD     ;
  8346.         EXX               ; DHL=Start address of next RAM disk file entry.
  8347.  
  8348. ; At this point we have the registers and alternate registers pointing
  8349. ; to the actual bytes in the RAM disk for the file to be deleted and the next file,
  8350. ; with length bytes of the catalogue entry for the file to be deleted containing
  8351. ; the length of bytes for all subsequent files that need to be moved down in memory.
  8352. ; A loop is entered to move all of these bytes where the delete file began.
  8353.  
  8354. ; DHL holds the address of the byte to be moved.
  8355. ; E contains the value which should be OUTed to $5B5C to page in the relevant RAM page.
  8356.  
  8357. L1FEA:  LD   A,$07        ; Select physical RAM bank 7.
  8358.         DI                ; Disable interrupts whilst performing paging operations.
  8359.         OUT  (C),A        ; Page in selected RAM bank.
  8360.  
  8361.         LD   A,(IX+$10)   ; Decrement end address.
  8362.         SUB  $01          ;
  8363.         LD   (IX+$10),A   ;
  8364.         JR   NC,L200D     ; If no carry then the decrement is finished.
  8365.  
  8366.         LD   A,(IX+$11)   ; Otherwise decrement the middle byte.
  8367.         SUB  $01          ;
  8368.         LD   (IX+$11),A   ;
  8369.         JR   NC,L200D     ; If no carry then the decrement is finished.
  8370.  
  8371.         LD   A,(IX+$12)   ; Otherwise decrement the highest byte.
  8372.         SUB  $01          ;
  8373.         LD   (IX+$12),A   ;
  8374.         JR   C,L203E      ; Jump forward if finished moving the file.
  8375.  
  8376. L200D:  OUT  (C),E        ; Page in RAM bank containing the next file.
  8377.         LD   A,(HL)       ; Get the byte from the next file.
  8378.         INC  L            ; Increment DHL.
  8379.         JR   NZ,L2024     ; If not zero then the increment is finished.
  8380.  
  8381.         INC  H            ; Otherwise increment the middle byte.
  8382.         JR   NZ,L2024     ; If not zero then the increment is finished.
  8383.  
  8384.         EX   AF,AF'       ; Save the byte read from the next file.
  8385.        INC  D            ; Advance to next logical RAM bank for the next file.
  8386.  
  8387.        LD   A,D          ;
  8388.        CALL L1C64        ; Page in next logical RAM bank for next file entry (will update BANK_M).
  8389.  
  8390.        LD   A,(BANK_M)   ; $5B5C.
  8391.        LD   E,A          ; Get RAM bank configuration for the next file in E.
  8392.        LD   HL,$C000     ; The next file continues at the beginning of the next RAM bank.
  8393.        EX   AF,AF'       ; Retrieve the byte read from the next file.
  8394.  
  8395. L2024:  EXX               ; DHL=Address of file being deleted.
  8396.  
  8397.         DI                ; Disable interrupts whilst performing paging operations.
  8398.         OUT  (C),E        ; Page in next RAM bank containing the next file.
  8399.  
  8400.         LD   (HL),A       ; Store the byte taken from the next file.
  8401.         INC  L            ; Increment DHL.
  8402.         JR   NZ,L203B     ; If not zero then the increment is finished.
  8403.  
  8404.         INC  H            ; Otherwise increment the middle byte.
  8405.         JR   NZ,L203B     ; If not zero then the increment is finished.
  8406.  
  8407.         INC  D            ; Advance to next logical RAM bank for the file being deleted.
  8408.  
  8409.         LD   A,D          ;
  8410.         CALL L1C64        ; Page in next logical RAM bank for file being deleted entry (will update BANK_M).
  8411.  
  8412.         LD   A,(BANK_M)   ; $5B5C.
  8413.         LD   E,A          ; Get RAM bank configuration for the file being deleted in E.
  8414.         LD   HL,$C000     ; The file being deleted continues at the beginning of the next RAM bank.
  8415.  
  8416. L203B:  EXX               ; DHL=Address of byte in next file.
  8417.                           ; DHL'=Address of byte in file being deleted.
  8418.         JR   L1FEA        ;
  8419.  
  8420. ;The file has been moved
  8421.  
  8422. L203E:  LD   A,$04        ; Page in logical RAM bank 4 (physical RAM bank 7).
  8423.         CALL L1C64        ;
  8424.  
  8425.         LD   A,$00        ;
  8426.         LD   HL,$0014     ; AHL=20 bytes is the size of a catalogue entry.
  8427.  
  8428. L2048:  CALL L1CF3        ; Delete a catalogue entry.
  8429.  
  8430.         LD   E,(IX+$0D)   ;
  8431.         LD   D,(IX+$0E)   ;
  8432.         LD   C,(IX+$0F)   ; CDE=File length of file entry to delete.
  8433.  
  8434.         LD   A,D          ;
  8435.         RLCA              ;
  8436.         RL   C            ;
  8437.         RLCA              ;
  8438.         RL   C            ; C=RAM bank.
  8439.         LD   A,D          ;
  8440.         AND  $3F          ; Mask off upper bits to leave length in this bank (range 0-16383).
  8441.         LD   D,A          ; DE=Length in this bank.
  8442.  
  8443.         PUSH IX           ; Save address of catalogue entry to delete.
  8444.  
  8445. L2061:  PUSH DE           ;
  8446.         LD   DE,$FFEC     ; -20 (20 bytes is the size of a catalogue entry).
  8447.         ADD  IX,DE        ; Point to next catalogue entry.
  8448.         POP  DE           ; DE=Length in this bank.
  8449.  
  8450.         LD   L,(IX+$0A)   ;
  8451.         LD   H,(IX+$0B)   ;
  8452.         LD   A,(IX+$0C)   ; AHL=File start address.
  8453.         OR   A            ;
  8454.         SBC  HL,DE        ; Will move into next RAM bank?
  8455.         SUB  C            ;
  8456.         BIT  6,H          ;
  8457.         JR   NZ,L207C     ; Jump if same RAM bank.
  8458.  
  8459.         SET  6,H          ; New address in next RAM bank.
  8460.         DEC  A            ; Next RAM bank.
  8461.  
  8462. L207C:  LD   (IX+$0A),L   ;
  8463.         LD   (IX+$0B),H   ;
  8464.         LD   (IX+$0C),A   ; Save new start address of file.
  8465.  
  8466.         LD   L,(IX+$10)   ;
  8467.         LD   H,(IX+$11)   ;
  8468.         LD   A,(IX+$12)   ; Fetch end address of file.
  8469.         OR   A            ;
  8470.         SBC  HL,DE        ; Will move into next RAM bank?
  8471.         SUB  C            ;
  8472.         BIT  6,H          ;
  8473.         JR   NZ,L2099     ; Jump if same RAM bank.
  8474.  
  8475.         SET  6,H          ; New address in next RAM bank.
  8476.         DEC  A            ; Next RAM bank.
  8477.  
  8478. L2099:  LD   (IX+$10),L   ;
  8479.         LD   (IX+$11),H   ;
  8480.         LD   (IX+$12),A   ; Save new end address of file.
  8481.  
  8482.         PUSH IX           ;
  8483.         POP  HL           ; HL=Address of next catalogue entry.
  8484.  
  8485.         PUSH DE           ;
  8486.         LD   DE,(SFNEXT)  ; $5B83.
  8487.         OR   A            ;
  8488.         SBC  HL,DE        ; End of catalogue reached?
  8489.         POP  DE           ; DE=Length in this bank.
  8490.         JR   NZ,L2061     ; Jump if not to move next entry.
  8491.  
  8492.         LD   DE,(SFNEXT)  ; $5B83. Start address of the next available catalogue entry.
  8493.  
  8494.         POP  HL           ;
  8495.         PUSH HL           ; HL=Start address of catalogue entry to delete.
  8496.  
  8497.         OR   A            ;
  8498.         SBC  HL,DE        ;
  8499.         LD   B,H          ;
  8500.         LD   C,L          ; BC=Length of catalogue entries to move.
  8501.         POP  HL           ;
  8502.         PUSH HL           ; HL=Start address of catalogue entry to delete.
  8503.         LD   DE,$0014     ; 20 bytes is the size of a catalogue entry.
  8504.         ADD  HL,DE        ; HL=Start address of previous catalogue entry.
  8505.         EX   DE,HL        ; DE=Start address of previous catalogue entry.
  8506.         POP  HL           ; HL=Start address of catalogue entry to delete.
  8507.         DEC  DE           ; DE=End address of catalogue entry to delete.
  8508.         DEC  HL           ; HL=End address of next catalogue entry.
  8509.         LDDR              ; Move all catalogue entries.
  8510.  
  8511.         LD   HL,(SFNEXT)  ; $5B83. Start address of the next available catalogue entry.
  8512.         LD   DE,$0014     ; 20 bytes is the size of a catalogue entry.
  8513.         ADD  HL,DE        ;
  8514.         LD   (SFNEXT),HL  ; $5B83. Store the new location of the next available catalogue entry.
  8515.         RET               ;
  8516.  
  8517. ; ------------------------
  8518. ; Print RAM Disk Catalogue
  8519. ; ------------------------
  8520. ; This routine prints catalogue filenames in alphabetically order.
  8521. ; It does this by repeatedly looping through the catalogue to find
  8522. ; the next 'highest' name.
  8523.  
  8524. L20D2:  LD   A,$04        ; Page in logical RAM bank 4
  8525.         CALL L1C64        ;  (physical RAM bank 7)
  8526.  
  8527.         LD   HL,L2121     ; HL points to ten $00 bytes, the initial comparison filename.
  8528.  
  8529. L20DA:  LD   BC,L212B     ; BC point to ten $FF bytes.
  8530.         LD   IX,$EBEC     ; IX points to first catalogue entry.
  8531.  
  8532. L20E1:  CALL L05D6        ; Check for BREAK.
  8533.  
  8534.         PUSH IX           ; Save address of catalogue entry.
  8535.  
  8536.         EX   (SP),HL      ; HL points to current catalogue entry. Top of stack points to ten $00 data.
  8537.         LD   DE,(SFNEXT)  ; $5B83. Find address of next free catalogue entry.
  8538.         OR   A            ;
  8539.         SBC  HL,DE        ; Have we reached end of catalogue?
  8540.  
  8541.         POP  HL           ; Fetch address of catalogue entry.
  8542.         JR   Z,L2111      ; Jump ahead if end of catalogue reached.
  8543.  
  8544.         LD   D,H          ;
  8545.         LD   E,L          ; DE=Current catalogue entry.
  8546.         PUSH HL           ;
  8547.         PUSH BC           ;
  8548.         CALL L1C8A        ; Compare current filename (initially ten $00 bytes).
  8549.         POP  BC           ;
  8550.         POP  HL           ;
  8551.         JR   NC,L210A     ; Jump if current catalogue name is 'above' the previous.
  8552.  
  8553.         LD   D,B          ;
  8554.         LD   E,C          ; DE=Last filename
  8555.         PUSH HL           ;
  8556.         PUSH BC           ;
  8557.         CALL L1C8A        ; Compare current filename (initially ten $FF bytes).
  8558.         POP  BC           ;
  8559.         POP  HL           ;
  8560.         JR   C,L210A      ; Jump if current catalogue name is 'below' the previous.
  8561.  
  8562.         PUSH IX           ;
  8563.         POP  BC           ; BC=Address of current catalogue entry name.
  8564.  
  8565. L210A:  LD   DE,$FFEC     ; -20 (20 bytes is the size of a catalogue entry).
  8566.         ADD  IX,DE        ; Point to next catalogue entry.
  8567.         JR   L20E1        ; Check next filename.
  8568.  
  8569. L2111:  PUSH HL           ; HL points to current catalogue entry.
  8570.         LD   HL,L212B     ; Address of highest theoretical filename data.
  8571.         OR   A            ;
  8572.         SBC  HL,BC        ; Was a new filename to print found?
  8573.         POP  HL           ;
  8574.         RET  Z            ; Return if all filenames printed.
  8575.  
  8576.         LD   H,B          ;
  8577.         LD   L,C          ; HL=Address of current catalogue entry name.
  8578.         CALL L2135        ; Print the catalogue entry.
  8579.         JR   L20DA        ; Repeat for next filename.
  8580.  
  8581. ; -----------------------------
  8582. ; Print Catalogue Filename Data
  8583. ; -----------------------------
  8584.  
  8585. L2121:  DB $00, $00, $00, $00, $00  ; Lowest theoretical filename.
  8586.         DB $00, $00, $00, $00, $00
  8587.  
  8588. L212B:  DB $FF, $FF, $FF, $FF, $FF  ; Highest theoretical filename.
  8589.         DB $FF, $FF, $FF, $FF, $FF
  8590.  
  8591. ; ----------------------------
  8592. ; Print Single Catalogue Entry
  8593. ; ----------------------------
  8594. ; Entry: HL=Address of filename.
  8595. ;        BC=Address of filename.
  8596.  
  8597. L2135:  PUSH HL           ; Save address of filename.
  8598.  
  8599.         PUSH BC           ;
  8600.         POP  HL           ; [No need to transfer BC to HL since they already have the same value].
  8601.  
  8602.         LD   DE,N_STR1    ; $5B67. Copy the filename to N_STR1 so that it
  8603.         LD   BC,$000A     ;        is visible when this RAM bank is paged out.
  8604.         LDIR              ;
  8605.  
  8606.         LD   A,$05        ; Page in logical RAM bank 5 (physical RAM bank 0).
  8607.         CALL L1C64        ;
  8608.  
  8609.         LD   HL,(OLDSP)   ; $5B81.
  8610.         LD   (OLDSP),SP   ; $5B81. Save temporary stack.
  8611.         LD   SP,HL        ; Use original stack.
  8612.  
  8613.         LD   HL,N_STR1    ; $5B67. HL points to filename.
  8614.         LD   B,$0A        ; 10 characters to print.
  8615.  
  8616. L2152:  LD   A,(HL)       ; Print each character of the filename.
  8617.         PUSH HL           ;
  8618.         PUSH BC           ;
  8619.         RST  28H          ;
  8620.         DEFW PRINT_A_1    ; $0010.
  8621.         POP  BC           ;
  8622.         POP  HL           ;
  8623.         INC  HL           ;
  8624.         DJNZ L2152        ;
  8625.  
  8626.         LD   A,$0D        ; Print a newline character.
  8627.         RST  28H          ;
  8628.         DEFW PRINT_A_1    ; $0010.
  8629.  
  8630.         RST  28H          ;
  8631.         DEFW TEMPS        ; $0D4D. Copy permanent colours to temporary colours.
  8632.  
  8633.         LD   HL,(OLDSP)   ; $5B81.
  8634.         LD   (OLDSP),SP   ; $5B81. Save original stack.
  8635.         LD   SP,HL        ; Switch back to temporary stack.
  8636.  
  8637.         LD   A,$04        ; Page in logical RAM bank 4 (physical RAM bank 7).
  8638.         CALL L1C64        ;
  8639.  
  8640.         POP  HL           ; HL=Address of filename.
  8641.         RET               ;
  8642.  
  8643.  
  8644. ; =======================================================
  8645. ; BASIC LINE AND COMMAND INTERPRETATION ROUTINES - PART 4
  8646. ; =======================================================
  8647.  
  8648. ; --------------
  8649. ; LPRINT Routine
  8650. ; --------------
  8651.  
  8652. L2174:  LD   A,$03        ; Printer channel.
  8653.         JR   L217A        ; Jump ahead.
  8654.  
  8655. ; --------------
  8656. ; PRINT Routine
  8657. ; --------------
  8658.  
  8659. L2178:  LD   A,$02        ; Main screen channel.
  8660.  
  8661. L217A:  RST  28H          ;
  8662.         DEFW SYNTAX_Z     ; $2530.
  8663.         JR   Z,L2182      ; Jump forward if syntax is being checked.
  8664.  
  8665.         RST  28H          ;
  8666.         DEFW CHAN_OPEN    ; $1601.
  8667.  
  8668. L2182:  RST  28H          ;
  8669.         DEFW TEMPS        ; $0D4D.
  8670.         RST  28H          ;
  8671.         DEFW PRINT_2      ; $1FDF. Delegate handling to ROM 1.
  8672.         CALL L18A1        ; "C Nonsense in BASIC" during syntax checking if not
  8673.                           ; at end of line or statement.
  8674.         RET               ;
  8675.  
  8676. ; -------------
  8677. ; INPUT Routine
  8678. ; -------------
  8679. ; This routine allows for values entered from the keyboard to be assigned
  8680. ; to variables. It is also possible to have print items embedded in the
  8681. ; INPUT statement and these items are printed in the lower part of the display.
  8682.  
  8683. L218C:  RST  28H          ;
  8684.         DEFW SYNTAX_Z     ; $2530.
  8685.         JR   Z,L2199      ; Jump forward if syntax is being checked.
  8686.  
  8687.         LD   A,$01        ; Open channel 'K'.
  8688.         RST  28H          ;
  8689.         DEFW CHAN_OPEN    ; $1601.
  8690.         RST  28H          ; Clear the lower part of the display.
  8691.         DEFW CLS_LOWER    ; $0D6E. [*BUG* - This call will re-select channel 'S' and so should have been called prior to opening
  8692.                           ; channel 'K'. It is a direct copy of the code that appears in the standard Spectrum ROM (and ROM 1). It is
  8693.                           ; debatable whether it is better to reproduce the bug so as to ensure that the INPUT routine operates the same
  8694.                           ; in 128K mode as it does in 48K mode. Credit: Geoff Wearmouth]
  8695.  
  8696. L2199:  LD   (IY+$02),$01 ; TV_FLAG. Signal that the lower screen is being handled. [Not a bug as has been reported elsewhere. The confusion seems to have
  8697.                           ; arisen due to the incorrect system variable being originally mentioned in the Spectrum ROM Disassembly by Logan and O'Hara]
  8698.         RST  28H          ;
  8699.         DEFW IN_ITEM_1    ; $20C1. Call the subroutine to deal with the INPUT items.
  8700.         CALL L18A1        ; Move on to the next statement if checking syntax.
  8701.         RST  28H          ;
  8702.         DEFW INPUT_1+$000A ; $20A0. Delegate handling to ROM 1.
  8703.         RET               ;
  8704.  
  8705. ; ------------
  8706. ; COPY Routine
  8707. ; ------------
  8708.  
  8709. L21A7:  JP   L08F0        ; Jump to new COPY routine.
  8710.  
  8711. ; -----------
  8712. ; NEW Routine
  8713. ; -----------
  8714.  
  8715. L21AA:  DI                ;
  8716.         JP   L019D        ; Re-initialise the machine.
  8717.  
  8718. ; --------------
  8719. ; CIRCLE Routine
  8720. ; --------------
  8721. ; This routine draws an approximation to the circle with centre co-ordinates
  8722. ; X and Y and radius Z. These numbers are rounded to the nearest integer before use.
  8723. ; Thus Z must be less than 87.5, even when (X,Y) is in the centre of the screen.
  8724. ; The method used is to draw a series of arcs approximated by straight lines.
  8725.  
  8726. L21AE:  RST  18H          ; Get character from BASIC line.
  8727.         CP   ','          ; $2C. Check for second parameter.
  8728.         JR   NZ,L21EB     ; Jump ahead (for error C) if not.
  8729.  
  8730.         RST  20H          ; Advance pointer into BASIC line.
  8731.         RST  28H          ; Get parameter.
  8732.         DEFW EXPT_1NUM    ; $1C82. Radius to calculator stack.
  8733.         CALL L18A1        ; Move to consider next statement if checking syntax.
  8734.         RST  28H          ;
  8735.         DEFW CIRCLE+$000D ; $232D. Delegate handling to ROM 1.
  8736.         RET               ;
  8737.  
  8738. ; ------------
  8739. ; DRAW Routine
  8740. ; ------------
  8741. ; This routine is entered with the co-ordinates of a point X0, Y0, say, in
  8742. ; COORDS. If only two parameters X, Y are given with the DRAW command, it
  8743. ; draws an approximation to a straight line from the point X0, Y0 to X0+X, Y0+Y.
  8744. ; If a third parameter G is given, it draws an approximation to a circular arc
  8745. ; from X0, Y0 to X0+X, Y0+Y turning anti-clockwise through an angle G radians.
  8746.  
  8747. L21BE:  RST  18H          ; Get current character.
  8748.         CP   ','          ; $2C.
  8749.         JR   Z,L21CA      ; Jump if there is a third parameter.
  8750.  
  8751.         CALL L18A1        ; Error C during syntax checking if not at end of line/statement.
  8752.         RST  28H          ;
  8753.         DEFW LINE_DRAW    ; $2477. Delegate handling to ROM 1.
  8754.         RET               ;
  8755.  
  8756. L21CA:  RST  20H          ; Get the next character.
  8757.         RST  28H          ;
  8758.         DEFW EXPT_1NUM    ; $1C82. Angle to calculator stack.
  8759.         CALL L18A1        ; Error C during syntax checking if not at end of line/statement.
  8760.         RST  28H          ;
  8761.         DEFW DR_3_PRMS+$0007 ; $2394. Delegate handling to ROM 1.
  8762.         RET               ;
  8763.  
  8764. ; -----------
  8765. ; DIM Routine
  8766. ; -----------
  8767. ; This routine establishes new arrays in the variables area. The routine starts
  8768. ; by searching the existing variables area to determine whether there is an existing
  8769. ; array with the same name. If such an array is found then it is 'reclaimed' before
  8770. ; the new array is established. A new array will have all its elements set to zero
  8771. ; if it is a numeric array, or to 'spaces' if it is an array of strings.
  8772.  
  8773. L21D5:  RST  28H          ; Search to see if the array already exists.
  8774.         DEFW LOOK_VARS    ; $28B2.
  8775.         JR   NZ,L21EB     ; Jump if array variable not found.
  8776.  
  8777.         RST  28H
  8778.         DEFW SYNTAX_Z     ; $2530.
  8779.         JR   NZ,L21E7     ; Jump ahead during syntax checking.
  8780.  
  8781.         RES  6,C          ; Test the syntax for string arrays as if they were numeric.
  8782.         RST  28H          ;
  8783.         DEFW STK_VAR      ; $2996. Check the syntax of the parenthesised expression.
  8784.         CALL L18A1        ; Error when checking syntax unless at end of line/statement.
  8785.  
  8786. ;An 'existing array' is reclaimed.
  8787.  
  8788. L21E7:  RST  28H          ;
  8789.         DEFW D_RUN        ; $2C15. Delegate handling to ROM 1.
  8790.         RET               ;
  8791.  
  8792. ; ----------------------------------
  8793. ; Error Report C - Nonsense in BASIC
  8794. ; ----------------------------------
  8795.  
  8796. L21EB:  CALL L05AC        ; Produce error report.
  8797.         DB $0B          ; "C Nonsense in BASIC"
  8798.  
  8799. ; --------------------
  8800. ; Clear Screen Routine
  8801. ; --------------------
  8802. ; Clear screen if it is not already clear.
  8803.  
  8804. L21EF:  BIT  0,(IY+$30)   ; FLAGS2. Is the screen clear?
  8805.         RET  Z            ; Return if it is.
  8806.  
  8807.         RST  28H          ;
  8808.         DEFW CL_ALL       ; $0DAF. Otherwise clear the whole display.
  8809.         RET               ;
  8810.  
  8811. ; ---------------------------
  8812. ; Evaluate Numeric Expression
  8813. ; ---------------------------
  8814. ; This routine is called when a numerical expression is typed directly into the editor or calculator.
  8815. ; A numeric expression is any that begins with '(', '-' or '+', or is one of the function keywords, e.g. ABS, SIN, etc,
  8816. ; or is the name of a numeric variable.
  8817.  
  8818. L21F8:  LD   HL,$FFFE     ; A line in the editing area is considered as line '-2'.
  8819.         LD   ($5C45),HL   ; PPC. Signal no current line number.
  8820.  
  8821. ;Check the syntax of the BASIC line
  8822.  
  8823.         RES  7,(IY+$01)   ; Indicate 'syntax checking' mode.
  8824.         CALL L228E        ; Point to start of the BASIC command line.
  8825.  
  8826.         RST  28H          ;
  8827.         DEFW SCANNING     ; $24FB. Evaluate the command line.
  8828.         BIT  6,(IY+$01)   ; Is it a numeric value?
  8829.         JR   Z,L223A      ; Jump to produce an error if a string result.
  8830.  
  8831.         RST  18H          ; Get current character.
  8832.         CP   $0D          ; Is it the end of the line?
  8833.         JR   NZ,L223A     ; Jump if not to produce an error if not.
  8834.  
  8835. ;The BASIC line has passed syntax checking so now execute it
  8836.  
  8837.         SET  7,(IY+$01)   ; If so, indicate 'execution' mode.
  8838.         CALL L228E        ; Point to start of the BASIC command line.
  8839.  
  8840.         LD   HL,L0321     ; Set up the error handler routine address.
  8841.         LD   (SYNRET),HL  ; $5B8B.
  8842.  
  8843.         RST  28H          ;
  8844.         DEFW SCANNING     ; $24FB. Evaluate the command line.
  8845.         BIT  6,(IY+$01)   ; Is it a numeric value?
  8846.         JR   Z,L223A      ; Jump to produce an error if a string result.
  8847.  
  8848.         LD   DE,LASTV     ; $5B8D. DE points to last calculator value.
  8849.         LD   HL,($5C65)   ; STKEND.
  8850.         LD   BC,$0005     ; The length of the floating point value.
  8851.         OR   A            ;
  8852.         SBC  HL,BC        ; HL points to value on top of calculator stack.
  8853.         LDIR              ; Copy the value in the workspace to the top of the calculator stack.
  8854.         JP   L223E        ; [Could have saved 1 byte by using a JR instruction]
  8855.  
  8856. L223A:  CALL L05AC        ; Produce error report.
  8857.         DB $19          ; "Q Parameter error"
  8858.  
  8859. L223E:  LD   A,$0D        ; Make it appear that 'Enter' has been pressed.
  8860.         CALL L226F        ; Process key press.
  8861.  
  8862.         LD   BC,$0001     ;
  8863.         RST  28H          ;
  8864.         DEFW BC_SPACES    ; $0030. Create a byte in the workspace.
  8865.  
  8866.         LD   ($5C5B),HL   ; K_CUR. Address of the cursor.
  8867.         PUSH HL           ; Save it.
  8868.  
  8869.         LD   HL,($5C51)   ; CURCHL. Current channel information.
  8870.         PUSH HL           ; Save it.
  8871.  
  8872.         LD   A,$FF        ; Channel 'R', the workspace.
  8873.         RST  28H          ;
  8874.         DEFW CHAN_OPEN    ; $1601.
  8875.  
  8876.         RST 28H
  8877.         DEFW PRINT_FP     ; $2DE3. Print a floating point number to the workspace.
  8878.  
  8879.         POP  HL           ; Get the current channel information address.
  8880.  
  8881.         RST  28H          ;
  8882.         DEFW CHAN_FLAG    ; $1615. Set appropriate flags back for the old channel.
  8883.  
  8884.         POP  DE           ; DE=Address of the old cursor position.
  8885.  
  8886.         LD   HL,($5C5B)   ; K_CUR. Address of the cursor.
  8887.         AND  A            ;
  8888.         SBC  HL,DE        ; HL=Length of floating point number.
  8889.  
  8890. L2264:  LD   A,(DE)       ; Fetch the character and make it appear to have been typed.
  8891.         CALL L226F        ; Process the key press.
  8892.         INC  DE           ;
  8893.         DEC  HL           ; Decrement floating point number character count.
  8894.         LD   A,H          ;
  8895.         OR   L            ;
  8896.         JR   NZ,L2264     ; Repeat for all characters.
  8897.  
  8898.         RET               ;
  8899.  
  8900. ; -----------------
  8901. ; Process Key Press
  8902. ; -----------------
  8903. ; Entry: A=Key code.
  8904.  
  8905. L226F:  PUSH HL           ; Save registers.
  8906.         PUSH DE           ;
  8907.  
  8908.         CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  8909.  
  8910.         LD   HL,$EC0D     ; Editor flags.
  8911.         RES  3,(HL)       ; Reset 'line altered' flag
  8912.  
  8913.         PUSH AF           ;
  8914.         LD   A,$02        ; Main screen
  8915.         RST  28H          ;
  8916.         DEFW CHAN_OPEN    ; $1601.
  8917.         POP  AF           ;
  8918.  
  8919.         CALL L2669        ; Process key press.
  8920.  
  8921.         LD   HL,$EC0D     ; Editor flags.
  8922.         RES  3,(HL)       ; Reset 'line altered' flag
  8923.  
  8924.         CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  8925.  
  8926.         POP  DE           ; Restore registers.
  8927.         POP  HL           ;
  8928.         RET               ;
  8929.  
  8930. ; ---------------------------
  8931. ; Find Start of BASIC Command
  8932. ; ---------------------------
  8933. ; Point to the start of a typed in BASIC command
  8934. ; and return first character in A.
  8935.  
  8936. L228E:  LD   HL,($5C59)   ; E_LINE. Get the address of command being typed in.
  8937.         DEC  HL           ;
  8938.         LD   ($5C5D),HL   ; CH_ADD. Store it as the address of next character to be interpreted.
  8939.         RST  20H          ; Get the next character.
  8940.         RET               ;
  8941.  
  8942. ; ---------------
  8943. ; Is LET Command?
  8944. ; ---------------
  8945. ; A typed in command resides in the editing workspace.
  8946. ; This function tests whether the text is a single LET command.
  8947. ; Exit: Zero flag set if a single LET command.
  8948.  
  8949. L2297:  CALL L228E        ; Point to start of typed in command.
  8950.         CP   $F1          ; Is it 'LET'?
  8951.         RET  NZ           ; Return if not with zero flag reset.
  8952.  
  8953.         LD   HL,($5C5D)   ; CH_ADD. HL points to next character.
  8954.  
  8955. L22A0:  LD   A,(HL)       ; Fetch next character.
  8956.         INC  HL           ;
  8957.         CP   $0D          ; Has end of line been found?
  8958.         RET  Z            ; Return if so with zero flag set.
  8959.  
  8960.         CP   ':'          ; $3A.  Has start of new statement been found?
  8961.         JR   NZ,L22A0     ; Loop back if not.
  8962.  
  8963.         OR   A            ; Return zero flag reset indicating a multi-statement
  8964.         RET               ; LET command.
  8965.  
  8966. ; ----------------------
  8967. ; Is Operator Character?
  8968. ; ----------------------
  8969. ; Exit: Zero flag set if character is an operator.
  8970.  
  8971. L22AB:  LD   B,A          ; Save B.
  8972.         LD   HL,L22BD     ; Start of operator token table.
  8973.  
  8974. L22AF:  LD   A,(HL)       ; Fetch character from the table.
  8975.         INC  HL           ; Advance to next entry.
  8976.         OR   A            ; End of table?
  8977.         JR   Z,L22B9      ; Jump if end of table reached.
  8978.  
  8979.         CP   B            ; Found required character?
  8980.         JR   NZ,L22AF     ; Jump if not to try next character in table.
  8981.  
  8982. ;Found
  8983.  
  8984.         LD   A,B          ; Restore character to A.
  8985.         RET               ; Return with zero flag set to indicate an operator.
  8986.  
  8987. ;Not found
  8988.  
  8989. L22B9:  OR   $FF          ; Reset zero flag to indicate not an operator.
  8990.         LD   A,B          ; Restore character to A.
  8991.         RET               ;
  8992.  
  8993. ; ---------------------
  8994. ; Operator Tokens Table
  8995. ; ---------------------
  8996.  
  8997. L22BD:  DB $2B, $2D, $2A  ; '+',  '-',  '*'
  8998.         DB $2F, $5E, $3D  ; '/',  '^',  '='
  8999.         DB $3E, $3C, $C7  ; '>',  '<',  '<='
  9000.         DB $C8, $C9, $C5  ; '>=', '<>', 'OR'
  9001.         DB $C6            ; 'AND'
  9002.         DB $00            ; End marker.
  9003.  
  9004. ; ----------------------
  9005. ; Is Function Character?
  9006. ; ----------------------
  9007. ; Exit: Zero set if a function token.
  9008.  
  9009. L22CB:  CP   $A5          ; 'RND'. (first 48K token)
  9010.         JR   C,L22DD      ; Jump ahead if not a token with zero flag reset.
  9011.  
  9012.         CP   $C4          ; 'BIN'.
  9013.         JR   NC,L22DD     ; Jump ahead if not a function token.
  9014.  
  9015.         CP   $AC          ; 'AT'.
  9016.         JR   Z,L22DD      ; Jump ahead if not a function token.
  9017.  
  9018.         CP   $AD          ; 'TAB'.
  9019.         JR   Z,L22DD      ; Jump ahead if not a function token.
  9020.  
  9021.         CP   A            ; Return zero flag set if a function token.
  9022.         RET               ;
  9023.  
  9024. L22DD:  CP   $A5          ; Return zero flag set if a function token.
  9025.         RET               ;
  9026.  
  9027. ; ----------------------------------
  9028. ; Is Numeric or Function Expression?
  9029. ; ----------------------------------
  9030. ; Exit: Zero flag set if a numeric or function expression.
  9031.  
  9032. L22E0:  LD   B,A          ; Fetch character code.
  9033.         OR   $20          ; Make lowercase.
  9034.         CP   'a'          ; $61. Is it 'a' or above?
  9035.         JR   C,L22ED      ; Jump ahead if not a letter.
  9036.  
  9037.         CP   '{'          ; $7B. Is it below '{'?
  9038. L22E9:  JR   NC,L22ED     ; Jump ahead if not.
  9039.  
  9040.         CP   A            ; Character is a letter so return
  9041.         RET               ; with zero flag set.
  9042.  
  9043. L22ED:  LD   A,B          ; Fetch character code.
  9044.         CP   '.'          ; $2E. Is it '.'?
  9045.         RET  Z            ; Return zero flag set indicating numeric.
  9046.  
  9047.         CALL L230A        ; Is character a number?
  9048.         JR   NZ,L2307     ; Jump ahead if not a number.
  9049.  
  9050. L22F6:  RST  20H          ; Get next character.
  9051.         CALL L230A        ; Is character a number?
  9052.         JR   Z,L22F6      ; Repeat for next character if numeric.
  9053.  
  9054.         CP   '.'          ; $2E. Is it '.'?
  9055.         RET  Z            ; Return zero flag set indicating numeric.
  9056.  
  9057.         CP   'E'          ; $45. Is it 'E'?
  9058.         RET  Z            ; Return zero flag set indicating  numeric.
  9059.  
  9060.         CP   'e'          ; $65. Is it 'e'?
  9061.         RET  Z            ; Return zero flag set indicating  numeric.
  9062.  
  9063.         JR   L22AB        ; Jump to test for operator tokens.
  9064.  
  9065. L2307:  OR   $FF          ; Reset the zero flag to indicate non-alphanumeric.
  9066.         RET               ;
  9067.  
  9068. ; ---------------------
  9069. ; Is Numeric Character?
  9070. ; ---------------------
  9071. ; Exit: Zero flag set if numeric character.
  9072.  
  9073. L230A:  CP   '0'          ; $30. Is it below '0'?
  9074.         JR   C,L2314      ; Jump below '0'.
  9075.  
  9076.         CP   ':'          ; $3A. Is it below ':'?
  9077.         JR   NC,L2314     ; Jump above '9'
  9078.  
  9079.         CP   A            ;
  9080.         RET               ; Set zero flag if numeric.
  9081.  
  9082. L2314:  CP   '0'          ; $30. This will cause zero flag to be reset.
  9083.         RET               ;
  9084.  
  9085. ; ------------
  9086. ; PLAY Routine
  9087. ; ------------
  9088.  
  9089. L2317:  LD   B,$00        ; String index.
  9090.         RST  18H          ;
  9091.  
  9092. L231A:  PUSH BC           ;
  9093.         RST  28H          ; Get string expression.
  9094.         DEFW EXPT_EXP
  9095.         POP  BC           ;
  9096.         INC  B            ;
  9097.         CP   ','          ; $2C. A ',' indicates another string.
  9098.         JR   NZ,L2327     ; Jump ahead if no more.
  9099.  
  9100.         RST  20H          ; Advance to the next character.
  9101.         JR   L231A        ; Loop back.
  9102.  
  9103. L2327:  LD   A,B          ; Check the index.
  9104.         CP   $09          ; Maximum of 8 strings (to support synthesisers, drum machines or sequencers).
  9105.         JR   C,L2330      ;
  9106.  
  9107.         CALL L05AC        ; Produce error report.
  9108.         DB $2B          ; "p (c) 1986 Sinclair Research Ltd" [*BUG* - This should be "Parameter error". The Spanish 128
  9109.                           ; produces "p Bad parameter" but to save memory perhaps the UK 128 was intended to use the existing
  9110.                           ; "Q Parameter error" and the change of the error code byte here was overlooked. In that case it would
  9111.                           ; have had a value of $19. Note that generation of this error when using the main screen editor will
  9112.                           ; result in a crash. Credit: Andrew Owen]
  9113.  
  9114. L2330:  CALL L18A1        ; Ensure end-of-statement or end-of-line.
  9115.         JP   L0985        ; Continue with PLAY code.
  9116.  
  9117.  
  9118. ; ========================
  9119. ; UNUSED ROUTINES - PART 1
  9120. ; ========================
  9121.  
  9122. ; There now follows 513 bytes of routines that are not used by the ROM, from $2336 (ROM 0) to $2536 (ROM 0).
  9123. ; They are remnants of the original Spanish 128's ROM code, although surprisingly they appear in a different
  9124. ; order within that ROM.
  9125.  
  9126. ; ----------------
  9127. ; Return to Editor
  9128. ; ----------------
  9129. ; [Never called by this ROM]
  9130.  
  9131. L2336:  LD   HL,TSTACK    ; $5BFF.
  9132.         LD   (OLDSP),HL   ; $5B81.
  9133.  
  9134.         CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  9135.         JP   L25CB        ; Jump ahead to the Editor.
  9136.  
  9137. ; ------------------------
  9138. ; BC=HL-DE, Swap HL and DE
  9139. ; ------------------------
  9140. ; Exit: BC=HL-DE.
  9141. ;       DE=HL, HL=DE.
  9142. ;
  9143. ; [Never called by this ROM]
  9144.  
  9145. L2342:  AND  A            ;
  9146.         SBC  HL,DE        ;
  9147.         LD   B,H          ;
  9148.         LD   C,L          ; BC=HL-DE.
  9149.         ADD  HL,DE        ;
  9150.         EX   DE,HL        ; HL=DE, DE=HL.
  9151.         RET               ;
  9152.  
  9153. ; ----------------------
  9154. ; Create Room for 1 Byte
  9155. ; ----------------------
  9156. ; Creates a single byte in the workspace, or automatically produces an error '4' if not.
  9157. ;
  9158. ; [Never called by this ROM]
  9159.  
  9160. L234A:  LD   BC,$0001     ; Request 1 byte.
  9161.         PUSH HL           ;
  9162.         PUSH DE           ;
  9163.         CALL L2358        ; Test whether there is space. If it fails this will cause the error
  9164.         POP  DE           ; handler in ROM 0 to be called. If MAKE_ROOM were called directly and
  9165.         POP  HL           ; and out of memory condition detected then the ROM 1 error handler would
  9166.         RST  28H          ; be called instead.
  9167.         DEFW MAKE_ROOM    ; $1655. The memory check passed so safely make the room.
  9168.         RET
  9169.  
  9170. ; ------------------
  9171. ; Room for BC Bytes?
  9172. ; ------------------
  9173. ; Test whether there is room for the specified number of bytes in the spare memory,
  9174. ; producing error "4 Out of memory" if not. This routine is very similar to that at
  9175. ; $3F66 with the exception that this routine assumes IY points at the system variables.
  9176. ; Entry: BC=Number of bytes required.
  9177. ; Exit : Returns if the room requested is available else an error '4' is produced.
  9178. ;
  9179. ; [Called by the routine at $234A (ROM 0), which is itself never called by this ROM]
  9180.  
  9181. L2358:  LD   HL,($5C65)   ; STKEND.
  9182.         ADD  HL,BC        ; Would adding the specified number of bytes overflow the RAM area?
  9183.         JR   C,L2368      ; Jump to produce an error if so.
  9184.  
  9185.         EX   DE,HL        ; DE=New end address.
  9186.         LD   HL,$0082     ; Would there be at least 130 bytes at the top of RAM?
  9187.         ADD  HL,DE        ;
  9188.         JR   C,L2368      ; Jump to produce an error if not.
  9189.  
  9190.         SBC  HL,SP        ; If the stack is lower in memory, would there still be enough room?
  9191.         RET  C            ; Return if there would.
  9192.  
  9193. L2368:  LD   (IY+$00),$03 ; Signal error "4 Out of Memory".
  9194.         JP   L0321        ; Jump to error handler routine.
  9195.  
  9196. ; ---------
  9197. ; HL = A*32
  9198. ; ---------
  9199. ; [Called by routines at $2383 (ROM 0) and $23B8 (ROM 0), which are themselves never called by this ROM]
  9200.  
  9201. L236F:  ADD  A,A          ; A*2.
  9202.         ADD  A,A          ; A*4. Then multiply by 8 in following routine.
  9203.  
  9204. ; --------
  9205. ; HL = A*8
  9206. ; --------
  9207. ; [Called by the routine at $23E1 (ROM 0), which ultimately is itself never called by this ROM]
  9208.  
  9209. L2371:  LD   L,A          ;
  9210.         LD   H,$00        ;
  9211.         ADD  HL,HL        ; A*2.
  9212.         ADD  HL,HL        ; A*4.
  9213.         ADD  HL,HL        ; A*8.
  9214.         RET               ; Return HL=A*8.
  9215.  
  9216. ; -------------------------
  9217. ; Find Amount of Free Space
  9218. ; -------------------------
  9219. ; Exit: Carry flag set if no more space, else HL holds the amount of free space.
  9220. ;
  9221. ; [Never called by this ROM]
  9222.  
  9223. L2378:  LD   HL,$0000     ;
  9224.         ADD  HL,SP        ; HL=SP.
  9225.         LD   DE,($5C65)   ; STKEND.
  9226.         OR   A            ;
  9227.         SBC  HL,DE        ; Effectively SP-STKEND, i.e. the amount of available space.
  9228.         RET               ;
  9229.  
  9230. ; -----------------------
  9231. ; Print Screen Buffer Row
  9232. ; -----------------------
  9233. ; Prints row from the screen buffer to the screen.
  9234. ; Entry: A=Row number.
  9235. ;
  9236. ; [Never called by this ROM]
  9237.  
  9238. L2384:  RES  0,(IY-$39)   ; KSTATE+1. Signal do not invert attribute value. [IY+$3B on the Spanish 128]
  9239.  
  9240.         CALL L236F        ; HL=A*32. Number of bytes prior to the requested row.
  9241.         PUSH HL           ; Save offset to requested row to print.
  9242.  
  9243.         LD   DE,($FF24)   ; Fetch address of screen buffer.
  9244.         ADD  HL,DE        ; Point to row entry.
  9245.         LD   D,H          ;
  9246.         LD   E,L          ; DE=Address of row entry.
  9247.         EX   (SP),HL      ; Stack address of row entry. HL=Offset to requested row to print.
  9248.  
  9249.         PUSH HL           ; Save offset to requested row to print.
  9250.         PUSH DE           ; Save address of row entry.
  9251.         LD   DE,$5800     ; Attributes file.
  9252.         ADD  HL,DE        ; Point to start of corresponding row in attributes file.
  9253.         EX   DE,HL        ; DE=Start address of corresponding row in attributes file.
  9254.         POP  HL           ; HL=Address of row entry.
  9255.  
  9256.         LD   BC,$0020     ; 32 columns.
  9257.         LD   A,($5C8F)    ; ATTR_T. Fetch the temporary colours.
  9258.         CALL L249B        ; Set the colours for the 32 columns in this row, processing
  9259.                           ; any colour control codes from the print string.
  9260.  
  9261.         POP  HL           ; HL=Offset to requested row to print.
  9262.         LD   A,H          ;
  9263.         LD   H,$00        ; Calculate corresponding display file address.
  9264.         ADD  A,A          ;
  9265.         ADD  A,A          ;
  9266.         ADD  A,A          ;
  9267.         ADD  A,$40        ;
  9268.         LD   D,A          ;
  9269.         LD   E,H          ;
  9270.         ADD  HL,DE        ;
  9271.         EX   DE,HL        ; DE=Display file address.
  9272.  
  9273.         POP  HL           ; HL=Offset to requested row to print.
  9274.         LD   B,$20        ; 32 columns.
  9275.         JP   L23E1        ; Print one row to the display file.
  9276.  
  9277. ; ---------------------------
  9278. ; Blank Screen Buffer Content
  9279. ; ---------------------------
  9280. ; Sets the specified number of screen buffer positions from the specified row to $FF.
  9281. ; Entry: A=Row number.
  9282. ;        BC=Number of bytes to set.
  9283. ;
  9284. ; [Never called by this ROM]
  9285.  
  9286. L23B8:  LD   D,$FF        ; The character to set the screen buffer contents to.
  9287.         CALL L236F        ; HL=A*32. Offset to the specified row.
  9288.         LD   A,D          ;
  9289.         LD   DE,($FF24)   ; Fetch the address of the screen buffer.
  9290.         ADD  HL,DE        ; HL=Address of first column in the requested row.
  9291.         LD   E,L          ;
  9292.         LD   D,H          ;
  9293.         INC  DE           ; DE=Address of second column in the requested row.
  9294.         LD   (HL),A       ; Store the character.
  9295.         DEC  BC           ;
  9296.         LDIR              ; Repeat for all remaining bytes required.
  9297.         RET               ;
  9298.  
  9299. ; -----------------------------------
  9300. ; Print Screen Buffer to Display File
  9301. ; -----------------------------------
  9302. ; [Never called by this ROM]
  9303.  
  9304. L23CB:  CALL L2488        ; Set attributes file from screen buffer.
  9305.  
  9306.         LD   DE,$4000     ; DE=First third of display file.
  9307.         LD   HL,($FF24)   ; Fetch address of screen buffer.
  9308.         LD   B,E          ; Display 256 characters.
  9309.         CALL L23E1        ; Display string.
  9310.  
  9311.         LD   D,$48        ; Middle third of display file.
  9312.         CALL L23E1        ; Display string.
  9313.  
  9314.         LD   D,$50        ; Last third of display file.
  9315.         LD   B,$C0        ; Display 192 characters.
  9316.  
  9317. ; ----------------------------------------------
  9318. ; Print Screen Buffer Characters to Display File
  9319. ; ----------------------------------------------
  9320. ; Displays ASCII characters, UDGs, graphic characters or two special symbols in the display file,
  9321. ; but does not alter the attributes file. Character code $FE is used to represent the error marker
  9322. ; bug symbol and the character code $FF is used to represent a null, which is displayed as a space.
  9323. ; Entry: DE=Display file address.
  9324. ;        HL=Points to string to print.
  9325. ;        B=Number of characters to print.
  9326. ;
  9327. ; [Used by routine at $23CB (ROM 0) and called by the routine at $2383 (ROM 0), both of which are themselves never called by this ROM]
  9328.  
  9329. L23E1:  LD   A,(HL)       ; Fetch the character.
  9330.         PUSH HL           ; Save string pointer.
  9331.         PUSH DE           ; Save display file address.
  9332.         CP   $FE          ; Was if $FE (bug) or $FF (null)?
  9333.         JR   C,L23EC      ; Jump ahead if not.
  9334.  
  9335.         SUB  $FE          ; Reduce range to $00-$01.
  9336.         JR   L2422        ; Jump ahead to show symbol.
  9337.  
  9338. ;Comes here if character code if below $FE
  9339.  
  9340. L23EC:  CP   $20          ; Is it a control character?
  9341.         JR   NC,L23F7     ; Jump ahead if not.
  9342.  
  9343. ;Comes here if a control character
  9344.  
  9345.         LD   HL,L2527     ; Graphic for a 'G' (not a normal G though). Used to indicate embedded colour control codes.
  9346.         AND  A            ; Clear the carry flag to indicate no need to switch back to RAM bank 7.
  9347.         EX   AF,AF'       ; Save the flag.
  9348.        JR   L242B        ; Jump ahead to display the symbol.
  9349.  
  9350. L23F7:  CP   $80          ; Is it a graphic character or UDG?
  9351.        JR   NC,L2409     ; Jump ahead if so.
  9352.  
  9353. ;Comes here if an ASCII character
  9354.  
  9355.        CALL L2371        ; HL=A*8.
  9356.        LD   DE,($5C36)   ; CHARS.
  9357.        ADD  HL,DE        ; Point to the character bit pattern.
  9358.        POP  DE           ; Fetch the display file address.
  9359.        CALL $FF28        ; Copy character into display file (via RAM Routine).
  9360.                          ; Can't use routine at $242C (ROM 0) since it does not perform a simple return.
  9361.         JR   L2450        ; Continue with next character.
  9362.  
  9363. ;Comes here if a graphic character or UDG
  9364.  
  9365. L2409:  CP   $90          ; Is it a graphic character?
  9366.         JR   NC,L2411     ; Jump ahead if not.
  9367.  
  9368. ;Comes here if a graphic character
  9369.  
  9370.         SUB  $7F          ; Reduce range to $01-$10.
  9371.         JR   L2422        ; Jump ahead to display the symbol.
  9372.  
  9373. ;Comes here if a UDG
  9374.  
  9375. L2411:  SUB  $90          ; Reduce range to $00-$6D.
  9376.         CALL L2371        ; HL=A*8.
  9377.  
  9378.         POP  DE           ; Fetch display file address.
  9379.         CALL L1F20        ; Use Normal RAM Configuration (RAM bank 0) to allow access to character bit patterns.
  9380.         PUSH DE           ; Save display file address.
  9381.  
  9382.         LD   DE,($5C7B)   ; UDG. Fetch address of UDGs.
  9383.         SCF               ; Set carry flag to indicate need to switch back to RAM bank 7.
  9384.         JR   L2429        ; Jump ahead to locate character bit pattern and display the symbol.
  9385.  
  9386. ;Come here if (HL) was $FE or $FF, or with a graphic character.
  9387. ;At this point A=$00 if (HL) was $FE indicating a bug symbol, or $01 if (HL) was $FF indicating a null,
  9388. ;or A=$01-$10 if a graphic character.
  9389.  
  9390. L2422:  LD   DE,L252F     ; Start address of the graphic character bitmap table.
  9391.         CALL L2371        ; HL=A*8 -> $0000 or $0008.
  9392.         AND  A            ; Clear carry flag to indicate no need to switch back to RAM bank 7.
  9393.  
  9394. L2429:  EX   AF,AF'       ; Save switch bank indication flag.
  9395.        ADD  HL,DE        ; Point to the symbol bit pattern data.
  9396.  
  9397. L242B:  POP  DE           ; Fetch display file address. Drop through into routine below.
  9398.  
  9399. ; ------------------------------------
  9400. ; Copy A Character <<< RAM Routine >>>
  9401. ; ------------------------------------
  9402. ; Routine copied to RAM at $FF36-$FF55 by subroutine at $246F (ROM 0).
  9403. ; Also used in ROM from above routine.
  9404. ;
  9405. ; This routine copies 8 bytes from HL to DE. It increments HL and D after
  9406. ; each byte, restoring D afterwards.
  9407. ; It is used to copy a character into the display file.
  9408. ; Entry: HL=Character data.
  9409. ;        DE=Display file address.
  9410. ;
  9411. ; [Called by a routine that is itself never called by this ROM]
  9412.  
  9413. L242C:  LD   C,D          ; Save D.
  9414.  
  9415.        LD   A,(HL)       ;
  9416.        LD   (DE),A       ; Copy byte 1.
  9417.  
  9418.        INC  HL           ;
  9419.        INC  D            ;
  9420.        LD   A,(HL)       ;
  9421.        LD   (DE),A       ; Copy byte 2.
  9422.  
  9423.        INC  HL           ;
  9424.        INC  D            ;
  9425.        LD   A,(HL)       ;
  9426.        LD   (DE),A       ; Copy byte 3.
  9427.  
  9428.        INC  HL           ;
  9429.        INC  D            ;
  9430.        LD   A,(HL)       ;
  9431.        LD   (DE),A       ; Copy byte 4.
  9432.  
  9433.        INC  HL           ;
  9434.        INC  D            ;
  9435.        LD   A,(HL)       ;
  9436.        LD   (DE),A       ; Copy byte 5.
  9437.  
  9438.        INC  HL           ;
  9439.        INC  D            ;
  9440.        LD   A,(HL)       ;
  9441.        LD   (DE),A       ; Copy byte 6.
  9442.  
  9443.        INC  HL           ;
  9444.        INC  D            ;
  9445.        LD   A,(HL)       ;
  9446.        LD   (DE),A       ; Copy byte 7.
  9447.  
  9448.        INC  HL           ;
  9449.        INC  D            ;
  9450.        LD   A,(HL)       ;
  9451.        LD   (DE),A       ; Copy byte 8.
  9452.  
  9453.        LD   D,C          ; Restore D. <<< Last byte copied to RAM >>>
  9454.  
  9455. ; When the above routine is used in ROM, it drops through to here.
  9456.  
  9457. L244C:  EX   AF,AF'       ; Need to switch back to RAM bank 7?
  9458.         CALL C,L1F45      ; If so then switch to use Workspace RAM configuration (physical RAM bank 7).
  9459.  
  9460. L2450:  POP  HL           ; Fetch address of string data.
  9461.         INC  HL           ; Move to next character.
  9462.         INC  DE           ; Advance to next display file column.
  9463.         DJNZ L23E1        ; Repeat for all requested characters.
  9464.  
  9465.         RET               ;
  9466.  
  9467. ; ---------------------------------
  9468. ; Toggle ROMs 1 <<< RAM Routine >>>
  9469. ; ---------------------------------
  9470. ; Routine copied to RAM at $FF28-$FF35 by subroutine at $246F (ROM 0).
  9471. ;
  9472. ; This routine toggles to the other ROM than the one held in BANK_M.
  9473. ; Entry: A'= Current paging configuration.
  9474. ;
  9475. ; [Called by a routine that is itself never called by this ROM]
  9476.  
  9477. L2456:  PUSH BC           ; Save BC
  9478.  
  9479.         DI                ; Disable interrupts whilst paging.
  9480.  
  9481.         LD   BC,$7FFD     ;
  9482.         LD   A,(BANK_M)   ; $5B5C. Fetch current paging configuration.
  9483.         XOR  $10          ; Toggle ROMs.
  9484.         OUT  (C),A        ; Perform paging.
  9485.         EI                ; Re-enable interrupts.
  9486.         EX   AF,AF'       ; Save the new configuration in A'. <<< Last byte copied to RAM >>>
  9487.  
  9488. ; ---------------------------------
  9489. ; Toggle ROMs 2 <<< RAM Routine >>>
  9490. ; ---------------------------------
  9491. ; Routine copied to RAM at $FF56-$FF60 by subroutine at $246F (ROM 0).
  9492. ;
  9493. ; This routine toggles to the other ROM than the one specified.
  9494. ; It is used to page back to the original configuration.
  9495. ; Entry: A'= Current paging configuration.
  9496. ;
  9497. ; [Called by a routine that is itself never called by this ROM]
  9498.  
  9499. L2464:  EX   AF,AF'       ; Retrieve current paging configuration.
  9500.        DI                ; Disable interrupts whilst paging.
  9501.        LD   C,$FD        ; Restore Paging I/O port number.
  9502.        XOR  $10          ; Toggle ROMs.
  9503.        OUT  (C),A        ; Perform paging.
  9504.        EI                ; Re-enable interrupts.
  9505.  
  9506.        POP  BC           ; Restore BC.
  9507.        RET               ; <<< Last byte copied to RAM >>>
  9508.  
  9509. ; -----------------------------------------
  9510. ; Construct 'Copy Character' Routine in RAM
  9511. ; -----------------------------------------
  9512. ; This routine copies 3 sections of code into RAM to construct a single
  9513. ; routine that can be used to copy the bit pattern for a character into
  9514. ; the display file.
  9515. ;
  9516. ; Copy $2456-$2463 (ROM 0) to $FF28-$FF35 (14 bytes).
  9517. ; Copy $242C-$244B (ROM 0) to $FF36-$FF55 (32 bytes).
  9518. ; Copy $2464-$246E (ROM 0) to $FF56-$FF60 (11 bytes).
  9519. ;
  9520. ; [Never called by this ROM]
  9521.  
  9522. L246F:  LD   HL,L2456     ; Point to the 'page in other ROM' routine.
  9523.        LD   DE,$FF28     ; Destination RAM address.
  9524.        LD   BC,$000E     ;
  9525.        LDIR              ; Copy the routine.
  9526.  
  9527.        PUSH HL           ;
  9528.        LD   HL,L242C     ; Copy a character routine.
  9529.        LD   C,$20        ;
  9530.        LDIR              ; Copy the routine.
  9531.  
  9532.        POP  HL           ; HL=$2464 (ROM 0), which is the address of the 'page back to original ROM' routine.
  9533.        LD   C,$0B        ;
  9534.        LDIR              ; Copy the routine.
  9535.        RET               ;
  9536.  
  9537. ; --------------------------------------
  9538. ; Set Attributes File from Screen Buffer
  9539. ; --------------------------------------
  9540. ; This routine parses the screen buffer string contents looking for colour
  9541. ; control codes and changing the attributes file contents correspondingly.
  9542. ;
  9543. ; [Called by the routine at $23CB (ROM 0), which is itself never called by this ROM]
  9544.  
  9545. L2488:  RES  0,(IY-$39)   ; KSTATE+1. Signal do not invert attribute value. [Spanish 128 uses IY-$3B]
  9546.  
  9547.        LD   DE,$5800     ; The start of the attributes file.
  9548.        LD   BC,$02C0     ; 22 rows of 32 columns.
  9549.        LD   HL,($FF24)   ; The address of the string to print.
  9550.        LD   A,($5C8D)    ; ATTR_P.
  9551.        LD   ($5C8F),A    ; ATTR_T. Use the permanent colours.
  9552.  
  9553. ; --------------------------------------
  9554. ; Set Attributes for a Screen Buffer Row
  9555. ; --------------------------------------
  9556. ; Entry: A=Colour byte.
  9557. ;        HL=Address within screen buffer.
  9558. ;        BC=Number of characters.
  9559. ;        DE=Address within attributes file.
  9560.  
  9561. L249B:  EX   AF,AF'       ; Save the colour byte.
  9562.  
  9563. ;The main loop returns here on each iteration
  9564.  
  9565. L249C:  PUSH BC           ; Save the number of characters.
  9566.  
  9567.         LD   A,(HL)       ; Fetch a character from the buffer.
  9568.         CP   $FF          ; Is it blank?
  9569.         JR   NZ,L24AA     ; Jump ahead if not.
  9570.  
  9571.         LD   A,($5C8D)    ; ATTR_P. Get the default colour byte.
  9572.         LD   (DE),A       ; Store it in the attributes file.
  9573.         INC  HL           ; Point to next screen buffer position.
  9574.         INC  DE           ; Point to next attributes file position.
  9575.         JR   L2507        ; Jump ahead to handle the next character.
  9576.  
  9577. ;Not a blank character
  9578.  
  9579. L24AA:  EX   AF,AF'       ; Get the colour byte.
  9580.        LD   (DE),A       ; Store it in the attributes file.
  9581.        INC  DE           ; Point to the next attributes file position.
  9582.        EX   AF,AF'       ; Save the colour byte.
  9583.         INC  HL           ; Point to the next screen buffer position.
  9584.  
  9585.         CP   $15          ; Is the string character OVER or above?
  9586.         JR   NC,L2507     ; Jump if it is to handle the next character.
  9587.  
  9588.         CP   $10          ; Is the string character below INK?
  9589.         JR   C,L2507      ; Jump if it is to handle the next character.
  9590.  
  9591. ;Screen buffer character is INK, PAPER, FLASH, BRIGHT or INVERSE.
  9592.  
  9593.         DEC  HL           ; Point back to the previous screen buffer position.
  9594.         JR   NZ,L24C2     ; Jump if not INK.
  9595.  
  9596. ;Screen character was INK so insert the new ink into the attribute byte.
  9597.  
  9598.         INC  HL           ; Point to the next screen buffer position.
  9599.         LD   A,(HL)       ; Fetch the ink colour from the next screen buffer position.
  9600.         LD   C,A          ; and store it in C.
  9601.         EX   AF,AF'       ; Get the colour byte.
  9602.        AND  $F8          ; Mask off the ink bits.
  9603.        JR   L2505        ; Jump ahead to store the new attribute value and then to handle the next character.
  9604.  
  9605. L24C2:  CP   $11          ; Is the string character PAPER?
  9606.        JR   NZ,L24D1     ; Jump ahead if not.
  9607.  
  9608. ;Screen character was PAPER so insert the new paper into the attribute byte.
  9609.  
  9610.        INC  HL           ; Point to the next screen buffer position.
  9611.        LD   A,(HL)       ; Fetch the paper colour from the next screen buffer position.
  9612.        ADD  A,A          ;
  9613.        ADD  A,A          ;
  9614.        ADD  A,A          ; Multiple by 8 so that ink colour become paper colour.
  9615.        LD   C,A          ;
  9616.        EX   AF,AF'       ; Get the colour byte.
  9617.         AND  $C7          ; Mask off the paper bits.
  9618.         JR   L2505        ; Jump ahead to store the new attribute value and then to handle the next character.
  9619.  
  9620. L24D1:  CP   $12          ; Is the string character FLASH?
  9621.         JR   NZ,L24DE     ; Jump ahead if not.
  9622.  
  9623. ;Screen character was FLASH
  9624.  
  9625.         INC  HL           ; Point to the next screen buffer position.
  9626.         LD   A,(HL)       ; Fetch the flash status from the next screen buffer position.
  9627.         RRCA              ; Shift the flash bit into bit 0.
  9628.         LD   C,A          ;
  9629.         EX   AF,AF'       ; Get the colour byte.
  9630.        AND  $7F          ; Mask off the flash bit.
  9631.        JR   L2505        ; Jump ahead to store the new attribute value and then to handle the next character.
  9632.  
  9633. L24DE:  CP   $13          ; Is the string character BRIGHT?
  9634.        JR   NZ,L24EC     ; Jump ahead if not.
  9635.  
  9636. ;Screen character was BRIGHT
  9637.  
  9638.        INC  HL           ; Point to the next screen buffer position.
  9639.        LD   A,(HL)       ; Fetch the bright status from the next screen buffer position.
  9640.        RRCA              ;
  9641.        RRCA              ; Shift the bright bit into bit 0.
  9642.        LD   C,A          ;
  9643.        EX   AF,AF'       ; Get the colour byte.
  9644.         AND  $BF          ; Mask off the bright bit.
  9645.         JR   L2505        ; Jump ahead to store the new attribute value and then to handle the next character.
  9646.  
  9647. L24EC:  CP   $14          ; Is the string character INVERSE?
  9648.         INC  HL           ; Point to the next screen buffer position.
  9649.         JR   NZ,L2507     ; Jump ahead if not to handle the next character.
  9650.  
  9651. ;Screen character was INVERSE
  9652.  
  9653.         LD   C,(HL)       ; Fetch the inverse status from the next screen buffer position.
  9654.         LD   A,($5C01)    ; KSTATE+1. Fetch inverting status (Bit 0 is 0 for non-inverting, 1 for inverting).
  9655.         XOR  C            ; Invert status.
  9656.         RRA               ; Shift status into the carry flag.
  9657.         JR   NC,L2507     ; Jump if not inverting to handle the next character.
  9658.  
  9659.         LD   A,$01        ; Signal inverting is active.
  9660.         XOR  (IY-$39)     ; KSTATE+1. Toggle the status.
  9661.         LD   ($5C01),A    ; KSTATE+1. Store the new status.
  9662.         EX   AF,AF'       ; Get the colour byte.
  9663.  
  9664.        CALL L2513        ; Swap ink and paper in the colour byte.
  9665.  
  9666. L2505:  OR   C            ; Combine the old and new colour values.
  9667.        EX   AF,AF'       ; Save the new colour byte.
  9668.  
  9669. L2507:  POP  BC           ; Fetch the number of characters.
  9670.         DEC  BC           ;
  9671.         LD   A,B          ;
  9672.         OR   C            ;
  9673.         JP   NZ,L249C     ; Repeat for all characters.
  9674.  
  9675.         EX   AF,AF'       ; Get colour byte.
  9676.        LD   ($5C8F),A    ; ATTR_T. Make it the new temporary colour.
  9677.        RET               ;
  9678.  
  9679. ; ---------------------------------
  9680. ; Swap Ink and Paper Attribute Bits
  9681. ; ---------------------------------
  9682. ; Entry: A=Attribute byte value.
  9683. ; Exit : A=Attribute byte value with paper and ink bits swapped.
  9684. ;
  9685. ; [Called by the routine at $2488 (ROM 0), which is itself never called by this ROM]
  9686.  
  9687. L2513:  LD   B,A          ; Save the original colour byte.
  9688.  
  9689.        AND  $C0          ; Keep only the flash and bright bits.
  9690.        LD   C,A          ;
  9691.        LD   A,B          ;
  9692.        ADD  A,A          ; Shift ink bits into paper bits.
  9693.        ADD  A,A          ;
  9694.        ADD  A,A          ;
  9695.        AND  $38          ; Keep only the paper bits.
  9696.        OR   C            ; Combine with the flash and bright bits.
  9697.        LD   C,A          ;
  9698.  
  9699.        LD   A,B          ; Get the original colour byte.
  9700.        RRA               ;
  9701.        RRA               ;
  9702.        RRA               ; Shift the paper bits into the ink bits.
  9703.        AND  $07          ; Keep only the ink bits.
  9704.        OR   C            ; Add with the paper, flash and bright bits.
  9705.        RET               ;
  9706.  
  9707. ; --------------
  9708. ; Character Data
  9709. ; --------------
  9710.  
  9711. ;Graphic control code indicator
  9712.  
  9713. L2527:  DB $00          ; 0 0 0 0 0 0 0 0
  9714.        DB $3C          ; 0 0 1 1 1 1 0 0      XXXX
  9715.        DB $62          ; 0 1 1 0 0 0 1 0     XX   X
  9716.        DB $60          ; 0 1 1 0 0 0 0 0     XX
  9717.        DB $6E          ; 0 1 1 0 1 1 1 0     XX XXX
  9718.        DB $62          ; 0 1 1 0 0 0 1 0     XX   X
  9719.        DB $3E          ; 0 0 1 1 1 1 1 0      XXXX
  9720.        DB $00          ; 0 0 0 0 0 0 0 0
  9721.  
  9722. ;Error marker
  9723.  
  9724. L252F:  DB $00          ; 0 0 0 0 0 0 0 0
  9725.        DB $6C          ; 0 1 1 0 1 1 0 0     XX XX
  9726.        DB $10          ; 0 0 0 1 0 0 0 0       X
  9727.        DB $54          ; 0 1 0 1 0 1 0 0     X X X
  9728.        DB $BA          ; 1 0 1 1 1 0 1 0    X XXX X
  9729.        DB $38          ; 0 0 1 1 1 0 0 0      XXX
  9730.        DB $54          ; 0 1 0 1 0 1 0 0     X X X
  9731.        DB $82          ; 1 0 0 0 0 0 1 0    X     X
  9732.  
  9733. ; <<< End of Unused ROM Routines >>>
  9734.  
  9735.  
  9736. ; =================
  9737. ; KEY ACTION TABLES
  9738. ; =================
  9739.  
  9740. ; -------------------------
  9741. ; Editing Keys Action Table
  9742. ; -------------------------
  9743. ; Each editing key code maps to the appropriate handling routine.
  9744. ; This includes those keys which mirror the functionality of the
  9745. ; add-on keypad; these are found by trapping the keyword produced
  9746. ; by the keystrokes in 48K mode.
  9747. ; [Surprisingly there is no attempt to produce an intelligible layout;
  9748. ; instead the first 16 keywords have been used. Additionally the entries for DELETE
  9749. ; and ENTER should probably come in the first six entries for efficiency reasons.]
  9750.  
  9751. L2537:  DB $15          ; Number of table entries.
  9752.        DB $0B          ; Key code: Cursor up.
  9753.        DEFW L2A94        ; CURSOR-UP handler routine.
  9754.        DB $0A          ; Key code: Cursor Down.
  9755.        DEFW L2AB5        ; CURSOR-DOWN handler routine.
  9756.        DB $08          ; Key code: Cursor Left.
  9757.        DEFW L2AD7        ; CURSOR-LEFT handler routine.
  9758.        DB $09          ; Key code: Cursor Right.
  9759.        DEFW L2AE3        ; CURSOR-RIGHT handler routine.
  9760.        DB $AD          ; Key code: Extend Mode + P.
  9761.        DEFW L2A4F        ; TEN-ROWS-UP handler routine.
  9762.        DB $AC          ; Key code: Symbol Shift + I.
  9763.        DEFW L2A25        ; TEN-ROWS-DOWN handler routine.
  9764.        DB $AF          ; Key code: Extend Mode + I.
  9765.        DEFW L29D4        ; WORD-LEFT handler routine.
  9766.        DB $AE          ; Key code: Extend Mode + Shift + J.
  9767.        DEFW L29E1        ; WORD-RIGHT handler routine.
  9768.        DB $A6          ; Key code: Extend Mode + N, or Graph + W.
  9769.        DEFW L2983        ; TOP-OF-PROGRAM handler routine.
  9770.        DB $A5          ; Key code: Extend Mode + T, or Graph + V.
  9771.        DEFW L29AB        ; END-OF-PROGRAM handler routine.
  9772.        DB $A8          ; Key code: Extend Mode Symbol Shift + 2, or Graph Y.
  9773.        DEFW L2A87        ; START-OF-LINE handler routine.
  9774.        DB $A7          ; Key code: Extend Mode + M, or Graph + X.
  9775.        DEFW L2A7A        ; END-OF-LINE handler routine.
  9776.        DB $AA          ; Key code: Extend Mode + Shift + K.
  9777.        DEFW L291B        ; DELETE-RIGHT handler routine.
  9778.        DB $0C          ; Key code: Delete.
  9779.        DEFW L292B        ; DELETE handler routine.
  9780.        DB $B3          ; Key code: Extend Mode + W.
  9781.        DEFW L3017        ; DELETE-WORD-RIGHT handler routine.
  9782.        DB $B4          ; Key code: Extend Mode + E.
  9783.        DEFW L2FBC        ; DELETE-WORD-LEFT handler routine.
  9784.        DB $B0          ; Key code: Extend Mode + J.
  9785.        DEFW L3072        ; DELETE-TO-END-OF-LINE handler routine.
  9786.        DB $B1          ; Key code: Extend Mode + K.
  9787.        DEFW L303E        ; DELETE-TO-START-OF-LINE handler routine.
  9788.        DB $0D          ; Key code: Enter.
  9789.        DEFW L2944        ; ENTER handler routine.
  9790.        DB $A9          ; Key code: Extend Mode + Symbol Shift + 8, or Graph + Z.
  9791.        DEFW L269B        ; TOGGLE handler routine.
  9792.        DB $07          ; Key code: Edit.
  9793.        DEFW L2704        ; MENU handler routine.
  9794.  
  9795. ; ----------------------
  9796. ; Menu Keys Action Table
  9797. ; ----------------------
  9798. ; Each menu key code maps to the appropriate handling routine.
  9799.  
  9800. L2577:  DB $04          ; Number of entries.
  9801.        DB $0B          ; Key code: Cursor up.
  9802.        DEFW L272E        ; MENU-UP handler routine.
  9803.        DB $0A          ; Key code: Cursor down.
  9804.        DEFW L2731        ; MENU-DOWN handler routine.
  9805.        DB $07          ; Key code: Edit.
  9806.        DEFW L2717        ; MENU-SELECT handler routine.
  9807.        DB $0D          ; Key code: Enter.
  9808.        DEFW L2717        ; MENU-SELECT handler routine.
  9809.  
  9810.  
  9811. ; ======================
  9812. ; MENU ROUTINES - PART 3
  9813. ; ======================
  9814.  
  9815. ; ------------------------
  9816. ; Initialise Mode Settings
  9817. ; ------------------------
  9818. ; Called before Main menu displayed.
  9819.  
  9820. L2584:  CALL L28BE        ; Reset Cursor Position.
  9821.  
  9822.        LD   HL,$0000     ; No top line.
  9823.        LD   ($FC9A),HL   ; Line number at top of screen.
  9824.  
  9825.        LD   A,$82        ; Signal waiting for key press, and menu is displayed.
  9826.        LD   ($EC0D),A    ; Store the Editor flags.
  9827.  
  9828.        LD   HL,$0000     ; No current line number.
  9829.        LD   ($5C49),HL   ; E_PPC. Current line number.
  9830.  
  9831.        CALL L35BC        ; Reset indentation settings.
  9832.        CALL L365E        ; Reset to 'L' Mode
  9833.        RET               ; [Could have saved one byte by using JP $365E (ROM 0)]
  9834.  
  9835. ; --------------
  9836. ; Show Main Menu
  9837. ; --------------
  9838.  
  9839. L259F:  LD   HL,TSTACK    ; $5BFF.
  9840.        LD   (OLDSP),HL   ; $5B81.
  9841.  
  9842.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  9843.  
  9844.        LD   A,$02        ; Select main screen.
  9845.        RST  28H          ;
  9846.        DEFW CHAN_OPEN    ; $1601.
  9847.  
  9848. L25AD:  LD   HL,L2744     ; Jump table for Main Menu.
  9849.        LD   ($F6EA),HL   ; Store current menu jump table address.
  9850.        LD   HL,L2754     ; The Main Menu text.
  9851.        LD   ($F6EC),HL   ; Store current menu text table address.
  9852.  
  9853.        PUSH HL           ; Store address of menu on stack.
  9854.  
  9855.        LD   HL,$EC0D     ; Editor flags.
  9856.        SET  1,(HL)       ; Indicate 'menu displayed'.
  9857.        RES  4,(HL)       ; Signal return to main menu.
  9858.        DEC  HL           ; Current menu index.
  9859.        LD   (HL),$00     ; Select top entry.
  9860.  
  9861.        POP  HL           ; Retrieve address of menu.
  9862.  
  9863.        CALL L36A8        ; Display menu and highlight first item.
  9864.  
  9865.        JP   L2653        ; Jump ahead to enter the main key waiting and processing loop.
  9866.  
  9867.  
  9868. ; ========================
  9869. ; EDITOR ROUTINES - PART 2
  9870. ; ========================
  9871.  
  9872. ; -----------------------------------------------
  9873. ; Return to Editor / Calculator / Menu from Error
  9874. ; -----------------------------------------------
  9875.  
  9876. L25CB:  LD   IX,$FD6C     ; Point IX at editing settings information.
  9877.  
  9878.        LD   HL,TSTACK    ; $5BFF.
  9879.        LD   (OLDSP),HL   ; $5B81.
  9880.  
  9881.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  9882.  
  9883.        LD   A,$02        ;
  9884.        RST  28H          ;
  9885.        DEFW CHAN_OPEN    ; $1601. Select main screen.
  9886.  
  9887.        CALL L3668        ; Reset 'L' mode.
  9888.        LD   HL,$5C3B     ; FLAGS.
  9889.  
  9890. L25E3:  BIT  5,(HL)       ; Has a key been pressed?
  9891.        JR   Z,L25E3      ; Wait for a key press.
  9892.  
  9893.        LD   HL,$EC0D     ; Editor flags.
  9894.        RES  3,(HL)       ; Signal line has not been altered.
  9895.  
  9896.        BIT  6,(HL)       ; Is editing area the lower screen?
  9897.        JR   NZ,L2604     ; If so then skip printing a banner and jump ahead to return to the Editor.
  9898.  
  9899.        LD   A,($EC0E)    ; Fetch mode.
  9900.        CP   $04          ; Calculator mode?
  9901.        JR   Z,L2601      ; Jump ahead if so.
  9902.  
  9903.        CP   $00          ; Edit Menu mode?
  9904.        JP   NZ,L28C7     ; Jump if not to re-display Main menu.
  9905.  
  9906. ;Edit menu Print mode
  9907.  
  9908.        CALL L3848        ; Clear screen and print "128 BASIC" in the banner line.
  9909.        JR   L2604        ; Jump ahead to return to the Editor.
  9910.  
  9911. ;Calculator mode
  9912.  
  9913. L2601:  CALL L384D        ; Clear screen and print "Calculator" in the banner line.
  9914.  
  9915. ; --------------------
  9916. ; Return to the Editor
  9917. ; --------------------
  9918. ; Either as the result of a re-listing, an error or from completing the Edit Menu Print option.
  9919.  
  9920. ; [*BUG* - Occurs only with ZX Interface 1 attached and a BASIC line such as 1000 OPEN #4, "X" (the line number must be greater than 999).
  9921. ;          This produces the error message "Invalid device expression, 1000:1" but the message is too long to fit on a single line. When using the lower screen
  9922. ;          for editing, spurious effects happen to the bottom lines. When using the full screen editor, a crash occurs. Credit: Toni Baker, ZX Computing Monthly]
  9923.  
  9924. ; [The bug is caused by system variable DF_SZ being increased to 3 as a result of the error message spilling onto an extra line. The error can be resolved
  9925. ; by inserting a LD (IY+$31),$02 instruction at $2604 (ROM 0). Credit: Paul Farrow]
  9926.  
  9927. L2604:  CALL L30D6        ; Reset Below-Screen Line Edit Buffer settings to their default values.
  9928.        CALL L3222        ; Reset Above-Screen Line Edit Buffer settings to their default values.
  9929.  
  9930.        LD   A,($EC0E)    ; Fetch the mode.
  9931.        CP   $04          ; Calculator mode?
  9932.        JR   Z,L2653      ; Jump ahead if not to wait for a key press.
  9933.  
  9934. ;Calculator mode
  9935.  
  9936.        LD   HL,($5C49)   ; E_PPC. Fetch current line number.
  9937.        LD   A,H          ;
  9938.        OR   L            ; Is there a current line number?
  9939.        JR   NZ,L262D     ; Jump ahead if so.
  9940.  
  9941.        LD   HL,($5C53)   ; PROG. Address of start of BASIC program.
  9942.        LD   BC,($5C4B)   ; VARS. Address of start of variables area.
  9943.        AND  A            ;
  9944.        SBC  HL,BC        ; HL=Length of program.
  9945.        JR   NZ,L262A     ; Jump if a program exists.
  9946.  
  9947. ;No program exists
  9948.  
  9949.        LD   HL,$0000     ;
  9950.        LD   ($EC08),HL   ; Set no line number last edited.
  9951.  
  9952. L262A:  LD   HL,($EC08)   ; Fetch line number of last edited line.
  9953.  
  9954. L262D:  CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  9955.  
  9956.        RST  28H          ; Find address of line number held in HL, or the next line if it does not exist.
  9957.        DEFW LINE_ADDR    ; $196E. Return address in HL.
  9958.        RST  28H          ; Find line number for specified address, and return in DE.
  9959.        DEFW LINE_NO      ; $1695. Fetch the line number for the line found.
  9960.  
  9961.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  9962.  
  9963.        LD   ($5C49),DE   ; E_PPC. Save the current line number.
  9964.  
  9965.        LD   HL,$EC0D     ; Editor flags.
  9966.        BIT  5,(HL)       ; Process the BASIC line?
  9967.        JR   NZ,L2653     ; Jump ahead if calculator mode.
  9968.  
  9969.        LD   HL,$0000     ;
  9970.        LD   ($EC06),HL   ; Signal no editable characters in the line prior to the cursor.
  9971.  
  9972.        CALL L152F        ; Relist the BASIC program.
  9973.  
  9974.        CALL L29F2        ; Set attribute at editing position so as to show the cursor.
  9975.        CALL L2944        ; Call the ENTER handler routine.
  9976.  
  9977. ; -----------------
  9978. ; Main Waiting Loop
  9979. ; -----------------
  9980. ; Enter a loop to wait for a key press. Handles key presses for menus, the Calculator and the Editor.
  9981.  
  9982. L2653:  LD   SP,TSTACK    ; $5BFF. Use temporary stack.
  9983.  
  9984.        CALL L3668        ; Reset 'L' mode.
  9985.  
  9986.        CALL L367F        ; Wait for a key. [Note that it is possible to change CAPS LOCK mode whilst on a menu]
  9987.        PUSH AF           ; Save key code.
  9988.  
  9989.        LD   A,($5C39)    ; PIP. Tone of keyboard click.
  9990.        CALL L26EC        ; Produce a key click noise.
  9991.  
  9992.        POP  AF           ; Retrieve key code.
  9993.        CALL L2669        ; Process the key press.
  9994.  
  9995.        JR   L2653        ; Wait for another key.
  9996.  
  9997. ; -----------------
  9998. ; Process Key Press
  9999. ; -----------------
  10000. ; Handle key presses for the menus and the Editor.
  10001. ; Entry: A=Key code.
  10002. ;        Zero flag set if a menu is being displayed.
  10003.  
  10004. L2669:  LD   HL,$EC0D     ; Editor flags.
  10005.        BIT  1,(HL)       ; Is a menu is displayed?
  10006.        PUSH AF           ; Save key code and flags.
  10007.  
  10008.        LD   HL,L2577     ; Use menu keys lookup table.
  10009.        JR   NZ,L2677     ; Jump if menu is being displayed.
  10010.  
  10011.        LD   HL,L2537     ; Use editing keys lookup table.
  10012.  
  10013. L2677:  CALL L3FCE        ; Find and call the action handler for this key press.
  10014.        JR   NZ,L2681     ; Jump ahead if no match found.
  10015.  
  10016.        CALL NC,L26E7     ; If required then produce error beep.
  10017.  
  10018.        POP  AF           ; Restore key code.
  10019.        RET               ;
  10020.  
  10021. ;No action defined for key code
  10022.  
  10023. L2681:  POP  AF           ; Restore key code and flags.
  10024.        JR   Z,L2689      ; Jump if menu is not being displayed.
  10025.  
  10026. ;A menu is being displayed, so just ignore key press
  10027.  
  10028.        XOR  A            ; Select 'L' mode.
  10029.        LD   ($5C41),A    ; MODE.
  10030.        RET               ;
  10031.  
  10032. ;A menu is not being displayed
  10033.  
  10034. L2689:  LD   HL,$EC0D     ; Editor flags.
  10035.        BIT  0,(HL)       ; Is the Screen Line Edit Buffer is full?
  10036.        JR   Z,L2694      ; Jump if not to process the key code.
  10037.  
  10038. ;The buffer is full so ignore the key press
  10039.  
  10040.        CALL L26E7        ; Produce error beep.
  10041.        RET               ; [Could have save a byte by using JP $26E7 (ROM 0)]
  10042.  
  10043. L2694:  CP   $A3          ; Was it a supported function key code?
  10044.        JR   NC,L2653     ; Ignore by jumping back to wait for another key.
  10045.                          ; [*BUG* - This should be RET NC since it was called from the loop at $2653 (ROM 0). Repeatedly pressing an unsupported
  10046.                          ; key will result in a stack memory leak and eventual overflow. Credit: John Steven (+3), Paul Farrow (128)]
  10047.        JP   L28F1        ; Jump forward to handle the character key press.
  10048.  
  10049. ; --------------------------
  10050. ; TOGGLE Key Handler Routine
  10051. ; --------------------------
  10052. ; Toggle between editing in the lower and upper screen areas.
  10053. ; Also used by the editing menu SCREEN option.
  10054.  
  10055. L269B:  LD   A,($EC0E)    ; Fetch mode.
  10056.        CP   $04          ; Calculator mode?
  10057.        RET  Z            ; Return if so (TOGGLE has no effect in Calculator mode).
  10058.  
  10059.        CALL L1630        ; Clear Editing Display.
  10060.  
  10061.        LD   HL,$EC0D     ; Editor flags.
  10062.        RES  3,(HL)       ; Reset 'line altered' flag.
  10063.  
  10064.        LD   A,(HL)       ;
  10065.        XOR  $40          ; Toggle screen editing area flag.
  10066.        LD   (HL),A       ;
  10067.        AND  $40          ;
  10068.        JR   Z,L26B6      ; Jump forward if the editing area is now the upper area.
  10069.  
  10070.        CALL L26BB        ; Set the lower area as the current editing area.
  10071.        JR   L26B9        ; Jump forward.
  10072.  
  10073. L26B6:  CALL L26CE        ; Set the upper area as the current editing area.
  10074.  
  10075. L26B9:  SCF               ; Signal do not produce an error beep.
  10076.        RET               ;
  10077.  
  10078. ; -------------------
  10079. ; Select Lower Screen
  10080. ; -------------------
  10081. ; Set the lower screen as the editing area.
  10082.  
  10083. L26BB:  CALL L3881        ; Clear lower editing area display.
  10084.        LD   HL,$EC0D     ; Editor flags.
  10085.        SET  6,(HL)       ; Signal using lower screen.
  10086.  
  10087.        CALL L2E2D        ; Reset to lower screen.
  10088.        CALL L3A88        ; Set default lower screen editing cursor settings.
  10089.        CALL L28DF        ; Set default lower screen editing settings.
  10090.  
  10091.        JR   L26D9        ; Jump ahead to continue.
  10092.  
  10093. ; -------------------
  10094. ; Select Upper Screen
  10095. ; -------------------
  10096. ; Set the upper screen as the editing area.
  10097.  
  10098. L26CE:  LD   HL,$EC0D     ; Editor flags.
  10099.        RES  6,(HL)       ; Signal using main screen.
  10100.  
  10101.        CALL L28BE        ; Reset Cursor Position.
  10102.        CALL L3848        ; Clear screen and print the "128 BASIC" banner line.
  10103.  
  10104. L26D9:  LD   HL,($FC9A)   ; Line number at top of screen.
  10105.        LD   A,H          ;
  10106.        OR   L            ; Is there a line?
  10107.        CALL NZ,L334A     ; If there is then get the address of BASIC line for this line number.
  10108.        CALL L152F        ; Relist the BASIC program.
  10109.        JP   L29F2        ; Set attribute at editing position so as to show the cursor, and return.
  10110.  
  10111. ; ------------------
  10112. ; Produce Error Beep
  10113. ; ------------------
  10114. ; This is the entry point to produce the error beep, e.g. when trying to cursor up or down past the BASIC program.
  10115. ; It produces a different tone and duration from the error beep of 48K mode. The change is pitch is due to the SRL A
  10116. ; instruction at $26EA (ROM 0), and the change in duration is due to the instruction at $26F1 (ROM 0) which loads HL with $0C80 as opposed
  10117. ; to $1A90 which is used when in 48K mode. The key click and key repeat sounds are produced by entering at $26EC (ROM 0) but with A
  10118. ; holding the value of system variable PIP. This produces the same tone as 48K mode but is of a much longer duration due to
  10119. ; HL being loaded with $0C80 as opposed to the value of $00C8 used in 48K mode. The Spanish 128 uses the same key click tone
  10120. ; and duration in 128K mode as it does in 48K mode, leading to speculation that the Spectrum 128 (and subsequent models) should
  10121. ; have done the same and hence suffer from a bug. However, there is no reason why this should be the case, and it can easily be
  10122. ; imagined that the error beep note duration of 48K mode would quickly become very irritating when in 128K mode where it is likely
  10123. ; to occur far more often. Hence the reason for its shorter duration. The reason for the longer key click is less clear, unless it
  10124. ; was to save memory by using a single routine. However, it would only have required an additional 3 bytes to set HL independently
  10125. ; for key clicks, which is not a great deal considering there is 1/2K of unused routines at $2336 (ROM 0). Since the
  10126. ; INPUT command is handled by ROM 1, it produces key clicks at the 48K mode duration even when executed from 128 BASIC mode.
  10127.  
  10128. L26E7:  LD   A,($5C38)    ; RASP.
  10129.        SRL  A            ; Divide by 2.
  10130.  
  10131. ;This entry point is called to produce the key click tone. In 48K mode, the key click sound uses an HL value of $00C8
  10132. ;and so is 16 times shorter than in 128K mode.
  10133.  
  10134. L26EC:  PUSH IX           ;
  10135.  
  10136.        LD   D,$00        ; Pitch;
  10137.        LD   E,A          ;
  10138.        LD   HL,$0C80     ; Duration.
  10139.  
  10140. L26F4:  RST  28H          ;
  10141.        DEFW BEEPER       ; $03B5. Produce a tone.
  10142.  
  10143.        POP  IX           ;
  10144.        RET               ;
  10145.  
  10146. ; --------------------
  10147. ; Produce Success Beep
  10148. ; --------------------
  10149.  
  10150. L26FA:  PUSH IX           ;
  10151.  
  10152.        LD   DE,$0030     ; Frequency*Time;
  10153.        LD   HL,$0300     ; Duration.
  10154.        JR   L26F4        ; Jump to produce the tone.
  10155.  
  10156.  
  10157. ; ======================
  10158. ; MENU ROUTINES - PART 4
  10159. ; ======================
  10160.  
  10161. ; ===============================
  10162. ; Menu Key Press Handler Routines
  10163. ; ===============================
  10164.  
  10165. ; -----------------------------
  10166. ; Menu Key Press Handler - MENU
  10167. ; -----------------------------
  10168. ; This is executed when the EDIT key is pressed, either from within a menu or from the BASIC editor.
  10169.  
  10170. L2704:  CALL L29EC        ; Remove cursor, restoring old attribute.
  10171.  
  10172.        LD   HL,$EC0D     ; HL points to Editor flags.
  10173.        SET  1,(HL)       ; Signal 'menu is being displayed'.
  10174.        DEC  HL           ; HL=$EC0C.
  10175.        LD   (HL),$00     ; Set 'current menu item' as the top item.
  10176.  
  10177. L270F:  LD   HL,($F6EC)   ; Address of text for current menu.
  10178.        CALL L36A8        ; Display menu and highlight first item.
  10179.  
  10180.        SCF               ; Signal do not produce an error beep.
  10181.        RET               ;
  10182.  
  10183. ; -------------------------------
  10184. ; Menu Key Press Handler - SELECT
  10185. ; -------------------------------
  10186.  
  10187. L2717:  LD   HL,$EC0D     ; HL points to Editor flags.
  10188.        RES  1,(HL)       ; Clear 'displaying menu' flag.
  10189.  
  10190.        DEC  HL           ; HL=$EC0C.
  10191.        LD   A,(HL)       ; A=Current menu option index.
  10192.  
  10193.        LD   HL,($F6EA)   ; HL points to jump table for current menu.
  10194.        PUSH HL           ;
  10195.        PUSH AF           ;
  10196.        CALL L373E        ; Restore menu screen area.
  10197.        POP  AF           ;
  10198.        POP  HL           ;
  10199.  
  10200.        CALL L3FCE        ; Call the item in the jump table corresponding to the
  10201.                          ; currently selected menu item.
  10202.        JP   L29F2        ; Set attribute at editing position so as to show the cursor, and return.
  10203.  
  10204. ; ----------------------------------
  10205. ; Menu Key Press Handler - CURSOR UP
  10206. ; ----------------------------------
  10207.  
  10208. L272E:  SCF               ; Signal move up.
  10209.        JR   L2732        ; Jump ahead to continue.
  10210.  
  10211. ; ------------------------------------
  10212. ; Menu Key Press Handler - CURSOR DOWN
  10213. ; ------------------------------------
  10214.  
  10215. L2731:  AND  A            ; Signal moving down.
  10216.  
  10217. L2732:  LD   HL,$EC0C     ;
  10218.        LD   A,(HL)       ; Fetch current menu index.
  10219.        PUSH HL           ; Save it.
  10220.  
  10221.        LD   HL,($F6EC)   ; Address of text for current menu.
  10222.        CALL C,L37A7      ; Call if moving up.
  10223.        CALL NC,L37B6     ; Call if moving down.
  10224.  
  10225.        POP  HL           ; HL=Address of current menu index store.
  10226.        LD   (HL),A       ; Store the new menu index.
  10227.  
  10228. ; Comes here to complete handling of Menu cursor up and down. Also as the handler routines
  10229. ; for Edit Menu return to 128 BASIC option and Calculator menu return to Calculator option,
  10230. ; which simply make a return.
  10231.  
  10232. L2742:  SCF               ;
  10233.        RET               ;
  10234.  
  10235.  
  10236. ; ===========
  10237. ; Menu Tables
  10238. ; ===========
  10239.  
  10240. ; ---------
  10241. ; Main Menu
  10242. ; ---------
  10243.  
  10244. ; Jump table for the main 128K menu, referenced at $25AD (ROM 0).
  10245.  
  10246. L2744:  DB $05          ; Number of entries.
  10247.        DB $00
  10248.        DEFW L2831        ; Tape Loader option handler.
  10249.        DB $01
  10250.        DEFW L286C        ; 128 BASIC option handler.
  10251.        DB $02
  10252.        DEFW L2885        ; Calculator option handler.
  10253.        DB $03
  10254.        DEFW L1B47        ; 48 BASIC option handler.
  10255.        DB $04
  10256.        DEFW L2816        ; Tape Tester option handler.
  10257.  
  10258. ; Text for the main 128K menu
  10259.  
  10260. L2754           DB $06                  ; Number of entries.
  10261.                 DB "128     "           ;DEFM "128     "   ; Menu title.
  10262.                 DB $FF
  10263. L275E           DC "Tape Loader"        ;DEFM "Tape Loade"
  10264.                                         ;DB 'r'+$80
  10265. L2769           DC "128 BASIC"          ;DEFM "128 BASI"
  10266.                                         ;DB 'C'+$80
  10267. L2772           DC "Calculator"         ;DEFM "Calculato"
  10268.                                         ;DB 'r'+$80
  10269.                 DC "48 BASIC"           ;DEFM "48 BASI"
  10270.                                         ;DB 'C'+$80
  10271. L2784           DC "TR-DOS"             ;DC "Tape Tester"       ;DEFM "Tape Teste"
  10272.                                         ;DB 'r'+$80
  10273.  
  10274.                 DC "      "             ;DB ' '+$80      ; $A0. End marker.
  10275.  
  10276. ; ---------
  10277. ; Edit Menu
  10278. ; ---------
  10279.  
  10280. ; Jump table for the Edit menu
  10281.  
  10282. L2790:  DB $05          ; Number of entries.
  10283.        DB $00
  10284.        DEFW L2742        ; (Return to) 128 BASIC option handler.
  10285.        DB $01
  10286.        DEFW L2851        ; Renumber option handler.
  10287.        DB $02
  10288.        DEFW L2811        ; Screen option handler.
  10289.        DB $03
  10290.        DEFW L2862        ; Print option handler.
  10291.        DB $04
  10292.        DEFW L281C        ; Exit option handler.
  10293.  
  10294. ; Text for the Edit menu
  10295.  
  10296. L27A0           DB $06                  ; Number of entries.
  10297.                 DB "Options "           ;DEFM "Options "
  10298.                 DB $FF
  10299.                 DC "128 BASIC"          ;DEFM "128 BASI"
  10300.                                         ;DB 'C'+$80
  10301.                 DC "Renumber"           ;DEFM "Renumbe"
  10302.                                         ;DB 'r'+$80
  10303.                 DC "Screen"             ;DEFM "Scree"
  10304.                                         ;DB 'n'+$80
  10305.                 DC "Print"              ;DEFM "Prin"
  10306.                                         ;DB 't'+$80
  10307.                 DC "Exit"               ;DEFM "Exi"
  10308.                                         ;DB 't'+$80
  10309.  
  10310.                 DC " "                  ;DB ' '+$80      ; $A0. End marker.
  10311.  
  10312. ; ---------------
  10313. ; Calculator Menu
  10314. ; ---------------
  10315.  
  10316. ; Jump table for the Calculator menu
  10317.  
  10318. L27CB:  DB $02          ; Number of entries.
  10319.        DB $00
  10320.        DEFW L2742        ; (Return to) Calculator option handler.
  10321.        DB $01
  10322.        DEFW L281C        ; Exit option handler.
  10323.  
  10324. ; Text for the Calculator menu
  10325.  
  10326. L27D2           DB 03                   ; Number of entries.
  10327.                 DB "Options "           ;DEFM "Options "
  10328.                 DB $FF
  10329.                 DC "Calculator"         ;DEFM "Calculato"
  10330.                                         ;DB 'r'+$80
  10331.                 DC "Exit"               ;DEFM "Exi"
  10332.                                         ;DB 't'+$80
  10333.  
  10334.                 DC " "                  ;DB ' '+$80      ; $A0. End marker.
  10335.  
  10336. ; ----------------
  10337. ; Tape Loader Text
  10338. ; ----------------
  10339.  
  10340. L27EB:  DB $16, $01, $00 ; AT 1,0;
  10341.        DB $10, $00      ; INK 0;
  10342.        DB $11, $07      ; PAPER 7;
  10343.        DB $13, $00      ; BRIGHT 1;
  10344.                 DC "To cancel - press BREAK twice"      ;DEFM "To cancel - press BREAK twic"
  10345.                                                         ;DB 'e'+$80
  10346.  
  10347.  
  10348. ; =====================
  10349. ; Menu Handler Routines
  10350. ; =====================
  10351.  
  10352. ; -------------------------
  10353. ; Edit Menu - Screen Option
  10354. ; -------------------------
  10355.  
  10356. L2811:  CALL L269B        ; Toggle between editing in the lower and upper screen areas.
  10357.        JR   L2874        ; Jump ahead.
  10358.  
  10359. ; ------------------------------
  10360. ; Main Menu - Tape Tester Option
  10361. ; ------------------------------
  10362.  
  10363. L2816:  CALL L3881      ;CALL L3857        ; Clear screen and print the "Tape Tester" in the banner.
  10364.         JP L3BEC        ;CALL L3BE9        ; Run the tape tester, exiting via the 'Exit' option menu handler.
  10365.  
  10366. ; -----------------------------------------
  10367. ; Edit Menu / Calculator Menu - Exit Option
  10368. ; -----------------------------------------
  10369.  
  10370. L281C:  LD   HL,$EC0D     ; Editor flags.
  10371.        RES  6,(HL)       ; Indicate main screen editing.
  10372.        CALL L28BE        ; Reset Cursor Position.
  10373.  
  10374.        LD   B,$00        ; Top row to clear.
  10375.        LD   D,$17        ; Bottom row to clear.
  10376.        CALL L3B5E        ; Clear specified display rows.
  10377.  
  10378.        CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  10379.        JP   L259F        ; Jump back to show the menu.
  10380.  
  10381. ; ------------------------------
  10382. ; Main Menu - Tape Loader Option
  10383. ; ------------------------------
  10384.  
  10385. L2831:  CALL L3852        ; Clear screen and print "Tape Loader" in the banner line.
  10386.  
  10387.        LD   HL,$5C3C     ; TVFLAG.
  10388.        SET  0,(HL)       ; Signal using lower screen area.
  10389.  
  10390.        LD   DE,L27EB     ; Point to message "To cancel - press BREAK twice".
  10391.        CALL L057D        ; Print the text.
  10392.  
  10393.        RES  0,(HL)       ; Signal using main screen area.
  10394.        SET  6,(HL)       ; [This bit is unused in the 48K Spectrum and only ever set in 128K mode via the Tape Loader option.
  10395.                          ; It is never subsequently tested or reset. It may have been the intention to use this to indicate that
  10396.                          ; the screen requires clearing after loading to remove the "Tape Loader" banner and the lower screen
  10397.                          ; message "To cancel - press BREAK twice"]
  10398.  
  10399.        LD   A,$07        ; Tape Loader mode.
  10400.        LD   ($EC0E),A    ; [Redundant since call to $1AF1 (ROM 0) will set it to $FF]
  10401.  
  10402.        LD   BC,$0000     ;
  10403.        CALL L372B        ; Perform 'Print AT 0,0;'.
  10404.  
  10405.         JP   L1AF1        ; Run the tape loader.
  10406.  
  10407. ; ---------------------------
  10408. ; Edit Menu - Renumber Option
  10409. ; ---------------------------
  10410.  
  10411. L2851:  CALL L3888        ; Run the renumber routine.
  10412.         CALL NC,L26E7     ; If not successful then produce error beep if required.
  10413.  
  10414.         LD   HL,$0000     ; There is no current line number.
  10415.         LD   ($5C49),HL   ; E_PPC. Current line number.
  10416.         LD   ($EC08),HL   ; Temporary E_PPC used by BASIC Editor.
  10417.  
  10418.         JR   L2865        ; Jump ahead to display the "128 BASIC" banner if required, set the menu mode and return.
  10419.  
  10420. ; ------------------------
  10421. ; Edit Menu - Print Option
  10422. ; ------------------------
  10423.  
  10424. L2862:  CALL L1B14        ; Perform an LLIST.
  10425.  
  10426. ;Edit Menu - Renumber option joins here
  10427.  
  10428. L2865:  LD   HL,$EC0D     ; Editor flags.
  10429.         BIT  6,(HL)       ; Using lower editing screen?
  10430.         JR   NZ,L2874     ; Jump ahead if so.
  10431.  
  10432. L286C:  LD   HL,$5C3C     ; TVFLAG.
  10433.         RES  0,(HL)       ; Allow leading space.
  10434.         CALL L3848        ; Clear screen and print the "128 BASIC" banner line.
  10435.  
  10436. ;Edit Menu - Screen option joins here
  10437.  
  10438. L2874:  LD   HL,$EC0D     ; Editor flags.
  10439.         RES  5,(HL)       ; Signal not to process the BASIC line.
  10440.         RES  4,(HL)       ; Signal return to main menu.
  10441.  
  10442.         LD   A,$00        ; Select Edit menu mode. [Could have saved 1 byte by using XOR A]
  10443.         LD   HL,L2790     ; Edit Menu jump table.
  10444.         LD   DE,L27A0     ; Edit Menu text table.
  10445.         JR   L28B1        ; Store the new mode and menu details.
  10446.  
  10447. ; -----------------------------
  10448. ; Main Menu - Calculator Option
  10449. ; -----------------------------
  10450.  
  10451. L2885:  LD   HL,$EC0D     ; Editor flags.
  10452.         SET  5,(HL)       ; Signal to process the BASIC line.
  10453.         SET  4,(HL)       ; Signal return to calculator.
  10454.         RES  6,(HL)       ; Signal editing are is the main screen.
  10455.  
  10456.         CALL L28BE        ; Reset cursor position.
  10457.  
  10458.         CALL L384D        ; Clear screen and print "Calculator" in the banner line.
  10459.  
  10460.         LD   A,$04        ; Set calculator mode.
  10461.         LD   ($EC0E),A    ; Store mode.
  10462.  
  10463.         LD   HL,$0000     ; No current line number.
  10464.         LD   ($5C49),HL   ; E_PPC. Store current line number.
  10465.  
  10466.         CALL L152F        ; Relist the BASIC program.
  10467.  
  10468.         LD   BC,$0000     ; B=Row. C=Column. Top left of screen.
  10469.         LD   A,B          ; Preferred column.
  10470.         CALL L29F8        ; Store editing position and print cursor.
  10471.  
  10472.         LD   A,$04        ; Select calculator mode.
  10473.         LD   HL,L27CB     ; Calculator Menu jump table
  10474.         LD   DE,L27D2     ; Calculator Menu text table
  10475.  
  10476. ;Edit Menu - Print option joins here
  10477.  
  10478. L28B1:  LD   ($EC0E),A    ; Store mode.
  10479.         LD   ($F6EA),HL   ; Store address of current menu jump table.
  10480.         LD   ($F6EC),DE   ; Store address of current menu text.
  10481.         JP   L2604        ; Return to the Editor.
  10482.  
  10483.  
  10484. ; ========================
  10485. ; EDITOR ROUTINES - PART 3
  10486. ; ========================
  10487.  
  10488. ; ---------------------
  10489. ; Reset Cursor Position
  10490. ; ---------------------
  10491.  
  10492. L28BE:  CALL L2E1F        ; Reset to main screen.
  10493.         CALL L3A7F        ; Set default main screen editing cursor details.
  10494.         JP   L28E8        ; Set default main screen editing settings.
  10495.  
  10496. ; -------------------
  10497. ; Return to Main Menu
  10498. ; -------------------
  10499.  
  10500. L28C7:  LD   B,$00        ; Top row of editing area.
  10501.         LD   D,$17        ; Bottom row of editing area.
  10502.         CALL L3B5E        ; Clear specified display rows.
  10503.  
  10504.         JP   L25AD        ; Jump to show Main menu.
  10505.  
  10506. ; ---------------------------------
  10507. ; Main Screen Error Cursor Settings
  10508. ; ---------------------------------
  10509. ; Main screen editing cursor settings.
  10510. ; Gets copied to $F6EE.
  10511.  
  10512. L28D1:  DB $06          ; Number of bytes in table.
  10513.         DB $00          ; $F6EE = Cursor position - row 0.
  10514.         DB $00          ; $F6EF = Cursor position - column 0.
  10515.         DB $00          ; $F6F0 = Cursor position - column 0 preferred.
  10516.         DB $04          ; $F6F1 = Top row before scrolling up.
  10517.         DB $10          ; $F6F2 = Bottom row before scrolling down.
  10518.         DB $14          ; $F6F3 = Number of rows in the editing area.
  10519.  
  10520. ; ---------------------------------
  10521. ; Lower Screen Good Cursor Settings
  10522. ; ---------------------------------
  10523. ; Lower screen editing cursor settings.
  10524. ; Gets copied to $F6EE.
  10525.  
  10526. L28D8:  DB $06          ; Number of bytes in table.
  10527.         DB $00          ; $F6EE = Cursor position - row 0.
  10528.         DB $00          ; $F6EF = Cursor position - column 0.
  10529.         DB $00          ; $F6F0 = Cursor position - column 0 preferred.
  10530.         DB $00          ; $F6F1 = Top row before scrolling up.
  10531.         DB $01          ; $F6F2 = Bottom row before scrolling down.
  10532.         DB $01          ; $F6F3 = Number of rows in the editing area.
  10533.  
  10534. ; ----------------------------------------
  10535. ; Initialise Lower Screen Editing Settings
  10536. ; ----------------------------------------
  10537. ; Used when selecting lower screen. Copies 6 bytes from $28D9 (ROM 0) to $F6EE.
  10538.  
  10539. L28DF:  LD   HL,L28D8     ; Default lower screen editing information.
  10540.         LD   DE,$F6EE     ; Editing information stores.
  10541.         JP   L3FBA        ; Copy bytes.
  10542.  
  10543. ; ---------------------------------------
  10544. ; Initialise Main Screen Editing Settings
  10545. ; ---------------------------------------
  10546. ; Used when selecting main screen. Copies 6 bytes from $28D2 (ROM 0) to $F6EE.
  10547.  
  10548. L28E8:  LD   HL,L28D1     ; Default main screen editing information.
  10549.         LD   DE,$F6EE     ; Editing information stores.
  10550.         JP   L3FBA        ; Copy bytes.
  10551.  
  10552. ; -------------------------------
  10553. ; Handle Key Press Character Code
  10554. ; -------------------------------
  10555. ; This routine handles a character typed at the keyboard, inserting it into the Screen Line Edit Buffer
  10556. ; as appropriate.
  10557. ; Entry: A=Key press character code.
  10558.  
  10559. L28F1:  LD   HL,$EC0D     ; Editor flags.
  10560.         OR   A            ; Clear carry flag. [Redundant instruction since carry flag return state never checked]
  10561.         OR   A            ; [Redundant instruction]
  10562.         BIT  0,(HL)       ; Is the Screen Line Edit Buffer is full?
  10563.         JP   NZ,L29F2     ; Jump if it is to set attribute at editing position so as to show the cursor, and return.
  10564.  
  10565.         RES  7,(HL)       ; Signal got a key press.
  10566.         SET  3,(HL)       ; Signal current line has been altered.
  10567.  
  10568.         PUSH HL           ; Save address of the flags.
  10569.         PUSH AF           ; Save key code.
  10570.  
  10571.         CALL L29EC        ; Remove cursor, restoring old attribute.
  10572.  
  10573.         POP  AF           ;
  10574.         PUSH AF           ; Get and save key code.
  10575.  
  10576.         CALL L2E81        ; Insert the character into the Screen Line Edit Buffer.
  10577.  
  10578.         POP  AF           ; Get key code.
  10579.  
  10580.         LD   A,B          ; B=Current cursor column position.
  10581.         CALL L2B78        ; Find next Screen Line Edit Buffer editable position to right, moving to next row if necessary.
  10582.  
  10583.         POP  HL           ; Get address of the flags.
  10584.         SET  7,(HL)       ; Signal wait for a key.
  10585.         JP   NC,L29F2     ; Jump if new position not available to set cursor attribute at existing editing position, and return.
  10586.  
  10587.         LD   A,B          ; A=New cursor column position.
  10588.         JP   C,L29F8      ; Jump if new position is editable to store editing position and print cursor.
  10589.                           ; [This only needs to be JP $29F8 (ROM 0), thereby saving 3 bytes, since a branch to $29F2 (ROM 0) would have been taken above if the carry flag was reset]
  10590.         JP   L29F2        ; Set attribute at editing position so as to show the cursor, and return.
  10591.  
  10592. ; --------------------------------
  10593. ; DELETE-RIGHT Key Handler Routine
  10594. ; --------------------------------
  10595. ; Delete a character to the right. An error beep is not produced if there is nothing to delete.
  10596. ;
  10597. ; Symbol: DEL
  10598. ;         -->
  10599. ;
  10600. ; Exit: Carry flag set to indicate not to produce an error beep.
  10601.  
  10602. L291B:  LD   HL,$EC0D     ; HL points to Editor flags.
  10603.         SET  3,(HL)       ; Indicate 'line altered'.
  10604.  
  10605.         CALL L29EC        ; Remove cursor, restoring old attribute. Exit with C=row, B=column.
  10606.  
  10607.         CALL L2F12        ; Delete character to the right, shifting subsequent rows as required.
  10608.  
  10609.         SCF               ; Signal do not produce an error beep.
  10610.         LD   A,B          ; A=The new cursor editing position.
  10611.         JP   L29F8        ; Store editing position and print cursor, and then return.
  10612.  
  10613. ; --------------------------
  10614. ; DELETE Key Handler Routine
  10615. ; --------------------------
  10616. ; Delete a character to the left. An error beep is not produced if there is nothing to delete.
  10617. ;
  10618. ; Symbol: DEL
  10619. ;         <--
  10620. ;
  10621. ; Exit: Carry flag set to indicate not to produce an error beep.
  10622.  
  10623. L292B:  LD   HL,$EC0D     ; HL points to Editor flags.
  10624.         RES  0,(HL)       ; Signal that the Screen Line Edit Buffer is not full.
  10625.         SET  3,(HL)       ; Indicate 'line altered'.
  10626.  
  10627.         CALL L29EC        ; Remove cursor, restoring old attribute. Exit with C=row, B=column.
  10628.  
  10629.         CALL L2B5B        ; Select previous column position (Returns carry flag set if editable).
  10630.         CCF               ; Signal do not produce an error beep if not editable.
  10631.         JP   C,L29F2      ; Jump if not editable to set attribute at editing position so as to show the cursor, and return.
  10632.  
  10633.         CALL L2F12        ; Delete character to the right, shifting subsequent rows as required.
  10634.  
  10635.         SCF               ; Signal do not produce an error beep.
  10636.         LD   A,B          ; A=The new cursor editing position.
  10637.         JP   L29F8        ; Store editing position and print cursor, and then return.
  10638.  
  10639. ; -------------------------
  10640. ; ENTER Key Handler Routine
  10641. ; -------------------------
  10642. ; This routine handles ENTER being pressed. If not on a BASIC line then it does nothing. If on an
  10643. ; unaltered BASIC line then insert a blank row after it and move the cursor to it. If on an altered
  10644. ; BASIC line then attempt to enter it into the BASIC program, otherwise return to produce an error beep.
  10645. ; Exit: Carry flag reset to indicate to produce an error beep.
  10646.  
  10647. L2944:  CALL L29EC        ; Remove cursor, restoring old attribute.
  10648.  
  10649.         PUSH AF           ; Save preferred column number.
  10650.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  10651.         PUSH BC           ; Stack current editing position.
  10652.         LD   B,$00        ; Column 0.
  10653.         CALL L2E41        ; Is this a blank row? i.e. Find editable position on this row to the right, returning column number in B.
  10654.         POP  BC           ; Retrieve current editing position.
  10655.         JR   C,L295E      ; Jump ahead if editable position found, i.e. not a blank row.
  10656.  
  10657. ;No editable characters on the row, i.e. a blank row
  10658.  
  10659.         LD   HL,$0020     ;
  10660.         ADD  HL,DE        ; Point to the flag byte for the row.
  10661.         LD   A,(HL)       ; Fetch the flag byte.
  10662.         CPL               ; Invert it.
  10663.         AND  $09          ; Keep the 'first row' and 'last row' flags.
  10664.         JR   Z,L297A      ; Jump if both flags were set indicating not on a BASIC line.
  10665.  
  10666. ;On a BASIC line
  10667.  
  10668. L295E:  LD   A,($EC0D)    ; Editor flags.
  10669.         BIT  3,A          ; Has the current line been altered?
  10670.         JR   Z,L296A      ; Jump ahead if not.
  10671.  
  10672. ;The current BASIC line has been altered
  10673.  
  10674.         CALL L2C8E        ; Enter line into program.
  10675.         JR   NC,L297F     ; Jump if syntax error to produce an error beep.
  10676.  
  10677. L296A:  CALL L2C4C        ; Find end of the current BASIC line in the Screen Line Edit Buffer, scrolling up rows as required. Returns column number into B.
  10678.         CALL L2B78        ; Find address of end position in current BASIC line. Returns address into HL.
  10679.         CALL L2ECE        ; Insert a blank line in the Screen Line Edit Buffer, shifting subsequent rows down.
  10680.  
  10681. ;Display the cursor on the first column of the next row
  10682.  
  10683.         LD   B,$00        ; First column.
  10684.         POP  AF           ; A=Preferred column number.
  10685.         SCF               ; Signal do not produce an error beep.
  10686.         JP   L29F8        ; Store editing position and print cursor, and then return.
  10687.  
  10688. ;Cursor is on a blank row, which is not part of a BASIC line
  10689.  
  10690. L297A:  POP  AF           ; Discard stacked item.
  10691.         SCF               ; Signal do not produce an error beep.
  10692.         JP   L29F2        ; Set attribute at current editing position so as to show the cursor, and return.
  10693.  
  10694. ;A syntax error occurred so return signalling to produce an error beep
  10695.  
  10696. L297F:  POP  AF           ; Discard stacked item.
  10697.         JP   L29F2        ; Set attribute at current editing position so as to show the cursor, and return.
  10698.  
  10699. ; ----------------------------------
  10700. ; TOP-OF-PROGRAM Key Handler Routine
  10701. ; ----------------------------------
  10702. ; Move to the first row of the first line of the BASIC program. An error beep is not produced if there is no program.
  10703. ;
  10704. ; Symbol: ------
  10705. ;         / \/ \
  10706. ;          |  |
  10707. ;
  10708. ; Exit: Carry flag set to indicate not to produce an error beep.
  10709.  
  10710. L2983:  LD   A,($EC0E)    ; Fetch mode.
  10711.         CP   $04          ; Calculator mode?
  10712.         RET  Z            ; Exit if so.
  10713.  
  10714. ;Editor mode
  10715.  
  10716.         CALL L29EC        ; Remove cursor, restoring old attribute.
  10717.  
  10718.         LD   HL,$0000     ; The first possible line number.
  10719.  
  10720.         CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  10721.  
  10722.         RST  28H          ; Find address of line number 0, or the next line if it does not exist.
  10723.         DEFW LINE_ADDR    ; $196E. Return address in HL.
  10724.         RST  28H          ; Find line number for specified address, and return in DE.
  10725.         DEFW LINE_NO      ; $1695. DE=Address of first line in the BASIC program.
  10726.  
  10727.         CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  10728.  
  10729.         LD   ($5C49),DE   ; E_PPC. Store the current line number.
  10730.  
  10731.         LD   A,$0F        ; Paper 1, Ink 7 - Blue.
  10732.         CALL L3A96        ; Set the cursor colour.
  10733.  
  10734.         CALL L152F        ; Relist the BASIC program.
  10735.         SCF               ; Signal do not produce an error beep.
  10736.         JP   L29F2        ; Set attribute at editing position so as to show the cursor, and return.
  10737.  
  10738. ; ----------------------------------
  10739. ; END-OF-PROGRAM Key Handler Routine
  10740. ; ----------------------------------
  10741. ; Move to the last row of the bottom line of the BASIC program. An error beep is not produced if there is no program.
  10742. ;
  10743. ; Symbol:   |  |
  10744. ;          \ /\ /
  10745. ;          ------
  10746. ;
  10747. ; Exit: Carry flag set to indicate not to produce an error beep.
  10748.  
  10749. L29AB:  LD   A,($EC0E)    ; Fetch mode.
  10750.         CP   $04          ; Calculator mode?
  10751.         RET  Z            ; Exit if so.
  10752.  
  10753. ;Editor mode
  10754.  
  10755.         CALL L29EC        ; Remove cursor, restoring old attribute.
  10756.  
  10757.         LD   HL,$270F     ; The last possible line number, 9999.
  10758.  
  10759.         CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  10760.  
  10761.         RST  28H          ; Find address of line number 9999, or the previous line if it does not exist.
  10762.         DEFW LINE_ADDR    ; $196E. Return address in HL.
  10763.  
  10764.         EX   DE,HL        ; DE=Address of last line number.
  10765.  
  10766.         RST  28H          ; Find line number for specified address, and return in DE.
  10767.         DEFW LINE_NO      ; $1695. DE=Address of last line in the BASIC program.
  10768.  
  10769.         CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  10770.  
  10771.         LD   ($5C49),DE   ; E_PPC. Store the current line number.
  10772.  
  10773.         LD   A,$0F        ; Paper 1, Ink 7 - Blue.
  10774.         CALL L3A96        ; Set the cursor colour.
  10775.  
  10776.         CALL L152F        ; Relist the BASIC program.
  10777.         SCF               ; Signal do not produce an error beep.
  10778.         JP   L29F2        ; Set attribute at editing position so as to show the cursor, and return.
  10779.  
  10780. ; -----------------------------
  10781. ; WORD-LEFT Key Handler Routine
  10782. ; -----------------------------
  10783. ; This routine moves to the start of the current word that the cursor is on, or if it is on the first
  10784. ; character of a word then it moves to the start of the previous word. If there is no word to move to
  10785. ; then signal to produce an error beep.
  10786. ;
  10787. ; Symbol: <--
  10788. ;         <--
  10789. ;
  10790. ; Exit: Carry flag reset to indicate to produce an error beep.
  10791.  
  10792. L29D4:  CALL L29EC        ; Remove cursor, restoring old attribute.
  10793.  
  10794.         CALL L2BEA        ; Find start of the current word to the left.
  10795.         JP   NC,L29F2     ; Jump if no word to the left to restore cursor attribute at current editing position, and return.
  10796.                           ; [Could have saved 4 bytes by joining the routine below, i.e. JR $29E7]
  10797.  
  10798.         LD   A,B          ; A=New cursor column number. Carry flag is set indicating not to produce an error beep.
  10799.         JP   L29F8        ; Store editing position and print cursor, and then return.
  10800.  
  10801. ; ------------------------------
  10802. ; WORD-RIGHT Key Handler Routine
  10803. ; ------------------------------
  10804. ; This routine moves to the start of the next word. If there is no word to move to then signal to produce an error beep.
  10805. ;
  10806. ; Symbol: -->
  10807. ;         -->
  10808. ;
  10809. ; Exit: Carry flag reset to indicate to produce an error beep.
  10810.  
  10811. L29E1:  CALL L29EC        ; Remove cursor, restoring old attribute.
  10812.  
  10813.         CALL L2C09        ; Find start of the current word to the right.
  10814.         JR   NC,L29F2     ; Jump if no word to the right to restore cursor attribute at current editing position, and return.
  10815.  
  10816.         LD   A,B          ; A=The new cursor editing column number. Carry is set indicating not to produce an error beep.
  10817.         JR   L29F8        ; Store editing position and print cursor, and then return.
  10818.  
  10819. ; -------------
  10820. ; Remove Cursor
  10821. ; -------------
  10822. ; Remove editing cursor colour from current position.
  10823. ; Exit: C=row number.
  10824. ;       B=Column number.
  10825.  
  10826. L29EC:  CALL L2A07        ; Get current cursor position (C=row, B=column, A=preferred column).
  10827.         JP   L364F        ; Restore previous colour to character square
  10828.  
  10829. ; -----------
  10830. ; Show Cursor
  10831. ; -----------
  10832. ; Set editing cursor colour at current position.
  10833. ; Exit: C=row number.
  10834. ;       B=Column number.
  10835.  
  10836. L29F2:  CALL L2A07        ; Get current cursor position (C=row, B=column, A=preferred column).
  10837.         JP   L3640        ; Set editing position character square to cursor colour to show it.
  10838.                           ; [Could have saved 1 byte by using a JR instruction to join the end of the routine below]
  10839.  
  10840. ; --------------
  10841. ; Display Cursor
  10842. ; --------------
  10843. ; Set editing cursor position and colour and then show it.
  10844. ; Entry: C=Row number.
  10845. ;        B=Column number.
  10846. ;        A=Preferred column number.
  10847.  
  10848. L29F8:  CALL L2A11        ; Store new editing position.
  10849.  
  10850.         PUSH AF           ;
  10851.         PUSH BC           ;
  10852.  
  10853.         LD   A,$0F        ; Paper 1, Ink 7 - Blue.
  10854.         CALL L3A96        ; Store new cursor colour.
  10855.  
  10856.         POP  BC           ;
  10857.         POP  AF           ;
  10858.  
  10859.         JP   L3640        ; Set editing position character square to cursor colour to show it.
  10860.  
  10861. ; ---------------------
  10862. ; Fetch Cursor Position
  10863. ; ---------------------
  10864. ; Returns the three bytes of the cursor position.
  10865. ; Exit : C=Row number.
  10866. ;        B=Column number
  10867. ;        A=Preferred column number.
  10868.  
  10869. L2A07:  LD   HL,$F6EE     ; Editing info.
  10870.         LD   C,(HL)       ; Row number.
  10871.         INC  HL           ;
  10872.         LD   B,(HL)       ; Column number.
  10873.         INC  HL           ;
  10874.         LD   A,(HL)       ; Preferred column number.
  10875.         INC  HL           ;
  10876.         RET               ;
  10877.  
  10878. ; ---------------------
  10879. ; Store Cursor Position
  10880. ; ---------------------
  10881. ; Store new editing cursor position.
  10882. ; Entry: C=Row number.
  10883. ;        B=Column number.
  10884. ;        A=Preferred column number.
  10885.  
  10886. L2A11:  LD   HL,$F6EE     ; Editing information.
  10887.         LD   (HL),C       ; Row number.
  10888.         INC  HL           ;
  10889.         LD   (HL),B       ; Column number.
  10890.         INC  HL           ;
  10891.         LD   (HL),A       ; Preferred column number.
  10892.         RET               ;
  10893.  
  10894. ; --------------------------------------------------
  10895. ; Get Current Character from Screen Line Edit Buffer
  10896. ; --------------------------------------------------
  10897. ; Entry: C=Row number.
  10898. ;        B=Column number.
  10899. ; Exit : A=Character.
  10900.  
  10901. L2A1A:  PUSH HL           ;
  10902.  
  10903.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  10904.         LD   H,$00        ; [Could have saved 2 bytes by calling the unused routine at $2E7B (ROM 0)]
  10905.         LD   L,B          ;
  10906.         ADD  HL,DE        ; Point to the column position within the row.
  10907.         LD   A,(HL)       ; Get character at this position.
  10908.  
  10909.         POP  HL           ;
  10910.         RET               ;
  10911.  
  10912. ; ---------------------------------
  10913. ; TEN-ROWS-DOWN Key Handler Routine
  10914. ; ---------------------------------
  10915. ; Move down 10 rows within the BASIC program, attempting to place the cursor as close to the preferred column number as possible.
  10916. ; An error beep is produced if there is not 10 rows below.
  10917. ;
  10918. ; Symbol:  |  |
  10919. ;         \ /\ /
  10920. ;
  10921. ; Exit: Carry flag reset to indicate to produce an error beep.
  10922.  
  10923. L2A25:  CALL L29EC        ; Remove cursor, restoring old attribute.
  10924.         LD   E,A          ; E=Preferred column.
  10925.  
  10926.         LD   D,$0A        ; The ten lines to move down.
  10927.  
  10928. L2A2B:  PUSH DE           ;
  10929.         CALL L2B30        ; Move down to the next row, shifting rows up as appropriate. If moving onto a new BASIC line then
  10930.         POP  DE           ; insert the previous BASIC line into the BASIC program if it has been altered. Returns new row number in C.
  10931.         JR   NC,L29F2     ; Jump if there was no row below to set attribute at editing position so as to show the cursor, and return.
  10932.  
  10933.         LD   A,E          ; A=Preferred column.
  10934.         CALL L2A11        ; Store cursor editing position.
  10935.  
  10936.         LD   B,E          ; B=Preferred column.
  10937.         CALL L2AF9        ; Find closest Screen Line Edit Buffer editable position to the right else to the left, returning column number in B.
  10938.         JR   NC,L2A42     ; Jump if no editable position found on the row, i.e. a blank row.
  10939.  
  10940.         DEC  D            ; Decrement row counter.
  10941.         JR   NZ,L2A2B     ; Repeat to move down to the next row.
  10942.  
  10943.         LD   A,E          ; A=Preferred column.
  10944.         JR   C,L29F8      ; Jump if editable row exists to store editing position and print cursor, and then return.
  10945.                           ; [Redundant check of the carry flag, should just be JR $29F8 (ROM 0)]
  10946.  
  10947. ;A blank row was found below, must be at the end of the BASIC program
  10948.  
  10949. L2A42:  PUSH DE           ;
  10950.         CALL L2B0B        ; Move back up to the previous row.
  10951.         POP  DE           ;
  10952.  
  10953.         LD   B,E          ; B=Preferred column.
  10954.         CALL L2AF9        ; Find closest Screen Line Edit Buffer editable position to the right else to the left, returning column number in B.
  10955.  
  10956.         LD   A,E          ; A=Preferred column.
  10957.         OR   A            ; Carry will be reset indicating to produce an error beep.
  10958.         JR   L29F8        ; Store editing position and print cursor, and then return.
  10959.  
  10960. ; -------------------------------
  10961. ; TEN-ROWS-UP Key Handler Routine
  10962. ; -------------------------------
  10963. ; Move up 10 rows within the BASIC program, attempting to place the cursor as close to the preferred column number as possible.
  10964. ; An error beep is produced if there is not 10 rows above.
  10965. ;
  10966. ; Symbol: / \/ \
  10967. ;          |  |
  10968. ;
  10969. ; Exit: Carry flag reset to indicate to produce an error beep.
  10970.  
  10971. L2A4F:  CALL L29EC        ; Remove cursor, restoring old attribute.
  10972.         LD   E,A          ; E=Preferred column.
  10973.  
  10974.         LD   D,$0A        ; The ten lines to move up.
  10975.  
  10976. L2A55:  PUSH DE           ;
  10977.         CALL L2B0B        ; Move up to the previous row, shifting rows down as appropriate. If moving onto a new BASIC line then
  10978.         POP  DE           ; insert the previous BASIC line into the BASIC program if it has been altered.
  10979.         JR   NC,L29F2     ; Jump if there was no row above to set cursor attribute colour at existing editing position, and return.
  10980.  
  10981.         LD   A,E          ; A=Preferred column.
  10982.         CALL L2A11        ; Store cursor editing position.
  10983.  
  10984.         LD   B,E          ; B=Preferred column.
  10985.         CALL L2B02        ; Find closest Screen Line Edit Buffer editable position to the left else right, return column number in B.
  10986.         JR   NC,L2A6D     ; Jump if no editable positions were found in the row, i.e. it is a blank row.
  10987.  
  10988.         DEC  D            ; Decrement row counter.
  10989.         JR   NZ,L2A55     ; Repeat to move up to the previous row.
  10990.  
  10991.         LD   A,E          ; A=Preferred column.
  10992.         JP   C,L29F8      ; Jump if editable row exists to store editing position and print cursor, and then return.
  10993.                           ; [Redundant check of the carry flag, should just be JP $29F8 (ROM 0)]
  10994.  
  10995. ;A blank row was found above, must be at the start of the BASIC program [???? Can this ever be the case?]
  10996.  
  10997. L2A6D:  PUSH AF           ; Save the preferred column number and the flags.
  10998.  
  10999.         CALL L2B30        ; Move back down to the next row. Returns new row number in C.
  11000.  
  11001.         LD   B,$00        ; Column 0.
  11002.         CALL L2BD4        ; Find editable position in the Screen Line Edit Buffer row to the right, return column position in B.
  11003.  
  11004.         POP  AF           ; A=Preferred column. Carry will be reset indicating to produce an error beep.
  11005.         JP   L29F8        ; Store editing position and print cursor, and then return.
  11006.  
  11007. ; -------------------------------
  11008. ; END-OF-LINE Key Handler Routine
  11009. ; -------------------------------
  11010. ; Move to the end of the current BASIC line. An error beep is produced if there is no characters in the current BASIC line.
  11011. ;
  11012. ; Symbol: -->|
  11013. ;         -->|
  11014. ;
  11015. ; Exit: Carry flag reset to indicate to produce an error beep and set not to produce an error beep.
  11016.  
  11017. L2A7A:  CALL L29EC        ; Remove cursor, restoring old attribute.
  11018.  
  11019.         CALL L2C4C        ; Find the end of the current BASIC line in the Screen Line Edit Buffer.
  11020.         JP   NC,L29F2     ; Jump if a blank row to set attribute at existing editing position so as to show the cursor, and return.
  11021.  
  11022.         LD   A,B          ; A=The new cursor editing column number. Carry is set indicating not to produce an error beep.
  11023.         JP   L29F8        ; Store editing position and print cursor, and then return.
  11024.  
  11025. ; ---------------------------------
  11026. ; START-OF-LINE Key Handler Routine
  11027. ; ---------------------------------
  11028. ; Move to the start of the current BASIC line. An error beep is produced if there is no characters in the current BASIC line.
  11029. ;
  11030. ; Symbol: |<--
  11031. ;         |<--
  11032. ;
  11033. ; Exit: Carry flag reset to indicate to produce an error beep.
  11034.  
  11035. L2A87:  CALL L29EC        ; Remove cursor, restoring old attribute.
  11036.  
  11037.         CALL L2C31        ; Find the start of the current BASIC line in the Screen Line Edit Buffer.
  11038.         JP   NC,L29F2     ; Jump if a blank row to set attribute at existing editing position so as to show the cursor, and return.
  11039.  
  11040.         LD   A,B          ; A=The new cursor editing position. Carry is set indicating not to produce an error beep.
  11041.         JP   L29F8        ; Store editing position and print cursor, and then return.
  11042.  
  11043. ; -----------------------------
  11044. ; CURSOR-UP Key Handler Routine
  11045. ; -----------------------------
  11046. ; Move up 1 row, attempting to place the cursor as close to the preferred column number as possible.
  11047. ; An error beep is produced if there is no row above.
  11048. ; Exit: Carry flag reset to indicate to produce an error beep.
  11049.  
  11050. L2A94:  CALL L29EC        ; Remove cursor, restoring old attribute.
  11051.  
  11052.         LD   E,A          ; E=Preferred column.
  11053.         PUSH DE           ;
  11054.         CALL L2B0B        ; Move up to the previous row, shifting rows down as appropriate. If moving onto a new BASIC line then
  11055.         POP  DE           ; insert the previous BASIC line into the BASIC program if it has been altered.
  11056.         JP   NC,L29F2     ; Jump if there was no row above to set cursor attribute colour at existing editing position, and return.
  11057.  
  11058.         LD   B,E          ; B=Preferred column.
  11059.         CALL L2B02        ; Find closest Screen Line Edit Buffer editable position to the left else right, return column number in B.
  11060.         LD   A,E          ; A=Preferred column.
  11061.         JP   C,L29F8      ; Jump if an editable position was found to store editing position and print cursor, and then return.
  11062.  
  11063. ;A blank row was found above, must be at the start of the BASIC program [???? Can this ever be the case?]
  11064.  
  11065.         PUSH AF           ; Save the preferred column number and the flags.
  11066.  
  11067.         CALL L2B30        ; Move down to the next row, shifting rows up as appropriate. Returns new row number in C.
  11068.  
  11069.         LD   B,$00        ; Column 0.
  11070.         CALL L2AF9        ; Find closest Screen Line Edit Buffer editable position to the right.
  11071.  
  11072.         POP  AF           ; A=Preferred column. Carry flag is reset indicating to produce an error beep.
  11073.         JP   L29F8        ; Store editing position and print cursor, and then return.
  11074.  
  11075. ; -------------------------------
  11076. ; CURSOR-DOWN Key Handler Routine
  11077. ; -------------------------------
  11078. ; Move down 1 row, attempting to place the cursor as close to the preferred column number as possible.
  11079. ; An error beep is produced if there is no row below.
  11080. ; Exit: Carry flag reset to indicate to produce an error beep.
  11081.  
  11082. L2AB5:  CALL L29EC        ; Remove cursor, restoring old attribute.
  11083.  
  11084.         LD   E,A          ; E=Preferred column.
  11085.         PUSH DE           ;
  11086.         CALL L2B30        ; Move down to the next row, shifting rows up as appropriate. If moving onto a new BASIC line then
  11087.         POP  DE           ; insert the previous BASIC line into the BASIC program if it has been altered. Returns new row number in C.
  11088.         JP   NC,L29F2     ; Jump if there was no row below to set attribute at editing position so as to show the cursor, and return.
  11089.  
  11090.         LD   B,E          ; B=Preferred column.
  11091.         CALL L2B02        ; Find closest Screen Line Edit Buffer editable position to the left else right, return column number in B.
  11092.         LD   A,E          ; A=Preferred column.
  11093.         JP   C,L29F8      ; Jump if an editable position was found to store editing position and print cursor, and then return.
  11094.  
  11095. ;A blank row was found above, must be at the start of the BASIC program [???? Can this ever be the case?]
  11096.  
  11097.         PUSH DE           ; Save the preferred column.
  11098.         CALL L2B0B        ; Move up to the previous row, shifting rows down as appropriate.
  11099.         POP  DE           ;
  11100.  
  11101.         LD   B,E          ; B=Preferred column.
  11102.         CALL L2AF9        ; Find closest Screen Line Edit Buffer editable position to the right else to the left, returning column number in B.
  11103.  
  11104.         LD   A,E          ; A=Preferred column.
  11105.         OR   A            ; Reset carry flag to indicate to produce an error beep.
  11106.         JP   L29F8        ; Store editing position and print cursor, and then return.
  11107.  
  11108. ; -------------------------------
  11109. ; CURSOR-LEFT Key Handler Routine
  11110. ; -------------------------------
  11111. ; Move left 1 character, stopping if the start of the first row of the first BASIC line is reached.
  11112. ; An error beep is produced if there is no character to the left or no previous BASIC line to move to.
  11113. ; Exit: Carry flag reset to indicate to produce an error beep.
  11114.  
  11115. L2AD7:  CALL L29EC        ; Remove cursor, restoring old attribute. Returns with C=row, B=column.
  11116.  
  11117.         CALL L2B5B        ; Find next Screen Line Edit Buffer editable position to left, wrapping to previous row as necessary.
  11118.         JP   C,L29F8      ; Jump if editable position found to store editing position and print cursor, and then return.
  11119.  
  11120. ;A blank row was found above, must be at the start of the BASIC program
  11121.  
  11122.         JP   L29F2        ; Set cursor attribute at existing editing position, and return. Carry flag is reset indicating to produce an error beep.
  11123.  
  11124. ; --------------------------------
  11125. ; CURSOR-RIGHT Key Handler Routine
  11126. ; --------------------------------
  11127. ; Move right 1 character, stopping if the end of the last row of the last BASIC line is reached.
  11128. ; An error beep is produced if there is no character to the right or no next BASIC line to move to.
  11129. ; Exit: Carry flag reset to indicate to produce an error beep.
  11130.  
  11131. L2AE3:  CALL L29EC        ; Remove cursor, restoring old attribute.
  11132.  
  11133.         CALL L2B78        ; Find next Screen Line Edit Buffer editable position to right, wrapping to next row if necessary.
  11134.         JP   C,L29F8      ; Jump if editable position found to store editing position and print cursor, and then return.
  11135.  
  11136. ;A blank row was found below, must be at the end of the BASIC program
  11137.  
  11138.         PUSH AF           ; Save the carry flag and preferred column number.
  11139.  
  11140.         CALL L2B0B        ; Move up to the previous row, shifting rows down as appropriate.
  11141.  
  11142.         LD   B,$1F        ; Column 31.
  11143.         CALL L2BDF        ; Find the last editable column position searching to the left, returning the column number in B. (Returns carry flag set if there is one)
  11144.                           ;
  11145.         POP  AF           ; Carry flag is reset indicating to produce an error beep.
  11146.         JP   L29F8        ; Store editing position and print cursor, and then return.
  11147.  
  11148.  
  11149. ; =============================
  11150. ; Edit Buffer Routines - Part 1
  11151. ; =============================
  11152.  
  11153. ; -----------------------------------------------------------------------------
  11154. ; Find Closest Screen Line Edit Buffer Editable Position to the Right else Left
  11155. ; -----------------------------------------------------------------------------
  11156. ; This routine searches the specified Screen Line Edit Buffer row from the specified column to the right
  11157. ; looking for the first editable position. If one cannot be found then a search is made to the left.
  11158. ; Entry: B=Column number.
  11159. ; Exit : Carry flag set if character at specified column is editable.
  11160. ;        B=Number of closest editable column.
  11161. ;        HL=Address of closest editable position.
  11162.  
  11163. L2AF9:  PUSH DE           ;
  11164.  
  11165.         CALL L2BD4        ; Find Screen Line Edit Buffer editable position from previous column (or current column if the previous column does not exist) to the right, return column position in B.
  11166.         CALL NC,L2BDF     ; If no editable character found then search to the left for an editable character, return column position in B.
  11167.  
  11168.         POP  DE           ;
  11169.         RET               ;
  11170.  
  11171. ; -----------------------------------------------------------------------------
  11172. ; Find Closest Screen Line Edit Buffer Editable Position to the Left else Right
  11173. ; -----------------------------------------------------------------------------
  11174. ; This routine searches the specified Screen Line Edit Buffer row from the specified column to the left
  11175. ; looking for the first editable position. If one cannot be found then a search is made to the right.
  11176. ; Entry: B=Column number.
  11177. ; Exit : Carry flag set if character at specified column is editable.
  11178. ;        B=Number of closest editable column.
  11179. ;        HL=Address of closest editable position.
  11180.  
  11181. L2B02:  PUSH DE           ;
  11182.  
  11183.         CALL L2BDF        ; Find Screen Line Edit Buffer editable position to the left, returning column position in B.
  11184.         CALL NC,L2BD4     ; If no editable character found then search from previous column (or current column if the previous column does not exist) to the right, return column position in B.
  11185.  
  11186.         POP  DE           ;
  11187.         RET               ;
  11188.  
  11189. ; ----------------------------------------------------------------------------------------------
  11190. ; Insert BASIC Line, Shift Edit Buffer Rows Down If Required and Update Display File If Required
  11191. ; ----------------------------------------------------------------------------------------------
  11192. ; Called from the cursor up and down related key handlers. For example, when cursor up key is pressed the current
  11193. ; BASIC line may need to be inserted into the BASIC program if it has been altered. It may also be necessary
  11194. ; to shift all rows down should the upper scroll threshold be reached. If the cursor was on a blank row between BASIC
  11195. ; lines then it is necessary to shift all BASIC lines below it up, i.e. remove the blank row.
  11196. ; Entry: C=Current cursor row number in the Screen Line Edit Buffer.
  11197. ; Exit : C=New cursor row number in the Screen Line Edit Buffer.
  11198. ;        Carry flag set if a new row was moved to.
  11199.  
  11200. L2B0B:  CALL L2C7C        ; If current BASIC line has been altered and moved off of then insert it into the program.
  11201.         JR   NC,L2B2F     ; Jump if BASIC line was not inserted. [Could have saved 1 byte by using RET NC]
  11202.  
  11203.         PUSH BC           ; Save the new cursor row and column numbers.
  11204.  
  11205.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  11206.         LD   B,$00        ; Column 0.
  11207.         CALL L2E41        ; Is this a blank row? i.e. Find editable position on this row to the right, returning column number in B.
  11208.         CALL NC,L2F80     ; If no editable position found then the cursor is on a blank row so shift all BASIC lines below it up to close the gap.
  11209.  
  11210.         POP  BC           ; Retrieve the new cursor row and column numbers.
  11211.  
  11212.         LD   HL,$F6F1     ; Point to the editing area information.
  11213.         LD   A,(HL)       ; Fetch the upper scroll threshold.
  11214.         CP   C            ; Is it on the threshold?
  11215.         JR   C,L2B2D      ; Jump if on a row below the threshold.
  11216.  
  11217. ;The upper row threshold for triggering scrolling the screen has been reached so proceed to scroll down one row
  11218.  
  11219.         PUSH BC           ; Save the new cursor row and column numbers.
  11220.         CALL L166F        ; Shift all edit buffer rows down, and update display file if required.
  11221.         POP  BC           ;
  11222.         RET  C            ; Return if edit buffer rows were shifted.
  11223.  
  11224. ;The edit buffer rows were not shifted down
  11225.  
  11226.         LD   A,C          ; On the top row of the editing area?
  11227.         OR   A            ;
  11228.         RET  Z            ; Return with carry flag reset if on the top row.
  11229.  
  11230. L2B2D:  DEC  C            ; Move onto the previous row.
  11231.         SCF               ; Signal a new row was moved to.
  11232.  
  11233. L2B2F:  RET               ;
  11234.  
  11235. ; --------------------------------------------------------------------------------------------
  11236. ; Insert BASIC Line, Shift Edit Buffer Rows Up If Required and Update Display File If Required
  11237. ; --------------------------------------------------------------------------------------------
  11238. ; Called from the cursor up and down related key handlers. For example, when cursor down key is pressed the current
  11239. ; BASIC line may need to be inserted into the BASIC program if it has been altered. It may also be necessary
  11240. ; to shift all rows up should the lower scroll threshold be reached. If the cursor was on a blank row between BASIC
  11241. ; lines then it is necessary to shift all BASIC lines below it up, i.e. remove the blank row.
  11242. ; Entry: C=Current cursor row number in the Screen Line Edit Buffer.
  11243. ; Exit : C=New cursor row number in the Screen Line Edit Buffer.
  11244. ;        Carry flag set if a new row was moved to.
  11245.  
  11246. L2B30:  PUSH BC           ; Save row number.
  11247.  
  11248.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of row held in C, i.e. the new cursor row.
  11249.         LD   B,$00        ; Column 0.
  11250.         CALL L2E41        ; Is this a blank row? i.e. Find editable position on this row to the right, returning column number in B.
  11251.  
  11252.         POP  BC           ; Get row number.
  11253.         JR   C,L2B3F      ; Jump if editable position found, i.e. the row exists. [Could have saved 2 bytes by using JP NC,$2F80 (ROM 0)]
  11254.  
  11255.         JP   L2F80        ; Cursor is on a blank row so shift all BASIC lines below it up to close the gap.
  11256.  
  11257. L2B3F:  CALL L2C68        ; Insert the BASIC Line into the BASIC program if the line has been altered.
  11258.         JR   NC,L2B5A     ; Jump if the line was inserted into the program. [Could have saved 1 byte by using RET NC]
  11259.  
  11260. ;The BASIC line was not inserted into the program. C=New cursor row number, B=New cursor column number, A=New cursor preferred column number
  11261.  
  11262.         LD   HL,$F6F1     ; Point to the editing area information.
  11263.         INC  HL           ; Point to the 'Bottom Row Scroll Threshold' value. [Could have saved 1 byte by using LD HL,$F6F2]
  11264.         LD   A,C          ; Fetch the new cursor row number.
  11265.         CP   (HL)         ; Is it on the lower scroll threshold?
  11266.         JR   C,L2B58      ; Jump if on a row above the threshold.
  11267.  
  11268. ;The lower row threshold for triggering scrolling the screen has been reached so proceed to scroll up one row
  11269.  
  11270.         PUSH BC           ; Save the new cursor row and column numbers.
  11271.         PUSH HL           ; Save the editing area information address.
  11272.         CALL L1639        ; Shift all edit buffer rows up, and update display file if required.
  11273.         POP  HL           ;
  11274.         POP  BC           ;
  11275.         RET  C            ; Return if edit buffer rows were shifted.
  11276.  
  11277. ;The edit buffer rows were not shifted up
  11278.  
  11279.         INC  HL           ; Point to the 'Number of Rows in the Editing Area' value.
  11280.         LD   A,(HL)       ; A=Number of rows in the editing area.
  11281.         CP   C            ; On the last row of the editing area?
  11282.         RET  Z            ; Return with carry flag reset if on the bottom row.
  11283.  
  11284. L2B58:  INC  C            ; Move onto the next row.
  11285.         SCF               ; Signal a new row was moved to.
  11286.  
  11287. L2B5A:  RET               ;
  11288.  
  11289. ; ---------------------------------------------------------------------------------------
  11290. ; Find Next Screen Line Edit Buffer Editable Position to Left, Wrapping Above if Required
  11291. ; ---------------------------------------------------------------------------------------
  11292. ; This routine searches to the left to see if an editable position exists. If there is no editable position
  11293. ; available to the left on the current row then the previous row is examined from the last column position.
  11294. ; Entry: B=Column number.
  11295. ;        Carry flag reset.
  11296. ; Exit : Carry flag set if a position to the 'left' exists.
  11297. ;        B=Number of new editable position.
  11298. ;        HL=Address of new editable position.
  11299.  
  11300. L2B5B:  LD   D,A          ; Save the key code character.
  11301.  
  11302.         DEC  B            ; Back one column position.
  11303.         JP   M,L2B66      ; Jump if already at beginning of row.
  11304.  
  11305.         LD   E,B          ; E=Column number.
  11306.         CALL L2BDF        ; Find Screen Line Edit Buffer editable position to the left, returning column position in B.
  11307.         LD   A,E          ; A=Column number.
  11308.         RET  C            ; Return if the new column is editable, i.e. the cursor can be moved within this row.
  11309.  
  11310. ;Wrap above to the previous row
  11311.  
  11312. L2B66:  PUSH DE           ; E=Store the column number.
  11313.         CALL L2B0B        ; Move up to the previous row, shifting rows down as appropriate. If moving onto a new BASIC line then
  11314.         POP  DE           ; insert the previous BASIC line into the BASIC program if it has been altered.
  11315.         LD   A,E          ; A=Column number.
  11316.         RET  NC           ; Return if there was no row above.
  11317.  
  11318. ;A row above exists
  11319.  
  11320.         LD   B,$1F        ; Column 31.
  11321.         CALL L2BDF        ; Find the last editable column position searching to the left, returning the column number in B. (Returns carry flag set if there is one)
  11322.         LD   A,B          ; A=Column number of the closest editable position.
  11323.         RET  C            ; Return if an editable position was found, i.e. the cursor can be moved.
  11324.  
  11325. ;Return column 0
  11326.  
  11327.         LD   A,D          ; Restore the key code character.
  11328.         LD   B,$00        ; Set column position 0.
  11329.         RET               ; [*BUG* - This should really ensure the carry flag is reset to signal that no editable position to the left exists, e.g. by using OR A.
  11330.                           ; Fortunately, the carry flag is always reset when this routine is called and so the bug is harmless. Credit: Paul Farrow]
  11331.  
  11332. ; ----------------------------------------------------------------------------------------
  11333. ; Find Next Screen Line Edit Buffer Editable Position to Right, Wrapping Below if Required
  11334. ; ----------------------------------------------------------------------------------------
  11335. ; This routine searches to the right to see if an editable position exists. If there is no editable position
  11336. ; available to the right on the current row then the next row is examined from the first column position.
  11337. ; The routine is also called when a character key has been pressed and in this case if the cursor moves to the next
  11338. ; row then a blank row is inserted and all affected rows are shifted down.
  11339. ; Entry: B=Column number.
  11340. ;        C=Row number.
  11341. ; Exit : Carry flag set if a position to the 'right' exists.
  11342. ;        B=Number of closest editable column, i.e. new column number.
  11343. ;        A=New column position, i.e. preferred column number or indentation column number.
  11344. ;        HL=Address of the new editable position.
  11345.  
  11346. L2B78:  LD   D,A          ; Save the key code character.
  11347.  
  11348.         INC  B            ; Advance to the next column position.
  11349.         LD   A,$1F        ; Column 31.
  11350.         CP   B            ;
  11351.         JR   C,L2B85      ; Jump if reached end of row.
  11352.  
  11353. ;New position is within the row
  11354.  
  11355.         LD   E,B          ; E=New column number.
  11356.         CALL L2BD4        ; Find Screen Line Edit Buffer editable position from previous column to the right, returning column position in B.
  11357.         LD   A,E          ; A=New column number.
  11358.         RET  C            ; Return if the new column is editable, i.e. the cursor can be moved within this row.
  11359.  
  11360. ;Need to wrap below to the next row
  11361.  
  11362. L2B85:  DEC  B            ; B=Original column position.
  11363.         PUSH BC           ; Save original column and row numbers.
  11364.         PUSH HL           ; HL=Address of the new editable position.
  11365.  
  11366.         LD   HL,$EC0D     ; Editor flags.
  11367.         BIT  7,(HL)       ; Got a key press?
  11368.         JR   NZ,L2BC0     ; Jump if not.
  11369.  
  11370. ;A key is being pressed so need to insert a new row
  11371.  
  11372.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  11373.         LD   HL,$0020     ;
  11374.         ADD  HL,DE        ; Point to the flag byte for the current row.
  11375.         LD   A,(HL)       ;
  11376.         BIT  1,A          ; Does the BASIC line row span onto another row?
  11377.         JR   NZ,L2BC0     ; Jump if so to test the next row (it could just be the cursor).
  11378.  
  11379. ;The BASIC line row does not span onto another row, i.e. cursor at end of line
  11380.  
  11381.         SET  1,(HL)       ; Signal that the row spans onto another row, i.e. a new blank row containing the cursor.
  11382.         RES  3,(HL)       ; Signal that the row is not the last row of the BASIC line.
  11383.  
  11384.         LD   HL,$0023     ; Point to the next row.
  11385.         ADD  HL,DE        ;
  11386.         EX   DE,HL        ; DE=Address of the next row. [Redundant calculation as never used. Could have saved 5 bytes]
  11387.  
  11388.         POP  HL           ; HL=Address of the new editable position.
  11389.         POP  BC           ; B=Original column number. C=Row number.
  11390.  
  11391.         PUSH AF           ; Save flag byte for the previous row.
  11392.         CALL L2B30        ; Move down to the next row, shifting rows up as appropriate. Returns new row number in C.
  11393.         POP  AF           ; Retrieve flag byte for the previous row.
  11394.  
  11395.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the new row, as specified in C.
  11396.  
  11397.         LD   HL,$0023     ;
  11398.         ADD  HL,DE        ; HL=Address of the row after the new row.
  11399.         EX   DE,HL        ; DE=Address of the row after the new row. HL=Address of the new row.
  11400.  
  11401.         RES  0,A          ; Signal 'not the start row of the BASIC line'.
  11402.         SET  3,A          ; Signal 'end row of the BASIC line'.
  11403.  
  11404.         CALL L2ED3        ; Insert a blank row into the Screen Edit Buffer at row specified by C, shifting rows down.
  11405.  
  11406. ; [*BUG* - When typing a line that spills over onto a new row, the new row needs to be indented. However, instead of the newly inserted
  11407. ;          row being indented, it is the row after it that gets indented. The indentation occurs within the Screen Line Edit Buffer and is not
  11408. ;          immediately reflected in the display file. When the newly typed line is executed or inserted into the program area, the Screen Line Edit Buffer
  11409. ;          gets refreshed and hence the effect of the bug is never normally seen. The bug can be fixed by inserting the following instructions. Credit: Paul Farrow.
  11410. ;
  11411. ;       LD   HL,$FFDD     ; -35.
  11412. ;       ADD  HL,DE
  11413. ;       EX   DE,HL        ; DE=Points to the start of the previous row.]
  11414.  
  11415.         CALL L35F4        ; Indent the row by setting the appropriate number of null characters in the current Screen Line Edit Buffer row.
  11416.  
  11417.         LD   A,B          ; A=First column after indentation.
  11418.         SCF               ; Signal not to produce an error beep.
  11419.         RET               ;
  11420.  
  11421. ;Wrap below to the next row. Either a key was not being pressed, or a key was being pressed and the BASIC line spans onto a row below (which could contain the cursor only)
  11422.  
  11423. L2BC0:  POP  HL           ; HL=Address of the new editable position.
  11424.         POP  BC           ; B=Original column position.
  11425.  
  11426.         PUSH DE           ; E=New column number.
  11427.         CALL L2B30        ; Move down to the next row, shifting rows up as appropriate. If moving onto a new BASIC line then
  11428.         POP  DE           ; insert the previous BASIC line into the BASIC program if it has been altered. Returns new row number in C.
  11429.         LD   A,B          ; A=Original column position.
  11430.         RET  NC           ; Return if there was no row below.
  11431.  
  11432. ;A row below exists
  11433.  
  11434.         LD   B,$00        ; Column 0.
  11435.         CALL L2BD4        ; Find Screen Line Edit Buffer editable position to the right, returning column position in B.
  11436.         LD   A,B          ; A=New column position.
  11437.         RET  C            ; Return if an editable position was found, i.e. the cursor can be moved.
  11438.  
  11439. ;Return column 0
  11440.  
  11441.         LD   A,E          ; A=Preferred column number.
  11442.         LD   B,$00        ; Column 0.
  11443.         RET               ; Return with carry flag reset.
  11444.  
  11445. ; --------------------------------------------------------------------------------
  11446. ; Find Screen Line Edit Buffer Editable Position from Previous Column to the Right
  11447. ; --------------------------------------------------------------------------------
  11448. ; This routine finds the first editable character position in the specified Screen Line Edit Buffer row from the previous column to the right.
  11449. ; It first checks the current column, then the previous column and then the columns to the right. The column containing the first non-null
  11450. ; character encountered is returned.
  11451. ; Entry: B=Column number to start searching from.
  11452. ;        C=Row number.
  11453. ; Exit : Carry flag set if an editable character was found.
  11454. ;        B=Number of closest editable column.
  11455.  
  11456. L2BD4:  PUSH DE           ; Save registers.
  11457.         PUSH HL           ;
  11458.  
  11459.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  11460.         CALL L2E41        ; Find editable position on this row from the previous column to the right, returning column number in B.
  11461.  
  11462.         JP   L2C65        ; Restore registers and return. [Could have saved a byte by using JR $2C07 (ROM 0)]
  11463.  
  11464. ; ----------------------------------------------------------
  11465. ; Find Screen Line Edit Buffer Editable Position to the Left
  11466. ; ----------------------------------------------------------
  11467. ; This routine finds the first editable character position in the Screen Line Edit Buffer row from the current column to the left.
  11468. ; It first checks the current column and returns this if it contains an editable character. Otherwise it searches the columns to
  11469. ; the left and if an editable character is found then it returns the column to the right of it.
  11470. ; Entry: B=Column number to start searching from.
  11471. ;        C=Row number.
  11472. ; Exit : Carry flag set if an editable character was found.
  11473. ;        B=Number of the column after the editable position.
  11474.  
  11475. L2BDF:  PUSH DE           ; Save registers.
  11476.         PUSH HL           ;
  11477.  
  11478.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  11479.         CALL L2E63        ; Find editable position from current column to the left, returning the column number in B.
  11480.  
  11481.         JP   L2C65        ; Restore registers and return. [Could have saved a byte by using JR $2C07 (ROM 0)]
  11482.  
  11483. ; -----------------------------------------------------
  11484. ; Find Start of Word to Left in Screen Line Edit Buffer
  11485. ; -----------------------------------------------------
  11486. ; This routine searches for the start of the current word to the left within the current Screen Line Edit Buffer.
  11487. ; It is called from the WORD-LEFT key handler routine.
  11488. ; Entry: C=Row number.
  11489. ; Exit : Carry flag set if word to the left is found.
  11490. ;        B=Column position of the found word.
  11491.  
  11492. L2BEA:  PUSH DE           ; Save registers.
  11493.         PUSH HL           ;
  11494.  
  11495. ;Search towards the left of this row until a space or start of line is found
  11496.  
  11497. L2BEC:  CALL L2B5B        ; Find next Screen Line Edit Buffer editable position to left, moving to next row if necessary.
  11498.         JR   NC,L2C07     ; Jump if not editable, i.e. at start of line.
  11499.  
  11500. L2BF1:  CALL L2A1A        ; Get character at new position.
  11501.         CP   ' '          ; $20. Is it a space?
  11502.         JR   Z,L2BEC      ; Jump back if it is, until a non-space or start of line is found.
  11503.  
  11504. ;Search towards the left of this row until the start of the word or start of the line is found
  11505.  
  11506. L2BF8:  CALL L2B5B        ; Find next Screen Line Edit Buffer editable position to left, moving to next row if necessary.
  11507.         JR   NC,L2C07     ; Jump if not editable, i.e. at start of line.
  11508.  
  11509.         CALL L2A1A        ; Get character at new position.
  11510.         CP   ' '          ; $20. Is it a space?
  11511.         JR   NZ,L2BF8     ; Jump back if it is not, until a space or start of line is found.
  11512.  
  11513. ;A space prior to the word was found
  11514.  
  11515.         CALL L2B78        ; Find next Screen Line Edit Buffer editable position to right to start of the word, moving to next row if necessary.
  11516.                           ; [Returns carry flag set since the character will exist]
  11517.  
  11518. L2C07:  JR   L2C65        ; Jump forward to restore registers and return.
  11519.  
  11520. ; ------------------------------------------------------
  11521. ; Find Start of Word to Right in Screen Line Edit Buffer
  11522. ; ------------------------------------------------------
  11523. ; This routine searches for the start of the current word to the right within the current Screen Line Edit Buffer.
  11524. ; It is called from the WORD-RIGHT key handler routine.
  11525. ; Entry: C=Row number.
  11526. ; Exit : Carry flag set if word to the right is found.
  11527. ;        B=Column position of the found word.
  11528.  
  11529. L2C09:  PUSH DE           ; Save registers.
  11530.         PUSH HL           ;
  11531.  
  11532. ;Search towards the right of this row until a space or end of line is found
  11533.  
  11534. L2C0B:  CALL L2B78        ; Find next Screen Line Edit Buffer editable position to right, moving to next row if necessary.
  11535.         JR   NC,L2C2B     ; Jump if none editable, i.e. at end of line.
  11536.  
  11537.         CALL L2A1A        ; Get character at new position.
  11538.         CP   ' '          ; $20. Is it a space?
  11539.         JR   NZ,L2C0B     ; Jump back if it is not, until a space or end of line is found.
  11540.  
  11541. ;Search towards the right of this row until the start of a new word or end of the line is found
  11542.  
  11543. L2C17:  CALL L2B78        ; Find next Screen Line Edit Buffer editable position to right, moving to next row if necessary.
  11544.         JR   NC,L2C2B     ; Jump if none editable, i.e. at end of line.
  11545.  
  11546.         CALL L2E41        ; Find editable position on this row from the previous column to the right, returning column number in B.
  11547.         JR   NC,L2C2B     ; Jump if none editable, i.e. at start of next line.
  11548.  
  11549.         CALL L2A1A        ; Get character at new position.
  11550.         CP   ' '          ; $20. Is it a space?
  11551.         JR   Z,L2C17      ; Loop back until a non-space is found, i.e. start of a word.
  11552.  
  11553. ;Start of new word found
  11554.  
  11555.         SCF               ; Indicate cursor position can be moved.
  11556.         JR   L2C65        ; Jump forward to restore registers and return.
  11557.  
  11558. ;End of line or start of next line was found
  11559.  
  11560. L2C2B:  CALL NC,L2B5B     ; If no word on this row then find next Screen Line Edit Buffer editable position to left,
  11561.                           ; moving to previous row if necessary thereby restoring the row number to its original value.
  11562.                           ; [Carry flag is always reset by here so the test on the flag is unnecessary]
  11563.         OR   A            ; Clear carry flag to indicate cursor position can not be moved.
  11564.         JR   L2C65        ; Jump forward to restore registers and return.
  11565.  
  11566. ; -----------------------------------------------------------
  11567. ; Find Start of Current BASIC Line in Screen Line Edit Buffer
  11568. ; -----------------------------------------------------------
  11569. ; This routine searches for the start of the BASIC line, wrapping
  11570. ; to the previous rows as necessary.
  11571. ; It is called from the START-OF-LINE key handler routine.
  11572. ; Entry: C=Row number.
  11573. ; Exit : Carry flag set if row is not blank.
  11574. ;        B=New cursor column.
  11575.  
  11576. L2C31:  PUSH DE           ; Save registers.
  11577.         PUSH HL           ;
  11578.  
  11579. L2C33:  CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  11580.         LD   HL,$0020     ;
  11581.         ADD  HL,DE        ; Point to flag byte of next row.
  11582.         BIT  0,(HL)       ; On first row of the BASIC line?
  11583.         JR   NZ,L2C45     ; Jump if on the first row of the BASIC line.
  11584.  
  11585. ;Not on the first row of the BASIC line
  11586.  
  11587.         CALL L2B0B        ; Move up to the previous row, shifting rows down as appropriate. If moving onto a new BASIC line then
  11588.                           ; insert the previous BASIC line into the BASIC program if it has been altered.
  11589.         JR   C,L2C33      ; Jump back if still on the same BASIC line, i.e. was not on first row of the BASIC line.
  11590.  
  11591.         JR   L2C65        ; Jump forward to restore registers and return.
  11592.  
  11593. ;On the first row of the BASIC line, so find the starting column
  11594.  
  11595. L2C45:  LD   B,$00        ; Column 0.
  11596.         CALL L2BD4        ; Find Screen Line Edit Buffer editable position to the right, return column position in B. (Returns carry flag reset if blank row)
  11597.         JR   L2C65        ; Jump forward to restore registers and return.
  11598.  
  11599. ; ---------------------------------------------------------
  11600. ; Find End of Current BASIC Line in Screen Line Edit Buffer
  11601. ; ---------------------------------------------------------
  11602. ; This routine searches for the end of the BASIC line, wrapping
  11603. ; to the next rows as necessary.
  11604. ; It is called from the END-OF-LINE key handler routine.
  11605. ; Entry: C=Row number.
  11606. ; Exit : Carry flag set if row is not blank.
  11607. ;        B=New cursor column.
  11608.  
  11609. L2C4C:  PUSH DE           ; Save registers.
  11610.         PUSH HL           ;
  11611.  
  11612. L2C4E:  CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  11613.         LD   HL,$0020     ;
  11614.         ADD  HL,DE        ; Point to flag byte of next row.
  11615.         BIT  3,(HL)       ; On last row of the BASIC line?
  11616.         JR   NZ,L2C60     ; Jump if on the last row of the BASIC line.
  11617.  
  11618. ;Not on the last row of the BASIC line
  11619.  
  11620.         CALL L2B30        ; Move down to the next row, shifting rows up as appropriate. If moving onto a new BASIC line then
  11621.                           ; insert the previous BASIC line into the BASIC program if it has been altered. Returns new row number in C.
  11622.         JR   C,L2C4E      ; Jump back if still on the same BASIC line, i.e. was not on last row of the BASIC line.
  11623.  
  11624.         JR   L2C65        ; Jump forward to restore registers and return.
  11625.  
  11626. ;On the last row of the BASIC line, so find the last column
  11627.  
  11628. L2C60:  LD   B,$1F        ; Column 31.
  11629.         CALL L2BDF        ; Find the last editable column position searching to the left, returning the column number in B. (Returns carry flag reset if blank row)
  11630.  
  11631. L2C65:  POP  HL           ; Restore registers.
  11632.         POP  DE           ;
  11633.         RET               ;
  11634.  
  11635. ; -----------------------------------------
  11636. ; Insert BASIC Line into Program if Altered
  11637. ; -----------------------------------------
  11638. ; Entry: C=Row number.
  11639. ; Exit : Carry flag set if BASIC line was not inserted into the program.
  11640.  
  11641. L2C68:  LD   A,($EC0D)    ; Editor flags.
  11642.         BIT  3,A          ; Has the current line been altered?
  11643.         SCF               ; Signal line not inserted into BASIC program.
  11644.         RET  Z            ; Return if it has not.
  11645.  
  11646.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  11647.         LD   HL,$0020     ;
  11648.         ADD  HL,DE        ; HL points to the flag byte for the row.
  11649.         BIT  3,(HL)       ; Is this the end of the BASIC line?
  11650.         SCF               ; Signal line not inserted into BASIC program.
  11651.         RET  Z            ; Return if it is not.
  11652.  
  11653.         JR   L2C8E        ; Insert line into BASIC program.
  11654.  
  11655. ; -----------------------------------------------------------------------
  11656. ; Insert Line into BASIC Program If Altered and the First Row of the Line
  11657. ; -----------------------------------------------------------------------
  11658. ; Entry: C=Row number.
  11659. ;        B=Column number.
  11660. ; Exit : Carry flag set if successful, reset if a syntax error.
  11661.  
  11662. L2C7C:  LD   A,($EC0D)    ; Editor flags.
  11663.         BIT  3,A          ; Has current line been altered?
  11664.         SCF               ; Signal success.
  11665.         RET  Z            ; Return if it has not.
  11666.  
  11667.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  11668.         LD   HL,$0020     ;
  11669.         ADD  HL,DE        ; Point to the flag byte for the row.
  11670.         BIT  0,(HL)       ; Is this the first row of the BASIC line?
  11671.         SCF               ; Signal success.
  11672.         RET  Z            ; Return if it is not.
  11673.  
  11674. ; ------------------------------
  11675. ; Insert Line into BASIC Program
  11676. ; ------------------------------
  11677. ; This routine parses a line and if valid will insert it into the BASIC program. If in calculator mode
  11678. ; then the line is not inserted into the BASIC program. If a syntax error is found then the location to
  11679. ; show the error marker is determined.
  11680. ; Entry: C=Row number.
  11681. ; Exit : Carry flag reset if a syntax error.
  11682. ;        Carry flag set if the BASIC line was inserted successfully, and C=Cursor row number, B=Cursor column number, A=Preferred cursor column number.
  11683.  
  11684. L2C8E:  LD   A,$02        ; Signal on first row of BASIC line.
  11685.  
  11686. ;Find the start address of the row in the Screen Line Edit Buffer
  11687.  
  11688. L2C90:  CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  11689.         LD   HL,$0020     ;
  11690.         ADD  HL,DE        ; Point to the flag byte for the row.
  11691.         BIT  0,(HL)       ; First row of the BASIC line?
  11692.         JR   NZ,L2CA3     ; Jump ahead if so.
  11693.  
  11694.         DEC  C            ; Move to previous row.
  11695.         JP   P,L2C90      ; Jump back until found the first row of the BASIC line or the top of the screen.
  11696.  
  11697. ;First row of the BASIC line is above the screen
  11698.  
  11699.         LD   C,$00        ; Row 0.
  11700.         LD   A,$01        ; Signal first row of BASIC line above screen.
  11701.  
  11702. ;DE=Start address of the first row of the BASIC line
  11703. ;HL=Address of the flag byte for the first row of the BASIC line
  11704.  
  11705. L2CA3:  LD   HL,$EC00     ; BASIC line insertion flags.
  11706.         LD   DE,$EC03     ; BASIC line insertion error flags.
  11707.         OR   $80          ; Signal location of cursor not yet found.
  11708.         LD   (HL),A       ;
  11709.         LD   (DE),A       ;
  11710.  
  11711.         INC  HL           ;
  11712.         INC  DE           ;
  11713.         LD   A,$00        ; [Could have saved 1 byte by using XOR A]
  11714.         LD   (HL),A       ; Starting column number of the first visible row of the BASIC line being entered.
  11715.         LD   (DE),A       ;
  11716.  
  11717.         INC  HL           ;
  11718.         INC  DE           ;
  11719.         LD   A,C          ; Fetch the row number of the first visible row of the BASIC line being entered.
  11720.         LD   (HL),A       ; Store the start row number of the first visible row of the BASIC line being entered.
  11721.         LD   (DE),A       ;
  11722.  
  11723.         LD   HL,$0000     ;
  11724.         LD   ($EC06),HL   ; No editable characters in the line prior to the cursor.
  11725.  
  11726.         CALL L335F        ; Copy 'Insert Keyword Representation Into Keyword Construction Buffer' routine to RAM.
  11727.         CALL L3C67        ; Tokenize the typed BASIC line.
  11728.  
  11729.         PUSH IX           ; IX=Address of cursor settings.
  11730.  
  11731.         CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  11732.         CALL L026B        ; Syntax check/execute the command line.
  11733.         CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  11734.  
  11735.         POP  IX           ; IX=Address of cursor settings.
  11736.  
  11737.         LD   A,($5C3A)    ; ERR_NR. Fetch error code.
  11738.         INC  A            ; Was an error code set?
  11739.         JR   NZ,L2CEF     ; Jump ahead if so.
  11740.  
  11741.         LD   HL,$EC0D     ; Editor flags.
  11742.         RES  3,(HL)       ; Signal line has not been altered.
  11743.  
  11744.         CALL L365E        ; Reset to 'L' Mode.
  11745.  
  11746.         LD   A,($EC0E)    ; Fetch mode.
  11747.         CP   $04          ; Calculator mode?
  11748.         CALL NZ,L152F     ; If not calculator mode then relist the BASIC program.
  11749.  
  11750.         CALL L26FA        ; Produce success beep.
  11751.         CALL L2A07        ; Get current cursor position (C=Row, B=Column, A=Preferred column).
  11752.  
  11753.         SCF               ; Set the carry flag to signal that that BASIC line was inserted successfully.
  11754.         RET               ;
  11755.  
  11756. ; A syntax error occurred
  11757. ; -----------------------
  11758.  
  11759. L2CEF:  LD   HL,$EC00     ; BASIC line insertion flags.
  11760.         LD   DE,$EC03     ; BASIC line insertion error flags.
  11761.         LD   A,(DE)       ; Fetch the BASIC line insertion error flags.
  11762.         RES  7,A          ; Signal location of cursor found.
  11763.         LD   (HL),A       ; Update the BASIC line insertion flags with the error flags.
  11764.  
  11765.         INC  HL           ;
  11766.         INC  DE           ;
  11767.         LD   A,(DE)       ;
  11768.         LD   (HL),A       ; Restore the initial column number, i.e. column 0.
  11769.  
  11770.         INC  HL           ;
  11771.         INC  DE           ;
  11772.         LD   A,(DE)       ;
  11773.         LD   (HL),A       ; Restore the initial row number, i.e. row number of the first visible row of the BASIC line being entered.
  11774.  
  11775.         CALL L3C63        ; Locate the position to insert the error marker into the typed BASIC line.
  11776.         JR   C,L2D0A      ; Jump if the error marker was found.
  11777.  
  11778. ;Assume the error maker is at the same position as the cursor
  11779.  
  11780.         LD   BC,($EC06)   ; Fetch the number of editable characters in the line prior to the cursor within the Screen Line Edit Buffer.
  11781.  
  11782. ;The position of the error marker within the typed BASIC line has been determined. Now shift the cursor to the corresponding position on the screen.
  11783.  
  11784. L2D0A:  LD   HL,($EC06)   ; Fetch the number of editable characters in the line prior to the cursor within the Screen Line Edit Buffer.
  11785.         OR   A            ;
  11786.         SBC  HL,BC        ; HL=Difference between the cursor and the error marker positions (negative if the error marker is after the cursor).
  11787.  
  11788.         PUSH AF           ; Save the flags.
  11789.         PUSH HL           ; HL=Difference between the cursor and error marker.
  11790.         CALL L2A07        ; Get current cursor position, returning C=row number, B=column number, A=preferred column number.
  11791.         POP  HL           ; HL=Difference between the cursor and error marker.
  11792.         POP  AF           ; Restore the flags.
  11793.         JR   C,L2D2A      ; Jump if error marker is after the cursor position.
  11794.  
  11795.         JR   Z,L2D45      ; Jump if cursor is at the same location as the error marker.
  11796.  
  11797. ;The error marker is before the cursor position. Move the cursor back until it is at the same position as the error marker.
  11798.  
  11799. L2D1B:  PUSH HL           ; Save the number of positions to move.
  11800.         LD   A,B          ; B=Cursor column number.
  11801.         CALL L2B5B        ; Find previous editable position to the left in the Screen Line Edit Buffer, moving to previous row if necessary.
  11802.         POP  HL           ; Retrieve the number of positions to move.
  11803.         JR   NC,L2D45     ; Jump if no previous editable position exists.
  11804.  
  11805.         DEC  HL           ; Decrement the number of positions to move.
  11806.         LD   A,H          ;
  11807.         OR   L            ;
  11808.         JR   NZ,L2D1B     ; Jump back if the cursor position requires further moving.
  11809.  
  11810.         JR   L2D45        ; Jump ahead to continue.
  11811.  
  11812. ;The error marker is after the cursor position. Move the cursor back until it is at the same position as the error marker.
  11813.  
  11814. L2D2A:  PUSH HL           ; Save the number of positions that the error marker is before the cursor. This will be a
  11815.                           ; negative number is the cursor is after the error marker.
  11816.  
  11817. L2D2B:  LD   HL,$EC0D     ; Editor flags.
  11818.         RES  7,(HL)       ; Signal 'got a key press'. Used in routine at $2B78 (ROM 0) to indicate that a new character has caused the need to shift the cursor position.
  11819.  
  11820.         POP  HL           ; Retrieve the negative difference in the cursor and error marker positions.
  11821.         EX   DE,HL        ; DE=Negative difference in the cursor and error marker positions.
  11822.  
  11823.         LD   HL,$0000     ; Make the negative difference a positive number by subtracting it from 0.
  11824.         OR   A            ;
  11825.         SBC  HL,DE        ; HL=Positive difference in the cursor and error marker positions.
  11826.  
  11827. L2D38:  PUSH HL           ; Save the number of positions to move.
  11828.         LD   A,B          ; B=Cursor column number.
  11829.         CALL L2B78        ; Find next editable position to the right in the Screen Line Edit Buffer, moving to next row if necessary.
  11830.         POP  HL           ; Retrieve the number of positions to move.
  11831.         JR   NC,L2D45     ; Jump if no next editable position exists.
  11832.  
  11833.         DEC  HL           ; Decrement the number of positions to move.
  11834.         LD   A,H          ;
  11835.         OR   L            ;
  11836.         JR   NZ,L2D38     ; Jump back if the cursor position requires further moving.
  11837.  
  11838. ;The cursor position is at the location of the error marker position
  11839.  
  11840. L2D45:  LD   HL,$EC0D     ; Editor flags.
  11841.         SET  7,(HL)       ; Set 'waiting for key press' flag.
  11842.  
  11843. ; [*BUG* - When moving the cursor up or down, an attempt is made to place the cursor at the same column position that it had on the previous row (the preferred column).
  11844. ;          If this is not possible then the cursor is placed at the end of the row. However, it is the intention that the preferred column is still remembered
  11845. ;          and hence an attempt is made to place the cursor at this column whenever it is subsequently moved. However, a bug at this point in the ROM causes
  11846. ;          the preferred column position for the cursor to be overwritten with random data. If the cursor was moved from its original position
  11847. ;          into its error position then the preferred column gets set to zero and the next up or down cursor movement will cause the cursor marker
  11848. ;          to jump to the left-hand side of the screen. However, if the cursor remained in the same position then the preferred column gets set to
  11849. ;          a random value and so on the next up or down cursor movement the cursor marker can jump to a random position on the screen. The bug can
  11850. ;          can reproduced by typing a line that is just longer than one row, pressing enter twice and then cursor down. The cursor marker will probably
  11851. ;          jump somewhere in the middle of the screen. Press an arrow again and the computer may even crash. Credit: Ian Collier (+3), Andrew Owen (128)]
  11852.  
  11853. ; [The bug can be fixed by pre-loading the A register with the current preferred column number. Credit: Paul Farrow.
  11854. ;
  11855. ;       LD   A,($F6F0)    ; Fetch the preferred column position.]
  11856.  
  11857.         CALL L2A11        ; Store cursor editing position.
  11858.  
  11859.         LD   A,$17        ; Paper 2, Ink 7 - Red.
  11860.         CALL L3A96        ; Set the cursor colour to show the position of the error.
  11861.  
  11862.         OR   A            ; Reset the carry flag to signal that a syntax error occurred.
  11863.         RET               ;
  11864.  
  11865. ; ----------------------------------------------
  11866. ; Fetch Next Character from BASIC Line to Insert
  11867. ; ----------------------------------------------
  11868. ; This routine fetches a character from the BASIC line being inserted. The line may span above or below the screen, and so the character
  11869. ; is retrieved from the appropriate buffer.
  11870. ; Exit : A=Character fetched from the current position, or 'Enter' if end of line found.
  11871.  
  11872. L2D54:  LD   HL,$EC00     ; Point to the 'insert BASIC line' details.
  11873.         BIT  7,(HL)       ; Has the column with the cursor been found?
  11874.         JR   Z,L2D62      ; Jump if it has been found.
  11875.  
  11876.         LD   HL,($EC06)   ;
  11877.         INC  HL           ; Increment the count of the number of editable characters in the BASIC line up to the cursor.
  11878.         LD   ($EC06),HL   ;
  11879.  
  11880. L2D62:  LD   HL,$EC00     ; Point to the 'insert BASIC line' details.
  11881.         LD   A,(HL)       ; Fetch flags.
  11882.         INC  HL           ;
  11883.         LD   B,(HL)       ; Fetch the column number of the character being examined.
  11884.         INC  HL           ;
  11885.         LD   C,(HL)       ; Fetch the row number of the character being examined.
  11886.         PUSH HL           ;
  11887.         AND  $0F          ; Extract the status code.
  11888.  
  11889. ;Register A:
  11890. ;  Bit 0: 1=First row of the BASIC line off top of screen.
  11891. ;  Bit 1: 1=On first row of the BASIC line.
  11892. ;  Bit 2: 1=Using lower screen and only first row of the BASIC line visible.
  11893. ;  Bit 3: 1=At end of last row of the BASIC line (always 0 at this point).
  11894.  
  11895.         LD   HL,L2D85     ; Jump table to select appropriate handling routine.
  11896.         CALL L3FCE        ; Call handler routine.
  11897.  
  11898. ;Register L:
  11899. ;  $01 - A character was returned from the Above-Screen Line Edit Buffer row.
  11900. ;  $02 - A character was returned from the Screen Line Edit Buffer row.
  11901. ;  $04 - A character was returned from the Below-Screen Line Edit Buffer row.
  11902. ;  $08 - At the end of the last row of the BASIC line.
  11903. ;Register A holds the character fetched or 'Enter' if at the end of the BASIC line.
  11904.  
  11905.         LD   E,L          ; E=Return status.
  11906.         POP  HL           ;
  11907.         JR   Z,L2D79      ; Jump if no match found.
  11908.  
  11909.         LD   A,$0D        ; A='Enter' character.
  11910.  
  11911. L2D79:  LD   (HL),C       ; Save the next character position row to examine.
  11912.         DEC  HL           ;
  11913.         LD   (HL),B       ; Save the next character position column to examine.
  11914.         DEC  HL           ;
  11915.         PUSH AF           ; Save the character.
  11916.         LD   A,(HL)       ; Fetch the current status flags.
  11917.         AND  $F0          ; Keep the upper nibble.
  11918.         OR   E            ; Update the location flags that indicate where to obtain the next character from.
  11919.         LD   (HL),A       ; Store the status flags.
  11920.         POP  AF           ; Retrieve the character.
  11921.         RET               ;
  11922.  
  11923. ; -------------------------------
  11924. ; Fetch Next Character Jump Table
  11925. ; -------------------------------
  11926. ; Jump to one of three handling routines when fetching the next character from the BASIC line to insert.
  11927.  
  11928. L2D85:  DB $03           ; Number of table entries.
  11929.         DB $02           ; On first row of the BASIC line.
  11930.         DEFW L2DAC         ;
  11931.         DB $04           ; Using lower screen and only first row of the BASIC line visible.
  11932.         DEFW L2DE9         ;
  11933.         DB $01           ; First row of the BASIC line off top of screen.
  11934.         DEFW L2D8F         ;
  11935.  
  11936. ; -------------------------------------------------------------------------------------
  11937. ; Fetch Character from the Current Row of the BASIC Line in the Screen Line Edit Buffer
  11938. ; -------------------------------------------------------------------------------------
  11939. ; Fetch character from the current row of the BASIC line in the Screen Line Edit Buffer, skipping nulls until the end of
  11940. ; the BASIC line is found.
  11941. ; Entry: C=Row number.
  11942. ; Exit : L=$01 - A character was returned from the Above-Screen Line Edit Buffer row, with A holding the character.
  11943. ;          $02 - A character was returned from the Screen Line Edit Buffer row, with A holding the character.
  11944. ;          $04 - A character was returned from the Below-Screen Line Edit Buffer row, with A holding the character.
  11945. ;          $08 - At the end of the last row of the BASIC line, with A holding an 'Enter' character.
  11946. ;        Zero flag set to indicate a match from the handler table was found.
  11947.  
  11948. ;Table entry point - First row of BASIC line off top of screen
  11949.  
  11950. L2D8F:  CALL L32B7        ; Find row address in Above-Screen Line Edit Buffer, return in DE.
  11951.  
  11952. L2D92:  CALL L2E0E        ; Fetch character from Above-Screen Line Edit Buffer row.
  11953.         JR   NC,L2D9E     ; Jump if end of row reached.
  11954.  
  11955.         CP   $00          ; Is it a null character, i.e. not editable?
  11956.         JR   Z,L2D92      ; Jump back if so until character found or end of row reached.
  11957.  
  11958.         LD   L,$01        ; Signal a character was returned from the Above-Screen Line Edit Buffer row, with A holding the character.
  11959.         RET               ; Return with zero flag reset to indicate match found.
  11960.  
  11961. ;End of row reached - no more editable characters in Above-Screen Line Edit Buffer row
  11962.  
  11963. L2D9E:  INC  C            ; Next row.
  11964.         LD   B,$00        ; Column 0.
  11965.         LD   HL,($F9DB)   ; [*BUG* - This should be LD HL,$F9DB. The bug manifests itself when Enter is pressed on an edited BASIC line that goes off
  11966.                           ; the top of the screen and causes corruption to that line. The bug at $30D0 (ROM 0) that sets default data for the Below-Screen Line Edit Buffer
  11967.                           ; implies that originally there was the intention to have a pointer into the next location to use within that buffer, and so it seems to
  11968.                           ; reasonable to assume the same arrangement would have been intended for the Above-Screen Line Edit Buffer. If that were the case then the
  11969.                           ; instruction here was intended to fetch the next address within the Above-Screen Line Edit Buffer. Credit: Ian Collier (+3), Andrew Owen (128)]
  11970.  
  11971.         LD   A,C          ; Fetch the row number.
  11972.         CP   (HL)         ; Exceeded last row of Above-Screen Line Edit Buffer?
  11973.         JR   C,L2D8F      ; Jump back if not exceeded last row the Above-Screen Line Edit Buffer.
  11974.  
  11975. ;All characters from rows off top of screen fetched so continue onto the rows on screen
  11976.  
  11977. ; [Note it is not possible to have more than 20 rows off the top of the screen]
  11978.  
  11979.         LD   B,$00        ; Column 0.
  11980.         LD   C,$00        ; Row 0. This is the first visible row of the BASIC line on screen.
  11981.  
  11982. ; Table entry point - On visible row of BASIC line
  11983. ; ------------------------------------------------
  11984.  
  11985. ;C=Row number of the first visible row of the BASIC line in the Screen Line Edit Buffer
  11986. ;B=Starting column number of the first visible row of the BASIC line in the Screen Line Edit Buffer
  11987.  
  11988. L2DAC:  PUSH HL           ; Save address of the table entry.
  11989.  
  11990.         LD   HL,$F6EE     ; Point to the cursor position details.
  11991.         LD   A,(HL)       ; Fetch the row number of the cursor.
  11992.         CP   C            ; Is cursor on the first visible row of the BASIC line?
  11993.         JR   NZ,L2DBE     ; Jump if not.
  11994.  
  11995. ;Cursor on first visible row of the BASIC line in the Screen Line Edit Buffer.
  11996.  
  11997.         INC  HL           ;
  11998.         LD   A,(HL)       ; Fetch the column number of the cursor.
  11999.         CP   B            ; Reached the column with the cursor in the first visible row of the BASIC line?
  12000.         JR   NZ,L2DBE     ; Jump if not.
  12001.  
  12002.         LD   HL,$EC00     ; BASIC line insertion flags.
  12003.         RES  7,(HL)       ; Indicate that the column with the cursor has been found.
  12004.  
  12005. L2DBE:  POP  HL           ; Retrieve address of the table entry.
  12006.  
  12007. L2DBF:  CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  12008.         CALL L2E0E        ; Fetch character from Screen Line Edit Buffer row at column held in B, then increment B.
  12009.         JR   NC,L2DCE     ; Jump if end of row reached.
  12010.  
  12011.         CP   $00          ; Is the character a null, i.e. not editable?
  12012.         JR   Z,L2DAC      ; Jump back if null to keep fetching characters until a character is found or the end of the row is reached.
  12013.  
  12014. ;A character in the current row of the BASIC line was found
  12015.  
  12016.         LD   L,$02        ; L=Signal a character was returned from the Screen Line Edit Buffer row, with A holding the character.
  12017.         RET               ; Return with zero flag reset to indicate match found.
  12018.  
  12019. ;End of row reached - no editable characters in the Screen Line Edit Buffer row
  12020.  
  12021. L2DCE:  LD   HL,$0020     ;
  12022.         ADD  HL,DE        ; Point to the flag byte for the row.
  12023.         BIT  3,(HL)       ; Is it the last row of the BASIC line?
  12024.         JR   Z,L2DDB      ; Jump if not.
  12025.  
  12026. ;On last row of the BASIC line and finished fetching characters from the line
  12027.  
  12028.         LD   L,$08        ; L=Signal at the end of the last row of the BASIC line.
  12029.         LD   A,$0D        ; A='Enter' character.
  12030.         RET               ; Return with zero flag reset to indicate match found.
  12031.  
  12032. ;Not on the last row of the BASIC line so move to the beginning of the next, if it is on screen.
  12033.  
  12034. L2DDB:  LD   HL,$F6F3     ; Point to the 'top row scroll threshold' value.
  12035.         INC  C            ; Next row of the BASIC line in the Screen Line Edit Buffer.
  12036.         LD   A,(HL)       ; Fetch the number of the last row in the Screen Line Edit Buffer.
  12037.         CP   C            ; Exceeded the upper scroll threshold?
  12038.         LD   B,$00        ; Column 0.
  12039.         JR   NC,L2DBF     ; Jump back if not to retrieve the character from the next row.
  12040.  
  12041. ;The upper row threshold for triggering scrolling the screen has been reached so proceed to scroll up one line
  12042.  
  12043.         LD   B,$00        ; Column 0. [Redundant byte]
  12044.         LD   C,$01        ; Row 1. (Row 0 holds a copy of the last row visible on screen)
  12045.  
  12046. ; Table entry point - Using lower screen and only top row of a multi-row BASIC line is visible
  12047. ; --------------------------------------------------------------------------------------------
  12048.  
  12049. L2DE9:  CALL L31C3        ; Find the address of the row specified by C in Below-Screen Line Edit Buffer, into DE.
  12050.  
  12051. L2DEC:  CALL L2E0E        ; Fetch character from Below-Screen Line Edit Buffer row, incrementing the column number.
  12052.         JR   NC,L2DF8     ; Jump if end of row reached.
  12053.  
  12054.         CP   $00          ; Is the character a null, i.e. not editable?
  12055.         JR   Z,L2DEC      ; Jump back if null to keep fetching characters until a character is found or the end of the row is reached.
  12056.  
  12057.         LD   L,$04        ; L=Signal a character was returned from the Below-Screen Line Edit Buffer row, with A holding the character.
  12058.         RET               ; Return with zero flag reset to indicate match found.
  12059.  
  12060. ;End of row reached - no editable characters in the (below screen) Below-Screen Line Edit Buffer row
  12061.  
  12062. L2DF8:  LD   HL,$0020     ;
  12063.         ADD  HL,DE        ; Point to the flag byte for the row.
  12064.         BIT  3,(HL)       ; Is it the last row of the BASIC line?
  12065.         JR   NZ,L2E09     ; Jump if so.
  12066.  
  12067.         INC  C            ; Next row.
  12068.         LD   B,$00        ; Column 0.
  12069.  
  12070.         LD   A,($F6F5)    ; Fetch number of rows in the Below-Screen Line Edit Buffer.
  12071.         CP   C            ; Exceeded last line in Below-Screen Line Edit Buffer?
  12072.         JR   NC,L2DE9     ; Jump back if not to retrieve the character from the next row.
  12073.  
  12074. ;All characters from rows off bottom of screen fetched so return an 'Enter'
  12075.  
  12076. ; [Note it is not possible to have more than 20 rows off the bottom of the screen]
  12077.  
  12078. L2E09:  LD   L,$08        ; L=Signal at the end of the last row of the BASIC line.
  12079.         LD   A,$0D        ; A='Enter' character.
  12080.         RET               ; Return with zero flag reset to indicate match found.
  12081.  
  12082. ; ------------------------------------
  12083. ; Fetch Character from Edit Buffer Row
  12084. ; ------------------------------------
  12085. ; Entry: B =Column number.
  12086. ;        DE=Start address of row in Edit Buffer.
  12087. ; Exit : Carry flag set indicates character fetched, reset if column out of range.
  12088.  
  12089. L2E0E:  LD   A,$1F        ; Column 31.
  12090.         CP   B            ; Is column
  12091.         CCF               ;
  12092.         RET  NC           ; Return if B is greater than 31.
  12093.  
  12094.         LD   L,B          ;
  12095.         LD   H,$00        ; HL=Column number.
  12096.         ADD  HL,DE        ;
  12097.         LD   A,(HL)       ; Fetch the character at the specified column.
  12098.         INC  B            ; Increment the column number.
  12099.         SCF               ; Signal character fetched.
  12100.         RET               ;
  12101.  
  12102. ; -----------------------
  12103. ; Upper Screen Rows Table
  12104. ; -----------------------
  12105. ; Copied to $EC15-$EC16.
  12106.  
  12107. L2E1B:  DB $01          ; Number of bytes to copy.
  12108.         DB $14          ; Number of editing rows (20 for upper screen).
  12109.  
  12110. ; -----------------------
  12111. ; Lower Screen Rows Table
  12112. ; -----------------------
  12113. ; Copied to $EC15-$EC16.
  12114.  
  12115. L2E1D:  DB $01          ; Number of bytes to copy.
  12116.         DB $01          ; Number of editing rows (1 for lower screen).
  12117.  
  12118. ; --------------------
  12119. ; Reset to Main Screen
  12120. ; --------------------
  12121.  
  12122. L2E1F:  LD   HL,$5C3C     ; TVFLAG.
  12123.         RES  0,(HL)       ; Signal using main screen.
  12124.         LD   HL,L2E1B     ; Upper screen lines table.
  12125.         LD   DE,$EC15     ; Destination workspace variable. The number of editing rows on screen.
  12126.         JP   L3FBA        ; Copy one byte from $2E1C (ROM 0) to $EC15
  12127.  
  12128. ; ---------------------
  12129. ; Reset to Lower Screen
  12130. ; ---------------------
  12131.  
  12132. L2E2D:  LD   HL,$5C3C     ; TVFLAG.
  12133.         SET  0,(HL)       ; Signal using lower screen.
  12134.  
  12135.         LD   BC,$0000     ;
  12136.         CALL L372B        ; Perform 'PRINT AT 0,0;'.
  12137.  
  12138.         LD   HL,L2E1D     ; Lower screen lines table.
  12139.         LD   DE,$EC15     ; Destination workspace variable. The number of editing rows on screen.
  12140.         JP   L3FBA        ; Copy one byte from $2E1E (ROM 0) to $EC15
  12141.  
  12142. ; --------------------------------------------------------------------
  12143. ; Find Edit Buffer Editable Position from Previous Column to the Right
  12144. ; --------------------------------------------------------------------
  12145. ; This routine finds the first editable character position in the specified edit buffer row from the previous column to the right.
  12146. ; It first checks the current column, then the previous column and then the columns to the right. The column containing the first
  12147. ; non-null character encountered is returned.
  12148. ; Entry: B =Column number to start searching from.
  12149. ;        DE=Start of row in edit buffer.
  12150. ; Exit : Carry flag set if an editable character was found.
  12151. ;        HL=Address of closest editable position.
  12152. ;        B =Number of closest editable column.
  12153.  
  12154. L2E41:  LD   H,$00        ; [Could have saved 1 byte by calling routine at $2E7B (ROM 0)]
  12155.         LD   L,B          ; HL=Column number.
  12156.         ADD  HL,DE        ; HL=Address in edit buffer of the specified column.
  12157.  
  12158.         LD   A,(HL)       ; Fetch the contents.
  12159.         CP   $00          ; Is it a null character, i.e. end-of-line or past the end-of-line?
  12160.         SCF               ;
  12161.         RET  NZ           ; Return if this character is part of the edited line.
  12162.  
  12163.         LD   A,B          ;
  12164.         OR   A            ;
  12165.         JR   Z,L2E5B      ; Jump ahead if the first column.
  12166.  
  12167.         PUSH HL           ; Otherwise check the
  12168.         DEC  HL           ; preceding byte
  12169.         LD   A,(HL)       ; and if it is non-zero
  12170.         CP   $00          ; then return with
  12171.         SCF               ; HL pointing to the
  12172.         POP  HL           ; first zero byte.
  12173.         RET  NZ           ;
  12174.  
  12175. L2E56:  LD   A,(HL)       ; Get the current character.
  12176.         CP   $00          ; Is it a null (i.e. end-of-line)?
  12177.         SCF               ; Signal position is editable.
  12178.         RET  NZ           ; Return if this character is part of the edited line.
  12179.  
  12180. L2E5B:  INC  HL           ; Advance to the next position.
  12181.         INC  B            ; Increment the column number.
  12182.         LD   A,B          ;
  12183.         CP   $1F          ; Reached the end of the row?
  12184.         JR   C,L2E56      ; Jump back if more columns to check.
  12185.  
  12186.         RET               ; Return with carry flag reset if specified column position does not exist.
  12187.  
  12188. ; ----------------------------------------------
  12189. ; Find Edit Buffer Editable Position to the Left
  12190. ; ----------------------------------------------
  12191. ; This routine finds the first editable character position in the specified edit buffer row from the current column to the left.
  12192. ; It first checks the current column and returns this if it contains an editable character. Otherwise it searches the columns to
  12193. ; the left and if an editable character is found then it returns the column to the right of it.
  12194. ; Entry: B =Column number to start searching from.
  12195. ;        DE=Start of row in edit buffer.
  12196. ; Exit : Carry flag set if an editable character was found.
  12197. ;        HL=Address of closest editable position.
  12198. ;        B =Number of the column after the editable position.
  12199.  
  12200. L2E63:  LD   H,$00        ; [Could have saved 1 byte by calling routine at $2E7B (ROM 0)]
  12201.         LD   L,B          ; HL=Column number.
  12202.         ADD  HL,DE        ; HL=Address in edit buffer of the specified column.
  12203.  
  12204.         LD   A,(HL)       ; Fetch the contents.
  12205.         CP   $00          ; Is it a null character, i.e. end-of-line or past the end-of-line?
  12206.         SCF               ; Signal position is editable.
  12207.         RET  NZ           ; Return if an editable character was found.
  12208.  
  12209. L2E6C:  LD   A,(HL)       ; Get the current character.
  12210.         CP   $00          ; Is it a null, i.e. non-editable?
  12211.         JR   NZ,L2E78     ; Jump if not.
  12212.  
  12213.         LD   A,B          ; At column 0?
  12214.         OR   A            ;
  12215.         RET  Z            ; Return if so.
  12216.  
  12217.         DEC  HL           ; Next column position to test.
  12218.         DEC  B            ; Decrement column index number.
  12219.         JR   L2E6C        ; Repeat test on previous column.
  12220.  
  12221. L2E78:  INC  B            ; Advance to the column after the editable position.
  12222.         SCF               ; Signal position is editable.
  12223.         RET               ;
  12224.  
  12225. ; -------------------------------
  12226. ; Fetch Edit Buffer Row Character
  12227. ; -------------------------------
  12228. ; Entry: DE=Add of edit buffer row.
  12229. ;        B =Column number.
  12230. ; Exit : A =Character at specified column.
  12231. ;
  12232. ; [Not used by the ROM]
  12233.  
  12234. L2E7B:  LD   H,$00        ;
  12235.         LD   L,B          ; HL=Column number.
  12236.         ADD  HL,DE        ; HL=Address in edit buffer of the specified column.
  12237.         LD   A,(HL)       ; Get the current character.
  12238.         RET               ;
  12239.  
  12240. ; ---------------------------------------------
  12241. ; Insert Character into Screen Line Edit Buffer
  12242. ; ---------------------------------------------
  12243. ; Called when a non-action key is pressed. It inserts a character into the Screen Line Edit Buffer if there is room.
  12244. ; Entry: A=Character code.
  12245. ;        B=Cursor column position.
  12246. ;        C=Cursor row position.
  12247.  
  12248. L2E81:  LD   HL,$EC0D     ; Editor flags.
  12249.         OR   A            ; Clear carry flag. [Redundant since carry flag return state never checked]
  12250.         BIT  0,(HL)       ; Is the Screen Line Edit Buffer is full?
  12251.         RET  NZ           ; Return if it is.
  12252.  
  12253.         PUSH BC           ; Save cursor position.
  12254.         PUSH AF           ; Save key code. [Redundant since $30B4 (ROM 0) preserves AF]
  12255.  
  12256.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  12257.  
  12258.         POP  AF           ; Get key code. [Redundant since $30B4 (ROM 0) preserves AF]
  12259.  
  12260. ;Insert the character into the current row. If a spill from this row occurs then insert that character into the start of the
  12261. ;following row and shift all existing characters right by one. Repeat this process until all rows have been shifted.
  12262.  
  12263. L2E8E:  CALL L16AC        ; Insert character into edit buffer row at current cursor position, shifting the row right. Returns carry flag reset.
  12264.                           ; Zero flag will be set if byte shift out of last column position was $00.
  12265.  
  12266.         PUSH AF           ; Save key code and flags.
  12267.  
  12268.         EX   DE,HL        ; HL=Address of edit buffer row. DE=Address of flags.
  12269.         CALL L3604        ; Print a row of the edit buffer to the screen.
  12270.         EX   DE,HL        ; DE=Address of edit buffer row. HL=Address of flags.
  12271.  
  12272.         POP  AF           ; Get key code and flags.
  12273.         CCF               ; Sets the carry flag since it was reset via the call to $16AC (ROM 0). [Redundant since never tested]
  12274.         JR   Z,L2ECC      ; Jump ahead to make a return if there was no spill out from column 31, with the carry flag set.
  12275.  
  12276. ;There was a spill out from the current row, and so this character will need to be inserted as the first character of the following row.
  12277. ;If this is the last row of the BASIC line then a new row will need to be inserted.
  12278.  
  12279.         PUSH AF           ; Save key code.
  12280.  
  12281.         LD   B,$00        ; First column in the next row.
  12282.         INC  C            ; Next row.
  12283.  
  12284.         LD   A,($EC15)    ; The number of editing rows on screen.
  12285.         CP   C            ; Has the bottom of the Screen Line Edit Buffer been reached?
  12286.         JR   C,L2EC8      ; Jump ahead if so.
  12287.  
  12288. ;The editing screen is not full
  12289.  
  12290.         LD   A,(HL)       ; Fetch contents of flag byte for the row (byte after the 32 columns).
  12291.         LD   E,A          ; E=Old flags.
  12292.         AND  $D7          ; Mask off 'last row of BASIC line' flag. [Other bits not used, could have used AND $F7]
  12293.         CP   (HL)         ; Has the status changed?
  12294.         LD   (HL),A       ; Store the new flags, marking it as not the last BASIC row.
  12295.         LD   A,E          ; A=Original flags byte for the row.
  12296.         SET  1,(HL)       ; Signal that the row spans onto another row.
  12297.  
  12298.         PUSH AF           ; Save the flags.
  12299.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the following row, as specified in C.
  12300.         POP  AF           ; Fetch the flags.
  12301.         JR   Z,L2EC2      ; Jump if the character was not inserted into the last row of the BASIC line.
  12302.  
  12303. ;The character was inserted into the last row of the BASIC line causing a spill of an existing character into a new row,
  12304. ;and therefore a new 'last' row needs to be inserted.
  12305.  
  12306.         RES  0,A          ; Signal not the first row of the BASIC line.
  12307.         CALL L2ED3        ; Insert a blank line into the Screen Edit Buffer.
  12308.         JR   NC,L2ECC     ; Jump if the buffer is full to exit.
  12309.  
  12310.         CALL L35F4        ; Indent the row by setting the appropriate number of null characters in the current Screen Line Edit Buffer row.
  12311.  
  12312.         POP  AF           ; Get key code.
  12313.         JR   L2E8E        ; Jump back to insert the character in the newly inserted row. [Could have saved 2 bytes by using JR $2EC5 (ROM 0)]
  12314.  
  12315. ;The character was not inserted into the last row of the BASIC line, so find the first editable position on the following row, i.e.
  12316. ;skip over any indentation.
  12317.  
  12318. L2EC2:  CALL L2E41        ; Find editable position on this row from the previous column to the right, returning column number in B.
  12319.         POP  AF           ; Get key code.
  12320.         JR   L2E8E        ; Jump back to insert the character into the first editable position of next the row.
  12321.  
  12322. ;The Screen Edit Line Buffer is full and the character insertion requires shifting of all rows that are off screen in the Below-Screen Line Edit Buffer.
  12323.  
  12324. L2EC8:  POP  AF           ; Get key code.
  12325.         CALL L316E        ; Insert the character at the start of the Below-Screen Line Edit Buffer, shifting all existing characters to the right.
  12326.  
  12327. ;All paths join here
  12328.  
  12329. L2ECC:  POP  BC           ; Retrieve cursor position.
  12330.         RET               ;
  12331.  
  12332. ; ------------------------------------------------------------
  12333. ; Insert Blank Row into Screen Edit Buffer, Shifting Rows Down
  12334. ; ------------------------------------------------------------
  12335. ; This routine inserts a blank row at the specified row, shifting affected rows down.
  12336. ; Entry: C=Row number to insert the row at.
  12337. ; Exit : Carry flag set to indicate edit buffer rows were shifted.
  12338.  
  12339. L2ECE:  CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  12340.         LD   A,$09        ; Signal 'first row' and 'last row', indicating a new blank row.
  12341.  
  12342. ;DE=Address of row within Screen Line Edit Buffer.
  12343. ;C=Row number to insert the row at.
  12344. ;A=Screen Line Edit Buffer row flags value.
  12345.  
  12346. L2ED3:  PUSH BC           ; Save registers.
  12347.         PUSH DE           ;
  12348.  
  12349.         LD   B,C          ; B=Row number.
  12350.         LD   HL,L2EEF     ; The empty row data.
  12351.         LD   C,A          ; C=Flags for the row.
  12352.  
  12353.         PUSH BC           ;
  12354.         CALL L1675        ; Shift all Screen Line Edit Buffer rows down and insert a new blank row, updating the display file if required.
  12355.         POP  BC           ;
  12356.         LD   A,C          ; A=Flags for the row.
  12357.         JR   NC,L2EEC     ; Jump if no edit buffer rows were shifted.
  12358.  
  12359. ;Rows were shifted down
  12360.  
  12361.         LD   C,B          ; B=Row number, where the new blank row now is.
  12362.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  12363.  
  12364.         LD   HL,$0020     ; Point to the flag byte for the row.
  12365.         ADD  HL,DE        ;
  12366.         LD   (HL),A       ; Store the flag byte value for the row.
  12367.         SCF               ; Signal edit buffer rows were shifted.
  12368.  
  12369. L2EEC:  POP  DE           ; Restore registers.
  12370.         POP  BC           ;
  12371.         RET               ;
  12372.  
  12373. ; --------------------------
  12374. ; Empty Edit Buffer Row Data
  12375. ; --------------------------
  12376.  
  12377. L2EEF:  DB $00          ; 32 null column markers, i.e. none of the columns are editable.
  12378.         DB $00
  12379.         DB $00
  12380.         DB $00
  12381.         DB $00
  12382.         DB $00
  12383.         DB $00
  12384.         DB $00
  12385.         DB $00
  12386.         DB $00
  12387.         DB $00
  12388.         DB $00
  12389.         DB $00
  12390.         DB $00
  12391.         DB $00
  12392.         DB $00
  12393.         DB $00
  12394.         DB $00
  12395.         DB $00
  12396.         DB $00
  12397.         DB $00
  12398.         DB $00
  12399.         DB $00
  12400.         DB $00
  12401.         DB $00
  12402.         DB $00
  12403.         DB $00
  12404.         DB $00
  12405.         DB $00
  12406.         DB $00
  12407.         DB $00
  12408.         DB $00
  12409.  
  12410.         DB $09          ; Flags:
  12411.                           ;   Bit 0: 1=The first row of the BASIC line.
  12412.                           ;   Bit 1: 0=Does not span onto another row.
  12413.                           ;   Bit 2: 0=Not used (always 0).
  12414.                           ;   Bit 3: 1=The last row of the BASIC line.
  12415.                           ;   Bit 4: 0=No associated line number.
  12416.                           ;   Bit 5: 0=Not used (always 0).
  12417.                           ;   Bit 6: 0=Not used (always 0).
  12418.                           ;   Bit 7: 0=Not used (always 0).
  12419.         DEFW $0000        ; There is no BASIC line number associated with this edit row.
  12420.  
  12421. ; -------------------------------------------------------------------
  12422. ; Delete a Character from a BASIC Line in the Screen Line Edit Buffer
  12423. ; -------------------------------------------------------------------
  12424. ; Delete a character at the specified position, shifting subsequent characters left as applicable.
  12425. ; Entry: B=Column number.
  12426. ;        C=Row number.
  12427.  
  12428. L2F12:  PUSH BC           ; Save initial cursor row and column numbers.
  12429.  
  12430.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  12431.  
  12432.         PUSH BC           ; Stack initial cursor row and column numbers again.
  12433.  
  12434. ;Enter a loop to find the last row of the BASIC line or the end of the visible screen, whichever comes first
  12435.  
  12436. L2F17:  LD   HL,$0020     ;
  12437.         ADD  HL,DE        ; Point to the flag byte for this row.
  12438.         BIT  1,(HL)       ; Does the row span onto another row?
  12439.         LD   A,$00        ; A null character will be inserted. [Could have saved 1 byte by using XOR A and placing it above the BIT 1,(HL) instruction]
  12440.         JR   Z,L2F31      ; Jump ahead if the row does not span onto another row, i.e. the last row.
  12441.  
  12442. ;The row spans onto another
  12443.  
  12444.         INC  C            ; C=Advance to the next row.
  12445.         LD   HL,$0023     ;
  12446.         ADD  HL,DE        ;
  12447.         EX   DE,HL        ; DE points to the first character of the next row. HL points to the first character of the current row.
  12448.  
  12449.         LD   A,($EC15)    ; A=Number of editing lines.
  12450.         CP   C            ; Has the end of the screen been reached?
  12451.         JR   NC,L2F17     ; Jump back if within screen range to find the last row of the BASIC line.
  12452.  
  12453. ;The end of the screen has been reached without the end of the BASIC line having been reached
  12454.  
  12455.         DEC  C            ; Point to last row on screen.
  12456.         CALL L31C9        ; Shift all characters of the BASIC Line held within the Below-Screen Line Edit Buffer.
  12457.  
  12458. ;A loop is entered to shift all characters to the left, beginning with the last row of the BASIC line in the Screen Line Edit Buffer
  12459. ;and until the row that matches the current cursor position is reached.
  12460.  
  12461. L2F31:  POP  HL           ; Fetch the initial cursor row and column numbers.
  12462.  
  12463. L2F32:  PUSH HL           ; Stack initial cursor row and column numbers.
  12464.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the last row, as specified in C.
  12465.         POP  HL           ; HL=Initial cursor row and column numbers.
  12466.  
  12467.         LD   B,A          ; B=Character to insert.
  12468.         LD   A,C          ; A=Row number to delete from.
  12469.         CP   L            ; Deleting from the same row as the cursor is on within the BASIC line?
  12470.         LD   A,B          ; A=Character to insert.
  12471.         PUSH AF           ; Save the flags status.
  12472.         JR   NZ,L2F41     ; Jump if not deleting from the row containing the cursor.
  12473.  
  12474. ;Deleting from the row matching the cursor position within the BASIC line, therefore only shift those bytes after the cursor position
  12475.  
  12476.         LD   B,H          ; B=Initial column number.
  12477.         JR   L2F4A        ; Jump ahead to continue, with zero flag set to indicate deleting from the row contain the cursor.
  12478.  
  12479. ;Deleting on row after that matching the cursor position, therefore shift all editable characters within the row
  12480.  
  12481. L2F41:  PUSH AF           ; Save the character to insert.
  12482.         PUSH HL           ; Save initial cursor row and column numbers.
  12483.  
  12484.         LD   B,$00        ;
  12485.         CALL L2E41        ; Find first editable position on this row searching to the right, returning column number in B.
  12486.  
  12487.         POP  HL           ; HL=Initial cursor row and column numbers.
  12488.         POP  AF           ; A=Character to insert, and zero flag reset to indicate not deleting from the row contain the cursor.
  12489.  
  12490. ;DE=Start address of Screen Line Edit Buffer row.
  12491. ;A=Character to shift into right of row.
  12492. ;B=The column to start shifting at.
  12493. ;C=Row number to start shifting from.
  12494. ;Zero flag is set if deleting from the row matching the cursor position.
  12495.  
  12496. L2F4A:  PUSH HL           ; HL=Initial cursor row and column numbers.
  12497.  
  12498.         LD   HL,$F6F4     ; Deleting flags.
  12499.         SET  0,(HL)       ; Signal deleting on the row matching the cursor position.
  12500.         JR   Z,L2F54      ; Jump if deleting from the row matching the cursor position.
  12501.  
  12502.         RES  0,(HL)       ; Signal not deleting on the row matching the cursor position.
  12503.  
  12504. L2F54:  CALL L16C1        ; Insert the character into the end of the edit buffer row, shifting all columns left until the cursor position is reached.
  12505.  
  12506.         PUSH AF           ; A=Character shifted out, and therefore to be potentially shifted into the end of the previous row.
  12507.         PUSH BC           ; B=New column number. C=Row number.
  12508.         PUSH DE           ; DE=Start address of row to delete from.
  12509.  
  12510.         LD   HL,$F6F4     ; Deleting flags.
  12511.         BIT  0,(HL)       ; Deleting from the row matching the cursor position?
  12512.         JR   NZ,L2F6F     ; Jump ahead if so.
  12513.  
  12514. ;Deleting from a row after the cursor position
  12515.  
  12516.         LD   B,$00        ; Column 0.
  12517.         CALL L2BD4        ; Is there an editable character on the row?
  12518.         JR   C,L2F6F      ; Jump if there is.
  12519.  
  12520. ;Shifting the characters on this row has resulted in a blank row, so shift all rows below screen up to remove this blank row
  12521.  
  12522.         CALL L2F80        ; Shift up all BASIC line rows below to close the gap.
  12523.  
  12524.         POP  DE           ; DE=Start address of row to delete from.
  12525.         POP  BC           ; B=New column number. C=Row number.
  12526.         JR   L2F74        ; Jump ahead.
  12527.  
  12528. ;There are characters remaining on the row following the shift so display this to the screen and then continue to shift the remaining rows
  12529.  
  12530. L2F6F:  POP  HL           ; HL=Start address of the row.
  12531.         POP  BC           ; B=New column number. C=Row number.
  12532.  
  12533.         CALL L3604        ; Print the row of the edit buffer to the screen, if required.
  12534.  
  12535. L2F74:  POP  AF           ; A=Character to insert.
  12536.  
  12537.         DEC  C            ; Previous row.
  12538.         LD   B,A          ; B=Character to insert.
  12539.  
  12540.         POP  HL           ; HL=Initial cursor row and column numbers.
  12541.         POP  AF           ; Retrieve the flags status (zero flag set if deleting from the row matching the cursor position).
  12542.         LD   A,B          ; A=Character to insert.
  12543.         JP   NZ,L2F32     ; Jump back if not deleting from the row matching the cursor position, i.e. all rows after the cursor have not yet been shifted.
  12544.  
  12545. ; [*BUG* - The 'line altered' flag is not cleared when an 'edited' null line is entered. To reproduce the bug, insert a couple of BASIC lines, type a character,
  12546. ;          delete it, and then cursor up or down onto a program line. The line is considered to have been changed and so is processed as if it consists
  12547. ;          of characters. Further, when cursor down is pressed to move to a BASIC line below, that line is deemed to have changed and hence moving off from it
  12548. ;          causing that line to be re-inserted into the BASIC program. Credit: Ian Collier (+3), Paul Farrow (128)]
  12549.  
  12550. ; [The fix for the bug is to check whether all characters have been deleted from the line and if so to reset the 'line altered' flag.
  12551. ; This would require the following code to be inserted at this point. Credit: Paul Farrow.
  12552. ;
  12553. ;       PUSH DE           ;
  12554. ;       LD   HL,$0020     ;
  12555. ;       ADD  HL,DE        ; Point to the flag byte for this row.
  12556. ;       POP  DE
  12557. ;       BIT  0,(HL)       ; First row of BASIC line in addition to the last?
  12558. ;       JR   Z,SKIP_CLEAR ; Jump ahead if not.
  12559. ;
  12560. ;       LD   B,$00        ;
  12561. ;       CALL $2E41 (ROM 0) ; Is this a blank row? i.e. Find editable position on this row to the right, returning column number in B.
  12562. ;       JR   C,SKIP_CLEAR ; Jump if a character exists on the line.
  12563. ;
  12564. ;       LD   HL,$EC0D
  12565. ;       RES  3,(HL)       ; Signal that the current line has not been altered.
  12566. ;
  12567. ;SKIP_CLEAR:
  12568. ;       XOR A             ; Set the preferred column to 0.]
  12569.  
  12570.         SCF               ; [Redundant since never subsequently checked]
  12571.         POP  BC           ; Retrieve initial cursor row and column numbers.
  12572.         RET               ;
  12573.  
  12574. ; -----------------------------------------------------------
  12575. ; Shift Rows Up to Close Blank Row in Screen Line Edit Buffer
  12576. ; -----------------------------------------------------------
  12577. ; The cursor is on a blank row but has been moved off of it. Therefore shift all BASIC lines below it up so as to remove the blank row.
  12578. ; Entry: DE=Address of the row in the Screen Line Edit Buffer containing the cursor.
  12579. ;        C =Row number in the Screen Line Edit Buffer containing the cursor.
  12580. ;        Carry flag set if rows were shifted up, i.e. a row below existed.
  12581.  
  12582. L2F80:  LD   HL,$0020     ;
  12583.         ADD  HL,DE        ; Point to the flag byte for the row.
  12584.         LD   A,(HL)       ;
  12585.         BIT  0,(HL)       ; Is the cursor on a blank row (which is flagged as the first row of a BASIC line)?
  12586.         JR   NZ,L2FB2     ; Jump ahead if it is. [Could have improved speed by jumping to $2FB6 (ROM 0) since DE already holds the start address of the row]
  12587.  
  12588. ;Cursor not on a blank row but is on its own row at the end of a multi-row BASIC line
  12589.  
  12590.         PUSH AF           ; Save the cursor row flag byte.
  12591.         PUSH BC           ; Save the cursor row number in C.
  12592.  
  12593.         LD   A,C          ; Is the cursor on row 0?
  12594.         OR   A            ;
  12595.         JR   NZ,L2FA4     ; Jump ahead if it is not, i.e. there is at least one row above.
  12596.  
  12597. ;Cursor on row 0, hence a BASIC line must be off the top of the screen [???? Can this ever be the case?]
  12598.  
  12599.         PUSH BC           ; Save the cursor row number.
  12600.  
  12601.         LD   HL,($FC9A)   ; Line number at top of screen.
  12602.         CALL L334A        ; Find closest line number (or $0000 if no line).
  12603.         LD   ($FC9A),HL   ; Line number at top of screen.
  12604.  
  12605.         LD   A,($F9DB)    ; Fetch the number of rows of the BASIC line that are in the Above-Screen Line Edit Buffer,
  12606.         LD   C,A          ; i.e. that are off the top of the screen.
  12607.         DEC  C            ; Decrement the row count, i.e. one less row off the top of the screen.
  12608.         CALL L32B7        ; DE=Address of row in Above-Screen Line Edit Buffer.
  12609.  
  12610.         POP  BC           ; Retrieve the cursor row number.
  12611.         JR   L2FA8        ; Jump ahead.
  12612.  
  12613. ;There is a row above so set this as the last row of the BASIC line
  12614.  
  12615. L2FA4:  DEC  C            ; Previous row, i.e. the last row of the BASIC line that contains editable characters.
  12616.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the previous row.
  12617.  
  12618. L2FA8:  POP  BC           ; Retrieve the cursor row number.
  12619.         POP  AF           ; Retrieve the cursor row flag byte, which indicates last row of BASIC line.
  12620.  
  12621.         LD   HL,$0020     ; Point to the flag byte for the previous row.
  12622.         ADD  HL,DE        ;
  12623.         RES  1,(HL)       ; Signal that the previous row does not span onto another row.
  12624.         OR   (HL)         ; Keep the previous row's first BASIC row flag.
  12625.         LD   (HL),A       ; Update the flag byte for the previous row.
  12626.  
  12627. ;Shift up all rows below the old cursor position within the Screen Line Edit Buffer and including the Below-Screen Line Edit Buffer, and update the display file if required
  12628.  
  12629. L2FB2:  LD   B,C          ; B=Row number in the Screen Line Edit Buffer.
  12630.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  12631.         CALL L30DF        ; Shift up rows of the BASIC line in the Below-Screen Line Edit Buffer, or insert the next line BASIC line if buffer empty.
  12632.         JP   L1648        ; Shift Screen Line Edit Buffer rows up from row specified by B and update the display file if required.
  12633.                           ; [Could have saved 3 bytes by replacing the instructions CALL $30DF (ROM 0) / JP $1648 (ROM 0) with JP $1645 (ROM 0)]
  12634.  
  12635. ; ------------------------------------
  12636. ; DELETE-WORD-LEFT Key Handler Routine
  12637. ; ------------------------------------
  12638. ; This routine deletes to the start of the current word that the cursor is on, or if it is on the first
  12639. ; character of a word then it deletes to the start of the previous word. Since the function works by deleting one
  12640. ; character at a time, display file updates are disabled whilst the function is executing to prevent screen flicker.
  12641. ; If there is no word to delete then an error beep is requested.
  12642. ;
  12643. ; Symbol: <-- DEL
  12644. ;         <--
  12645. ;
  12646. ; Exit: Carry flag reset to indicate to produce an error beep and set not to produce an error beep.
  12647.  
  12648. L2FBC:  CALL L3084        ; Remove cursor attribute, disable display file updates and get current cursor position. Exits with HL pointing to the editing area information.
  12649.  
  12650. L2FBF:  PUSH HL           ; Save address of the editing area information.
  12651.         CALL L3095        ; Does a previous character exist in the current Screen Line Edit Buffer row?
  12652.         JR   Z,L2FF7      ; Jump if at the start of the BASIC line to print all rows.
  12653.  
  12654.         CALL L2B5B        ; Is previous column position editable? (Returns carry flag set if editable)
  12655.         POP  HL           ; Retrieve address of the editing area information.
  12656.         JR   NC,L2FF8     ; Jump if not editable to print all rows.
  12657.  
  12658. ;A previous character exists and is editable
  12659.  
  12660.         CALL L2A1A        ; Get character from current cursor position.
  12661.         PUSH AF           ; Save current character.
  12662.         PUSH HL           ; Save address of the editing area information.
  12663.         CALL L2F12        ; Delete character to the right, shifting subsequent rows as required.
  12664.         POP  HL           ; Retrieve address of the editing area information.
  12665.         POP  AF           ; Retrieve current character.
  12666.         CP   $20          ; Is it a space?
  12667.         JR   Z,L2FBF      ; Jump back if so to find the end of the last word.
  12668.  
  12669. ;The end of the word to delete has been found, so enter a loop to search for the start of the word
  12670.  
  12671. L2FD9:  PUSH HL           ; Save address of the editing area information.
  12672.         CALL L3095        ; Does a previous character exist in the current Screen Line Edit Buffer row?
  12673.         JR   Z,L2FF7      ; Jump if at the start of a BASIC line to print all rows.
  12674.  
  12675.         CALL L2B5B        ; Is previous column position editable? (Returns carry flag set if editable)
  12676.         POP  HL           ; Retrieve address of the editing area information.
  12677.         JR   NC,L2FF8     ; Jump if not editable to print all rows.
  12678.  
  12679.         CALL L2A1A        ; Get character from current cursor position
  12680.         CP   $20          ; Is it a space?
  12681.         JR   Z,L2FF3      ; Jump if so.
  12682.  
  12683. ;Character is not a space
  12684.  
  12685.         PUSH HL           ; Save address of the editing area information.
  12686.         CALL L2F12        ; Delete character to the right, shifting subsequent rows as required.
  12687.         POP  HL           ; Retrieve address of the editing area information.
  12688.         JR   L2FD9        ; Jump back to delete next character until start of the word found.
  12689.  
  12690. ;A space prior to a word has been found
  12691.  
  12692. L2FF3:  PUSH HL           ; Save address of the editing area information.
  12693.         CALL L2B78        ; Find next Screen Line Edit Buffer editable position to right, moving to next row if necessary.
  12694.  
  12695. L2FF7:  POP  HL           ; Retrieve address of the editing area information.
  12696.  
  12697. ;Print all rows to the screen
  12698.  
  12699. L2FF8:  LD   A,B          ; Fetch the new end column number.
  12700.  
  12701.         PUSH AF           ; Save the flags status.
  12702.         PUSH HL           ; Save address of the editing area information.
  12703.  
  12704.         LD   HL,$EEF5     ;
  12705.         RES  2,(HL)       ; Re-enable display file updates.
  12706.  
  12707.         LD   A,($EC15)    ; The number of editing rows on screen. [This will end up being used as the alternate cursor column]
  12708.  
  12709.         PUSH BC           ; Save the row and new column numbers.
  12710.         LD   B,$00        ; B=Print from row 0.
  12711.         LD   C,A          ; C=Number of editing rows on screen.
  12712.         CP   A            ; Set the zero flag to signal not to change cursor position settings.
  12713.         CALL L1605        ; Print all Screen Line Edit Buffer rows to the display file.
  12714.         POP  BC           ; Retrieve the row and new column numbers.
  12715.  
  12716.         LD   HL,$EC0D     ; Editor flags.
  12717.         SET  3,(HL)       ; Indicate current line has been altered.
  12718.         POP  HL           ; Retrieve address of the editing area information.
  12719.  
  12720. ; [*BUG* - The preferred cursor column field gets corrupted with the number of editing rows on screen. Credit: Ian Collier (+3), Andrew Owen (128)]
  12721.  
  12722. ; [The bug can be fixed by pre-loading the A register with the current preferred column number. Credit: Paul Farrow.
  12723. ;
  12724. ;       LD   A,($F6F0)    ; Fetch the preferred column position.]
  12725.  
  12726.         CALL L29F8        ; Store editing position and print cursor.
  12727.  
  12728.         POP  AF           ; Retrieve the flags status.
  12729.         RET               ;
  12730.  
  12731. ; -------------------------------------
  12732. ; DELETE-WORD-RIGHT Key Handler Routine
  12733. ; -------------------------------------
  12734. ; This routine deletes to the start of the next word. Since the function works by deleting one character
  12735. ; at a time, display file updates are disabled whilst the function is executing to prevent screen flicker.
  12736. ; If there is no word to delete then an error beep is requested.
  12737. ;
  12738. ; Symbol: --> DEL
  12739. ;         -->
  12740. ;
  12741. ; Exit: Carry flag set to indicate not to produce an error beep.
  12742.  
  12743. L3017:  CALL L3084        ; Remove cursor attribute, disable display file updates and get current cursor position. Exits with HL pointing to the editing area information.
  12744.  
  12745. L301A:  PUSH HL           ; Save address of the editing area information.
  12746.         CALL L2A1A        ; Get character from current cursor position.
  12747.         POP  HL           ; Retrieve address of the editing area information.
  12748.         CP   $00          ; Is it a null character, i.e. end of BASIC line?
  12749.         SCF               ; Signal do not produce an error beep.
  12750.         JR   Z,L2FF8      ; Jump if end of the BASIC line to print all rows.
  12751.  
  12752.         PUSH AF           ; Save the character.
  12753.         PUSH HL           ; Save address of the editing area information.
  12754.         CALL L2F12        ; Delete character to the right, shifting subsequent rows as required.
  12755.         POP  HL           ; Retrieve address of the editing area information.
  12756.         POP  AF           ; Retrieve the character.
  12757.  
  12758.         CP   $20          ; Was the character a space?
  12759.         JR   NZ,L301A     ; Jump back if not to delete the next character until the end of the word is found.
  12760.  
  12761. L302F:  CALL L2A1A        ; Get character from current cursor position.
  12762.         CP   $20          ; Is it a space?
  12763.         SCF               ; Signal do not produce an error beep.
  12764.         JR   NZ,L2FF8     ; Jump if not to print all rows.
  12765.  
  12766.         PUSH HL           ; Save address of the editing area information.
  12767.         CALL L2F12        ; Delete character to the right, shifting subsequent rows as required.
  12768.         POP  HL           ; Retrieve address of the editing area information.
  12769.         JR   L302F        ; Jump back to delete all subsequent spaces until the start of the next word or the end of the line is found.
  12770.  
  12771. ; -------------------------------------------
  12772. ; DELETE-TO-START-OF-LINE Key Handler Routine
  12773. ; -------------------------------------------
  12774. ; Delete to the start of the current BASIC line. Since the function works by deleting one character at
  12775. ; a time, display file updates are disabled whilst the function is executing to prevent screen flicker.
  12776. ; An error beep is not produced if there is no characters in the current BASIC line.
  12777. ;
  12778. ; Symbol: |<-- DEL
  12779. ;         |<--
  12780. ;
  12781. ; Exit: Carry flag set to indicate not to produce an error beep.
  12782.  
  12783. L303E:  CALL L3084        ; Remove cursor attribute, disable display file updates and get current cursor position. Exits with HL pointing to the editing area information.
  12784.  
  12785. L3041:  PUSH HL           ; Save address of the editing area information.
  12786.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  12787.  
  12788.         LD   HL,$0020     ;
  12789.         ADD  HL,DE        ; Point to the flag byte for the row.
  12790.         BIT  0,(HL)       ; Is it the first row of the BASIC line?
  12791.         JR   NZ,L3059     ; Jump if so.
  12792.  
  12793. ;Not in the first row of a BASIC line
  12794.  
  12795.         CALL L2B5B        ; Is previous column position editable? (Returns carry flag set if editable)
  12796.         JR   NC,L306D     ; Jump if not editable since nothing to delete.
  12797.  
  12798.         CALL L2F12        ; Delete character to the right, shifting subsequent rows as required.
  12799.         POP  HL           ; Retrieve address of the editing area information.
  12800.         JR   L3041        ; Jump back to delete next character until first row of the BASIC line is found.
  12801.  
  12802.         PUSH HL           ; [Redundant byte]
  12803.  
  12804. ;In the first row of the BASIC line
  12805.  
  12806. L3059:  LD   A,B          ; Fetch the new end column number.
  12807.         CP   $00          ; Is it at the start of the row?
  12808.         JR   Z,L306D      ; Jump if so since nothing to delete.
  12809.  
  12810.         DEC  B            ; Point to previous column.
  12811.         CALL L2A1A        ; Get character from current cursor position.
  12812.         INC  B            ; Point back to the new end column.
  12813.         CP   $00          ; Is it a null character, i.e. not editable?
  12814.         JR   Z,L306D      ; Jump if so since nothing to delete.
  12815.  
  12816.         DEC  B            ; Point to previous column.
  12817.         CALL L2F12        ; Delete character to the right, shifting subsequent rows as required.
  12818.         JR   L3059        ; Jump back to delete the next character until the start of the BASIC line is found.
  12819.  
  12820. L306D:  POP  HL           ; Retrieve address of the editing area information.
  12821.  
  12822. L306E:  SCF               ; Signal not to produce error beep.
  12823.         JP   L2FF8        ; Jump back to print all rows.
  12824.  
  12825. ; -----------------------------------------
  12826. ; DELETE-TO-END-OF-LINE Key Handler Routine
  12827. ; -----------------------------------------
  12828. ; Delete to the end of the current BASIC line. Since the function works by deleting one character at
  12829. ; a time, display file updates are disabled whilst the function is executing to prevent screen flicker.
  12830. ; An error beep is not produced if there is no characters in the current BASIC line.
  12831. ;
  12832. ; Symbol: -->| DEL
  12833. ;         -->|
  12834. ;
  12835. ; Exit: Carry flag set to indicate not to produce an error beep.
  12836.  
  12837. L3072:  CALL L3084        ; Remove cursor attribute, disable display file updates and get current cursor position. Exits with HL pointing to the editing area information.
  12838.  
  12839. L3075:  CALL L2A1A        ; Get character from current cursor position.
  12840.         CP   $00          ; Is it a null character, i.e. at end of BASIC line?
  12841.         SCF               ; Signal not to produce an error beep.
  12842.         JR   Z,L306E      ; Jump if end of BASIC line to print all rows.
  12843.  
  12844.         PUSH HL           ; Save address of the editing area information.
  12845.         CALL L2F12        ; Delete character to the right, shifting subsequent rows as required.
  12846.         POP  HL           ; Retrieve address of the editing area information.
  12847.         JR   L3075        ; Jump back to delete the next character until the end of the BASIC line is found.
  12848.  
  12849. ; ---------------------------------------------------------
  12850. ; Remove Cursor Attribute and Disable Updating Display File
  12851. ; ---------------------------------------------------------
  12852. ; This routine is called by the DELETE key handler routines. Aside from removing the cursor from the display,
  12853. ; it prevents display file updates occurring whilst the delete functions are executing.
  12854. ; Exit: HL=Address of the editing area information.
  12855. ;       A=Cursor column number preferred.
  12856. ;       B=Cursor column number.
  12857. ;       C=Cursor row number.
  12858.  
  12859. L3084:  LD   HL,$EC0D     ; Editor flags.
  12860.         RES  0,(HL)       ; Signal that the Screen Line Edit Buffer is not full.
  12861.  
  12862.         CALL L29EC        ; Remove cursor, restoring old attribute.
  12863.  
  12864.         LD   HL,$EEF5     ;
  12865.         SET  2,(HL)       ; Indicate not to print edit buffer rows, therefore preventing intermediate screen updates.
  12866.  
  12867.         LD   HL,$F6F1     ; Point to the editing area information.
  12868.         RET               ;
  12869.  
  12870. ; -----------------------------------------------------
  12871. ; Previous Character Exists in Screen Line Edit Buffer?
  12872. ; -----------------------------------------------------
  12873. ; This routine tests the whether a previous character exists in the current BASIC line within
  12874. ; the Screen Line Edit Buffer.
  12875. ; Entry: C=Row number.
  12876. ;        B=Column number.
  12877. ; Exit : Zero flag set if at start of the BASIC line (first column or leading null).
  12878.  
  12879. L3095:  CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  12880.         LD   HL,$0020     ;
  12881.         ADD  HL,DE        ; HL=Address of the flag byte for this row.
  12882.         BIT  0,(HL)       ; Is this the first row of a BASIC line?
  12883.         JR   Z,L30AE      ; Jump if not.
  12884.  
  12885. ;On first row of a BASIC line
  12886.  
  12887.         LD   A,B          ; Fetch the column number.
  12888.         CP   $00          ; At the start of the row?
  12889.         JR   Z,L30B2      ; Jump ahead if so.
  12890.  
  12891.         DEC  B            ; Move to the previous column.
  12892.         CALL L2A1A        ; Get current character from Screen Line Edit Buffer.
  12893.  
  12894.         INC  B            ; Move back to the original column.
  12895.         CP   $00          ; Does the position contain a null?
  12896.         JR   Z,L30B2      ; Jump if not.
  12897.  
  12898. L30AE:  LD   A,$01        ;
  12899.         OR   A            ; Reset the zero flag.
  12900.         RET               ;
  12901.  
  12902. L30B2:  XOR  A            ; Set the zero flag.
  12903.         RET               ;
  12904.  
  12905. ; -------------------------------------------
  12906. ; Find Row Address in Screen Line Edit Buffer
  12907. ; -------------------------------------------
  12908. ; Find address in Screen Line Edit Buffer of specified row.
  12909. ; This routine calculates DE = $EC16 + $0023*C.
  12910. ; Entry: C=Row number.
  12911. ; Exit : DE=Address of edit row.
  12912.  
  12913. L30B4:  LD   HL,$EC16     ; Point to the Screen Line Edit Buffer.
  12914.  
  12915. L30B7:  PUSH AF           ; Save A.
  12916.  
  12917.         LD   A,C          ; A=Edit row number.
  12918.         LD   DE,$0023     ; 35 bytes per row.
  12919.  
  12920. L30BC:  OR   A            ; Row requested found?
  12921.         JR   Z,L30C3      ; Jump to exit if so.
  12922.  
  12923.         ADD  HL,DE        ; Advance to next row.
  12924.         DEC  A            ;
  12925.         JR   L30BC        ; Jump to test if requested row found.
  12926.  
  12927. L30C3:  EX   DE,HL        ; Transfer address to DE.
  12928.  
  12929.         POP  AF           ; Restore A.
  12930.         RET               ;
  12931.  
  12932. ; --------------------------------------------
  12933. ; Find Position within Screen Line Edit Buffer
  12934. ; --------------------------------------------
  12935. ; Find the address of a specified row and column in the Screen Line Edit Buffer.
  12936. ; The routine calculates DE = $EC16 + $0023*C + B.
  12937. ; Entry: B=Column number.
  12938. ;        C=Row number.
  12939. ; Exit : HL=Address of specified position.
  12940.  
  12941. ; [Not used by the ROM]
  12942.  
  12943. L30C6:  PUSH DE           ;
  12944.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the row specified in C.
  12945.         LD   H,$00        ;
  12946.         LD   L,B          ;
  12947.         ADD  HL,DE        ; DE = $EC16 + $0023*C + B.
  12948.         POP  DE           ;
  12949.         RET               ;
  12950.  
  12951. ; --------------------------------------
  12952. ; Below-Screen Line Edit Buffer Settings
  12953. ; --------------------------------------
  12954. ; This table holds the default values for the Below-Screen Line Edit Buffer settings starting at $F6F5. It should only contain a table of 3 bytes to tie up
  12955. ; with the space allocated within the Editor workspace variables at $F6F5. As a result, the last 2 bytes will get copied into the Below-Screen Line Edit Buffer
  12956. ; itself. It appears that the word at $F6F6 is supposed to be a pointer to the next available or accessed location within the buffer but this facility
  12957. ; is never used. Therefore the table need only be 1 byte long, in which case it would be more efficient for the routine at $30D6 (ROM 0) to simply set the byte
  12958. ; at $F6F5 directly.
  12959.  
  12960. L30D0:  DB $05          ; Number of bytes in table.
  12961.         DB $00          ; $F6F5 = Number of rows held in the Below-Screen Line Edit Buffer.
  12962.         DEFW $0000        ; $F6F6/7. [*BUG* - These two bytes should not be here and the table should only contain 3 bytes. Credit: Paul Farrow]
  12963.         DEFW $F6F8        ; $F6F8/9 = Points to next location within the Below-Screen Line Edit Buffer.
  12964.  
  12965. ; ------------------------------------------
  12966. ; Set Below-Screen Line Edit Buffer Settings
  12967. ; ------------------------------------------
  12968. ; Sets the default values for the Below-Screen Line Edit Buffer settings.
  12969. ; Copy 5 bytes from $30D1-$30D5 (ROM 0) to $F6F5-$F6F9.
  12970.  
  12971. L30D6:  LD   HL,L30D0     ; Default Below-Screen Line Edit Buffer settings.
  12972.         LD   DE,$F6F5     ; Destination address.
  12973.         JP   L3FBA        ; Copy bytes.
  12974.  
  12975. ; ----------------------------------------------
  12976. ; Shift Up Rows in Below-Screen Line Edit Buffer
  12977. ; ----------------------------------------------
  12978. ; Shifts up all rows in the Below-Screen Line Edit Buffer, or if empty then
  12979. ; copies a BASIC line from the program area into the Below-Screen Line Edit Buffer.
  12980. ; Exit: HL=Address of the Below-Screen Line Edit Buffer.
  12981.  
  12982. L30DF:  PUSH BC           ; Save BC.
  12983.         PUSH DE           ; Save DE.
  12984.  
  12985.         LD   HL,$F6F5     ; Point to the Below-Screen Line Edit Buffer details.
  12986.         PUSH HL           ; Save it.
  12987.         LD   A,(HL)       ; A=Number of rows held in Below-Screen Line Edit Buffer.
  12988.         OR   A            ; Are there any rows below screen?
  12989.         JR   NZ,L3101     ; Jump if so.
  12990.  
  12991. ;There are no rows in the Below-Screen Line Edit Buffer
  12992.  
  12993.         PUSH HL           ; Save the address of the Below-Screen Line Edit Buffer details.
  12994.         CALL L335F        ; Copy 'Insert Keyword Representation Into Keyword Construction Buffer' routine into RAM.
  12995.  
  12996.         LD   HL,($F9D7)   ; HL=Line number of the BASIC line in the program area being edited.
  12997.         CALL L3352        ; Create line number representation in the Keyword Construction Buffer of the next BASIC line.
  12998.         JR   NC,L30F8     ; Jump if next line does not exist, with HL holding $0000.
  12999.  
  13000.         LD   ($F9D7),HL   ; Store the new line number.
  13001.  
  13002. L30F8:  LD   B,H          ;
  13003.         LD   C,L          ; BC=Line number of the next BASIC line, or last BASIC line in the program.
  13004.         POP  HL           ; Retrieve the address of the Below-Screen Line Edit Buffer details.
  13005.         CALL L32D6        ; Copy the BASIC line into the Below-Screen Line Edit Buffer, or empty the first buffer row if the BASIC line does not exist.
  13006.         DEC  A            ; Decrement the count of the number of rows held in the Below-Screen Line Edit Buffer, i.e. assume the rows have been shifted.
  13007.         JR   L3116        ; Jump forward.
  13008.  
  13009. ;There are rows in the Below-Screen Line Edit Buffer so shift all rows up
  13010.  
  13011. L3101:  LD   HL,$EC0D     ; Editor flags.
  13012.         RES  0,(HL)       ; Signal that the Screen Line Edit Buffer is not full.
  13013.  
  13014.         LD   HL,$F6F8     ; Below-Screen Line Edit Buffer, the temporary copy of line being edited.
  13015.         LD   D,H          ;
  13016.         LD   E,L          ;
  13017.         LD   BC,$0023     ; Move all rows in the Below-Screen Line Edit Buffer up by one row.
  13018.         ADD  HL,BC        ;
  13019.         LD   BC,$02BC     ; 20 rows.
  13020.         LDIR              ;
  13021.         DEC  A            ; Decrement the count of the number of rows held in the Below-Screen Line Edit Buffer.
  13022.         SCF               ; [Redundant since never subsequently checked]
  13023.  
  13024. L3116:  POP  DE           ; DE=Points to number of rows held in the Below-Screen Line Edit Buffer.
  13025.         LD   (DE),A       ; Update the number of rows held in the Below-Screen Line Edit Buffer
  13026.  
  13027.         LD   HL,$F6F8     ; HL=Address of first row in the Below-Screen Line Edit Buffer.
  13028.  
  13029.         POP  DE           ; Restore DE.
  13030.         POP  BC           ; Restore BC.
  13031.         RET               ;
  13032.  
  13033. ; ------------------------------------------------
  13034. ; Shift Down Rows in Below-Screen Line Edit Buffer
  13035. ; ------------------------------------------------
  13036. ; Shifts down all rows in the Below-Screen Line Edit Buffer, or the last Screen Line Edit Buffer
  13037. ; row contains a complete BASIC line then it empties the Below-Screen Line Edit Buffer.
  13038. ; Entry: DE=Start address in Screen Line Edit Buffer of the last editing row.
  13039. ; Exit : Carry flag reset to indicate Below-Screen Line Edit Buffer full.
  13040. ;        A =Number of rows held in the Below-Screen Line Edit Buffer.
  13041. ;        HL=Address of first row in the Below-Screen Line Edit Buffer.
  13042.  
  13043. L311E:  PUSH BC           ; Save BC.
  13044.         PUSH DE           ; DE=Start address in Screen Line Edit Buffer of the last editing row.
  13045.  
  13046.         LD   HL,$0020     ;
  13047.         ADD  HL,DE        ; Point to the flag byte for the edit buffer row.
  13048.         LD   A,(HL)       ; Fetch flag byte.
  13049.         CPL               ; Invert bits.
  13050.         AND  $11          ;
  13051.         JR   NZ,L313F     ; Jump if not the first row of the BASIC line or no associated line number stored.
  13052.  
  13053. ;First row of the BASIC line or an associated line number stored
  13054.  
  13055.         PUSH HL           ; HL=Points at flag byte of the last Screen Line Edit Buffer row.
  13056.         PUSH DE           ; DE=Address of the last Screen Line Edit Buffer row.
  13057.         INC  HL           ;
  13058.         LD   D,(HL)       ;
  13059.         INC  HL           ;
  13060.         LD   E,(HL)       ; DE=Corresponding BASIC line number.
  13061.         PUSH DE           ; Save it.
  13062.  
  13063.         CALL L335F        ; Copy 'Insert Keyword Representation Into Keyword Construction Buffer' routine to RAM.
  13064.  
  13065.         POP  HL           ; HL=Corresponding line number for last editing row.
  13066.         CALL L334A        ; Find the closest line number.
  13067.         JR   NC,L313D     ; Jump if line does not exist.
  13068.  
  13069.         LD   ($F9D7),HL   ; Store as the line number of the BASIC line being edited.
  13070.  
  13071. L313D:  POP  DE           ; DE=Address of the last Screen Line Edit Buffer row.
  13072.         POP  HL           ; HL=Points at flag byte of edit buffer row.
  13073.  
  13074. L313F:  BIT  0,(HL)       ; Is it the first row of the BASIC line?
  13075.         LD   HL,$F6F5     ; Point to the Below-Screen Line Edit Buffer details.
  13076.         PUSH HL           ; Save the address of the Below-Screen Line Edit Buffer details.
  13077.         JR   Z,L314C      ; Jump if not the first row of the BASIC line.
  13078.  
  13079. ;The first row of the BASIC line, hence after the shift there will not be a row straggling off the bottom of the screen
  13080.  
  13081.         LD   A,$00        ; Signal no rows held in the Below-Screen Line Edit Buffer. [Could have saved 1 byte by using XOR A]
  13082.         SCF               ; Signal Below-Screen Line Edit Buffer is not full.
  13083.         JR   L3116        ; Store new flag.
  13084.  
  13085. ;Not the first row the BASIC line
  13086.  
  13087. L314C:  LD   A,(HL)       ; Fetch the number of rows held in the Below-Screen Line Edit Buffer.
  13088.         CP   $14          ; Has the bottom of the buffer been reached?
  13089.         JR   Z,L3116      ; Jump if so, with the carry flag reset to indicate the buffer is full.
  13090.  
  13091. ;The Below-Screen Line Edit Buffer is not full so copy the last Screen Line Edit Buffer row into the top 'visible' Below-Screen Line Edit Buffer row
  13092.  
  13093.         LD   BC,$0023     ; Length of an edit buffer row.
  13094.         LD   HL,$F6F8     ; Address of the first row in the Below-Screen Line Edit Buffer.
  13095.         EX   DE,HL        ; HL=Address of the last row in the Screen Line Edit Buffer, DE=Address of the first row in the Below-Screen Line Edit Buffer.
  13096.         LDIR              ; Copy the last Screen Line Edit Buffer row into the first Below-Screen Line Edit Buffer row, i.e. the 'visible' edit buffer row.
  13097.  
  13098. ;Copy all Below-Screen Line Edit Buffer rows down
  13099.  
  13100.         LD   HL,$F9D6     ;
  13101.         LD   D,H          ;
  13102.         LD   E,L          ; DE=End of the last row in the Below-Screen Line Edit Buffer.
  13103.         LD   BC,$0023     ; Length of an edit buffer row.
  13104.         OR   A            ;
  13105.         SBC  HL,BC        ; HL=End of penultimate row in the Below-Screen Line Edit Buffer.
  13106.         LD   BC,$02BC     ; Length of the Below-Screen Line Edit Buffer minus one row.
  13107.         LDDR              ; Shift all the rows down by one.
  13108.  
  13109.         INC  A            ; Increment the number of rows held in the Below-Screen Line Edit Buffer.
  13110.         SCF               ; Signal Below-Screen Line Edit Buffer is not full.
  13111.         JR   L3116        ; Jump to store the number of rows held in the Below-Screen Line Edit Buffer.
  13112.  
  13113. ; ---------------------------------------------------
  13114. ; Insert Character into Below-Screen Line Edit Buffer
  13115. ; ---------------------------------------------------
  13116. ; Called when a non-action key is pressed and rows of the BASIC line spans into the Below-Screen Line Edit Buffer and therefore
  13117. ; require shifting.
  13118. ; Entry: HL=Current row's flag byte.
  13119. ;        A=Character code to insert at the start of the first row of the Below-Screen Line Edit Buffer.
  13120.  
  13121. L316E:  PUSH BC           ; Save registers.
  13122.         PUSH DE           ;
  13123.  
  13124.         PUSH AF           ; Save the character to insert.
  13125.  
  13126.         LD   B,$00        ; Column 0.
  13127.         LD   C,$01        ; Row 1.
  13128.         PUSH HL           ; Save address of the row's flag byte.
  13129.         CALL L31C3        ; Find row address specified by C in the Below-Screen Line Edit Buffer, into DE.
  13130.         POP  HL           ; Retrieve address of the row's flag byte.
  13131.  
  13132.         BIT  3,(HL)       ; Is this the end row of the BASIC line?
  13133.         RES  3,(HL)       ; Indicate that it is no longer the end row of the BASIC line.
  13134.         JR   NZ,L31A0     ; Jump if it was the end row of the BASIC line.
  13135.  
  13136. ;The row in the Below-Screen Line Edit Buffer is not the last row of the BASIC line.
  13137.  
  13138. ;Insert the character into the current row. If a spill from this row occurs then insert that character into the start of the
  13139. ;following row and shift all existing characters right by one. Repeat this process until all rows have been shifted.
  13140.  
  13141. L3180:  CALL L2E41        ; Find first editable position on this row from the previous column to the right, returning column number in B.
  13142.         POP  AF           ; A=Character to insert.
  13143.  
  13144. L3184:  CALL L16AC        ; Insert character into the start of the edit buffer row, shifting the row right. Returns carry flag reset.
  13145.         JR   Z,L31BA      ; Jump if the byte shifted out of the last column position was $00, hence no more shifting required.
  13146.  
  13147. ;The end character of the row has spilled out so it must be inserted as the first editable character of the following row
  13148.  
  13149.         PUSH AF           ; Stack the character which needs to be inserted into the next row.
  13150.  
  13151.         LD   B,$00        ; B=First column in the next row.
  13152.         INC  C            ; C=Next row.
  13153.         LD   A,C          ;
  13154.         CP   $15          ; Has the bottom row of the Below-Screen Line Edit Buffer been reached, i.e. row 21?
  13155.         JR   C,L31A0      ; Jump ahead if not.
  13156.  
  13157. ;The bottom row of the Below-Screen Line Edit Buffer has been reached
  13158.  
  13159.         DEC  HL           ; Point to last character of the current row.
  13160.         LD   A,(HL)       ; Get the character.
  13161.         INC  HL           ; Point back to the flag byte of this row.
  13162.         CP   $00          ; Is the character a null character? [Could have saved 1 byte by using AND A]
  13163.         JR   Z,L31A0      ; Jump ahead if it is.
  13164.  
  13165. ;The Below-Screen Line Edit Buffer is completely full
  13166.  
  13167.         PUSH HL           ; Save address of the flag byte.
  13168.         LD   HL,$EC0D     ; Editor flags.
  13169.         SET  0,(HL)       ; Signal that the Screen Line Edit Buffer (including Below-Screen Line Edit Buffer) is full.
  13170.         POP  HL           ; HL=Address of the flag byte.
  13171.  
  13172. ;Check whether there is another row to shift
  13173.  
  13174. L31A0:  BIT  1,(HL)       ; Does the row span onto another row?
  13175.         SET  1,(HL)       ; Signal that the row spans onto another row.
  13176.         RES  3,(HL)       ; Signal not the last row of the BASIC line.
  13177.         CALL L31C3        ; Find the address of the row specified by C in Below-Screen Line Edit Buffer, into DE.
  13178.         JR   NZ,L3180     ; Jump back if spans onto another row to shift it also.
  13179.  
  13180. ;All existing rows have now been shifted but a new row needs to be inserted
  13181.  
  13182.         PUSH BC           ; B=Column number. C=Row number.
  13183.         PUSH DE           ; DE=Start address of the row in the edit buffer.
  13184.         CALL L35E6        ; Null all column positions in the edit buffer row.
  13185.         LD   (HL),$08     ; Set the flag byte for the row to indicate it is the last row of the BASIC line.
  13186.         POP  DE           ; DE=Start address of the row in the edit buffer.
  13187.         POP  BC           ; B=Column number. C=Row number.
  13188.  
  13189.         CALL L35F4        ; Indent the row by setting the appropriate number of null characters.
  13190.  
  13191.         POP  AF           ; Get character to insert.
  13192.         JR   L3184        ; Jump back to insert it.
  13193.  
  13194. ;The shifting of all rows has completed
  13195.  
  13196. L31BA:  LD   A,C          ; Get the row number.
  13197.         LD   ($F6F5),A    ; Store as the number of rows held within the Below-Screen Line Edit Buffer.
  13198.         SET  3,(HL)       ; Mark this row as the last row of the BASIC line.
  13199.  
  13200.         POP  DE           ; Restore registers.
  13201.         POP  BC           ;
  13202.         RET               ;
  13203.  
  13204. ; -------------------------------------------------
  13205. ; Find Row Address in Below-Screen Line Edit Buffer
  13206. ; -------------------------------------------------
  13207. ; Find address in the Below-Screen Line Edit Buffer of specified row.
  13208. ; This routine calculates DE = $F6F8 + $0023*C.
  13209. ; Entry: C=Row number.
  13210. ; Exit : Address of edit row in DE.
  13211.  
  13212. L31C3:  LD   HL,$F6F8     ; Address of the Below-Screen Line Edit Buffer.
  13213.         JP   L30B7        ; Jump to find the row address and return.
  13214.  
  13215. ; -------------------------------------------------------------------------
  13216. ; Delete a Character from a BASIC Line in the Below-Screen Line Edit Buffer
  13217. ; -------------------------------------------------------------------------
  13218. ; Delete a character at the specified position, shifting subsequent characters left as applicable.
  13219. ; Exit: A=Character shifted out of the top row of the Below-Screen Line Edit Buffer.
  13220.  
  13221. L31C9:  PUSH BC           ; Save registers.
  13222.         PUSH DE           ;
  13223.  
  13224.         LD   HL,$EC0D     ; Editor flags.
  13225.         RES  0,(HL)       ; Signal that the Screen Line Edit Buffer (including Below-Screen Line Edit Buffer) is not full.
  13226.  
  13227.         LD   A,($F6F5)    ; A=Number of rows held in the Below-Screen Line Edit Buffer.
  13228.         LD   C,A          ; C=Number of rows held in the Below-Screen Line Edit Buffer.
  13229.         OR   A            ; Are there any rows in the Below-Screen Line Edit Buffer?
  13230.         LD   A,$00        ; A null character.
  13231.         JR   Z,L321B      ; Jump if there are no rows. [Redundant check since this routine should never be called if there are no rows in this buffer]
  13232.  
  13233. ;There is at least one row in the Below-Screen Line Edit Buffer
  13234.  
  13235. L31D9:  CALL L31C3        ; Find the address of the last used row within Below-Screen Line Edit Buffer, into DE.
  13236.         PUSH AF           ; Save the character to insert.
  13237.  
  13238.         LD   B,$00        ; Start searching from column 0.
  13239.         CALL L2E41        ; Find editable position on this row to the right, returning column number in B.
  13240.         JR   NC,L31F2     ; Jump if no editable position found, i.e. a blank row.
  13241.  
  13242. ;The row is not blank
  13243.  
  13244.         POP  AF           ; A=Character to insert.
  13245.  
  13246. ;DE=Address within a row of edit buffer.
  13247. ;A=Character to shift into right of row.
  13248. ;B=The column to start shifting at.
  13249.  
  13250.         CALL L16C1        ; Insert the character into the end of the edit buffer row, shifting all columns left until the cursor position is reached.
  13251.  
  13252.         PUSH AF           ; A=Character shifted out, zero flag set if the shifted out character was a null ($00).
  13253.         PUSH BC           ; Save the row number.
  13254.  
  13255.         LD   B,$00        ; Start searching from column 0.
  13256.         CALL L2E41        ; Is this now a blank row? i.e. Find editable position on this row to the right, returning column number in B.
  13257.         POP  BC           ; C=Row number.
  13258.         JR   C,L3216      ; Jump if editable position found.
  13259.  
  13260. ;The row is already blank or the result of the shift has caused it to become blank.
  13261. ;HL points to the last blank character in the row.
  13262.  
  13263. L31F2:  INC  HL           ; Point to the flag byte for the blank row.
  13264.         LD   A,(HL)       ; Fetch the flag byte.
  13265.         PUSH AF           ; Save the flag byte for the blank row.
  13266.         PUSH BC           ; Save the row number.
  13267.  
  13268.         LD   A,C          ; Fetch the row number of this blank row.
  13269.         CP   $01          ; Is this the first row in the Below-Screen Line Edit Buffer?
  13270.         JR   NZ,L3204     ; Jump if not.
  13271.  
  13272. ;The first row in the Below-Screen Line Edit Buffer is empty and hence the BASIC line now fits completely on screen, i.e. within the Screen Line Edit Buffer
  13273.  
  13274.         LD   A,($EC15)    ; The number of editing rows on screen.
  13275.         LD   C,A          ; C=Bottom row number in the Screen Line Edit Buffer.
  13276.         CALL L30B4        ; DE=Start address in Screen Line Edit Buffer of the bottom row, as specified in C.
  13277.         JR   L3208        ; Jump ahead to continue.
  13278.  
  13279. ;The blank row is not the first row in the Below-Screen Line Edit Buffer, and hence there are further rows above to be shifted
  13280.  
  13281. L3204:  DEC  C            ; Previous row within the Below-Screen Line Edit Buffer.
  13282.         CALL L31C3        ; Find the address of the row specified by C in Below-Screen Line Edit Buffer, into DE.
  13283.  
  13284. L3208:  POP  BC           ; Retrieve the row number.
  13285.         POP  AF           ; A=Flag byte value for the blank row.
  13286.  
  13287.         LD   HL,$0020     ;
  13288.         ADD  HL,DE        ; Point to the flag byte for the row above.
  13289.         RES  1,(HL)       ; Signal that the row above does not span onto another row.
  13290.         OR   (HL)         ; Or in the flag bits from the blank row, essentially this will retain the 'last row' bit.
  13291.         LD   (HL),A       ; Update the flag byte for the row above.
  13292.  
  13293.         LD   HL,$F6F5     ; Point to the number of rows held in the Below-Screen Line Edit Buffer.
  13294.         DEC  (HL)         ; Decrement the row count.
  13295.  
  13296. ;Continue with the next row
  13297.  
  13298. L3216:  POP  AF           ; Fetch the character shifted out from the current row, ready for insertion into the row above.
  13299.         DEC  C            ; Previous row.
  13300.         JR   NZ,L31D9     ; Jump back if the character shifted out was not null, i.e. more rows above to shift.
  13301.  
  13302. ;All rows in the Below-Screen Line Edit Buffer have been shifted
  13303.  
  13304.         SCF               ; [Redundant since never subsequently checked]
  13305.  
  13306. L321B:  POP  DE           ; Restore registers.
  13307.         POP  BC           ;
  13308.         RET               ;
  13309.  
  13310. ; --------------------------------------
  13311. ; Above-Screen Line Edit Buffer Settings
  13312. ; --------------------------------------
  13313. ; This table holds the default values for the Below-Screen Line Edit Buffer settings starting at $F9DB.
  13314. ; It appears that the word at $F9DC is supposed to be a pointer to the next available or accessed location within the buffer but this facility
  13315. ; is never used. Therefore the table need only be 1 byte long, in which case it would be more efficient for the routine at $3222 (ROM 0) to simply
  13316. ; set the byte at $F9DB directly.
  13317.  
  13318. L321E:  DB $03          ; Number of bytes in table.
  13319.         DB $00          ; $F9DB = Number of rows held in the Above-Screen Line Edit Buffer.
  13320.         DEFW $F9DE        ; $F9DC/D = Points to next available location within the Above-Screen Line Edit Buffer.
  13321.  
  13322. ; ------------------------------------------
  13323. ; Set Above-Screen Line Edit Buffer Settings
  13324. ; ------------------------------------------
  13325. ; Sets the default values for the Above-Screen Line Edit Buffer settings.
  13326. ; Copy 3 bytes from $321F-$3221 (ROM 0) to $F9DB-$F9DD.
  13327.  
  13328. L3222:  LD   HL,L321E     ; Default Above-Screen Line Edit Buffer settings.
  13329.         LD   DE,$F9DB     ; Destination address.
  13330.         JP   L3FBA        ; Copy bytes.
  13331.  
  13332. ; ----------------------------------------------------
  13333. ; Shift Rows Down in the Above-Screen Line Edit Buffer
  13334. ; ----------------------------------------------------
  13335. ; If Above-Screen Line Edit Buffer contains row then decrement the count, i.e. less rows off screen.
  13336. ; If the Above-Screen Line Edit Buffer is empty then load in the new BASIC line at the top of the screen.
  13337. ; Exit : HL=Address of next row to use within the Above-Screen Line Edit Buffer.
  13338. ;        Carry flag reset if Above-Screen Line Edit Buffer is empty, i.e. no edit buffer rows were shifted.
  13339.  
  13340. L322B:  PUSH BC           ; Save registers.
  13341.         PUSH DE           ;
  13342.  
  13343.         LD   HL,$F9DB     ; Point to the Above-Screen Line Edit Buffer settings.
  13344.         PUSH HL           ; Save address of the Above-Screen Line Edit Buffer settings.
  13345.  
  13346.         LD   A,(HL)       ; Fetch number of rows of the BASIC line that are off the top of the screen.
  13347.         OR   A            ; Are there any rows off the top of the screen?
  13348.         JR   NZ,L3253     ; Jump if there are.
  13349.  
  13350. ;There are no rows of the BASIC line off the top of the screen so use the top line that is visible on screen
  13351.  
  13352.         PUSH HL           ; Save address of the Above-Screen Line Edit Buffer settings.
  13353.  
  13354.         CALL L335F        ; Copy 'Insert Keyword Representation Into Keyword Construction Buffer' routine to RAM.
  13355.  
  13356.         LD   HL,($FC9A)   ; HL=New line number at top of screen.
  13357.         CALL L334A        ; Verify the line number exists, or fetch the next line number if not.
  13358.         JR   NC,L3244     ; Jump if the line does not exist.
  13359.  
  13360.         LD   ($FC9A),HL   ; Store the line number found as the one at the top of screen.
  13361.  
  13362. L3244:  LD   B,H          ;
  13363.         LD   C,L          ; BC=New line number at top of screen.
  13364.  
  13365.         POP  HL           ; HL=Address of the Above-Screen Line Edit Buffer settings.
  13366.         INC  HL           ;
  13367.         INC  HL           ;
  13368.         INC  HL           ; Point to the first row of the Above-Screen Line Edit Buffer.
  13369.         JR   NC,L325D     ; Jump if the line did not exist.
  13370.  
  13371. ;The line specified as the one at the top of the screen does exists
  13372.  
  13373. ; [*BUG* - HL points to the start of the first row of the Above-Screen Line Edit Buffer but it should point to the settings fields
  13374. ;          3 bytes earlier since the call to $32D6 (ROM 0) will advance HL by 3 bytes.
  13375. ;          The bug manifests itself when modifying a BASIC line that spans off the top of the screen. It causes corruption
  13376. ;          to the line number, causing a new BASIC line to be inserted rather than updating the line being edited. When editing lines with
  13377. ;          a high line number, the corrupted line number can end up larger 9999 and hence the line is deemed invalid when Enter is pressed
  13378. ;          to insert the line into the BASIC program. The effects of the bug are often masked by the bug at $2DA1 (ROM 0) which performs LD HL,($F9DB)
  13379. ;          instead of LD HL,$F9DB and thereby fails to detect when the end of the Above-Screen Line Edit Buffer has been reached. The bug can
  13380. ;          be fixed by inserted three DEC HL instructions before the call to $32D6 (ROM 0). Credit: Paul Farrow]
  13381.  
  13382.         CALL L32D6        ; Copy the new BASIC line into the Above-Screen Line Edit Buffer.
  13383.  
  13384.         DEC  A            ; Decrement the count of the number of rows held in the Above-Screen Line Edit Buffer.
  13385.         EX   DE,HL        ; HL=Start of the next row in the Above-Screen Line Edit Buffer.
  13386.         JR   L325D        ; Jump ahead to continue.
  13387.  
  13388. ;There are rows of the BASIC line off the top of the screen
  13389.  
  13390. L3253:  LD   HL,($F9DC)   ; HL=Address of the next location within the Above-Screen Line Edit Buffer to use.
  13391.         LD   BC,$0023     ;
  13392.         SBC  HL,BC        ; Point to the previous row location within the Above-Screen Line Edit Buffer.
  13393.         SCF               ; Signal to update the number of rows held in the Above-Screen Line Edit Buffer.
  13394.         DEC  A            ; Decrement the count of the number of rows held in the Above-Screen Line Edit Buffer.
  13395.  
  13396. ;A=New number of rows held in the Above-Screen Line Edit Buffer.
  13397. ;HL=Address of a next row to use within the Above-Screen Line Edit Buffer.
  13398. ;Carry flag reset if no need to update the count of the number of rows in the Above-Screen Line Edit Buffer.
  13399.  
  13400. L325D:  EX   DE,HL        ; DE=Address of next row to use within the Above-Screen Line Edit Buffer.
  13401.         POP  HL           ; HL=Address of the Above-Screen Line Edit Buffer settings.
  13402.         JR   NC,L3262     ; Jump if no need to update the count of the number of rows in the Above-Screen Line Edit Buffer.
  13403.  
  13404.         LD   (HL),A       ; Store the number of rows held in the Above-Screen Line Edit Buffer.
  13405.  
  13406. L3262:  INC  HL           ;
  13407.         LD   (HL),E       ;
  13408.         INC  HL           ;
  13409.         LD   (HL),D       ; Store the address of the next row to use within the Above-Screen Line Edit Buffer.
  13410.         EX   DE,HL        ; HL=Address of next row to use within the Above-Screen Line Edit Buffer.
  13411.  
  13412.         POP  DE           ; Restore registers.
  13413.         POP  BC           ;
  13414.         RET               ;
  13415.  
  13416. ; ---------------------------------------------------------------
  13417. ; Shift Row Up into the Above-Screen Line Edit Buffer if Required
  13418. ; ---------------------------------------------------------------
  13419. ; This routine is used to shift up a Screen Line Edit Buffer or a Below-Screen Line Edit Buffer row into the Above-Screen Line Edit Buffer.
  13420. ; If shifting the top row of the Screen Line Edit Buffer would result in a straggle into the Above-Screen Line Edit Buffer
  13421. ; then the top row is shifted into the next available location within the Above-Screen Line Edit Buffer. If the shift would
  13422. ; place the start of a BASIC line on the top row then the Above-Screen Line Edit Buffer is set as empty.
  13423. ; The routine is also called when relisting the BASIC program. The first BASIC line may straggle above the screen and so it is necessary to
  13424. ; load the BASIC line into the Above-Screen Line Edit Buffer. This is achieved by using the Below-Screen Line Edit Buffer as a temporary
  13425. ; line workspace. This routine is called to shift each row into the Above-Screen Line Edit Buffer as appropriate.
  13426. ; Entry: DE=Start address of the first row in the Screen Line Edit Buffer, or start address of a Below-Screen Line Edit Buffer row.
  13427. ; Exit : HL=Address of next row to use within the Below-Screen or Screen Line Edit Buffer.
  13428. ;        Carry flag set if the Line Edit Buffer if not full.
  13429.  
  13430. L326A:  PUSH BC           ; Save registers.
  13431.         PUSH DE           ;
  13432.  
  13433.         LD   HL,$0020     ;
  13434.         ADD  HL,DE        ; Point to the flag byte for this row within the Below-Screen or Screen Line Edit Buffer.
  13435.         LD   A,(HL)       ; Fetch the flag byte.
  13436.         CPL               ;
  13437.         AND  $11          ;
  13438.         JR   NZ,L3282     ; Jump if not the first row of the BASIC line or no associated line number stored.
  13439.  
  13440. ;First row of the BASIC line and associated line number stored
  13441.  
  13442.         PUSH DE           ; DE=Start address of the row.
  13443.         PUSH HL           ; HL=Address of the flag byte for the row in the Line Edit Buffer.
  13444.  
  13445.         INC  HL           ;
  13446.         LD   D,(HL)       ;
  13447.         INC  HL           ;
  13448.         LD   E,(HL)       ; DE=Line number of the corresponding BASIC line.
  13449.         LD   ($FC9A),DE   ; Store this as the line number that is at the top of the screen.
  13450.  
  13451.         POP  HL           ; HL=Address of the flag byte for the row in the Below-Screen or Screen Line Edit Buffer.
  13452.         POP  DE           ; DE=Start address of the row.
  13453.  
  13454. L3282:  BIT  3,(HL)       ; Is this the last row of the BASIC line?
  13455.         LD   HL,$F9DB     ; Point to the Above-Screen Line Edit Buffer settings.
  13456.         PUSH HL           ; Stack the address of the Above-Screen Line Edit Buffer settings.
  13457.         JR   Z,L32A0      ; Jump if not the last row of the BASIC line.
  13458.  
  13459. ;The last row of the BASIC line
  13460.  
  13461.         PUSH HL           ; Stack the address of the Above-Screen Line Edit Buffer settings.
  13462.  
  13463.         CALL L335F        ; Copy 'Insert Keyword Representation Into Keyword Construction Buffer' routine to RAM.
  13464.  
  13465.         LD   HL,($FC9A)   ; Line number at top of screen.
  13466.         CALL L3352        ; Create line number representation in the Keyword Construction Buffer of the next BASIC line.
  13467.         LD   ($FC9A),HL   ; Update the line number at top of screen.
  13468.  
  13469.         POP  HL           ; HL=Address of the Above-Screen Line Edit Buffer settings.
  13470.         INC  HL           ;
  13471.         INC  HL           ;
  13472.         INC  HL           ; Point to the start of the Above-Screen Line Edit Buffer.
  13473.  
  13474.         LD   A,$00        ; No rows held in the Above-Screen Line Edit Buffer. [Could have saved 1 byte by using XOR A]
  13475.         SCF               ; Signal to update the number of rows count.
  13476.         JR   L325D        ; Jump back to store the new Above-Screen Line Edit Buffer settings.
  13477.  
  13478. ;Not the last row of the BASIC line
  13479.  
  13480. L32A0:  LD   A,(HL)       ; Fetch the number of rows held in the Above-Screen or Screen Line Edit Buffer.
  13481.         CP   $14          ; Are there 20 rows, i.e. the buffer is full?
  13482.         JR   Z,L32B3      ; Jump if the buffer is full, with the carry flag reset.
  13483.  
  13484. ;Shift the top row of the Screen Line Edit Buffer into the Above-Screen Line Edit Buffer
  13485.  
  13486.         INC  A            ; Increment the count of the number of rows in the Above-Screen Line Edit Buffer.
  13487.         LD   HL,($F9DC)   ; Fetch the address of the next row to use within the Above-Screen Line Edit Buffer.
  13488.         LD   BC,$0023     ; The length of one row in the edit buffer, including the 3 data bytes.
  13489.         EX   DE,HL        ; DE=Address of next location within the Above-Screen Line Edit Buffer, HL=Address of the row in the Below-Screen or Screen Line Edit Buffer to store.
  13490.         LDIR              ; Copy the row of the BASIC line into the Above-Screen Line Edit Buffer.
  13491.  
  13492.         EX   DE,HL        ; HL=Address of next row to use within the Above-Screen Line Edit Buffer.
  13493.         SCF               ; Signal to update the count of the number of rows.
  13494.         JR   L325D        ; Jump back to store the new Above-Screen Line Edit Buffer settings.
  13495.  
  13496. ;Above-Screen Line Edit Buffer is full
  13497.  
  13498. L32B3:  POP  HL           ; HL=Address of the Above-Screen Line Edit Buffer settings.
  13499.         POP  DE           ; Restore registers.
  13500.         POP  BC           ;
  13501.         RET               ;
  13502.  
  13503. ; -------------------------------------------------
  13504. ; Find Row Address in Above-Screen Line Edit Buffer
  13505. ; -------------------------------------------------
  13506. ; Find the address in the Above-Screen Line Edit Buffer of the specified row.
  13507. ; This routine calculates DE = $F9DE + $0023*C.
  13508. ; Entry: C=Row number.
  13509. ; Exit : DE=Address of edit row.
  13510. ;
  13511. L32B7:  LD   HL,$F9DE     ; Point to the start of the Above-Screen Line Edit Buffer.
  13512.         JP   L30B7        ; Find the row address.
  13513.  
  13514. ; ----------------------------------------------
  13515. ; BASIC Line Character Action Handler Jump Table
  13516. ; ----------------------------------------------
  13517.  
  13518. L32BD:  DB $08          ; Number of table entries.
  13519.         DB $0D          ; Code: Enter.
  13520.         DEFW L35CC        ; Address of the 'Enter' action handler routine.
  13521.         DB $01          ; Code: NULL.
  13522.         DEFW L35DA        ; Null remaining columns of an edit buffer row.
  13523.         DB $12          ; Code: FLASH.
  13524.         DEFW L335A        ; Fetch next de-tokenized character from the BASIC line within the program area.
  13525.         DB $13          ; Code: BRIGHT.
  13526.         DEFW L335A        ; Fetch next de-tokenized character from the BASIC line within the program area.
  13527.         DB $14          ; Code: INVERSE.
  13528.         DEFW L335A        ; Fetch next de-tokenized character from the BASIC line within the program area.
  13529.         DB $15          ; Code: OVER.
  13530.         DEFW L335A        ; Fetch next de-tokenized character from the BASIC line within the program area.
  13531.         DB $10          ; Code: INK.
  13532.         DEFW L335A        ; Fetch next de-tokenized character from the BASIC line within the program area.
  13533.         DB $11          ; Code: PAPER.
  13534.         DEFW L335A        ; Fetch next de-tokenized character from the BASIC line within the program area.
  13535.  
  13536. ; ------------------------------------------------------------------------
  13537. ; Copy a BASIC Line into the Above-Screen or Below-Screen Line Edit Buffer
  13538. ; ------------------------------------------------------------------------
  13539. ; Copy a BASIC line into the Above-Screen or Below-Screen Line Edit Buffer, handling indentation.
  13540. ; Entry: HL=Address of the previous row's flag byte in Above-Screen or Below-Screen Line Edit Buffer.
  13541. ;        BC=Line number corresponding to the row being edited.
  13542. ; Exit : A=Number of rows in the Above-Screen Line Edit Buffer.
  13543. ;        HL=Address of the first row of the BASIC line being edited in the Above-Screen Line Edit Buffer.
  13544. ;        DE=Address of the last row of the BASIC line being edited in the Above-Screen Line Edit Buffer.
  13545.  
  13546. L32D6:  LD   D,H          ; HL=Address of the previous row's flag byte in the Above-Screen/Below-Screen Line Edit Buffer.
  13547.         LD   E,L          ; DE=Address of the previous row's flag byte in the Above-Screen/Below-Screen Line Edit Buffer.
  13548.         INC  DE           ;
  13549.         INC  DE           ;
  13550.         INC  DE           ; Advance to the start of the row in the edit buffer.
  13551.         PUSH DE           ; DE=Address of the start of the BASIC line in the Above-Screen/Below-Screen Line Edit Buffer.
  13552.  
  13553.         LD   HL,$0020     ;
  13554.         ADD  HL,DE        ; Point to the flag byte for the row.
  13555.         LD   (HL),$01     ; Signal the first row of the BASIC line.
  13556.         INC  HL           ;
  13557.         LD   (HL),B       ;
  13558.         INC  HL           ;
  13559.         LD   (HL),C       ; Store the corresponding BASIC line number.
  13560.  
  13561.         LD   C,$01        ; Row 1.
  13562.         LD   B,$00        ; Column 0.
  13563.  
  13564. ;Enter a loop to process each character from the current BASIC line
  13565.  
  13566. L32EA:  PUSH BC           ; Save the column and row numbers.
  13567.         PUSH DE           ; Save the Above-Screen/Below-Screen Line Edit Buffer address.
  13568.  
  13569.         LD   A,($EC0E)    ; Fetch mode.
  13570.         CP   $04          ; Calculator mode?
  13571.         CALL NZ,L3517     ; If not then fetch the next de-tokenized character from the BASIC line within the program area.
  13572.  
  13573.         POP  DE           ; Retrieve the Above-Screen/Below-Screen Line Edit Buffer address.
  13574.         POP  BC           ; Retrieve the column and row numbers.
  13575.         JR   C,L3307      ; Jump if Editor mode and a character was available (if calculator mode then carry flag was reset by test above).
  13576.  
  13577. ;Calculator mode, or Editor mode and a character was not available
  13578.  
  13579.         LD   A,C          ; A=Row number.
  13580.         CP   $01          ; Is it row 1?
  13581.         LD   A,$0D        ; A='Enter' character.
  13582.         JR   NZ,L3307     ; Jump if not.
  13583.  
  13584. ;Row 1
  13585.  
  13586.         LD   A,B          ; A=Column number.
  13587.         OR   A            ; Is it column 0?
  13588.         LD   A,$01        ; A='Null' character, the code used to indicate to null edit positions.
  13589.         JR   Z,L3307      ; Jump if so.
  13590.  
  13591.         LD   A,$0D        ; A='Enter' character.
  13592.  
  13593. L3307:  LD   HL,L32BD     ; The action handler table.
  13594.         CALL L3FCE        ; Call the action handler routine to process the character.
  13595.         JR   C,L332C      ; Jump if no more characters are available.
  13596.  
  13597.         JR   Z,L32EA      ; Jump back if an action handler was found so as to process the next character.
  13598.  
  13599. ;A character was available but there was no action handler routine to process it
  13600.  
  13601.         PUSH AF           ; A=Character.
  13602.         LD   A,$1F        ;
  13603.         CP   B            ; Exceeded column 31?
  13604.         JR   NC,L3326     ; Jump ahead if not.
  13605.  
  13606. ;Exceeded last column
  13607.  
  13608.         LD   A,$12        ; New flag byte value indicating the row spans onto another row and there is an associated line number.
  13609.         CALL L3331        ; Mark this row as spanning onto the next and clear the following row's flags.
  13610.         JR   C,L3323      ; Jump ahead if not at bottom of the line edit buffer.
  13611.  
  13612. ;At the bottom of the edit buffer so process the line as if an 'Enter' character had been encountered
  13613.  
  13614.         POP  AF           ; Discard the stacked item.
  13615.         LD   A,$0D        ; A='Enter' character.
  13616.         JR   L3307        ; Jump back to process the 'Enter' code.
  13617.  
  13618. ;The edit buffer has room for another character
  13619.  
  13620. L3323:  CALL L35F4        ; Indent the row by setting the appropriate number of null characters in the current Above-Screen Line Edit Buffer row.
  13621.  
  13622. L3326:  POP  AF           ; A=Character.
  13623.         CALL L35C5        ; Store the character in the current row/column in the Above-Screen Line Edit Buffer.
  13624.         JR   L32EA        ; Jump back to handle the next character.
  13625.  
  13626. ;No more characters are available
  13627.  
  13628. L332C:  POP  HL           ; HL=Address of the BASIC line being edited in the Above-Screen Line Edit Buffer.
  13629.         LD   A,C          ; A=Number of rows in the Above-Screen Line Edit Buffer.
  13630.         RET  Z            ; [Redundant since carry flag is always set by here, and zero flag never subsequently checked]
  13631.  
  13632.         SCF               ; [Redundant since never subsequently checked]
  13633.         RET               ;
  13634.  
  13635. ; ------------------------------------------
  13636. ; Set 'Continuation' Row in Line Edit Buffer
  13637. ; ------------------------------------------
  13638. ; This routine is used when the insertion of a BASIC line needs to span onto a another row.
  13639. ; It marks the current row as 'not the last row of the BASIC line' and clears the following
  13640. ; row's flags
  13641. ; Entry: DE=Address of start of line edit buffer row.
  13642. ;        B=Column number (will be $20).
  13643. ;        C=Row number.
  13644. ;        A=New flag byte value (will be $12).
  13645. ; Exit : Carry flag reset if bottom of line edit buffer reached.
  13646. ;        HL=Address of the flag byte for the new row.
  13647.  
  13648. L3331:  PUSH AF           ; Save the new flag byte value.
  13649.         CALL L35E6        ; HL=Address of flag byte for the row.
  13650.         POP  AF           ; Retrieve the new flag byte value.
  13651.         XOR  (HL)         ; Toggle to set 'associated line number' and 'row spans onto another row' flags.
  13652.         LD   (HL),A       ; Store the new flag byte value.
  13653.  
  13654.         LD   A,C          ; A=Row number.
  13655.         CP   $14          ; At bottom of line edit buffer?
  13656.         RET  NC           ; Return if so.
  13657.  
  13658.         INC  C            ; Advance the row number.
  13659.         LD   HL,$0023     ;
  13660.         ADD  HL,DE        ; Point to the start of the next row.
  13661.         EX   DE,HL        ;
  13662.         LD   HL,$0020     ;
  13663.         ADD  HL,DE        ; Point to the flag byte for the next row.
  13664.         LD   (HL),$00     ; Clear the flags to indicate no BASIC line on this row.
  13665.         SCF               ; Signal still on a row within the edit buffer.
  13666.         RET               ;
  13667.  
  13668.  
  13669. ; ============================
  13670. ; BASIC Line Handling Routines
  13671. ; ============================
  13672.  
  13673. ; -----------------------------------------------------
  13674. ; Find Address of BASIC Line with Specified Line Number
  13675. ; -----------------------------------------------------
  13676. ; This routine finds the address of the BASIC line in the program area with the specified line number,
  13677. ; or the next line is the specified one does not exist.
  13678. ; Entry: HL=Line number.
  13679. ; Exit : Carry flag set if line exists.
  13680. ;        DE=Points to the command of the BASIC line within the program area.
  13681. ;        HL=Line number ($0000 for no line number).
  13682.  
  13683. L334A:  CALL L34B6        ; Find the address of the BASIC line in the program area with the specified line number.
  13684.         RET  C            ; Return if the line exists.
  13685.  
  13686.         LD   HL,$0000     ; No line number.
  13687.         RET               ;
  13688.  
  13689. ; ---------------------------------------------------------------------
  13690. ; Create Next Line Number Representation in Keyword Construction Buffer
  13691. ; ---------------------------------------------------------------------
  13692. ; This routine is used to create a string representation of the line number for the next line after the specified line,
  13693. ; and store it in the Keyword Construction Buffer.
  13694. ; Entry: HL=Line number.
  13695. ;        A=Print leading space flag ($00=Print leading space).
  13696. ; Exit : Carry flag set to indicate specified line exists.
  13697. ;        DE=Points to the command field of the BASIC line.
  13698. ;        HL=Line number, or $0000 if line does not exist.
  13699.  
  13700. L3352:  CALL L3430        ; Create next line number representation in the Keyword Construction Buffer.
  13701.         RET  C            ; Return if line exists.
  13702.  
  13703.         LD   HL,$0000     ; Line not found.
  13704.         RET               ;
  13705.  
  13706. ; --------------------------------------------------------------------------
  13707. ; Fetch Next De-tokenized Character from Selected BASIC Line in Program Area
  13708. ; --------------------------------------------------------------------------
  13709. ; Exit: Carry flag reset if a character was available.
  13710. ;       A=Character fetched.
  13711.  
  13712. L335A:  CALL L3517        ; Fetch the next de-tokenized character from the BASIC line within the program area.
  13713.         CCF               ;
  13714.         RET  NC           ; Return if a character was available. [*BUG* - This should just be a RET. Its effect is harmless since the routine
  13715.                           ; below has previously been called and hence simply overwrites the data already copied to RAM. Credit: Ian Collier (+3), Andrew Owen (128)]
  13716.  
  13717. ; --------------------------------------------------------------------------------------
  13718. ; Copy 'Insert Keyword Representation into Keyword Construction Buffer' Routine into RAM
  13719. ; --------------------------------------------------------------------------------------
  13720. ; Copies Insert Keyword Representation Into Keyword Construction Buffer routine into physical RAM bank 7, and resets pointers to indicate
  13721. ; that there is no BASIC line currently being de-tokenized.
  13722.  
  13723. L335F:  LD   HL,$0000     ; Signal no line number of command.
  13724.         LD   ($FC9F),HL   ; Signal no further character to fetch from the BASIC line within the program area.
  13725.         LD   ($FCA1),HL   ; Signal no further character to fetch from the Keyword Construction Buffer.
  13726.  
  13727.         LD   HL,L3374     ; Source for Insert Keyword Representation Into Keyword Construction Buffer routine.
  13728.         LD   DE,$FCAE     ; Destination for Insert Keyword Representation Into Keyword Construction Buffer routine.
  13729.         LD   BC,$00BC     ;
  13730.         LDIR              ; Copy the routine to RAM bank 7 at address $FCAE.
  13731.         RET               ;
  13732.  
  13733. ; ----------------------------------------------------------------------------------
  13734. ; Insert Keyword Representation into Keyword Construction Buffer <<< RAM Routine >>>
  13735. ; ----------------------------------------------------------------------------------
  13736. ; This routine copies a keyword string from ROM 1 into the Keyword Construction Buffer,
  13737. ; terminating it with an 'end of BASIC line' marker (code ' '+$80). Only standard Spectrum
  13738. ; keywords are handled by this routine (SPECTRUM and PLAY are processed elsewhere).
  13739. ; The routine is run from RAM bank 7 at $FCAE so that access to both ROMs is available.
  13740. ; Depending on the value of A (which should be the ASCII code less $A5,
  13741. ; e.g. 'RND', the first (48K) keyword, has A=0), a different index into the
  13742. ; token table is taken. This is to allow speedier lookup since there are never more
  13743. ; than 15 keywords to advance through.
  13744. ; Entry: A=Keyword character code-$A5 (range $00-$5A).
  13745. ;        DE=Insertion address within Keyword Construction Buffer.
  13746. ;
  13747. ; Copied to physical RAM bank 7 at $FCAE-$FCFC by subroutine at $335F (ROM 0).
  13748.  
  13749. L3374:  DI                ; Disable interrupts whilst paging.
  13750.  
  13751.         LD   BC,$7FFD     ;
  13752.         LD   D,$17        ; Page in ROM 1, SCREEN 0, no locking, RAM bank 7.
  13753.         OUT  (C),D        ;
  13754.  
  13755.         CP   $50          ; Was the token $F5 or above?
  13756.         JR   NC,L33B1     ;
  13757.  
  13758.         CP   $40          ; Was the token $E5 or above?
  13759.         JR   NC,L33AA     ;
  13760.  
  13761.         CP   $30          ; Was the token $D5 or above?
  13762.         JR   NC,L33A3     ;
  13763.  
  13764.         CP   $20          ; Was the token $C5 or above?
  13765.         JR   NC,L339C     ;
  13766.  
  13767.         CP   $10          ; Was the token $B5 or above?
  13768.         JR   NC,L3395     ;
  13769.  
  13770. ;Used for token range $A5-$B4 ($00 <= A <= $0F)
  13771.  
  13772.         LD   HL,TOKENS+$0001 ; $0096. Token table entry "RND" in ROM 1.
  13773.         JR   L33B6        ;
  13774.  
  13775. ;Used for token range $B5-$C4 ($10 <= A <= $1F)
  13776.  
  13777. L3395:  SUB  $10          ;
  13778.         LD   HL,TOKENS+$003A ; $00CF. Token table entry "ASN" in ROM 1.
  13779.         JR   L33B6        ;
  13780.  
  13781. ;Used for token range $C5-$D4 ($20 <= A <= $2F)
  13782.  
  13783. L339C:  SUB  $20          ;
  13784.         LD   HL,TOKENS+$006B ; $0100. Token table entry "OR" in ROM 1.
  13785.         JR   L33B6        ;
  13786.  
  13787. ;Used for token range $D5-$E4 ($30 <= A <= $3F)
  13788.  
  13789. L33A3:  SUB  $30          ;
  13790.         LD   HL,TOKENS+$00A9 ; $013E. Token table entry "MERGE" in ROM 1.
  13791.         JR   L33B6        ;
  13792.  
  13793. ;Used for token range $E5-$F4 ($40 <= A <= $4F)
  13794.  
  13795. L33AA:  SUB  $40          ;
  13796.         LD   HL,TOKENS+$00F6 ; $018B. Token table entry "RESTORE" in ROM 1.
  13797.         JR   L33B6        ;
  13798.  
  13799. ;Used for token range $F5-$FF (A >= $50)
  13800.  
  13801. L33B1:  SUB  $50          ;
  13802.         LD   HL,TOKENS+$013F ; $01D4. Token table entry "PRINT" in ROM 1.
  13803.  
  13804. L33B6:  LD   B,A          ; Take a copy of the index value.
  13805.         OR   A            ; If A=0 then already have the entry address.
  13806.  
  13807. L33B8:  JR   Z,L33C3      ; If indexed item found then jump ahead to copy the characters of the token.
  13808.  
  13809. L33BA:  LD   A,(HL)       ; Fetch a character.
  13810.         INC  HL           ; Point to next character.
  13811.         AND  $80          ; Has end of token marker been found?
  13812.         JR   Z,L33BA      ; Loop back for next character if not.
  13813.  
  13814.         DEC  B            ; Count down the index of the required token.
  13815.         JR   L33B8        ; Jump back to test whether the required token has been reached.
  13816.  
  13817. ; -------------------------------------------
  13818. ; Copy Keyword Characters <<< RAM Routine >>>
  13819. ; -------------------------------------------
  13820. ; This routine copies a keyword string from ROM 1 into the Keyword Construction Buffer,
  13821. ; terminating it with an 'end of BASIC line' marker (code ' '+$80). A leading space will
  13822. ; be inserted if required and a trailing space is always inserted.
  13823. ; The routine is run from physical RAM bank 7 so that access to both ROMs is available.
  13824. ; Entry: HL=Address of keyword string in ROM 1.
  13825. ;        DE=Insertion address within Keyword Construction Buffer.
  13826. ;
  13827. ; Copied to physical RAM bank 7 at $FCFD-$FD2D by subroutine at $335F (ROM 0).
  13828.  
  13829. L33C3:  LD   DE,$FCA3     ; DE=Keyword Construction Buffer.
  13830.         LD   ($FCA1),DE   ; Store the start address of the constructed keyword.
  13831.  
  13832.         LD   A,($FC9E)    ; Print a leading space?
  13833.         OR   A            ;
  13834.         LD   A,$00        ;
  13835.         LD   ($FC9E),A    ; Signal leading space not required.
  13836.         JR   NZ,L33D9     ; Jump if leading space not required.
  13837.  
  13838.         LD   A,$20        ; Print a leading space.
  13839.         LD   (DE),A       ; Insert a leading space.
  13840.         INC  DE           ; Advance to next buffer position.
  13841.  
  13842. L33D9:  LD   A,(HL)       ; Fetch a character of the keyword.
  13843.         LD   B,A          ; Store it.
  13844.         INC  HL           ; Advance to next keyword character.
  13845.         LD   (DE),A       ; Store the keyword character in the BASIC line buffer.
  13846.         INC  DE           ; Advance to the next buffer position.
  13847.         AND  $80          ; Test if the end of the keyword string.
  13848.         JR   Z,L33D9      ; Jump back if not to repeat for all characters of the keyword.
  13849.  
  13850.         LD   A,B          ; Get keyword character back.
  13851.         AND  $7F          ; Mask off bit 7 which indicates the end of string marker.
  13852.         DEC  DE           ; Point back at the last character of the keyword copied into the buffer
  13853.         LD   (DE),A       ; and store it.
  13854.  
  13855.         INC  DE           ; Advance to the position in the buffer after the last character of the keyword.
  13856.         LD   A,' '+$80    ; $A0. Space + end marker.
  13857.         LD   (DE),A       ; Store an 'end of BASIC line so far' marker.
  13858.  
  13859.         LD   A,$07        ;
  13860.         LD   BC,$7FFD     ;
  13861.         OUT  (C),A        ; Page in ROM 0, SCREEN 0, no locking, RAM bank 7.
  13862.         EI                ; Re-enable interrupts.
  13863.         RET               ;
  13864.  
  13865. ; -------------------------
  13866. ; Identify Token from Table
  13867. ; -------------------------
  13868. ; This routine identifies the string within the Keyword Conversion Buffer and returns
  13869. ; the character code. The last character of the string to identify has bit 7 set.
  13870. ; Only 48K mode tokens are identified.
  13871. ; Exit: Carry flag set if token identified.
  13872. ;       A=Character code.
  13873. ;
  13874. ; Copied to RAM at $FD2E-$FD69 by routine at $335F (ROM 0).
  13875.  
  13876. L33F4:  DI                ; Disable interrupts whilst paging.
  13877.         LD   BC,$7FFD     ;
  13878.         LD   D,$17        ; Select ROM 1, SCREEN 0, RAM bank 7.
  13879.         OUT  (C),D        ;
  13880.  
  13881.         LD   HL,TOKENS+1  ; $0096. Address of token table in ROM 1.
  13882.         LD   B,$A5        ; Character code of the first token - 'RND'.
  13883.  
  13884. ;Entry point here used to match 128K mode tokens and mis-spelled tokens
  13885.  
  13886. L3401:  LD   DE,$FD74     ; Keyword Conversion Buffer holds the text to match against.
  13887.  
  13888. L3404:  LD   A,(DE)       ; Fetch a character from the buffer.
  13889.         AND  $7F          ; Mask off terminator bit.
  13890.         CP   $61          ; Is it lowercase?
  13891.         LD   A,(DE)       ; Fetch the character again from the buffer.
  13892.         JR   C,L340E      ; Jump if uppercase.
  13893.  
  13894.         AND  $DF          ; Make the character uppercase.
  13895.  
  13896. L340E:  CP   (HL)         ; Does the character match the current item in the token table?
  13897.         JR   NZ,L341A     ; Jump if it does not.
  13898.  
  13899.         INC  HL           ; Point to the next character in the buffer.
  13900.         INC  DE           ; Point to the next character in the token table.
  13901.         AND  $80          ; Has the terminator been reached?
  13902.         JR   Z,L3404      ; Jump back if not to test the next character in the token.
  13903.  
  13904. ;A match was found
  13905.  
  13906.         SCF               ; Signal a match was found.
  13907.         JR   L3426        ; Jump ahead to continue.
  13908.  
  13909. L341A:  INC  B            ; The next character code to test against.
  13910.         JR   Z,L3425      ; Jump if all character codes tested.
  13911.  
  13912. ;The token does not match so skip to the next entry in the token table
  13913.  
  13914. L341D:  LD   A,(HL)       ; Fetch the character from the token table.
  13915.         AND  $80          ; Has the end terminator been found?
  13916.         INC  HL           ; Point to the next character.
  13917.         JR   Z,L341D      ; Jump back if no terminator found.
  13918.  
  13919.         JR   L3401        ; Jump back to test against the next token.
  13920.  
  13921. ;All character codes tested and no match found
  13922.  
  13923. L3425:  OR   A            ; Clear the carry flag to indicate no match found.
  13924.  
  13925. ;The common exit point
  13926.  
  13927. L3426:  LD   A,B          ; Fetch the character code of the matching token ($00 for no match).
  13928.  
  13929.         LD   D,$07        ; Select ROM 0, SCREEN 0, RAM bank 7.
  13930.         LD   BC,$7FFD     ;
  13931.         OUT  (C),D        ;
  13932.         EI                ; Re-enable interrupts.
  13933.         RET               ; <<< Last byte copied to RAM >>>
  13934.  
  13935. ; ---------------------------------------------------------------------
  13936. ; Create Next Line Number Representation in Keyword Construction Buffer
  13937. ; ---------------------------------------------------------------------
  13938. ; This routine is used to create a string representation of the line number for the next line after the specified line,
  13939. ; and store it in the Keyword Construction Buffer.
  13940. ; Entry: HL=Line number.
  13941. ;        A=Print leading space flag ($00=Print leading space).
  13942. ; Exit : Carry flag set to indicate specified line available.
  13943. ;        DE=Points to the command field of the BASIC line.
  13944. ;        HL=Line number.
  13945.  
  13946. L3430:  CALL L34EA        ; Clear BASIC line construction pointers (address of next character in the Keyword Construction Buffer and the
  13947.                           ; address of the next character in the BASIC line within the program area being de-tokenized).
  13948.         OR   A            ; [*BUG* - Supposed to be XOR A to ensure that a leading space is shown before a command keyword is printed.
  13949.                           ; However, most of the time the A register will enter the routine holding $00 and so the bug is probably harmless. Credit: Paul Farrow]
  13950.         LD   ($FC9E),A    ; Print a leading space flag.
  13951.  
  13952.         CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  13953.  
  13954.         CALL L34F6        ; Find address of the specified BASIC line, into HL.
  13955.         JR   NC,L3491     ; Jump if suitable line number not found, i.e. end of program reached.
  13956.  
  13957.         JR   NZ,L344D     ; Jump if line number did not match, i.e. is higher than the line requested.
  13958.  
  13959. ;The line number requested exists
  13960.  
  13961.         LD   A,B          ; BC=Line number.
  13962.         OR   C            ;
  13963.         JR   Z,L344D      ; Jump if the first program line requested (line number of 0).
  13964.  
  13965. ;Fetch the next line
  13966.  
  13967.         CALL L34CF        ; Move to the start of the next BASIC line.
  13968.         CALL L34D9        ; Check whether at the end of the BASIC program.
  13969.         JR   NC,L3491     ; Jump if at the end of the BASIC program.
  13970.  
  13971. ;Insert line number into the BASIC Line Construction Buffer
  13972.  
  13973. L344D:  LD   D,(HL)       ; HL=Address of the BASIC line.
  13974.         INC  HL           ;
  13975.         LD   E,(HL)       ; DE=Line number.
  13976.  
  13977.         CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  13978.  
  13979.         PUSH DE           ; Save the line number.
  13980.         PUSH HL           ; Save the address of the BASIC line+1.
  13981.         PUSH IX           ; Save IX.
  13982.  
  13983.         LD   IX,$FCA3     ; IX=Keyword Construction Buffer, the location where the line number will be created.
  13984.         LD   ($FCA1),IX   ; Store the start of the buffer as the next location to store a character in.
  13985.  
  13986.         EX   DE,HL        ; HL=Line number.
  13987.         LD   B,$00        ; Signal no digit printed yet.
  13988.         LD   DE,$FC18     ; -1000.
  13989.         CALL L3495        ; Insert the thousand digit.
  13990.         LD   DE,$FF9C     ; -100.
  13991.         CALL L3495        ; Insert the hundred digit.
  13992.         LD   DE,$FFF6     ; -10.
  13993.         CALL L3495        ; Insert the ten digit.
  13994.         LD   DE,$FFFF     ; -1.
  13995.         CALL L3495        ; Insert the units digits. [Note that this is not designed to handle line number 0, which technically is not supported by Sinclair BASIC.
  13996.                           ; The call would need to be preceded by a LD B,$01 instruction to make this function support a line number of 0. Credit: Ian Collier (+3), Andrew Owen (128)]
  13997.  
  13998.         DEC  IX           ; IX points to previous ASCII digit.
  13999.         LD   A,(IX+$00)   ;
  14000.         OR   $80          ;
  14001.         LD   (IX+$00),A   ; Set bit 7 to mark it as the end of the line number representation.
  14002.  
  14003.         POP  IX           ; Restore registers.
  14004.         POP  HL           ; HL=Address of the BASIC line+1.
  14005.         POP  DE           ; DE=Line number.
  14006.  
  14007.         INC  HL           ; HL=Points to length field of the BASIC line.
  14008.         INC  HL           ;
  14009.         INC  HL           ; HL=Points to the command field of the BASIC line.
  14010.         LD   ($FC9F),HL   ; Store it as the next character to fetch when parsing the BASIC line to de-tokenize it.
  14011.  
  14012.         EX   DE,HL        ; DE=Points to the command field of the BASIC line, HL=Line number.
  14013.         SCF               ; Signal line exists.
  14014.         RET               ;
  14015.  
  14016. ;End of program reached, no line number available
  14017.  
  14018. L3491:  CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  14019.         RET               ; Return with carry flag reset to signal line does not exist.
  14020.  
  14021. ; ------------------------------
  14022. ; Insert ASCII Line Number Digit
  14023. ; ------------------------------
  14024. ; Insert text representation of a line number digit in a buffer.
  14025. ; Insert a $00 character for every leading zero.
  14026. ; Entry: DE=Subtraction amount (-1000, -100, -10, -1).
  14027. ;        HL=Line number.
  14028. ;        IX=Address of the buffer to write the ASCII line number to.
  14029. ;        B=Indicates if digit printed yet ($00=not printed).
  14030. ; Exit : IX points to next buffer location.
  14031. ;        B=$01 if digit printed.
  14032. ;        HL=Line number remainder.
  14033.  
  14034. L3495:  XOR  A            ; A=Counter.
  14035.  
  14036. L3496:  ADD  HL,DE        ; Keep adding DE
  14037.         INC  A            ; and incrementing the counter
  14038.         JR   C,L3496      ; until there is no carry.
  14039.  
  14040.         SBC  HL,DE        ; Adjust for the last addition and.
  14041.         DEC  A            ; counter value that caused the overflow.
  14042.  
  14043. ;A=Number of multiples of DE in the line number
  14044.  
  14045.         ADD  A,$30        ; Convert to an ASCII digit.
  14046.         LD   (IX+$00),A   ; Store in the buffer.
  14047.         CP   '0'          ; $30. Is it a zero?
  14048.         JR   NZ,L34B1     ; Jump ahead if not.
  14049.  
  14050.         LD   A,B          ; Get the 'digit printed' flag.
  14051.         OR   A            ;
  14052.         JR   NZ,L34B3     ; Jump ahead if already printed a digit.
  14053.  
  14054.         LD   A,$00        ; Otherwise this is a leading zero, so
  14055.         LD   (IX+$00),A   ; store a zero byte to indicate 'nothing to print'.
  14056.         JR   L34B3        ; and jump ahead to point to the next buffer location.
  14057.  
  14058. L34B1:  LD   B,$01        ; Indicate 'digit printed'.
  14059.  
  14060. L34B3:  INC  IX           ; Point to the next buffer location.
  14061.         RET               ;
  14062.  
  14063. ; -----------------------------------------------------
  14064. ; Find Address of BASIC Line with Specified Line Number
  14065. ; -----------------------------------------------------
  14066. ; This routine finds the address of the BASIC line in the program area with the specified line number,
  14067. ; or the next line is the specified one does not exist.
  14068. ; Entry: HL=Line number.
  14069. ;        A=$00 to print a leading space.
  14070. ; Exit : Carry flag set if line exists.
  14071. ;        DE=Points to the command of the BASIC line within the program area.
  14072. ;        HL=Line number.
  14073.  
  14074. L34B6:  CALL L34EA        ; Clear BASIC line construction pointers (address of next character in the Keyword Construction Buffer and the
  14075.                           ; address of the next character in the BASIC line within the program area being de-tokenized).
  14076.         OR   A            ; [*BUG* - Supposed to be XOR A to ensure that a leading space is shown before a command keyword is printed.
  14077.                           ; However, most of the time the A register will enter the routine holding $00 and so the bug is probably harmless. Credit: Paul Farrow]
  14078.         LD   ($FC9E),A    ; Store 'print a leading space' flag.
  14079.  
  14080.         CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  14081.  
  14082.         CALL L34F6        ; Find the address of the BASIC line with this line number, or the next line otherwise.
  14083.         JR   NC,L3491     ; Jump if does not exist.
  14084.  
  14085.         EX   DE,HL        ; HL=Address of BASIC line.
  14086.         LD   A,L          ;
  14087.         OR   H            ; Address of $0000, i.e. no line exists?
  14088.         SCF               ; Assume line number found.
  14089.         JP   NZ,L344D     ; Jump if a line was found.
  14090.  
  14091.         CCF               ; Reset carry flag to indicate line number does not exist
  14092.         JR   L3491        ; and jump to make a return.
  14093.  
  14094. ; -----------------------
  14095. ; Move to Next BASIC Line
  14096. ; -----------------------
  14097. ; Entry: HL=Address of current BASIC line.
  14098. ; Exit : HL=Address of next BASIC line.
  14099. ;        DE=Address of current BASIC line.
  14100.  
  14101. L34CF:  PUSH HL           ; Save the address of the original line.
  14102.  
  14103.         INC  HL           ; Skip past the line number.
  14104.         INC  HL           ;
  14105.         LD   E,(HL)       ; Retrieve the line length into DE.
  14106.         INC  HL           ;
  14107.         LD   D,(HL)       ;
  14108.         INC  HL           ;
  14109.         ADD  HL,DE        ; Point to the start of the next line.
  14110.  
  14111.         POP  DE           ; DE=Address of original line.
  14112.         RET               ;
  14113.  
  14114. ; --------------------------------
  14115. ; Check if at End of BASIC Program
  14116. ; --------------------------------
  14117. ; Check whether at the end of the BASIC program.
  14118. ; Entry: HL=Address of BASIC line.
  14119. ; Exit : Carry flag reset if end of BASIC program reached.
  14120.  
  14121. L34D9:  LD   A,(HL)       ;
  14122.         AND  $C0          ;
  14123.         SCF               ; Signal not at end of BASIC.
  14124.         RET  Z            ; Return if not at end of program.
  14125.  
  14126.         CCF               ; Signal at end of BASIC.
  14127.         RET               ;
  14128.  
  14129. ; --------------------
  14130. ; Compare Line Numbers
  14131. ; --------------------
  14132. ; Compare line number at (HL) has line number held in BC.
  14133. ; Entry: HL=Address of first line number.
  14134. ;        BC=Second line number.
  14135. ; Exit : Carry flag and zero flag set if the line number matches.
  14136. ;        Zero flag reset if no match, with carry flag set if line number held in BC
  14137. ;        is lower than the line number pointed to by HL.
  14138.  
  14139. L34E0:  LD   A,B          ; Test the first byte.
  14140.         CP   (HL)         ;
  14141.         RET  NZ           ; Return if not the same.
  14142.  
  14143.         LD   A,C          ; Test the second byte.
  14144.         INC  HL           ;
  14145.         CP   (HL)         ;
  14146.         DEC  HL           ;
  14147.         RET  NZ           ; Return if not the same.
  14148.  
  14149.         SCF               ; Signal line number matches.
  14150.         RET               ;
  14151.  
  14152. ; --------------------------------------
  14153. ; Clear BASIC Line Construction Pointers
  14154. ; --------------------------------------
  14155.  
  14156. L34EA:  PUSH HL           ;
  14157.  
  14158.         LD   HL,$0000     ;
  14159.         LD   ($FCA1),HL   ; Signal no next character to fetch from the Keyword Construction Buffer.
  14160.         LD   ($FC9F),HL   ; Signal no next character to fetch within the BASIC line in the program area.
  14161.  
  14162.         POP  HL           ;
  14163.         RET               ;
  14164.  
  14165. ; --------------------------
  14166. ; Find Address of BASIC Line
  14167. ; --------------------------
  14168. ; This routine finds the address of the BASIC line within the program area with the specified line number.
  14169. ; Entry: HL=Line number to find ($0000 for first program line).
  14170. ; Exit : Carry flag set if requested or next line exists.
  14171. ;        Zero flag reset if no match, with carry flag set if line number is lower than the first program line number.
  14172. ;        HL=Address of the BASIC line number, or $0000 if line does not exist.
  14173. ;        DE=Address of previous BASIC line number, or $0000 if line does not exist.
  14174. ;        BC=Line number.
  14175.  
  14176. L34F6:  PUSH HL           ;
  14177.         POP  BC           ; BC=Line number. [Quicker to have used the instructions LD B,H / LD C,L]
  14178.  
  14179.         LD   DE,$0000     ;
  14180.  
  14181.         LD   HL,($5C53)   ; PROG. Address of the start of BASIC program.
  14182.         CALL L34D9        ; Test for end of BASIC program.
  14183.         RET  NC           ; Return if at end of program.
  14184.  
  14185.         CALL L34E0        ; Compare line number at (HL) with BC.
  14186.         RET  C            ; Return if line number matches or is lower than the first program line number.
  14187.  
  14188.         LD   A,B          ;
  14189.         OR   C            ;
  14190.         SCF               ;
  14191.         RET  Z            ; Return with carry and zero flags set if first program line was requested (line number 0).
  14192.  
  14193. L350A:  CALL L34CF        ; Get address of next BASIC line.
  14194.         CALL L34D9        ; Test for end of BASIC program.
  14195.         RET  NC           ; Return if at end of program.
  14196.  
  14197.         CALL L34E0        ; Compare line number at (HL) with BC.
  14198.         JR   NC,L350A     ; If line number not the same or greater then back to test next line.
  14199.  
  14200.         RET               ; Exit with carry flag set if line found.
  14201.  
  14202. ; -----------------------------------------------------------------
  14203. ; Fetch Next De-tokenized Character from BASIC Line in Program Area
  14204. ; -----------------------------------------------------------------
  14205. ; This routine translates a tokenized BASIC line within the program area into the equivalent 'typed' line, i.e. non-tokenized.
  14206. ; The line number has been previously converted into a string representation and is held within the Keyword Construction Buffer
  14207. ; at $FCA3. On each call of this routine, the next character of the BASIC line representation is fetched. Initially this is the
  14208. ; line number characters from the Keyword Construction Buffer, and then the characters from the program line itself. As a token
  14209. ; character is encountered, it is converted into its string representation and stored in the Keyword Construction Buffer. Then
  14210. ; each character of this string is fetched in turn. Once all of these characters have been fetched, the next character will be
  14211. ; from the last position accessed within the BASIC line in the program area.
  14212. ; Exit: Carry flag set to indicate that a character was available.
  14213. ;       A=Character fetched.
  14214.  
  14215. L3517:  LD   HL,($FCA1)   ; Fetch the address of the character within the Keyword Construction Buffer.
  14216.         LD   A,L          ;
  14217.         OR   H            ; Is there an address defined, i.e. characters still within the buffer to fetch?
  14218.         JR   Z,L353C      ; Jump ahead if not.
  14219.  
  14220. ;There is a character within the Keyword Construction Buffer
  14221.  
  14222.         LD   A,(HL)       ; Fetch a character from the buffer.
  14223.         INC  HL           ; Point to the next character.
  14224.         CP   ' '+$80      ; $A0. Was it a trailing space, i.e. the last character?
  14225.         LD   B,A          ; Save the character.
  14226.         LD   A,$00        ; Signal 'print a leading space'.
  14227.         JR   NZ,L3529     ; Jump ahead if not.
  14228.  
  14229.         LD   A,$FF        ; Signal 'do not print a leading space'.
  14230.  
  14231. L3529:  LD   ($FC9E),A    ; Store the 'print a leading space' flag value.
  14232.  
  14233.         LD   A,B          ; Get the character back.
  14234.         BIT  7,A          ; Is it the last character in the buffer, i.e. the terminator bit is set?
  14235.         JR   Z,L3534      ; Jump ahead if not.
  14236.  
  14237.         LD   HL,$0000     ; Signal no more characters within the Keyword Construction Buffer to fetch.
  14238.  
  14239. L3534:  LD   ($FCA1),HL   ; Store the address of the next line number/keyword character within the construction buffer, or $0000 if no more characters.
  14240.         AND  $7F          ; Mask off the terminator bit.
  14241.         JP   L358F        ; Jump ahead to continue. [Could have saved 1 byte by using JR $358F (ROM 0)]
  14242.  
  14243. ;There is no line number/keyword defined within the buffer so fetch the next tokenized character from the BASIC line in the program area
  14244.  
  14245. L353C:  LD   HL,($FC9F)   ; Fetch the address of the next character within the BASIC line construction workspace.
  14246.         LD   A,L          ;
  14247.         OR   H            ; Is there a character defined, i.e. end of line not yet reached?
  14248.         JP   Z,L3591      ; Jump ahead if not. [Could have saved 1 byte by using JR $3591 (ROM 0)]
  14249.  
  14250.         CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  14251.  
  14252. L3547:  LD   A,(HL)       ; Fetch a character from the buffer.
  14253.         CP   $0E          ; Is it the hidden number marker indicating a floating-point representation?
  14254.         JR   NZ,L3554     ; Jump ahead if it is not.
  14255.  
  14256.         INC  HL           ; Skip over it the floating-point representation.
  14257.         INC  HL           ;
  14258.         INC  HL           ;
  14259.         INC  HL           ;
  14260.         INC  HL           ;
  14261.         INC  HL           ;
  14262.         JR   L3547        ; Jump back to fetch the next character.
  14263.  
  14264. L3554:  CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  14265.  
  14266.         INC  HL           ; Point to the next character.
  14267.         LD   ($FC9F),HL   ; Store the address of the next command within the BASIC line to fetch.
  14268.         CP   $A5          ; 'RND'. Is the current character a standard '48K' keyword? ('RND' = first 48K keyword)
  14269.         JR   C,L3567      ; Jump ahead if not.
  14270.  
  14271.         SUB  $A5          ; Reduce command code range to $00-$5A.
  14272.  
  14273. ; [*BUG* - The routine assumes all tokens require a leading and trailing space.
  14274. ;          However, this is not true for tokens '<=', '>=' and '<>'. Credit: Ian Collier (+3), Paul Farrow (128)]
  14275.  
  14276. ; [To fix the bug, the call to $FCAE would need to be replaced with code such as the following. Credit: Paul Farrow.
  14277. ;
  14278. ;       PUSH AF
  14279. ;       CALL $FCAE        ; Construct a string representation of the keyword in the Keyword Construction Buffer.
  14280. ;       POP  AF           ; DE=Address of last character copied.
  14281. ;
  14282. ;       CP   $22          ; Was it '<=' or above?
  14283. ;       JR   C,$3517 (ROM 0) ; Jump back if not to fetch and return the first character of the keyword string.
  14284. ;
  14285. ;       CP   $25          ; Was it '<>' or below?
  14286. ;       JR   NC,$3517 (ROM 0) ; Jump back if not to fetch and return the first character of the keyword string.
  14287. ;
  14288. ;       LD   HL,($FCA1)   ; Is there a leading space?
  14289. ;       LD   A,(HL)
  14290. ;       CP   ' '
  14291. ;       JR   NZ,NOT_LEADING ; Jump if there is not.
  14292. ;
  14293. ;       INC  HL
  14294. ;       LD   ($FCA1),HL   ; Skip past the leading space.
  14295. ;
  14296. ;NOT_LEADING:
  14297. ;       LD   A,$FF        ; Signal 'do not print a leading space'.
  14298. ;       LD   ($FC9E),A
  14299. ;
  14300. ;       LD   A,(DE)       ; Is there a trailing space?
  14301. ;       CP   ' '+$80
  14302. ;       JR   NZ,NOT_TRAILING ; Jump if there is not.
  14303. ;
  14304. ;       DEC  DE
  14305. ;       EX   DE,HL
  14306. ;       SET  7,(HL)       ; Set the terminator bit on the preceding character.
  14307. ;
  14308. ;NOT_TRAILING:            ; ]
  14309.  
  14310.         CALL $FCAE        ; Construct a string representation of the keyword in the Keyword Construction Buffer.
  14311.         JP   L3517        ; Jump back to fetch and return the first character of the keyword string. [Could have saved 1 byte by using JR $3517 (ROM 0)]
  14312.  
  14313. ;It is not a standard 48K keyword
  14314.  
  14315. L3567:  CP   $A3          ; Is it a '128K' keyword, i.e. 'SPECTRUM' or 'PLAY'?
  14316.         JR   C,L357B      ; Jump if not.
  14317.  
  14318. ;It is a 128K keyword
  14319.  
  14320.         JR   NZ,L3572     ; Jump if it is 'PLAY'.
  14321.  
  14322. ;Handle 'SPECTRUM'
  14323.  
  14324.         LD   HL,L3594     ; Keyword string "SPECTRUM".
  14325.         JR   L3575        ; Jump forward.
  14326.  
  14327. L3572:  LD   HL,L359C     ; Keyword string "PLAY".
  14328.  
  14329. L3575:  CALL $FCFD        ; Copy the keyword string characters into the Keyword Construction Buffer.
  14330.         JP   L3517        ; Jump back to fetch and return the first character of the keyword string. [Could have saved 1 byte by using JR $3517 (ROM 0)]
  14331.  
  14332. ;Not a keyword
  14333.  
  14334. L357B:  PUSH AF           ; Save the character.
  14335.         LD   A,$00        ;
  14336.         LD   ($FC9E),A    ; Signal to print a trailing space.
  14337.         POP  AF           ; Get the character back.
  14338.         CP   $0D          ; Is it an 'Enter' character?
  14339.         JR   NZ,L358F     ; Jump if not to exit.
  14340.  
  14341. ;The end of the line was found so signal no further characters to fetch
  14342.  
  14343.         LD   HL,$0000     ;
  14344.         LD   ($FCA1),HL   ; Signal no further character to fetch from the Keyword Construction Buffer.
  14345.         LD   ($FC9F),HL   ; Signal no further character to fetch from the BASIC line within the program area.
  14346.  
  14347. L358F:  SCF               ; Set the carry flag to indicate that a character was available.
  14348.         RET               ;
  14349.  
  14350. ;There was no character within the buffer
  14351.  
  14352. L3591:  SCF               ;
  14353.         CCF               ; Reset the carry flag to indicate that a character was not available.
  14354.         RET               ;
  14355.  
  14356.  
  14357. ; =============================
  14358. ; Edit Buffer Routines - Part 2
  14359. ; =============================
  14360.  
  14361. ; ---------------------
  14362. ; Keywords String Table
  14363. ; ---------------------
  14364. ; The following strings are terminated by having bit 7 set, referenced at $356D (ROM 0) and $3F87 (ROM 0).
  14365. ; The table consists of the new 128K mode keywords and mis-spelled keywords.
  14366.  
  14367. L3594           DC "SPECTRUM"           ;DEFM "SPECTRU"
  14368.                                         ;DB 'M'+$80
  14369. L359C           DC "PLAY"               ;DEFM "PLA"
  14370.                                         ;DB 'Y'+$80
  14371.                 DC "GOTO"               ;DEFM "GOT"
  14372.                                         ;DB 'O'+$80
  14373.                 DC "GOSUB"              ;DEFM "GOSU"
  14374.                                         ;DB 'B'+$80
  14375.                 DC "DEFFN"              ;DEFM "DEFF"
  14376.                                         ;DB 'N'+$80
  14377.                 DC "OPEN#"              ;DEFM "OPEN"
  14378.                                         ;DB '#'+$80
  14379.                 DC "CLOSE#"             ;DEFM "CLOSE"
  14380.                                         ;DB '#'+$80
  14381.  
  14382. ; --------------------
  14383. ; Indentation Settings
  14384. ; --------------------
  14385. ; Copied to $FD6A-$FD6B.
  14386.  
  14387. L35B9:  DB $02          ; Number of bytes in table.
  14388.         DB $01          ; Flag never subsequently used. Possibly intended to indicate the start of a new BASIC line and hence whether indentation required.
  14389.         DB $05          ; Number of characters to indent by.
  14390.  
  14391. ; ------------------------
  14392. ; Set Indentation Settings
  14393. ; ------------------------
  14394.  
  14395. L35BC:  LD   HL,L35B9     ; HL=Address of the indentation settings data table.
  14396.         LD   DE,$FD6A     ; Destination address.
  14397.         JP   L3FBA        ; Copy two bytes from $35B9-$35BA (ROM 0) to $FD6A-$FD6B.
  14398.  
  14399. ; --------------------------------------------
  14400. ; Store Character in Column of Edit Buffer Row
  14401. ; --------------------------------------------
  14402. ; Store character in the specified column of the current edit buffer row.
  14403. ; Entry: B=Column number.
  14404. ;        DE=Start address of row.
  14405. ;        A=Character to insert.
  14406. ; Exit : B=Next column number.
  14407.  
  14408. L35C5:  LD   L,B          ;
  14409.         LD   H,$00        ;
  14410.         ADD  HL,DE        ; Point to the required column.
  14411.         LD   (HL),A       ; Store the character.
  14412.         INC  B            ; Advance to the next column.
  14413.         RET               ;
  14414.  
  14415. ; ------------------------------
  14416. ; 'Enter' Action Handler Routine
  14417. ; ------------------------------
  14418. ; Entry: B=Initial column to null.
  14419. ;        DE=Address of start of edit row.
  14420. ; Exit : Carry flag set to indicate no more characters are available, i.e. end of line.
  14421.  
  14422. L35CC:  CALL L35E6        ; Null remaining column positions in the edit buffer row.
  14423.  
  14424.         LD   A,(HL)       ; Fetch the flag byte.
  14425.         OR   $18          ; Signal associated line number and last row in the BASIC line.
  14426.         LD   (HL),A       ; Update the flag byte.
  14427.  
  14428.         LD   HL,$FD6A     ; [Redundant since flag never subsequently tested. Deleting these instructions would have saved 5 bytes]
  14429.         SET  0,(HL)       ; Flag possibly intended to indicate the start of a new BASIC line and hence whether indentation required.
  14430.  
  14431.         SCF               ; Signal no more characters are available, i.e. end of line.
  14432.         RET               ;
  14433.  
  14434. ; -------------------------------------
  14435. ; 'Null Columns' Action Handler Routine
  14436. ; -------------------------------------
  14437. ; Entry: B=Initial column to null.
  14438. ;        DE=Address of start of edit row.
  14439. ; Exit : Carry flag set to indicate no more characters are available, i.e. end of line.
  14440.  
  14441. L35DA:  CALL L35E6        ; Null remaining column positions in the edit buffer row.
  14442.  
  14443.         SET  3,(HL)       ; Signal last row of the BASIC line in the row flag byte.
  14444.  
  14445.         LD   HL,$FD6A     ; [Redundant since flag never subsequently tested. Deleting these instructions would have saved 5 bytes]
  14446.         SET  0,(HL)       ; Flag possibly intended to indicate the start of a new BASIC line and hence whether indentation required.
  14447.  
  14448.         SCF               ; Signal no more characters are available, i.e. end of line.
  14449.         RET               ;
  14450.  
  14451. ; ---------------------
  14452. ; Null Column Positions
  14453. ; ---------------------
  14454. ; This routine inserts null characters into the remainder of a line edit buffer row.
  14455. ; Entry: B=Initial column to null.
  14456. ;        DE=Address of start of edit row.
  14457. ; Exit : HL=Address of the row's flag byte.
  14458.  
  14459. L35E6:  LD   L,B          ;
  14460.         LD   H,$00        ; HL=Number of columns.
  14461.         ADD  HL,DE        ; Point to column position in line edit buffer row.
  14462.         LD   A,$20        ; 32 columns.
  14463.  
  14464. L35EC:  CP   B            ; Found specified column?
  14465.         RET  Z            ; Return if so.
  14466.  
  14467.         LD   (HL),$00     ; Store a null in the location.
  14468.         INC  HL           ; Next buffer position.
  14469.         INC  B            ; Increment column position counter.
  14470.         JR   L35EC        ; Repeat for next column.
  14471.  
  14472. ; ----------------------
  14473. ; Indent Edit Buffer Row
  14474. ; ----------------------
  14475. ; Indent a row by setting the appropriate number of characters in
  14476. ; an edit buffer row to nulls, i.e. character $00.
  14477. ; Entry: DE=Address of row within edit buffer.
  14478. ; Exit : B=First usable column number in the row.
  14479.  
  14480. L35F4:  LD   A,($FD6B)    ; Get the number of indentation columns.
  14481.         LD   B,$00        ; Start at first column.
  14482.  
  14483. L35F9:  LD   H,$00        ;
  14484.         LD   L,B          ; HL=Column position.
  14485.         ADD  HL,DE        ;
  14486.         LD   (HL),$00     ; Put a null in the column position.
  14487.         INC  B            ; Next position.
  14488.         DEC  A            ;
  14489.         JR   NZ,L35F9     ; Repeat for all remaining columns.
  14490.  
  14491.         RET               ;
  14492.  
  14493. ; -------------------------------------------------
  14494. ; Print Edit Buffer Row to Display File if Required
  14495. ; -------------------------------------------------
  14496. ; Print a row of the edit buffer to the display file if required.
  14497. ; Entry: HL=Address of edit buffer row.
  14498.  
  14499. L3604:  PUSH BC           ; Save registers.
  14500.         PUSH DE           ;
  14501.         PUSH HL           ;
  14502.  
  14503.         PUSH HL           ; Save edit buffer row address.
  14504.         LD   HL,$EEF5     ;
  14505.         BIT  2,(HL)       ; Is printing of the edit buffer row required?
  14506.         POP  HL           ; Retrieve edit buffer row address.
  14507.         JR   NZ,L3614     ; Jump if printing is not required.
  14508.  
  14509.         LD   B,C          ; B=Cursor row position.
  14510.         CALL L3B1E        ; Print the edit buffer row to the screen. Returns with the carry flag set.
  14511.  
  14512. L3614:  POP  HL           ; Restore registers.
  14513.         POP  DE           ;
  14514.         POP  BC           ;
  14515.         RET               ;
  14516.  
  14517. ; ----------------------------------------------
  14518. ; Shift Up Edit Rows in Display File if Required
  14519. ; ----------------------------------------------
  14520. ; This routine shifts edit rows in the display file up if required, replacing the bottom row with the
  14521. ; top entry from the Below-Screen Line Edit Buffer.
  14522. ; Entry: HL=Address of first row within the Below-Screen Line Edit Buffer.
  14523. ;        C =Number of editing rows on screen.
  14524. ;        B =Row number to shift from.
  14525.  
  14526. L3618:  PUSH BC           ; Save registers.
  14527.         PUSH DE           ;
  14528.         PUSH HL           ;
  14529.  
  14530.         PUSH HL           ; Save edit buffer row address.
  14531.         LD   HL,$EEF5     ;
  14532.         BIT  2,(HL)       ; Is updating of the display file required?
  14533.         POP  HL           ; Retrieve edit buffer row address.
  14534.         JR   NZ,L3628     ; Jump if updating is not required.
  14535.  
  14536.         LD   E,C          ; E=Cursor row position, i.e. row to shift from.
  14537.         CALL L3ABF        ; Shift up edit rows in the display file, replacing the bottom row with the
  14538.                           ; top entry from the Below-Screen Line Edit Buffer.
  14539.  
  14540. L3628:  POP  HL           ; Restore registers.
  14541.         POP  DE           ;
  14542.         POP  BC           ;
  14543.         RET               ;
  14544.  
  14545. ; ------------------------------------------------
  14546. ; Shift Down Edit Rows in Display File if Required
  14547. ; ------------------------------------------------
  14548. ; This routine shifts edit rows in the display file down if required, replacing the top row with the
  14549. ; bottom entry from the Above-Screen Line Edit Buffer.
  14550. ; Entry: HL=Address of next row to use within the Above-Screen Line Edit Buffer.
  14551. ;        C =Number of editing rows on screen.
  14552. ;        B =Row number to shift from.
  14553.  
  14554. L362C:  PUSH BC           ; Save registers.
  14555.         PUSH DE           ;
  14556.         PUSH HL           ;
  14557.  
  14558.         PUSH HL           ; Save edit buffer row address.
  14559.         LD   HL,$EEF5     ;
  14560.         BIT  2,(HL)       ; Is updating of the display file required?
  14561.         POP  HL           ; Retrieve edit buffer row address.
  14562.         JR   NZ,L363C     ; Jump if updating is not required.
  14563.  
  14564.         LD   E,C          ; E=Cursor row position, i.e. row to shift from.
  14565.         CALL L3AC6        ; Shift down edit rows in the display file, replacing the top row with the
  14566.                           ; bottom entry from the Above-Screen Line Edit Buffer.
  14567.  
  14568. L363C:  POP  HL           ; Restore registers.
  14569.         POP  DE           ;
  14570.         POP  BC           ;
  14571.         RET               ;
  14572.  
  14573. ; ---------------------------
  14574. ; Set Cursor Attribute Colour
  14575. ; ---------------------------
  14576. ; Entry: C=Row number, B=Column number.
  14577.  
  14578. L3640:  PUSH AF           ; Save registers.
  14579.         PUSH BC           ;
  14580.         PUSH DE           ;
  14581.         PUSH HL           ;
  14582.  
  14583.         LD   A,B          ; Swap B with C.
  14584.         LD   B,C          ;
  14585.         LD   C,A          ;
  14586.         CALL L3A9D        ; Set cursor position attribute.
  14587.  
  14588.         POP  HL           ; Restore registers.
  14589.         POP  DE           ;
  14590.         POP  BC           ;
  14591.         POP  AF           ;
  14592.         RET               ;
  14593.  
  14594. ; ------------------------------------------
  14595. ; Restore Cursor Position Previous Attribute
  14596. ; ------------------------------------------
  14597. ; Entry: C=row, B=column.
  14598.  
  14599. L364F:  PUSH AF           ; Save registers
  14600.         PUSH BC           ;
  14601.         PUSH DE           ;
  14602.         PUSH HL           ;
  14603.  
  14604.         LD   A,B          ; Column.
  14605.         LD   B,C          ; Row.
  14606.         LD   C,A          ; Column.
  14607.         CALL L3AB2        ; Restore cursor position attribute.
  14608.  
  14609.         POP  HL           ; Restore registers.
  14610.         POP  DE           ;
  14611.         POP  BC           ;
  14612.         POP  AF           ;
  14613.         RET               ;
  14614.  
  14615. ; --------------
  14616. ; Reset 'L' Mode
  14617. ; --------------
  14618.  
  14619. L365E:  LD   A,$00        ; Select 'L' mode.
  14620.         LD   ($5C41),A    ; MODE.
  14621.  
  14622.         LD   A,$02        ; Reset repeat key duration.
  14623.         LD   ($5C0A),A    ; REPPER
  14624.  
  14625. L3668:  LD   HL,$5C3B     ; FLAGS.
  14626.         LD   A,(HL)       ;
  14627.         OR   $0C          ; Select L-Mode and Print in L-Mode.
  14628.         LD   (HL),A       ;
  14629.  
  14630.         LD   HL,$EC0D     ; Editor flags.
  14631.         BIT  4,(HL)       ; Return to the calculator?
  14632.         LD   HL,FLAGS3    ; $5B66.
  14633.         JR   NZ,L367C     ; Jump ahead if so.
  14634.  
  14635.         RES  0,(HL)       ; Select Editor/Menu mode.
  14636.         RET               ;
  14637.  
  14638. L367C:  SET  0,(HL)       ; Select BASIC/Calculator mode.
  14639.         RET               ;
  14640.  
  14641. ; --------------------
  14642. ; Wait for a Key Press
  14643. ; --------------------
  14644. ; Exit: A holds key code.
  14645.  
  14646. L367F:  PUSH HL           ; Preserve contents of HL.
  14647.  
  14648. L3680:  LD   HL,$5C3B     ; FLAGS.
  14649.  
  14650. L3683:  BIT  5,(HL)       ;
  14651.         JR   Z,L3683      ; Wait for a key press.
  14652.  
  14653.         RES  5,(HL)       ; Clear the new key indicator flag.
  14654.  
  14655.         LD   A,($5C08)    ; Fetch the key pressed from LAST_K.
  14656.         LD   HL,$5C41     ; MODE.
  14657.         RES  0,(HL)       ; Remove extended mode.
  14658.  
  14659.         CP   $20          ; Is it a control code?
  14660.         JR   NC,L36A2     ; Jump if not to accept all characters and token codes (used for the keypad).
  14661.  
  14662.         CP   $10          ; Is it a cursor key?
  14663.         JR   NC,L3680     ; Jump back if not to wait for another key.
  14664.  
  14665.         CP   $06          ; Is it a cursor key?
  14666.         JR   C,L3680      ; Jump back if not to wait for another key.
  14667.  
  14668. ;Control code or cursor key
  14669.  
  14670.         CALL L36A4        ; Handle CAPS LOCK code and 'mode' codes.
  14671.         JR   NC,L3680     ; Jump back if mode might have changed.
  14672.  
  14673. L36A2:  POP  HL           ; Restore contents of HL.
  14674.         RET               ;
  14675.  
  14676. L36A4:  RST  28H          ;
  14677.         DEFW KEY_M_CL     ; $10DB. Handle CAPS LOCK code and 'mode' codes via ROM 1.
  14678.         RET               ;
  14679.  
  14680.  
  14681. ; ======================
  14682. ; MENU ROUTINES - PART 5
  14683. ; ======================
  14684.  
  14685. ; ------------
  14686. ; Display Menu
  14687. ; ------------
  14688. ; HL=Address of menu text.
  14689.  
  14690. L36A8:  PUSH HL           ; Save address of menu text.
  14691.  
  14692.         CALL L373B        ; Store copy of menu screen area and system variables.
  14693.  
  14694.         LD   HL,$5C3C     ; TVFLAG.
  14695.         RES  0,(HL)       ; Signal using main screen.
  14696.  
  14697.         POP  HL           ; HL=Address of menu text.
  14698.  
  14699.         LD   E,(HL)       ; Fetch number of table entries.
  14700.         INC  HL           ; Point to first entry.
  14701.  
  14702.         PUSH HL           ;
  14703.         LD   HL,L37EC     ; Set title colours.
  14704.         CALL L3733        ; Print them.
  14705.         POP  HL           ;
  14706.  
  14707.         CALL L3733        ; Print menu title pointed to by HL.
  14708.  
  14709.         PUSH HL           ;
  14710.         CALL L3822        ; Print Sinclair stripes.
  14711.         LD   HL,L37FA     ; Black ' '.
  14712.         CALL L3733        ; Print it.
  14713.         POP  HL           ; HL=Address of first menu item text.
  14714.  
  14715.         PUSH DE           ; Save number of menu items left to print.
  14716.  
  14717.         LD   BC,$0807     ;
  14718.         CALL L372B        ; Perform 'Print AT 8,7;' (this is the top left position of the menu).
  14719.  
  14720. L36D1:  PUSH BC           ; Save row print coordinates.
  14721.  
  14722.         LD   B,$0C        ; Number of columns in a row of the menu.
  14723.  
  14724.         LD   A,$20        ; Print ' '.
  14725.         RST  10H          ;
  14726.  
  14727. L36D7:  LD   A,(HL)       ; Fetch menu item character.
  14728.         INC  HL           ;
  14729.         CP   $80          ; End marker found?
  14730.         JR   NC,L36E0     ; Jump if end of text found.
  14731.  
  14732.         RST  10H          ; Print menu item character
  14733.         DJNZ L36D7        ; Repeat for all characters in menu item text.
  14734.  
  14735. L36E0:  AND  $7F          ; Clear bit 7 to yield a final text character.
  14736.         RST  10H          ; Print it.
  14737.  
  14738. L36E3:  LD   A,$20        ;
  14739.         RST  10H          ; Print trailing spaces
  14740.         DJNZ L36E3        ; Until all columns filled.
  14741.  
  14742.         POP  BC           ; Fetch row print coordinates.
  14743.         INC  B            ; Next row.
  14744.         CALL L372B        ; Print AT.
  14745.  
  14746.         DEC  E            ;
  14747.         JR   NZ,L36D1     ; Repeat for all menu items.
  14748.  
  14749.         LD   HL,$6F38     ; Coordinates, pixel (111, 56) = end row 13, column 7.
  14750.  
  14751.         POP  DE           ; Fetch number of menu items to E.
  14752.         SLA  E            ;
  14753.         SLA  E            ;
  14754.         SLA  E            ; Determine number of pixels to span all menu items.
  14755.         LD   D,E          ;
  14756.         DEC  D            ; D=8*Number of menu items - 1.
  14757.  
  14758.         LD   E,$6F        ; Number of pixels in width of menu.
  14759.         LD   BC,$FF00     ; B=-1, C=0. Plot a vertical line going up.
  14760.         LD   A,D          ; A=Number of vertical pixels to plot.
  14761.         CALL L3719        ; Plot line.
  14762.  
  14763.         LD   BC,$0001     ; B=0, C=1. Plot a horizontal line going to the right.
  14764.         LD   A,E          ; A=Number of horizontal pixels to plot.
  14765.         CALL L3719        ; Plot line.
  14766.  
  14767.         LD   BC,$0100     ; B=1, C=0. Plot a vertical line going down.
  14768.         LD   A,D          ; A=Number of vertical pixels to plot.
  14769.         INC  A            ; Include end pixel.
  14770.         CALL L3719        ; Plot line.
  14771.  
  14772.         XOR  A            ; A=Index of menu option to highlight.
  14773.         CALL L37CA        ; Toggle menu option selection so that it is highlight.
  14774.         RET               ; [Could have saved one byte by using JP $37CA (ROM 0)]
  14775.  
  14776. ; -----------
  14777. ; Plot a Line
  14778. ; -----------
  14779. ; Entry: H=Line pixel coordinate.
  14780. ;        L=Column pixel coordinate.
  14781. ;        B=Offset to line pixel coordinate ($FF, $00 or $01).
  14782. ;        C=Offset to column pixel coordinate ($FF, $00 or $01).
  14783. ;        A=number of pixels to plot.
  14784.  
  14785. L3719:  PUSH AF           ; Save registers.
  14786.         PUSH HL           ;
  14787.         PUSH DE           ;
  14788.         PUSH BC           ;
  14789.  
  14790.         LD   B,H          ; Coordinates to BC.
  14791.         LD   C,L          ;
  14792.         RST  28H          ;
  14793.         DEFW PLOT_SUB+4   ; $22E9. Plot pixel
  14794.  
  14795.         POP  BC           ; Restore registers.
  14796.         POP  DE           ;
  14797.         POP  HL           ;
  14798.         POP  AF           ;
  14799.  
  14800.         ADD  HL,BC        ; Determine coordinates of next pixel.
  14801.         DEC  A            ;
  14802.         JR   NZ,L3719     ; Repeat for all pixels.
  14803.  
  14804.         RET               ;
  14805.  
  14806. ; -------------------------
  14807. ; Print "AT B,C" Characters
  14808. ; -------------------------
  14809.  
  14810. L372B:  LD   A,$16        ; 'AT'.
  14811.         RST  10H          ; Print.
  14812.         LD   A,B          ; B=Row number.
  14813.         RST  10H          ; Print.
  14814.         LD   A,C          ; C=Column number.
  14815.         RST  10H          ; Print.
  14816.         RET               ;
  14817.  
  14818. ; ------------
  14819. ; Print String
  14820. ; ------------
  14821. ; Print characters pointed to by HL until $FF found.
  14822.  
  14823. L3733:  LD   A,(HL)       ; Fetch a character.
  14824.         INC  HL           ; Advance to next character.
  14825.         CP   $FF          ; Reach end of string?
  14826.         RET  Z            ; Return if so.
  14827.  
  14828.         RST  10H          ; Print the character.
  14829.         JR   L3733        ; Back for the next character.
  14830.  
  14831. ; ----------------------
  14832. ; Store Menu Screen Area
  14833. ; ----------------------
  14834. ; Store copy of menu screen area and system variables.
  14835.  
  14836. L373B:  SCF               ; Set carry flag to signal to save screen area.
  14837.         JR   L373F        ; Jump ahead to continue.
  14838.  
  14839. ; ------------------------
  14840. ; Restore Menu Screen Area
  14841. ; ------------------------
  14842. ; Restore menu screen area and system variables from copy.
  14843. ; Entry: IX=Address of the cursor settings information.
  14844.  
  14845. L373E:  AND  A            ; Reset carry flag to signal restore screen area.
  14846.  
  14847. L373F:  LD   DE,$EEF6     ; Store for TVFLAG.
  14848.         LD   HL,$5C3C     ; TVFLAG.
  14849.         JR   C,L3748      ; Jump if storing copies.
  14850.  
  14851.         EX   DE,HL        ; Exchange source and destination pointers.
  14852.  
  14853. L3748:  LDI               ; Transfer the byte.
  14854.         JR   C,L374D      ; Jump if storing copies.
  14855.  
  14856.         EX   DE,HL        ; Restore source and destination pointers.
  14857.  
  14858. L374D:  LD   HL,$5C7D     ; COORDS. DE=$EEF7 by now.
  14859.         JR   C,L3753      ; Jump if storing copies.
  14860.  
  14861.         EX   DE,HL        ; Exchange source and destination pointers.
  14862.  
  14863. L3753:  LD   BC,$0014     ; Copy 20 bytes.
  14864.         LDIR              ; Copy COORDS until ATTR_T.
  14865.         JR   C,L375B      ; Jump if storing copies.
  14866.  
  14867.         EX   DE,HL        ; Restore source and destination pointers.
  14868.  
  14869. L375B:  EX   AF,AF'       ; Save copy direction flag.
  14870.  
  14871.        LD   BC,$0707     ; Menu will be at row 7, column 7.
  14872.        CALL L3B94        ; B=Number of rows to end row of screen. C=Number of columns to the end column of the screen.
  14873.  
  14874.        LD   A,(IX+$01)   ; A=Rows above the editing area ($16 when using the lower screen, $00 when using the main screen).
  14875.        ADD  A,B          ; B=Row number within editing area.
  14876.        LD   B,A          ; B=Bottom screen row to store.
  14877.        LD   A,$0C        ; A=Number of rows to store. [Could have been just $07 freeing up 630 bytes of workspace]
  14878.  
  14879. L3769:  PUSH BC           ; B holds number of row to store.
  14880.        PUSH AF           ; A holds number of rows left to store.
  14881.        PUSH DE           ; DE=End of destination address.
  14882.  
  14883.        RST  28H          ;
  14884.        DEFW CL_ADDR      ; $0E9B. HL=Display file address of row B.
  14885.        LD   BC,$0007     ; Menu always starts at column 7.
  14886.        ADD  HL,BC        ; HL=Address of attribute byte at column 7.
  14887.        POP  DE           ;
  14888.  
  14889.        CALL L377E        ; Store / restore menu screen row.
  14890.  
  14891.        POP  AF           ;
  14892.        POP  BC           ;
  14893.        DEC  B            ; Next row.
  14894.        DEC  A            ; More rows to store / restore?
  14895.        JR   NZ,L3769     ; Repeat for next row
  14896.  
  14897.        RET               ;
  14898.  
  14899. ; -------------------------------
  14900. ; Store / Restore Menu Screen Row
  14901. ; -------------------------------
  14902. ; Entry: HL=Start address of menu row in display file.
  14903. ;        DE=Screen location/Workspace store for screen row.
  14904. ;        AF'=Carry flag set for store to workspace, reset for restore to screen.
  14905. ; Exit : DE=Screen location/workspace store for next screen row.
  14906.  
  14907. ;Save the display file bytes
  14908.  
  14909. L377E:  LD   BC,$080E     ; B=Menu row is 8 lines deep. C=Menu is 14 columns wide.
  14910.  
  14911. L3781:  PUSH BC           ; Save number of row lines.
  14912.         LD   B,$00        ; Just keep the column count in BC.
  14913.  
  14914.         PUSH HL           ; Save display file starting address.
  14915.  
  14916.         EX   AF,AF'       ; Retrieve copy direction flag.
  14917.        JR   C,L3789      ; Jump if storing copies of display file bytes.
  14918.  
  14919.        EX   DE,HL        ; Exchange source and destination pointers.
  14920.  
  14921. L3789:  LDIR              ; Copy the row of menu display file bytes.
  14922.        JR   C,L378E      ; Jump if storing copies of display file bytes.
  14923.  
  14924.        EX   DE,HL        ; Restore source and destination pointers.
  14925.  
  14926. L378E:  EX   AF,AF'       ; Save copy direction flag.
  14927.  
  14928.         POP  HL           ; Fetch display file starting address.
  14929.         INC  H            ; Advance to next line
  14930.  
  14931.         POP  BC           ; Fetch number of lines.
  14932.         DJNZ L3781        ; Repeat for next line.
  14933.  
  14934. ;Now save the attributes
  14935.  
  14936.         PUSH BC           ; B=0. C=Number of columns.
  14937.         PUSH DE           ; DE=Destination address.
  14938.         RST  28H          ;
  14939.         DEFW CL_ATTR      ; $0E88. HL=Address of attribute byte.
  14940.         EX   DE,HL        ; DE=Address of attribute byte.
  14941.         POP  DE           ;
  14942.         POP  BC           ;
  14943.  
  14944.         EX   AF,AF'       ; Retrieve copy direction flag.
  14945.        JR   C,L37A0      ; Jump if storing copies of attribute bytes.
  14946.  
  14947.        EX   DE,HL        ; Restore source and destination pointers.
  14948.  
  14949. L37A0:  LDIR              ; Copy the row of menu attribute bytes.
  14950.        JR   C,L37A5      ; Jump if storing copies of attribute bytes.
  14951.  
  14952.        EX   DE,HL        ; Restore source and destination pointers.
  14953.  
  14954. L37A5:  EX   AF,AF'       ; Save copy direction flag.
  14955.         RET               ;
  14956.  
  14957. ; ------------
  14958. ; Move Up Menu
  14959. ; ------------
  14960.  
  14961. L37A7:  CALL L37CA        ; Toggle old menu item selection to de-highlight it.
  14962.         DEC  A            ; Decrement menu index.
  14963.         JP   P,L37B1      ; Jump if not exceeded top of menu.
  14964.  
  14965.         LD   A,(HL)       ; Fetch number of menu items.
  14966.         DEC  A            ; Ignore the title.
  14967.         DEC  A            ; Make it indexed from 0.
  14968.  
  14969. L37B1:  CALL L37CA        ; Toggle new menu item selection to highlight it.
  14970.         SCF               ; Ensure carry flag is set to prevent immediately
  14971.         RET               ; calling menu down routine upon return.
  14972.  
  14973. ; --------------
  14974. ; Move Down Menu
  14975. ; --------------
  14976.  
  14977. L37B6:  PUSH DE           ; Save DE.
  14978.  
  14979.         CALL L37CA        ; Toggle old menu item selection to de-highlight it.
  14980.  
  14981.         INC  A            ; Increment menu index.
  14982.         LD   D,A          ; Save menu index.
  14983.  
  14984.         LD   A,(HL)       ; fetch number of menu items.
  14985.         DEC  A            ; Ignore the title.
  14986.         DEC  A            ; Make it indexed from 0.
  14987.         CP   D            ; Has bottom of menu been exceeded?
  14988.         LD   A,D          ; Fetch menu index.
  14989.         JP   P,L37C5      ; Jump if bottom menu not exceeded.
  14990.  
  14991.         XOR  A            ; Select top menu item.
  14992.  
  14993. L37C5:  CALL L37CA        ; Toggle new menu item selection to highlight it.
  14994.  
  14995.         POP  DE           ; Restore DE.
  14996.         RET               ;
  14997.  
  14998. ; --------------------------------------
  14999. ; Toggle Menu Option Selection Highlight
  15000. ; --------------------------------------
  15001. ; Entry: A=Menu option index to highlight.
  15002.  
  15003. L37CA:  PUSH AF           ; Save registers.
  15004.         PUSH HL           ;
  15005.         PUSH DE           ;
  15006.  
  15007.         LD   HL,$5907     ; First attribute byte at position (9,7).
  15008.         LD   DE,$0020     ; The increment for each row.
  15009.         AND  A            ;
  15010.         JR   Z,L37DA      ; Jump ahead if highlighting the first entry.
  15011.  
  15012. L37D6:  ADD  HL,DE        ; Otherwise increase HL
  15013.         DEC  A            ; for each row.
  15014.         JR   NZ,L37D6     ;
  15015.  
  15016. L37DA:  LD   A,$78        ; Flash 0, Bright 1, Paper 7, Ink 0 = Bright white.
  15017.         CP   (HL)         ; Is the entry already highlighted?
  15018.         JR   NZ,L37E1     ; Jump ahead if not.
  15019.  
  15020.         LD   A,$68        ; Flash 0, Bright 1, Paper 5, Ink 0 = Bright cyan.
  15021.  
  15022. L37E1:  LD   D,$0E        ; There are 14 columns to set.
  15023.  
  15024. L37E3:  LD   (HL),A       ; Set the attributes for all columns.
  15025.         INC  HL           ;
  15026.         DEC  D            ;
  15027.         JR   NZ,L37E3     ;
  15028.  
  15029.         POP  DE           ; Restore registers.
  15030.         POP  HL           ;
  15031.         POP  AF           ;
  15032.         RET               ;
  15033.  
  15034. ; ------------------------
  15035. ; Menu Title Colours Table
  15036. ; ------------------------
  15037.  
  15038. L37EC:  DB $16, $07, $07 ; AT 7,7;
  15039.         DB $15, $00      ; OVER 0;
  15040.         DB $14, $00      ; INVERSE 0;
  15041.         DB $10, $07      ; INK 7;
  15042.         DB $11, 00       ; PAPER 0;
  15043.         DB $13, $01      ; BRIGHT 1;
  15044.         DB $FF           ;
  15045.  
  15046. ; ----------------------
  15047. ; Menu Title Space Table
  15048. ; ----------------------
  15049.  
  15050. L37FA:  DB $11, $00      ; PAPER 0;
  15051.         DB ' '           ;
  15052.         DB $11, $07      ; PAPER 7;
  15053.         DB $10, $00      ; INK 0;
  15054.         DB $FF           ;
  15055.  
  15056. ; -----------------------------
  15057. ; Menu Sinclair Stripes Bitmaps
  15058. ; -----------------------------
  15059. ; Bit-patterns for the Sinclair stripes used on the menus.
  15060.  
  15061. L3802:  DB $01          ; 0 0 0 0 0 0 0 1           X
  15062.         DB $03          ; 0 0 0 0 0 0 1 1          XX
  15063.         DB $07          ; 0 0 0 0 0 1 1 1         XXX
  15064.         DB $0F          ; 0 0 0 0 1 1 1 1        XXXX
  15065.         DB $1F          ; 0 0 0 1 1 1 1 1       XXXXX
  15066.         DB $3F          ; 0 0 1 1 1 1 1 1      XXXXXX
  15067.         DB $7F          ; 0 1 1 1 1 1 1 1     XXXXXXX
  15068.         DB $FF          ; 1 1 1 1 1 1 1 1    XXXXXXXX
  15069.  
  15070.         DB $FE          ; 1 1 1 1 1 1 1 0    XXXXXXX
  15071.         DB $FC          ; 1 1 1 1 1 1 0 0    XXXXXX
  15072.         DB $F8          ; 1 1 1 1 1 0 0 0    XXXXX
  15073.         DB $F0          ; 1 1 1 1 0 0 0 0    XXXX
  15074.         DB $E0          ; 1 1 1 0 0 0 0 0    XXX
  15075.         DB $C0          ; 1 1 0 0 0 0 0 0    XX
  15076.         DB $80          ; 1 0 0 0 0 0 0 0    X
  15077.         DB $00          ; 0 0 0 0 0 0 0 0
  15078.  
  15079. ; ---------------------
  15080. ; Sinclair Strip 'Text'
  15081. ; ---------------------
  15082. ; CHARS points to RAM at $5A98, and characters ' ' and '!' redefined
  15083. ; as the Sinclair strips using the bit patterns above.
  15084.  
  15085. L3812:  DB $10, $02, ' ' ; INK 2;
  15086.         DB $11, $06, '!' ; PAPER 6;
  15087.         DB $10, $04, ' ' ; INK 4;
  15088.         DB $11, $05, '!' ; PAPER 5;
  15089.         DB $10, $00, ' ' ; INK 0;
  15090.         DB $FF           ;
  15091.  
  15092. ; --------------------------------------
  15093. ; Print the Sinclair stripes on the menu
  15094. ; --------------------------------------
  15095.  
  15096. L3822:  PUSH BC           ; Save registers.
  15097.         PUSH DE           ;
  15098.         PUSH HL           ;
  15099.  
  15100.         LD   HL,L3802     ; Graphics bit-patterns
  15101.         LD   DE,STRIP1    ; $5B98.
  15102.         LD   BC,$0010     ; Copy two characters.
  15103.         LDIR              ;
  15104.  
  15105.         LD   HL,($5C36)   ; Save CHARS.
  15106.         PUSH HL           ;
  15107.  
  15108.         LD   HL,STRIP1-$0100 ; $5A98.
  15109.         LD   ($5C36),HL   ; Set CHARS to point to new graphics.
  15110.  
  15111.         LD   HL,L3812     ; Point to the strip string.
  15112.         CALL L3733        ; Print it.
  15113.  
  15114.         POP  HL           ; Restore CHARS.
  15115.         LD   ($5C36),HL   ;
  15116.  
  15117.         POP  HL           ; Restore registers.
  15118.         POP  DE           ;
  15119.         POP  BC           ;
  15120.         RET               ;
  15121.  
  15122. ; ------------------------
  15123. ; Print '128 BASIC' Banner
  15124. ; ------------------------
  15125.  
  15126. L3848:  LD   HL,L2769     ; "128 BASIC" text from main menu.
  15127.         JR   L385A        ; Jump ahead to print banner.
  15128.  
  15129. ; -------------------------
  15130. ; Print 'Calculator' Banner
  15131. ; -------------------------
  15132.  
  15133. L384D:  LD   HL,L2772     ; "Calculator" text from main menu.
  15134.         JR   L385A        ; Jump ahead to print banner.
  15135.  
  15136. ; --------------------------
  15137. ; Print 'Tape Loader' Banner
  15138. ; --------------------------
  15139.  
  15140. L3852:  LD   HL,L275E     ; "Tape Loader" text from main menu.
  15141.         JR   L385A        ; Jump ahead to print banner.
  15142.  
  15143. ; --------------------------
  15144. ; Print 'Tape Tester' Banner
  15145. ; --------------------------
  15146.  
  15147. L3857:  LD   HL,L2784     ; "Tape Tester" text from main menu.
  15148.  
  15149. ; ------------
  15150. ; Print Banner
  15151. ; ------------
  15152.  
  15153. L385A:  PUSH HL           ; Address in memory of the text of the selected menu item.
  15154.  
  15155.         CALL L3881        ; Clear lower editing area display.
  15156.  
  15157.         LD   HL,$5AA0     ; Address of banner row in attributes.
  15158.         LD   B,$20        ; 32 columns.
  15159.         LD   A,$40        ; FLASH 0, BRIGHT 1, PAPER 0, INK 0.
  15160.  
  15161. L3865:  LD   (HL),A       ; Set a black row.
  15162.         INC  HL           ;
  15163.         DJNZ L3865        ;
  15164.  
  15165.         LD   HL,L37EC     ; Menu title colours table.
  15166.         CALL L3733        ; Print the colours as a string.
  15167.  
  15168.         LD   BC,$1500     ;
  15169.         CALL L372B        ; Perform 'Print AT 21,0;'.
  15170.  
  15171.         POP  DE           ; Address in memory of the text of the selected menu item.
  15172.         CALL L057D        ; Print the text.
  15173.  
  15174.         LD   C,$1A        ; B has not changed and still holds 21.
  15175.         CALL L372B        ; Perform 'Print AT 21,26;'.
  15176.         JP   L3822        ; Print Sinclair stripes and return to calling routine.
  15177.  
  15178. ; ---------------------------
  15179. ; Clear Lower Editing Display
  15180. ; ---------------------------
  15181.  
  15182. L3881:  LD   B,$15        ; Top row of editing area.
  15183.         LD   D,$17        ; Bottom row of editing area.
  15184.         JP   L3B5E        ; Reset Display.
  15185.  
  15186.  
  15187. ; ================
  15188. ; RENUMBER ROUTINE
  15189. ; ================
  15190. ; Exit: Carry flag reset if required to produce an error beep.
  15191.  
  15192. L3888:  CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  15193.  
  15194.         CALL L3A05        ; DE=Count of the number of BASIC lines.
  15195.         LD   A,D          ;
  15196.         OR   E            ; Were there any BASIC lines?
  15197.         JP   Z,L39C0      ; Jump if not to return since there is nothing to renumber.
  15198.  
  15199.         LD   HL,(RNSTEP)  ; $5B96. Fetch the line number increment for Renumber.
  15200.         RST  28H          ;
  15201.         DEFW HL_MULT_DE   ; $30A9. HL=HL*DE in ROM 1. HL=Number of lines * Line increment = New last line number.
  15202.                           ; [*BUG* - If there are more than 6553 lines then an arithmetic overflow will occur and hence
  15203.                           ; the test below to check if line 9999 would be exceeded will fail. The carry flag will be set
  15204.                           ; upon such an overflow and simply needs to be tested. The bug can be resolved by following the
  15205.                           ; call to HL_MULT_DE with a JP C,$39C0 (ROM 0) instruction. Credit: Ian Collier (+3), Andrew Owen (128)]
  15206.         EX   DE,HL        ; DE=Offset of new last line number from the first line number.
  15207.  
  15208.         LD   HL,(RNFIRST) ; $5B94. Starting line number for Renumber.
  15209.         ADD  HL,DE        ; HL=New last line number.
  15210.         LD   DE,$2710     ; 10000.
  15211.         OR   A            ;
  15212.         SBC  HL,DE        ; Would the last line number above 9999?
  15213.         JP   NC,L39C0     ; Jump if so to return since Renumber cannot proceed.
  15214.  
  15215. ;There is a program that can be renumbered
  15216.  
  15217.         LD   HL,($5C53)   ; PROG. HL=Address of first BASIC line.
  15218.  
  15219. L38AA:  RST  28H          ; Find the address of the next BASIC line from the
  15220.         DEFW NEXT_ONE     ; $19B8.  location pointed to by HL, returning it in DE.
  15221.  
  15222.         INC  HL           ; Advance past the line number bytes to point
  15223.         INC  HL           ; at the line length bytes.
  15224.         LD   (RNLINE),HL  ; $5B92. Store the address of the BASIC line's length bytes.
  15225.  
  15226.         INC  HL           ; Advance past the line length bytes to point
  15227.         INC  HL           ; at the command.
  15228.         LD   (N_STR1+4),DE ; $5B6B. Store the address of the next BASIC line.
  15229.  
  15230. L38B8:  LD   A,(HL)       ; Get a character from the BASIC line.
  15231.         RST  28H          ; Advance past a floating point number, if present.
  15232.         DEFW NUMBER       ; $18B6.
  15233.  
  15234.         CP   $0D          ; Is the character an 'ENTER'?
  15235.         JR   Z,L38C5      ; Jump if so to examine the next line.
  15236.  
  15237.         CALL L390E        ; Parse the line, renumbering any tokens that may be followed by a line number.
  15238.         JR   L38B8        ; Repeat for all remaining character until end of the line.
  15239.  
  15240. L38C5:  LD   DE,(N_STR1+4) ; $5B6B. DE=Address of the next BASIC line.
  15241.         LD   HL,($5C4B)   ; VARS. Fetch the address of the end of the BASIC program.
  15242.         AND  A            ;
  15243.         SBC  HL,DE        ; Has the end of the BASIC program been reached?
  15244.         EX   DE,HL        ; HL=Address of start of the current BASIC line.
  15245.         JR   NZ,L38AA     ; Jump back if not to examine the next line.
  15246.  
  15247. ;The end of the BASIC program has been reached so now it is time to update
  15248. ;the line numbers and line lengths.
  15249.  
  15250.         CALL L3A05        ; DE=Count of the number of BASIC lines.
  15251.         LD   B,D          ;
  15252.         LD   C,E          ; BC=Count of the number of BASIC lines.
  15253.         LD   DE,$0000     ;
  15254.         LD   HL,($5C53)   ; PROG. HL=Address of first BASIC line.
  15255.  
  15256. L38DD:  PUSH BC           ; BC=Count of number of lines left to update.
  15257.         PUSH DE           ; DE=Index of the current line.
  15258.  
  15259.         PUSH HL           ; HL=Address of current BASIC line.
  15260.  
  15261.         LD   HL,(RNSTEP)  ; $5B96. HL=Renumber line increment.
  15262.         RST  28H          ; Calculate new line number offset, i.e. Line increment * Line index.
  15263.         DEFW HL_MULT_DE   ; $30A9. HL=HL*DE in ROM 1.
  15264.         LD   DE,(RNFIRST) ; $5B94. The initial line number when renumbering.
  15265.         ADD  HL,DE        ; HL=The new line number for the current line.
  15266.         EX   DE,HL        ; DE=The new line number for the current line.
  15267.  
  15268.         POP  HL           ; HL=Address of current BASIC line.
  15269.  
  15270.         LD   (HL),D       ; Store the new line number for this line.
  15271.         INC  HL           ;
  15272.         LD   (HL),E       ;
  15273.         INC  HL           ;
  15274.         LD   C,(HL)       ; Fetch the line length.
  15275.         INC  HL           ;
  15276.         LD   B,(HL)       ;
  15277.         INC  HL           ;
  15278.         ADD  HL,BC        ; Point to the next line.
  15279.  
  15280.         POP  DE           ; DE=Index of the current line.
  15281.         INC  DE           ; Increment the line index.
  15282.  
  15283.         POP  BC           ; BC=Count of number of lines left to update.
  15284.         DEC  BC           ; Decrement counter.
  15285.         LD   A,B          ;
  15286.         OR   C            ;
  15287.         JR   NZ,L38DD     ; Jump back while more lines to update.
  15288.  
  15289.         CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  15290.         LD   (RNLINE),BC  ; $5B92. Clear the address of line length bytes of the 'current line being renumbered'.
  15291.                           ; [No need to clear this]
  15292.         SCF               ; Signal not to produce an error beep.
  15293.         RET               ;
  15294.  
  15295. ; -------------------------
  15296. ; Tokens Using Line Numbers
  15297. ; -------------------------
  15298. ; A list of all tokens that maybe followed by a line number and hence
  15299. ; require consideration.
  15300.  
  15301. L3907:  DB $CA          ; 'LINE'.
  15302.         DB $F0          ; 'LIST'.
  15303.         DB $E1          ; 'LLIST'.
  15304.         DB $EC          ; 'GO TO'.
  15305.         DB $ED          ; 'GO SUB'.
  15306.         DB $E5          ; 'RESTORE'.
  15307.         DB $F7          ; 'RUN'.
  15308.  
  15309. ; -----------------------------------------------
  15310. ; Parse a Line Renumbering Line Number References
  15311. ; -----------------------------------------------
  15312. ; This routine examines a BASIC line for any tokens that may be followed by a line number reference
  15313. ; and if one is found then the new line number if calculated and substituted for the old line number
  15314. ; reference. Although checks are made to ensure an out of memory error does not occur, the routine
  15315. ; simply returns silently in such scenarios and the renumber routine will continue onto the next BASIC
  15316. ; line.
  15317. ; Entry: HL=Address of current character in the current BASIC line.
  15318. ;        A=Current character.
  15319.  
  15320. L390E:  INC  HL           ; Point to the next character.
  15321.         LD   (HD_11+1),HL ; $5B79. Store it.
  15322.  
  15323.         EX   DE,HL        ; DE=Address of next character.
  15324.         LD   BC,$0007     ; There are 7 tokens that may be followed by a line
  15325.         LD   HL,L3907     ; number, and these are listed in the table at $3907 (ROM 0).
  15326.         CPIR              ; Search for a match for the current character.
  15327.         EX   DE,HL        ; HL=Address of next character.
  15328.         RET  NZ           ; Return if no match found.
  15329.  
  15330. ;A token that might be followed by a line number was found. If it is followed by a
  15331. ;line number then proceed to renumber the line number reference. Note that the statements
  15332. ;such as GO TO VAL "100" will not be renumbered. The line numbers of each BASIC line will
  15333. ;be renumbered as the last stage of the renumber process at $38D2 (ROM 0).
  15334.  
  15335.         LD   C,$00        ; Counts the number of digits in the current line number representation.
  15336.                           ; B will be $00 from above.
  15337.  
  15338. L391F:  LD   A,(HL)       ; Fetch the next character.
  15339.         CP   ' '          ; $20. Is it a space?
  15340.         JR   Z,L393F      ; Jump ahead if so to parse the next character.
  15341.  
  15342.         RST  28H          ;
  15343.         DEFW NUMERIC      ; $2D1B. Is the character a numeric digit?
  15344.         JR   NC,L393F     ; Jump if a numeric digit to parse the next character.
  15345.  
  15346.         CP   '.'          ; $2E. Is it a decimal point?
  15347.         JR   Z,L393F      ; Jump ahead if so to parse the next character.
  15348.  
  15349.         CP   $0E          ; Does it indicate a hidden number?
  15350.         JR   Z,L3943      ; Jump ahead if so to process it.
  15351.  
  15352.         OR   $20          ; Convert to lower case.
  15353.         CP   'e'          ; $65. Is it an exponent 'e'?
  15354.         JR   NZ,L393B     ; Jump if not to parse the next character.
  15355.  
  15356.         LD   A,B          ; Have any digits been found?
  15357.         OR   C            ;
  15358.         JR   NZ,L393F     ; Jump ahead to parse the next character.
  15359.  
  15360. ;A line number reference was not found
  15361.  
  15362. L393B:  LD   HL,(HD_11+1) ; $5B79. Retrieve the address of the next character.
  15363.         RET               ;
  15364.  
  15365. L393F:  INC  BC           ; Increment the number digit counter.
  15366.         INC  HL           ; Point to the next character.
  15367.         JR   L391F        ; Jump back to parse the character at this new address.
  15368.  
  15369. ;An embedded number was found
  15370.  
  15371. L3943:  LD   (HD_00),BC   ; $5B71. Note the number of digits in the old line number reference.
  15372.  
  15373.         PUSH HL           ; Save the address of the current character.
  15374.  
  15375.         RST  28H          ;
  15376.         DEFW NUMBER       ; $18B6. Advance past internal floating point representation, if present.
  15377.  
  15378.         CALL L3A36        ; Skip over any spaces.
  15379.  
  15380.         LD   A,(HL)       ; Fetch the new character.
  15381.         POP  HL           ; HL=Address of the current character.
  15382.         CP   ':'          ; $3A. Is it ':'?
  15383.         JR   Z,L3957      ; Jump if so.
  15384.  
  15385.         CP   $0D          ; Is it 'ENTER'?
  15386.         RET  NZ           ; Return if not.
  15387.  
  15388. ;End of statement/line found
  15389.  
  15390. L3957:  INC  HL           ; Point to the next character.
  15391.  
  15392.         RST  28H          ;
  15393.         DEFW STACK_NUM    ; $33B4. Move floating point number to the calculator stack.
  15394.         RST  28H          ;
  15395.         DEFW FP_TO_BC     ; $2DA2. Fetch the number line to BC. [*BUG* - This should test the carry flag to check whether
  15396.                           ; the number was too large to be transferred to BC. If so then the line number should be set to 9999,
  15397.                           ; as per the instructions at $396A (ROM 0). As a result, the call the LINE_ADDR below can result in a crash.
  15398.                           ; The bug can be resolved using a JR C,$396A (ROM 0) instruction. Credit: Ian Collier (+3), Andrew Owen (128)]
  15399.         LD   H,B          ;
  15400.         LD   L,C          ; Transfer the number line to HL.
  15401.  
  15402.         RST  28H          ; Find the address of the line number specified by HL.
  15403.         DEFW LINE_ADDR    ; $196E. HL=Address of the BASIC line, or the next one if it does not exist.
  15404.         JR   Z,L396F      ; Jump if the line exists.
  15405.  
  15406.         LD   A,(HL)       ; Has the end of the BASIC program been reached?
  15407.         CP   $80          ; [*BUG* - This tests for the end of the variables area and not the end of the BASIC program area. Therefore,
  15408.                           ; the renumber routine will not terminate properly if variables exist in memory when it is called.
  15409.                           ; Executing CLEAR prior to renumbering will overcome this bug.
  15410.                           ; It can be fixed by replacing CP $80 with the instructions AND $C0 / JR Z,$396F (ROM 0). Credit: Ian Collier (+3), Andrew Owen (128)]
  15411.         JR   NZ,L396F     ; Jump ahead if not.
  15412.  
  15413.         LD   HL,$270F     ; Make the reference point to line 9999.
  15414.         JR   L3980        ; Jump ahead to update the reference to use the new line number.
  15415.  
  15416. ;The reference line exists
  15417.  
  15418. L396F:  LD   (HD_0F+1),HL ; $5B77. Store the address of the referenced line.
  15419.         CALL L3A0B        ; DE=Count of the number of BASIC lines up to the referenced line.
  15420.         LD   HL,(RNSTEP)  ; $5B96. Fetch the line number increment.
  15421.         RST  28H          ;
  15422.         DEFW HL_MULT_DE   ; $30A9. HL=HL*DE in ROM 1. HL=Number of lines * Line increment = New referenced line number.
  15423.                           ; [An overflow could occur here and would not be detected. The code at $3898 (ROM 0)
  15424.                           ; should have trapped that such an overflow would occur and hence there would have been
  15425.                           ; no possibility of it occurring here.]
  15426.         LD   DE,(RNFIRST) ; $5B94. Starting line number for Renumber.
  15427.         ADD  HL,DE        ; HL=New referenced line number.
  15428.  
  15429. ;HL=New line number being referenced
  15430.  
  15431. L3980:  LD   DE,HD_0B+1   ; $5B73. Temporary buffer to generate ASCII representation of the new line number.
  15432.         PUSH HL           ; Save the new line number being referenced.
  15433.         CALL L3A3C        ; Create the ASCII representation of the line number in the buffer.
  15434.  
  15435.         LD   E,B          ;
  15436.         INC  E            ;
  15437.         LD   D,$00        ; DE=Number of digits in the new line number.
  15438.  
  15439.         PUSH DE           ; DE=Number of digits in the new line number.
  15440.         PUSH HL           ; HL=Address of the first non-'0' character in the buffer.
  15441.  
  15442.         LD   L,E          ;
  15443.         LD   H,$00        ; HL=Number of digits in the new line number.
  15444.         LD   BC,(HD_00)   ; $5B71. Fetch the number of digits in the old line number reference.
  15445.         OR   A            ;
  15446.         SBC  HL,BC        ; Has the number of digits changed?
  15447.         LD   (HD_00),HL   ; $5B71. Store the difference between the number of digits in the old and new line numbers.
  15448.         JR   Z,L39CF      ; Jump if they are the same length.
  15449.  
  15450.         JR   C,L39C5      ; Jump if the new line number contains less digits than the old.
  15451.  
  15452. ;The new line number contains more digits than the old line number
  15453.  
  15454.         LD   B,H          ;
  15455.         LD   C,L          ; BC=Length of extra space required for the new line number.
  15456.         LD   HL,(HD_11+1) ; $5B79. Fetch the start address of the old line number representation within the BASIC line.
  15457.         PUSH HL           ; Save start address of the line number reference.
  15458.         PUSH DE           ; DE=Number of non-'0' characters in the line number string.
  15459.  
  15460.         LD   HL,($5C65)   ; STKEND. Fetch the start of the spare memory.
  15461.         ADD  HL,BC        ; Would a memory overflow occur if the space were created?
  15462.         JR   C,L39BE      ; Jump if not to return without changing the line number reference.
  15463.  
  15464.         EX   DE,HL        ; DE=New STKEND address.
  15465.         LD   HL,$0082     ; Would there be at least 130 bytes at the top of RAM?
  15466.         ADD  HL,DE        ;
  15467.         JR   C,L39BE      ; Jump if not to return without changing the line number reference.
  15468.  
  15469.         SBC  HL,SP        ; Is the new STKEND address below the stack?
  15470.         CCF               ;
  15471.         JR   C,L39BE      ; Jump if not to return without changing the line number reference.
  15472.  
  15473.         POP  DE           ; DE=Number of non-'0' characters in the line number string.
  15474.         POP  HL           ; HL=Start address of line number reference.
  15475.         RST  28H          ;
  15476.         DEFW MAKE_ROOM    ; $1655. Create the space for the extra line number digits.
  15477.         JR   L39CF        ; Jump ahead to update the number digits.
  15478.  
  15479. ;No room available to insert extra line number digits
  15480.  
  15481. L39BE:  POP DE            ; Discard stacked items.
  15482.         POP HL            ;
  15483.  
  15484. ; [At this point the stack contains 3 surplus items. These are not explicitly popped off the stack since the call to $1F45 (ROM 0) will restore
  15485. ; the stack to the state it was in at $3888 (ROM 0) when the call to $1F20 (ROM 0) saved it.]
  15486.  
  15487. ;Exit if no BASIC program, renumbering would cause a line number overflow or renumbering would cause an out of memory condition
  15488.  
  15489. L39C0:  CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  15490.         AND  A            ; Reset the carry flag so that an error beep will be produced.
  15491.         RET               ;
  15492.  
  15493. ;The new line number contains less digits than the old line number
  15494.  
  15495. L39C5:  DEC  BC           ; BC=Number of digits in the old line number reference.
  15496.         DEC  E            ; Decrement number of digits in the new line number.
  15497.         JR   NZ,L39C5     ; Repeat until BC has been decremented by the number of digits in the new line number,
  15498.                           ; thereby leaving BC holding the number of digits in the BASIC line to be discarded.
  15499.  
  15500.         LD   HL,(HD_11+1) ; $5B79. Fetch the start address of the old line number representation within the BASIC line.
  15501.         RST  28H          ;
  15502.         DEFW RECLAIM_2    ; $19E8. Discard the redundant bytes.
  15503.  
  15504. ;The appropriate amount of space now exists in the BASIC line so update the line number value
  15505.  
  15506. L39CF:  LD   DE,(HD_11+1) ; $5B79. Fetch the start address of the old line number representation within the BASIC line.
  15507.         POP  HL           ; HL=Address of the first non-'0' character in the buffer.
  15508.         POP  BC           ; BC=Number of digits in the new line number.
  15509.         LDIR              ; Copy the new line number into place.
  15510.  
  15511.         EX   DE,HL        ; HL=Address after the line number text in the BASIC line.
  15512.         LD   (HL),$0E     ; Store the hidden number marker.
  15513.  
  15514.         POP  BC           ; Retrieve the new line number being referenced.
  15515.         INC  HL           ; HL=Address of the next position within the BASIC line.
  15516.         PUSH HL           ;
  15517.  
  15518.         RST  28H          ;
  15519.         DEFW STACK_BC     ; $2D2B. Put the line number on the calculator stack, returning HL pointing to it.
  15520.                           ; [*BUG* - This stacks the new line number so that the floating point representation can be copied.
  15521.                           ; However, the number is not actually removed from the calculator stack. Therefore the
  15522.                           ; amount of free memory reduces by 5 bytes as each line with a line number reference is renumbered.
  15523.                           ; A call to FP_TO_BC (at $2DA2 within ROM 1) after the floating point form has been copied would fix
  15524.                           ; the bug. Note that all leaked memory is finally reclaimed when control is returned to the Editor but the
  15525.                           ; bug could prevent large programs from being renumbered. Credit: Paul Farrow]
  15526.         POP  DE           ; DE=Address of the next position within the BASIC line.
  15527.         LD   BC,$0005     ;
  15528.         LDIR              ; Copy the floating point form into the BASIC line.
  15529.         EX   DE,HL        ; HL=Address of character after the newly inserted floating point number bytes.
  15530.         PUSH HL           ;
  15531.  
  15532.         LD   HL,(RNLINE)  ; $5B92. HL=Address of the current line's length bytes.
  15533.         PUSH HL           ;
  15534.  
  15535.         LD   E,(HL)       ;
  15536.         INC  HL           ;
  15537.         LD   D,(HL)       ; DE=Existing length of the current line.
  15538.         LD   HL,(HD_00)   ; $5B71. HL=Change in length of the line.
  15539.         ADD  HL,DE        ;
  15540.         EX   DE,HL        ; DE=New length of the current line.
  15541.  
  15542.         POP  HL           ; HL=Address of the current line's length bytes.
  15543.         LD   (HL),E       ;
  15544.         INC  HL           ;
  15545.         LD   (HL),D       ; Store the new length.
  15546.  
  15547.         LD   HL,(N_STR1+4) ; $5B6B. HL=Address of the next BASIC line.
  15548.         LD   DE,(HD_00)   ; $5B71. DE=Change in length of the current line.
  15549.         ADD  HL,DE        ;
  15550.         LD   (N_STR1+4),HL ; $5B6B. Store the new address of the next BASIC line.
  15551.  
  15552.         POP  HL           ; HL=Address of character after the newly inserted floating point number bytes.
  15553.         RET               ;
  15554.  
  15555. ; -------------------------------
  15556. ; Count the Number of BASIC Lines
  15557. ; -------------------------------
  15558. ; This routine counts the number of lines in the BASIC program, or if entered at $3A0B (ROM 0) counts
  15559. ; the number of lines up in the BASIC program to the address specified in HD_0F+1.
  15560. ; Exit: DE=Number of lines.
  15561.  
  15562. L3A05:  LD   HL,($5C4B)   ; VARS. Fetch the address of the variables
  15563.         LD   (HD_0F+1),HL ; $5B77.  and store it.
  15564.  
  15565. L3A0B:  LD   HL,($5C53)   ; PROG. Fetch the start of the BASIC program
  15566.         LD   DE,(HD_0F+1) ; $5B77.  and compare against the address of
  15567.         OR   A            ; the end address to check whether there is
  15568.         SBC  HL,DE        ; a BASIC program.
  15569.         JR   Z,L3A31      ; Jump if there is no BASIC program.
  15570.  
  15571.         LD   HL,($5C53)   ; PROG. Fetch the start address of the BASIC program.
  15572.         LD   BC,$0000     ; A count of the number of lines.
  15573.  
  15574. L3A1D:  PUSH BC           ; Save the line number count.
  15575.  
  15576.         RST  28H          ; Find the address of the next BASIC line from the
  15577.         DEFW NEXT_ONE     ; $19B8.  location pointed to by HL, returning it in DE.
  15578.  
  15579.         LD   HL,(HD_0F+1) ; $5B77. Fetch the start of the variables area,
  15580.         AND  A            ; i.e. end of the BASIC program.
  15581.         SBC  HL,DE        ;
  15582.         JR   Z,L3A2E      ; Jump if end of BASIC program reached.
  15583.  
  15584.         EX   DE,HL        ; HL=Address of current line.
  15585.  
  15586.         POP  BC           ; Retrieve the line number count.
  15587.         INC  BC           ; Increment line number count.
  15588.         JR   L3A1D        ; Jump back to look for the next line.
  15589.  
  15590. L3A2E:  POP  DE           ; Retrieve the number of BASIC lines and
  15591.         INC  DE           ; increment since originally started on a line.
  15592.         RET               ;
  15593.  
  15594. ;No BASIC program
  15595.  
  15596. L3A31:  LD   DE,$0000     ; There are no BASIC lines.
  15597.         RET               ;
  15598.  
  15599. ; -----------
  15600. ; Skip Spaces
  15601. ; -----------
  15602.  
  15603. L3A35:  INC  HL           ; Point to the next character.
  15604.  
  15605. L3A36:  LD   A,(HL)       ; Fetch the next character.
  15606.         CP   ' '          ; $20. Is it a space?
  15607.         JR   Z,L3A35      ; Jump if so to skip to next character.
  15608.  
  15609.         RET               ;
  15610.  
  15611. ; ---------------------------------------
  15612. ; Create ASCII Line Number Representation
  15613. ; ---------------------------------------
  15614. ; Creates an ASCII representation of a line number, replacing leading
  15615. ; zeros with spaces.
  15616. ; Entry: HL=The line number to convert.
  15617. ;        DE=Address of the buffer to build ASCII representation in.
  15618. ;        B=Number of non-'0' characters minus 1 in the ASCII representation.
  15619. ; Exit : HL=Address of the first non-'0' character in the buffer.
  15620.  
  15621. L3A3C:  PUSH DE           ; Store the buffer address.
  15622.  
  15623.         LD   BC,$FC18     ; BC=-1000.
  15624.         CALL L3A60        ; Insert how many 1000s there are.
  15625.         LD   BC,$FF9C     ; BC=-100.
  15626.         CALL L3A60        ; Insert how many 100s there are.
  15627.         LD   C,$F6        ; BC=-10.
  15628.         CALL L3A60        ; Insert how many 10s there are.
  15629.         LD   A,L          ; A=Remainder.
  15630.         ADD  A,'0'        ; $30. Convert into an ASCII character ('0'..'9').
  15631.         LD   (DE),A       ; Store it in the buffer.
  15632.         INC  DE           ; Point to the next buffer position.
  15633.  
  15634. ; Now skip over leading zeros
  15635.  
  15636.         LD   B,$03        ; Skip over 3 leading zeros at most.
  15637.         POP  HL           ; Retrieve the buffer start address.
  15638.  
  15639. L3A56:  LD   A,(HL)       ; Fetch a character.
  15640.         CP   '0'          ; $30. Is it a leading zero?
  15641.         RET  NZ           ; Return as soon as a non-'0' character is found.
  15642.  
  15643.         LD   (HL),' '     ; $20. Replace it with a space.
  15644.         INC  HL           ; Point to the next buffer location.
  15645.         DJNZ L3A56        ; Repeat until all leading zeros removed.
  15646.  
  15647.         RET               ;
  15648.  
  15649. ; ------------------------
  15650. ; Insert Line Number Digit
  15651. ; ------------------------
  15652. ; This routine effectively works out the result of HL divided by BC. It does this by
  15653. ; repeatedly adding a negative value until no overflow occurs.
  15654. ; Entry: HL=Number to test.
  15655. ;        BC=Negative amount to add.
  15656. ;        DE=Address of buffer to insert ASCII representation of the number of divisions.
  15657. ; Exit : HL=Remainder.
  15658. ;        DE=Next address in the buffer.
  15659.  
  15660. L3A60:  XOR  A            ; Assume a count of 0 additions.
  15661.  
  15662. L3A61:  ADD  HL,BC        ; Add the negative value.
  15663.         INC  A            ; Increment the counter.
  15664.         JR   C,L3A61      ; If no overflow then jump back to add again.
  15665.  
  15666.         SBC  HL,BC        ; Undo the last step
  15667.         DEC  A            ; and the last counter increment.
  15668.  
  15669.         ADD  A,'0'        ; $30. Convert to an ASCII character ('0'..'9').
  15670.         LD   (DE),A       ; Store it in the buffer.
  15671.         INC  DE           ; Point to the next buffer position.
  15672.         RET               ;
  15673.  
  15674.  
  15675. ; ========================
  15676. ; EDITOR ROUTINES - PART 4
  15677. ; ========================
  15678.  
  15679. ; ------------------------------------
  15680. ; Initial Lower Screen Cursor Settings
  15681. ; ------------------------------------
  15682. ; Copied to $FD6C-$FD73.
  15683.  
  15684. L3A6D:  DB $08          ; Number of bytes in table.
  15685.         DB $00          ; $FD6C. [Setting never used]
  15686.         DB $00          ; $FD6D = Rows above the editing area.
  15687.         DB $14          ; $FD6E. [Setting never used]
  15688.         DB $00          ; $FD6F. [Setting never used]
  15689.         DB $00          ; $FD70. [Setting never used]
  15690.         DB $00          ; $FD71. [Setting never used]
  15691.         DB $0F          ; $FD72 = Cursor attribute colour (blue paper, white ink).
  15692.         DB $00          ; $FD73 = Stored cursor position screen attribute colour (None = black paper, black ink).
  15693.  
  15694. ; -----------------------------------
  15695. ; Initial Main Screen Cursor Settings
  15696. ; -----------------------------------
  15697. ; Copied to $FD6C-$FD73.
  15698.  
  15699. L3A76:  DB $08          ; Number of bytes in table.
  15700.         DB $00          ; $FD6C. [Setting never used]
  15701.         DB $16          ; $FD6D = Rows above the editing area.
  15702.         DB $01          ; $FD6E. [Setting never used]
  15703.         DB $00          ; $FD6F. [Setting never used]
  15704.         DB $00          ; $FD70. [Setting never used]
  15705.         DB $00          ; $FD71. [Setting never used]
  15706.         DB $0F          ; $FD72 = Cursor attribute colour (blue paper, white ink).
  15707.         DB $00          ; $FD73 = Stored cursor position screen attribute colour (None = black paper, black ink).
  15708.  
  15709. ; --------------------------------------
  15710. ; Set Main Screen Editing Cursor Details
  15711. ; --------------------------------------
  15712. ; Set initial cursor editing settings when using the main screen.
  15713. ; Copies 8 bytes from $3A6E-$3A75 (ROM 0) to $FD6C-$FD73.
  15714.  
  15715. L3A7F:  LD   IX,$FD6C     ; Point IX at cursor settings in workspace.
  15716.  
  15717.         LD   HL,L3A6D     ; Initial values table for the lower screen cursor settings.
  15718.         JR   L3A8B        ; Jump ahead.
  15719.  
  15720. ; ---------------------------------------
  15721. ; Set Lower Screen Editing Cursor Details
  15722. ; ---------------------------------------
  15723. ; Set initial cursor editing settings when using the lower screen.
  15724. ; Copies 8 bytes from $3A77-$3A7E (ROM 0) to $FD6C-$FD73.
  15725.  
  15726. L3A88:  LD   HL,L3A76     ; Initial values table for the main screen cursor settings.
  15727.  
  15728. L3A8B:  LD   DE,$FD6C     ; DE=Cursor settings in workspace.
  15729.         JP   L3FBA        ; Jump to copy the settings.
  15730.  
  15731.  
  15732. ; ========================
  15733. ; UNUSED ROUTINES - PART 2
  15734. ; ========================
  15735.  
  15736. ; ----------
  15737. ; Print 'AD'
  15738. ; ----------
  15739. ; This routine prints to the current channel the contents of register A and then the contents of register D.
  15740. ;
  15741. ; [Never called by ROM].
  15742.  
  15743. L3A91:  RST  10H          ; Print character held in A.
  15744.         LD   A,D          ;
  15745.         RST  10H          ; Print character held in D.
  15746.         SCF               ;
  15747.         RET               ;
  15748.  
  15749.  
  15750. ; ========================
  15751. ; EDITOR ROUTINES - PART 5
  15752. ; ========================
  15753.  
  15754. ; -------------------
  15755. ; Store Cursor Colour
  15756. ; -------------------
  15757. ; Entry: A=Cursor attribute byte.
  15758. ;        IX=Address of the cursor settings information.
  15759.  
  15760. L3A96:  AND  $3F          ; Mask off flash and bright bits.
  15761.         LD   (IX+$06),A   ; Store it as the new cursor attribute value.
  15762.         SCF               ;
  15763.         RET               ;
  15764.  
  15765. ; -----------------------------
  15766. ; Set Cursor Position Attribute
  15767. ; -----------------------------
  15768. ; Entry: B=Row number
  15769. ;        C=Column number.
  15770. ;        IX=Address of the cursor settings information.
  15771.  
  15772. L3A9D:  LD   A,(IX+$01)   ; A=Rows above the editing area ($16 when using the lower screen, $00 when using the main screen).
  15773.         ADD  A,B          ; B=Row number within editing area.
  15774.         LD   B,A          ; B=Screen row number.
  15775.         CALL L3BA0        ; Get address of attribute byte into HL.
  15776.  
  15777.         LD   A,(HL)       ; Fetch current attribute byte.
  15778.         LD   (IX+$07),A   ; Store the current attribute byte.
  15779.         CPL               ; Invert colours.
  15780.         AND  $C0          ; Mask off flash and bright bits.
  15781.         OR   (IX+$06)     ; Get cursor colour.
  15782.         LD   (HL),A       ; Store new attribute value to screen.
  15783.  
  15784.         SCF               ; [Redundant since calling routine preserves AF]
  15785.         RET               ;
  15786.  
  15787. ; ---------------------------------
  15788. ; Restore Cursor Position Attribute
  15789. ; ---------------------------------
  15790. ; Entry: B=Row number
  15791. ;        C=Column number.
  15792. ;        IX=Address of the cursor settings information.
  15793.  
  15794. L3AB2:  LD   A,(IX+$01)   ; A=Rows above the editing area ($16 when using the lower screen, $00 when using the main screen).
  15795.         ADD  A,B          ; B=Row number within editing area.
  15796.         LD   B,A          ; B=Screen row number.
  15797.         CALL L3BA0        ; Get address of attribute byte into HL.
  15798.         LD   A,(IX+$07)   ; Get previous attribute value.
  15799.         LD   (HL),A       ; Set colour.
  15800.         RET               ;
  15801.  
  15802. ; ----------------------------------
  15803. ; Shift Up Edit Rows in Display File
  15804. ; ----------------------------------
  15805. ; This routine shifts edit rows in the display file up, replacing the bottom row with the
  15806. ; top entry from the Below-Screen Line Edit Buffer.
  15807. ; Entry: HL=Address of first row in the Below-Screen Line Edit Buffer.
  15808. ;        E =Number of editing rows on screen.
  15809. ;        B =Row number to shift from.
  15810.  
  15811. L3ABF:  PUSH HL           ; Save the address of the Below-Screen Line Edit Buffer row.
  15812.  
  15813.         LD   H,$00        ; Indicate to shift rows up.
  15814.         LD   A,E          ; A=Number of editing rows on screen.
  15815.         SUB  B            ; A=Number of rows to shift, i.e. from current row to end of edit screen.
  15816.         JR   L3ACD        ; Jump ahead.
  15817.  
  15818. ; ------------------------------------
  15819. ; Shift Down Edit Rows in Display File
  15820. ; ------------------------------------
  15821. ; This routine shifts edit rows in the display file down, replacing the top row with the
  15822. ; bottom entry from the Above-Screen Line Edit Buffer.
  15823. ; Entry: HL=Address of next row to use within the Above-Screen Line Edit Buffer.
  15824. ;        E =Number of editing rows on screen.
  15825. ;        B =Row number to shift from.
  15826.  
  15827. L3AC6:  PUSH HL           ; Save the address of the first row in Below-Screen Line Edit Buffer.
  15828.  
  15829.         LD   A,E          ; A=Number of editing rows on screen.
  15830.         LD   E,B          ; E=Row number to shift from.
  15831.         LD   B,A          ; B=Number of editing rows on screen.
  15832.         SUB  E            ; A=Number of rows to shift, i.e. from current row to end of edit screen.
  15833.         LD   H,$FF        ; Indicate to shift rows down.
  15834.  
  15835. ; Shift Rows
  15836. ; ----------
  15837.  
  15838. L3ACD:  LD   C,A          ; C=Number of rows to shift.
  15839.  
  15840.         LD   A,B          ; A=Row number to shift from.
  15841.         CP   E            ; Is it the final row of the editing screen?
  15842.         JR   Z,L3B1D      ; Jump if so to simply display the row.
  15843.  
  15844. ;Shift all display file and attributes rows up
  15845.  
  15846.         PUSH DE           ; Save number of editing rows on screen, in E.
  15847.         CALL L3B98        ; B=Inverted row number, i.e. 24-row number.
  15848.  
  15849. L3AD6:  PUSH BC           ; B=Inverted row number, C=Number of rows left to shift.
  15850.         LD   C,H          ; Store the direction flag.
  15851.  
  15852.         RST  28H          ;
  15853.         DEFW CL_ADDR      ; $0E9B. HL=Destination display file address, for the row number specified by 24-B.
  15854.         EX   DE,HL        ; DE=Destination display file address.
  15855.  
  15856.         XOR  A            ;
  15857.         OR   C            ; Fetch the direction flag.
  15858.         JR   Z,L3AE3      ; Jump if moving up to the previous row.
  15859.  
  15860.         INC  B            ; Move to the previous row (note that B is inverted, i.e. 24-row number).
  15861.         JR   L3AE4        ; Jump ahead.
  15862.  
  15863. L3AE3:  DEC  B            ; Move to the next row (note that B is inverted, i.e. 24-row number).
  15864.  
  15865. L3AE4:  PUSH DE           ; DE=Destination display file address.
  15866.         RST  28H          ;
  15867.         DEFW CL_ADDR      ; $0E9B. HL=Source display file address, for the row number held in B.
  15868.         POP DE            ; DE=Destination display file address.
  15869.  
  15870. ;Copy one row of the display file
  15871.  
  15872.         LD   A,C          ; Fetch the direction flag.
  15873.         LD   C,$20        ; 32 columns.
  15874.         LD   B,$08        ; 8 lines.
  15875.  
  15876. L3AEE:  PUSH BC           ;
  15877.         PUSH HL           ;
  15878.         PUSH DE           ;
  15879.         LD   B,$00        ;
  15880.         LDIR              ; Copy one line in the display file.
  15881.         POP  DE           ;
  15882.         POP  HL           ;
  15883.         POP  BC           ;
  15884.  
  15885.         INC  H            ; Next source line in the display file.
  15886.         INC  D            ; Next destination line in the display file.
  15887.         DJNZ L3AEE        ; Repeat for all lines in the row.
  15888.  
  15889. ;Copy one row of display attributes
  15890.  
  15891.         PUSH AF           ; Save the duration flag.
  15892.         PUSH DE           ; DE=Address of next destination row in the display file.
  15893.  
  15894.         RST  28H          ; HL=Address of next source row in the display file.
  15895.         DEFW CL_ATTR      ; $0E88. DE=Address of corresponding attribute cell.
  15896.         EX   DE,HL        ; HL=Address of corresponding source attribute cell.
  15897.         EX   (SP),HL      ; Store source attribute cell on the stack, and fetch the next destination row in the display file in HL.
  15898.  
  15899.         RST  28H          ; HL=Address of next destination row in the display file.
  15900.         DEFW CL_ATTR      ; $0E88. DE=Address of corresponding destination attribute cell.
  15901.         EX   DE,HL        ; HL=Address of corresponding destination attribute cell.
  15902.         EX   (SP),HL      ; Store destination attribute cell on the stack, and fetch the source attribute cell in HL.
  15903.         POP  DE           ; DE=Destination attribute cell.
  15904.  
  15905.         LD   BC,$0020     ;
  15906.         LDIR              ; Copy one row of the attributes file.
  15907.  
  15908. ;Repeat to shift the next row
  15909.  
  15910.         POP  AF           ; Retrieve the direction flag.
  15911.         POP  BC           ; B=Inverted row number, C=Number of rows left to shift.
  15912.         AND  A            ; Shifting up or down?
  15913.         JR   Z,L3B16      ; Jump if shifting rows up.
  15914.  
  15915.         INC  B            ; Move to the previous row, i.e. the row to copy (note that B is inverted, i.e. 24-row number).
  15916.         JR   L3B17        ; Jump ahead.
  15917.  
  15918. L3B16:  DEC  B            ; Move to the next row, i.e. the row to copy (note that B is inverted, i.e. 24-row number).
  15919.  
  15920. L3B17:  DEC  C            ; Decrement the row counter.
  15921.         LD   H,A          ; H=Direction flag.
  15922.         JR   NZ,L3AD6     ; Jump if back more rows to shift.
  15923.  
  15924.         POP  DE           ; E=Number of editing rows on screen.
  15925.         LD   B,E          ; B=Number of editing rows on screen.
  15926.  
  15927. L3B1D:  POP  HL           ; HL=Address of the Line Edit Buffer row to print (either in the Above-Screen Line Edit Buffer or in the Below-Screen Line Edit Buffer).
  15928.  
  15929. ; --------------------------------------------
  15930. ; Print a Row of the Edit Buffer to the Screen
  15931. ; --------------------------------------------
  15932. ; This routine prints all 32 characters of a row in the edit buffer to the display file.
  15933. ; When shifting all rows up, this routine prints the top entry of the Below-Screen Line Edit Buffer
  15934. ; to the first row of the display file.
  15935. ; When shifting all rows down, this routine prints the bottom entry of the Above-Screen Line Edit Buffer
  15936. ; to the last editing row of the display file.
  15937. ; Entry: B =Row number to print at.
  15938. ;        HL=Address of edit buffer row to print.
  15939.  
  15940. L3B1E:  CALL L3BB8        ; Exchange colour items.
  15941.  
  15942.         EX   DE,HL        ; Transfer address of edit buffer row to DE.
  15943.  
  15944.         LD   A,($5C3C)    ; TVFLAG.
  15945.         PUSH AF           ;
  15946.         LD   HL,$EC0D     ; Editor flags.
  15947.         BIT  6,(HL)       ; Test the editing area flag.
  15948.         RES  0,A          ; Allow leading space.
  15949.         JR   Z,L3B31      ; Jump if editing area is the main screen.
  15950.  
  15951.         SET  0,A          ; Suppress leading space.
  15952.  
  15953. L3B31:  LD   ($5C3C),A    ; TVFLAG.
  15954.  
  15955.         LD   C,$00        ; The first column position of the edit row.
  15956.         CALL L372B        ; Print AT.
  15957.  
  15958.         EX   DE,HL        ; HL=Address of edit buffer row.
  15959.         LD   B,$20        ; 32 columns.
  15960.  
  15961. L3B3C:  LD   A,(HL)       ; Character present in this position?
  15962.         AND  A            ;
  15963.         JR   NZ,L3B42     ; Jump if character found.
  15964.  
  15965.         LD   A,$20        ; Display a space for a null character.
  15966.  
  15967. L3B42:  CP   $90          ; Is it a single character or UDG?
  15968.         JR   NC,L3B55     ; Jump if it is a UDG.
  15969.  
  15970.         RST  28H          ; Print the character.
  15971.         DEFW PRINT_A_1    ; $0010.
  15972.  
  15973. L3B49:  INC  HL           ;
  15974.         DJNZ L3B3C        ; Repeat for all column positions.
  15975.  
  15976.         POP  AF           ; Restore original suppress leading space status.
  15977.         LD   ($5C3C),A    ; TVFLAG.
  15978.  
  15979.         CALL L3BB8        ; Exchange colour items.
  15980.         SCF               ; [Redundant since never subsequently checked]
  15981.         RET               ;
  15982.  
  15983. L3B55:  CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  15984.         RST  10H          ; Print it (need to page in RAM bank 0 to allow access to UDGs).
  15985.         CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  15986.         JR   L3B49        ; Jump back for next character.
  15987.  
  15988. ; ------------------
  15989. ; Clear Display Rows
  15990. ; ------------------
  15991. ; Entry: B=Top row to clear from.
  15992. ;        D=Bottom row to clear to.
  15993.  
  15994. L3B5E:  CALL L3BB8        ; Exchange 48 and 128 editing colour items.
  15995.  
  15996.         LD   A,D          ; Bottom row to clear.
  15997.         SUB  B            ;
  15998.         INC  A            ; A=Number of rows to clear.
  15999.         LD   C,A          ; C=Number of rows to clear.
  16000.         CALL L3B98        ; B=Number of rows to end of screen.
  16001.  
  16002. ;Clear display file row
  16003.  
  16004. L3B68:  PUSH BC           ; B=Row number. C=Row to clear.
  16005.  
  16006.         RST  28H          ;
  16007.         DEFW CL_ADDR      ; $0E9B. Find display file address.
  16008.  
  16009.         LD   C,$08        ; 8 lines in the row.
  16010.  
  16011. L3B6E:  PUSH HL           ; Save start of row address.
  16012.  
  16013.         LD   B,$20        ; 32 columns.
  16014.         XOR  A            ;
  16015.  
  16016. L3B72:  LD   (HL),A       ; Blank the row.
  16017.         INC  HL           ;
  16018.         DJNZ L3B72        ;
  16019.  
  16020.         POP  HL           ; Get start of row address.
  16021.         INC  H            ; Next line.
  16022.         DEC  C            ;
  16023.         JR   NZ,L3B6E     ; Repeat for all rows.
  16024.  
  16025.         LD   B,$20        ; 32 columns.
  16026.         PUSH BC           ;
  16027.         RST  28H          ;
  16028.         DEFW CL_ATTR      ; $0E88. Find attribute address.
  16029.         EX   DE,HL
  16030.         POP  BC           ; BC=32 columns.
  16031.  
  16032. ;Reset display file attributes
  16033.  
  16034.         LD   A,($5C8D)    ; ATTR_P.
  16035.  
  16036. L3B86:  LD   (HL),A       ; Set display file position attribute.
  16037.         INC  HL           ;
  16038.         DJNZ L3B86        ; Repeat for all attributes in the row.
  16039.  
  16040. ;Repeat for next row
  16041.  
  16042.         POP  BC           ; B=Row number. C=Number of rows to clear.
  16043.         DEC  B            ;
  16044.         DEC  C            ;
  16045.         JR   NZ,L3B68     ; Repeat for all rows.
  16046.  
  16047.         CALL L3BB8        ; Exchange 48 and 128 editing colour items.
  16048.         SCF               ; [Redundant since never subsequently checked]
  16049.         RET               ;
  16050.  
  16051. ; --------------------------------------
  16052. ; Find Rows and Columns to End of Screen
  16053. ; --------------------------------------
  16054. ; This routine calculates the number of rows to the end row of the screen and
  16055. ; the number of columns to the end column of the screen. It takes into account
  16056. ; the number of rows above the editing area.
  16057. ; Entry: B=Row number.
  16058. ;        C=Column number.
  16059. ; Exit : B=Number of rows to end row of screen.
  16060. ;        C=Number of columns to the end column of the screen.
  16061.  
  16062. L3B94:  LD   A,$21        ; Reverse column number.
  16063.         SUB  C            ;
  16064.         LD   C,A          ; C=33-C. Columns to end of screen.
  16065.  
  16066. ; --------------------------
  16067. ; Find Rows to End of Screen
  16068. ; --------------------------
  16069. ; This routine calculates the number of rows to the end row of the screen. It
  16070. ; takes into account the number of rows above the editing area.
  16071. ; Entry: B=Row number.
  16072. ; Exit : B=Number of rows to end of screen.
  16073. ;        IX=Address of the cursor settings information.
  16074.  
  16075. L3B98:  LD   A,$18        ; Row 24.
  16076.         SUB  B            ; A=24-B.
  16077.         SUB  (IX+$01)     ; Subtract the number of rows above the editing area.
  16078.         LD   B,A          ; B=Rows to end of screen.
  16079.         RET               ;
  16080.  
  16081. ; ---------------------
  16082. ; Get Attribute Address
  16083. ; ---------------------
  16084. ; Get the address of the attribute byte for the character position (B,C).
  16085. ; Entry: B=Row number.
  16086. ;        C=Column number.
  16087. ; Exit : HL=Address of attribute byte.
  16088.  
  16089. L3BA0:  PUSH BC           ; Save BC.
  16090.  
  16091.         XOR  A            ; A=0.
  16092.         LD   D,B          ;
  16093.         LD   E,A          ; DE=B*256.
  16094.         RR   D            ;
  16095.         RR   E            ;
  16096.         RR   D            ;
  16097.         RR   E            ;
  16098.         RR   D            ;
  16099.         RR   E            ; DE=B*32.
  16100.         LD   HL,$5800     ; Start of attributes file.
  16101.         LD   B,A          ; B=0.
  16102.         ADD  HL,BC        ; Add column offset.
  16103.         ADD  HL,DE        ; Add row offset.
  16104.  
  16105.         POP  BC           ; Restore BC.
  16106.         RET               ;
  16107.  
  16108. ; ---------------------
  16109. ; Exchange Colour Items
  16110. ; ---------------------
  16111. ; Exchange 128 Editor and main colour items.
  16112.  
  16113. L3BB8:  PUSH AF           ; Save registers.
  16114.         PUSH HL           ;
  16115.         PUSH DE           ;
  16116.  
  16117.         LD   HL,($5C8D)   ; ATTR_P, MASK_P. Fetch main colour items.
  16118.         LD   DE,($5C8F)   ; ATTR_T, MASK_T.
  16119.         EXX               ; Store them.
  16120.  
  16121.         LD   HL,($EC0F)   ; Alternate Editor ATTR_P, MASK_P. Fetch alternate Editor colour items.
  16122.         LD   DE,($EC11)   ; Alternate Editor ATTR_T, MASK_T.
  16123.         LD   ($5C8D),HL   ; ATTR_P, MASK_P. Store alternate Editor colour items as main colour items.
  16124.         LD   ($5C8F),DE   ; ATTR_T, MASK_T.
  16125.  
  16126.         EXX               ; Retrieve main colour items ATTR_T and MASK_T.
  16127.         LD   ($EC0F),HL   ; Alternate Editor ATTR_P, MASK_P.
  16128.         LD   ($EC11),DE   ; Alternate Editor ATTR_T, MASK_T. Store alternate Editor colour items as main colour items.
  16129.  
  16130.         LD   HL,$EC13     ; Alternate P_FLAG. Temporary Editor store for P_FLAG.
  16131.         LD   A,($5C91)    ; P_FLAG.
  16132.         LD   D,(HL)       ; Fetch alternate Editor version.
  16133.         LD   (HL),A       ; Store main version in alternate Editor store.
  16134.         LD   A,D          ; A=Alternate Editor version.
  16135.         LD   ($5C91),A    ; P_FLAG. Store it as main version.
  16136.  
  16137.         POP  DE           ; Restore registers.
  16138.         POP  HL           ;
  16139.         POP  AF           ;
  16140.         RET               ;
  16141.  
  16142.  
  16143. ; ===================
  16144. ; TAPE TESTER ROUTINE
  16145. ; ===================
  16146.  
  16147. ; The Tape Tester routine displays a bright blue bar completely across row 8,
  16148. ; with 6 black markers evenly distributed above it on row 7 (columns 1, 7, 13,
  16149. ; 19, 25 and 31). The tape port is read 2048 times and the number of highs/lows
  16150. ; counted. A cyan marker is placed on the blue bar to indicate the ratio of high
  16151. ; and lows. The higher the tape player volume, the further to the right the cyan
  16152. ; marker will appear. The Tape Tester can be exited by pressing BREAK (though only
  16153. ; SPACE checked), ENTER or EDIT (though only key 1 checked). Note that no attempt
  16154. ; to read the keypad is made and so it cannot be used to exit the Tape Tester.
  16155. ;
  16156. ; Although the Sinclair manual suggests setting the tape player volume such that
  16157. ; the cyan marker appears as far to the right of the screen as possible, this does
  16158. ; not guarantee the best possible loading volume. Instead, it appears better to
  16159. ; aim for the cyan marker appearing somewhere near the mid point of the blue bar.
  16160. ;
  16161. ; There are bugs in the Tape Tester code that can cause the cyan level marker to
  16162. ; spill over onto the first column of the row below. This is most likely to occur
  16163. ; when the Tape Tester is selected whilst a tape is already playing. The routine
  16164. ; initially reads the state of the tape input and assumes this represents silence.
  16165. ; It then monitors the tape input for 2048 samples and counts how many high levels
  16166. ; appear on the tape input. Should this initial reading of the tape port not
  16167. ; correspond to silence then when a true period of silence does occur it will be
  16168. ; interpreted as continuous noise and hence a maximum sample count. It is a maximum
  16169. ; sample count that leads to the cyan marker spilling onto the next row.
  16170.  
  16171. L3BE9:  CALL L3C56        ; Signal no key press.
  16172. L3BEC           LD HL,0X5C3C
  16173.                 RES 0,(HL)
  16174.                 SET 6,(HL)
  16175.                 LD HL,0XEC0E
  16176.                 LD (HL),0XFF
  16177.                 CALL L1F20
  16178.                 RST 0X28
  16179.                 DW 0X16B0
  16180.                 LD HL,(0X5C59)
  16181.                 LD BC,0X0A
  16182.                 RST 0X28
  16183.                 DW 0X1655
  16184.                 LD HL,L3C16
  16185.                 LD DE,(0X5C59)
  16186.                 LD BC,0X0A
  16187.                 LDIR
  16188.                 JP L1B11
  16189.  
  16190. L3C16           DB 0XF9,0XC0,0XB0,0X22,"15616",0X22
  16191.                
  16192. ;        DI                ; Turn interrupts off since need accurate timing.
  16193. ;        IN   A,($FE)      ; Read tape input port (bit 5).
  16194. ;        AND  $40          ; Set the zero flag based on the state of the input line.
  16195.  
  16196. ; [*BUG* - Ideally the input line should be read indefinitely and the routine only continue
  16197. ;          once the level has remained the same for a large number of consecutive samples.
  16198. ;          The chances of the bug occurring can be minimised by replacing the port read
  16199. ;          instructions above with the following code. Credit: Paul Farrow.
  16200. ;
  16201. ;       LD   BC,$7FFE     ; Tape input port and keyboard row B to SPACE.
  16202. ;       IN   A,(C)        ; Read the tape input port.
  16203. ;       AND  $40          ; Keep only the state of the input line.
  16204. ;
  16205. ;BF23_START:
  16206. ;       LD   E,A          ; Save the initial state of the tape input line.
  16207. ;       LD   HL,$1000     ; Number of samples to monitor for changes in input line state.
  16208. ;
  16209. ;BF23_LOOP:
  16210. ;       IN   A,(C)        ; Read the keyboard and tape input port.
  16211. ;       BIT  0,A          ; Test for SPACE (i.e. BREAK).
  16212. ;       JP   Z,$3C56 (ROM 0) ; Exit Tape Tester if SPACE/BREAK pressed.
  16213. ;
  16214. ;       AND  $40          ; Keep only the state of the input line.
  16215. ;       CP   E            ; Has the line input state changed?
  16216. ;       JR   NZ,BF23_START ; Jump if so to restart the sampling procedure.
  16217. ;
  16218. ;       DEC  HL           ; Decrement the number of samples left to test.
  16219. ;       LD   A,H          ;
  16220. ;       OR   L            ;
  16221. ;       JR   NZ,BF23_LOOP ; Jump if more samples to test.
  16222. ;
  16223. ;       LD   A,E          ; Fetch the input line state.]
  16224.  
  16225. ;       EX   AF,AF'       ; Save initial state of the tape input.
  16226.  
  16227. ;Print 6 black attribute square across row 7, at 6 column intervals.
  16228.  
  16229. ;        LD   HL,$58E1     ; Screen attribute position (7,1).
  16230. ;        LD   DE,$0006     ; DE=column spacing of the black squares.
  16231. ;        LD   B,E          ; Count 6 black squares.
  16232. ;        LD   A,D          ; A=Flash 0, Bright 0, Paper black, Ink black.
  16233.  
  16234. ;L3BFA:  LD   (HL),A       ; Set a black square.
  16235. ;        ADD  HL,DE        ; Move to next column position.
  16236. ;        DJNZ L3BFA        ; Repeat for all 6 black squares.
  16237.  
  16238. ;Now enter the main loop checking for the tape input signal
  16239.  
  16240. ;L3BFE:  LD   HL,$0000     ; Count of the number of high signals read from the tape port.
  16241. ;        LD   DE,$0800     ; Read 2048 tape samples. [*BUG* - This should be $07C0 so that the maximum sample count corresponds
  16242.                           ; to column 31 and not column 32, and hence a spill over onto the following row. Credit: Paul Farrow]
  16243.  
  16244. ;L3C04:  LD   BC,$BFFE     ; Read keyboard row H to ENTER.
  16245. ;        IN   A,(C)        ;
  16246. ;        BIT  0,A          ; Test for ENTER.
  16247. ;        JR   Z,L3C56      ; Jump to exit Tape Tester if ENTER pressed.
  16248.  
  16249. ;        LD   B,$7F        ; Read keyboard row B to SPACE.
  16250. ;        IN   A,(C)        ;
  16251. ;        BIT  0,A          ; Test for SPACE (i.e. BREAK).
  16252. ;        JR   Z,L3C56      ; Jump to exit Tape Tester if SPACE/BREAK pressed.
  16253.  
  16254. ;        LD   B,$F7        ; Read keyboard row 1 to 5.
  16255. ;        IN   A,(C)        ;
  16256. ;        BIT  0,A          ; Test for 1 (i.e. EDIT).
  16257. ;        JR   Z,L3C56      ; Jump to exit Tape Tester if 1/EDIT pressed.
  16258.  
  16259. ;L3C1D:  DEC  DE           ; Decrement sample counter.
  16260. ;        LD   A,D          ;
  16261. ;        OR   E            ;
  16262.         JR   Z,L3C2B      ; Zero flag set if all samples read.
  16263.  
  16264.         IN   A,($FE)      ;
  16265.         AND  $40          ; Read the tape port.
  16266.         JR   Z,0X3C1D;L3C1D      ; If low then continue with next sample.
  16267.  
  16268.         INC  HL           ; Tape port was high so increment high signal counter.
  16269.         JR   0X3C1D;L3C1D        ; Continue with next sample.
  16270.  
  16271. L3C2B:  RL   L            ; HL could hold up to $0800.
  16272.         RL   H            ;
  16273.         RL   L            ;
  16274.         RL   H            ; HL=HL*4. HL could now hold $0000 to $2000.
  16275.  
  16276.         EX   AF,AF'       ; Retrieve initial state of the tape port.
  16277.        JR   Z,L3C3D      ; This dictates how to interpret the number of high signals counted.
  16278.  
  16279. ;If the initial tape port level was high then invert the count in H, i.e. determine number of low signals.
  16280. ;Note that if H holds $00 then the following code will result in a column position for the cyan marker of 32,
  16281. ;and hence it will appear in the first column of the row below.
  16282.  
  16283.        EX   AF,AF'       ; Re-store initial state of the tape port.
  16284.         LD   A,$20        ; A=Column 32.
  16285.         SUB  H            ; A=32-H. H could hold up to $20 so A could be $00.
  16286.         LD   L,A          ; L=32-H. L holds a value between $00 to $20.
  16287.         JR   L3C3F        ;
  16288.  
  16289. ;If the initial tape port level was low then H holds the number of high signals found.
  16290.  
  16291. L3C3D:  EX   AF,AF'       ; Retrieve initial state of the tape port.
  16292.        LD   L,H          ; L holds a value between $00 to $20.
  16293.  
  16294. ;L holds the column at which to show the cyan marker.
  16295.  
  16296. L3C3F:  XOR  A            ;
  16297.        LD   H,A          ; Set H to $00.
  16298.        LD   DE,$591F     ; Attribute position (8,31).
  16299.        LD   B,$20        ; Print a blue bar 32 columns wide underneath the 6 black squares.
  16300.                          ; It is drawn here so that it erases the previous cyan marker.
  16301.        LD   A,$48        ; Flash 0, Bright 1, Paper blue, Ink black = Bright blue.
  16302.  
  16303.        EI                ;
  16304.        HALT              ; Wait for the screen to be redrawn.
  16305.        DI                ;
  16306.  
  16307. L3C4B:  LD   (DE),A       ; Set each blue square in the attributes file.
  16308.        DEC  DE           ; Move to previous attribute position.
  16309.        DJNZ L3C4B        ; Repeat for all 32 columns.
  16310.  
  16311.        INC  DE           ; Move back to first attribute column.
  16312.        ADD  HL,DE        ; Determine column to show cyan marker at.
  16313.        LD   A,$68        ; Flash 0, Bright 1, paper cyan, Ink 0 = Bright cyan.
  16314.        LD   (HL),A       ; Show the cyan marker.
  16315.  
  16316.        JR   0X3BFE;L3BFE        ; Go back and count a new set of samples.
  16317.  
  16318. ;Half second delay then clear key press flag. This is called upon entry and exit of the Tape Tester.
  16319.  
  16320. L3C56:  EI                ; Re-enable interrupts.
  16321.        LD   B,$19        ; Count 25 interrupts.
  16322.  
  16323. L3C59:  HALT              ; Wait for half a second.
  16324.        DJNZ L3C59        ;
  16325.  
  16326.        LD   HL,$5C3B     ; FLAGS.
  16327.        RES  5,(HL)       ; Signal no key press
  16328.        SCF               ; Setting the carry flag here serves no purpose.
  16329.        RET               ;
  16330.  
  16331.  
  16332. ; ========================
  16333. ; EDITOR ROUTINES - PART 5
  16334. ; ========================
  16335.  
  16336. ; -------------------
  16337. ; Tokenize BASIC Line
  16338. ; -------------------
  16339. ; This routine serves two purposes. The first is to tokenize a typed BASIC line into a tokenized version. The second is when a syntax error is subsequently
  16340. ; detected within the tokenized line, and it is then used to search for the position within the typed line where the error marker should be shown.
  16341. ;
  16342. ; This routine parses the BASIC line entered by the user and generates a tokenized version in the workspace area as pointed to by system variable E_LINE.
  16343. ; It suffers from a number of bugs related to the handling of '>' and '<' characters. The keywords '<>', '>=' and '<=' are the only keywords that
  16344. ; do not commence with letters and the routine traps these in a different manner to all other keywords. If a '<' or '>' is encountered then it is not
  16345. ; immediately copied to the BASIC line workspace since the subsequent character must be examined as it could be a '>' or '=' character and therefore
  16346. ; might form the keywords '<>', '>=' or '<='. A problem occurs if the subsequent character is a letter since the parser now expects the start of a
  16347. ; possible keyword. It should at this point insert the '<' or '>' into the BASIC line workspace but neglects to do this. It is only when the next non-letter
  16348. ; character is encountered that the '<' or '>' gets inserted, but this is now after the previously found string has been inserted. This results the following
  16349. ; types of errors:
  16350. ;
  16351. ; 'PRINT varA>varB' is seen by the parser as 'PRINT varAvarB>' and hence a syntax error occurs.
  16352. ; 'PRINT varA>varB1' is seen by the parser as 'PRINT varAvarB>1' and hence is accepted as a valid statement.
  16353. ;
  16354. ; A work-around is to follow the '<' or '>' with a space since this forces the '<' or '>' to be inserted before the next potential keyword is examined.
  16355. ;
  16356. ; A consequence of shifting a '<' or '>' is that a line such as 'PRINT a$>b$' is seen by the parser as 'PRINT a$b$>' and so it throws a syntax error.
  16357. ; The parser saved the '>' character for consideration when the next character was examined to see if it was part of the keywords '<>', '>=' or '<=',
  16358. ; but fails to discard it if the end of the statement is immediately encountered. Modifying the statement to a form that will be accepted will still cause
  16359. ; a syntax error since the parser mistakenly believes the '>' character applies to this statement.
  16360. ;
  16361. ; The parser identifies string literals contained within quotes and will not tokenize any keywords that appear inside them, except for the keywords "<>",
  16362. ; "<=" and ">=" which it neglects to check for. Keywords are also not tokenized following a REM statement, except again for "<>", "<=" and ">=", until the
  16363. ; end of the line is reached. This differs slightly to 48K BASIC mode. In 48K BASIC mode, typing a ':' following a REM statement will cause a change from
  16364. ; 'L' cursor mode to 'K' cursor mode and hence the next key press results in a keyword token being inserted. In 128K BASIC mode, typing a ':' will not change
  16365. ; to 'K' cursor mode and hence the next key press will just be the letter, number or symbol. This does not affect the running of the program since 48K BASIC
  16366. ; mode will ignore all characters after a REM command until the end of the line. However, creating such a REM statement in 128K BASIC mode that appears similar
  16367. ; to one created in 48K BASIC mode will result in more memory being used since the 'keyword' must be spelled out letter by letter.
  16368. ;
  16369. ; When being used to locate the error marker position, the same process is performed as when tokenizing but no characters are actually inserted into the workspace
  16370. ; (they are still there from when the line was originally tokenized). Instead, a check is made after each character is processed to see if the error marker address
  16371. ; held in system variable X_PTR has been reached. If it does match then the routine returns with BC holding the character position where the error marker should
  16372. ; be displayed at.
  16373.  
  16374. ;Entry point - A syntax error was detected so the error marker must be located
  16375.  
  16376. L3C63:  LD   A,$01        ; Signal to locate the error marker.
  16377.        JR   L3C69        ; Jump forward.
  16378.  
  16379. ;Entry point - Tokenize the BASIC line
  16380.  
  16381. L3C67:  LD   A,$00        ; Signal to tokenize the BASIC line. [Could have saved 1 byte by using XOR A]
  16382.  
  16383. L3C69:  LD   ($FD8A),A    ; Store the 'locate error marker' flag.
  16384.  
  16385.        LD   HL,$0000     ;
  16386.        LD   ($FD85),HL   ; Reset count of the number of characters in the typed BASIC line being inserted.
  16387.        LD   ($FD87),HL   ; Reset count of the number of characters in the tokenized version of the BASIC line being inserted.
  16388.        ADD  HL,SP        ;
  16389.        LD   ($FD8B),HL   ; Store the stack pointer.
  16390.  
  16391.        CALL L34EA        ; Clear BASIC line construction pointers (address of next character in the Keyword Construction Buffer and the
  16392.                          ; address of the next character in the BASIC line within the program area being de-tokenized).
  16393.  
  16394.        LD   A,$00        ; [Could have saved 1 byte by using XOR A]
  16395.        LD   ($FD84),A    ; Signal last character was not a keyword and was not a space.
  16396.                          ; [*BUG* - Should reset the '<' and '>' store at $FD89 to $00 here. Attempting to insert a BASIC line
  16397.                          ; such as 'PRINT VAL a$>b' will fail since the parser does not like '>' immediately after 'a$', due to the bug at $3CB8 (ROM 0).
  16398.                          ; The parser stores the '>' in $FD89 since it will check the following character in case it should replace the two
  16399.                          ; characters with the token '<>', '>=' or '<='. After the parser throws the syntax error, it does not clear
  16400.                          ; $FD89 and so even if the line is modified such that it should be accepted, e.g. 'PRINT VAL a$=b', the parser
  16401.                          ; believes the line is really '>PRINT VAL n$=b' and so throws another syntax error. Since a letter follows the '>',
  16402.                          ; the contents of $FD89 will get cleared and hence a second attempt to insert the line will now succeed. Credit: Paul Farrow]
  16403.  
  16404.        LD   HL,$FD74     ; HL=Start address of the Keyword Conversion Buffer.
  16405.        LD   ($FD7D),HL   ; Store as the next available location.
  16406.  
  16407.        CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  16408.        RST  28H          ;
  16409.        DEFW SET_MIN      ; $16B0. Clear the editing areas.
  16410.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  16411.  
  16412.        LD   A,$00        ; [Could have saved 1 byte by using XOR A, or 2 bytes by clearing this above]
  16413.        LD   ($FD81),A    ; Clear Keyword Conversion Buffer flags - not within REM, not with Quotes, no characters in the buffer.
  16414.  
  16415.        LD   HL,($5C59)   ; E_LINE.
  16416.        LD   ($FD82),HL   ; Store the address of the workspace for the tokenized BASIC line.
  16417.  
  16418.        LD   HL,$0000     ; [Could have saved 1 byte by using LD H,A followed by LD L,A]
  16419.        LD   ($FD7F),HL   ; Signal no space character between words in the Keyword Conversion Buffer.
  16420.  
  16421. ;Enter a loop to fetch each character from the BASIC line and insert it into the workspace, tokenizing along the way
  16422.  
  16423. L3CA1:  LD   HL,($FD85)   ;
  16424.        INC  HL           ; Increment count of the number of characters in the typed BASIC line.
  16425.        LD   ($FD85),HL   ;
  16426.  
  16427.        CALL L3D9D        ; Fetch the next character from BASIC line being inserted, return in B.
  16428.        LD   C,A          ; Save the character status value.
  16429.  
  16430. ;C=$01 if not a space, not a letter, not a '#' and not a '$'.
  16431. ;  $02 if a '#' or '$'.
  16432. ;  $03 if a space.
  16433. ;  $06 if a letter.
  16434. ;B=Character fetched.
  16435.  
  16436.        LD   A,($FD81)    ; Have any Keyword Conversion Buffer flags been set?
  16437.        CP   $00          ; Has anything be put into the buffer yet?
  16438.        JR   NZ,L3CF4     ; Jump if so.
  16439.  
  16440. ;The first character to potentially put into the Keyword Conversion Buffer
  16441.  
  16442. L3CB3:  LD   A,C          ; Retrieve the character status value.
  16443.        AND  $04          ; Is the character a letter?
  16444.        JR   Z,L3CED      ; Jump if not.
  16445.  
  16446. ;Insert the character
  16447.  
  16448. L3CB8:  
  16449.  
  16450. ; [*BUG* - At this point a '>' or '<' that was previously stored should be inserted into the BASIC line workspace. However, the routine proceeds with the new potential
  16451. ;          keyword and this is entered into the BASIC line workspace next. The '>' or '<' will only be inserted when the next non-letter character is encountered. This causes
  16452. ;          an expression such as 'a>b1' to be translated into 'ab>1'. Credit: Ian Collier (+3), Paul Farrow (128)]
  16453.  
  16454. ; [The bug can be fixed by testing if whether a '<' or '>' character is stored. Credit: Paul Farrow.
  16455. ;
  16456. ;       LD   A,($FD89)    ;
  16457. ;       AND  A            ; Was the last character a '>' or '<'?
  16458. ;       JR   Z,INSERT     ; Jump if not.
  16459. ;
  16460. ;       PUSH BC           ; Save the new character.
  16461. ;       LD   B,A          ;
  16462. ;       CALL $3E64 (ROM 0) ; Insert the '>' or '<' into the BASIC line workspace.
  16463. ;       POP  BC           ; Retrieve the new character.
  16464. ;       XOR  A            ;
  16465. ;       LD   ($FD89),A    ; Clear the '>' or '<'.
  16466. ;
  16467. ;INSERT:                  ; ]
  16468.  
  16469.        CALL L3DE9        ; Insert the character into the Keyword Conversion Buffer.
  16470.        JR   NC,L3CC4     ; Jump if no more room within the buffer, hence string is too large to be a token.
  16471.  
  16472.        LD   A,$01        ; Signal Keyword Conversion Buffer contains characters.
  16473.        LD   ($FD81),A    ;
  16474.        JR   L3CA1        ; Jump back to fetch and process the next character.
  16475.  
  16476. ;No room to insert the character into the Keyword Conversion Buffer hence string is too large to be a valid token
  16477.  
  16478. L3CC4:  LD   HL,($FD7F)   ; Fetch the address of the space character between words within the Keyword Conversion Buffer.
  16479.        LD   A,L          ;
  16480.        OR   H            ; Is there an address set?
  16481.        JP   NZ,L3D1E     ; Jump if so to copy the first word into the BASIC line workspace and the move the second word to the
  16482.                          ; start of the Keyword Conversion Buffer. Further characters can then be appended and the contents
  16483.                          ; re-evaluated in case a complete keyword is then available.
  16484.  
  16485. ;Copy the Keyword Conversion Buffer into the BASIC line workspace
  16486.  
  16487. L3CCC:  PUSH BC           ; Save the character to insert.
  16488.        CALL L3DCD        ; Copy Keyword Conversion Buffer contents into BASIC line workspace.
  16489.        POP  BC           ; Retrieve the character to insert.
  16490.  
  16491.        LD   A,$00        ;
  16492.        LD   ($FD81),A    ; Signal the Keyword Conversion Buffer is empty.
  16493.  
  16494. ;C=$01 if not a space, not a letter, not a '#' and not a '$'.
  16495. ;  $02 if a '#' or '$'.
  16496. ;  $03 if a space.
  16497. ;  $06 if a letter.
  16498. ;B=Character fetched.
  16499.  
  16500. L3CD6:  LD   A,C          ; Retrieve the character status value.
  16501.        AND  $01          ; Is it a space, or not a letter and not a '#' and not a '$'?
  16502.        JR   NZ,L3CB3     ; Jump back if so to insert the character either into the Keyword Conversion Buffer or the BASIC line workspace.
  16503.  
  16504. ;The string was too long to be a keyword and was followed by a space, a '#' or a '$'. Enter a loop to insert each character of the
  16505. ;string into the BASIC line workspace.
  16506.  
  16507.        LD   A,B          ; Retrieve the character to insert.
  16508.        CALL L3E16        ; Insert character into BASIC line workspace.
  16509.        RET  NC           ; Return if tokenizing is complete.
  16510.  
  16511.        LD   HL,($FD85)   ;
  16512.        INC  HL           ; Increment the count of the number of characters in the typed BASIC line being inserted.
  16513.        LD   ($FD85),HL   ;
  16514.  
  16515.        CALL L3D9D        ; Fetch the next character from BASIC line being inserted.
  16516.        LD   C,A          ; Save the flags.
  16517.  
  16518.        JR   L3CD6        ; Jump back to insert the character of the non-keyword string into the BASIC line workspace.
  16519.  
  16520. ;The character is not a letter so insert directly into the BASIC line workspace
  16521.  
  16522. L3CED:  LD   A,B          ; Retrieve the character to insert.
  16523.        CALL L3E16        ; Insert character into BASIC line workspace, tokenizing '<>', '<=' and '>=' if encountered.
  16524.        RET  NC           ; Return if tokenizing is complete.
  16525.  
  16526.        JR   L3CA1        ; Jump back to fetch and process the next character.
  16527.  
  16528. ;Keyword Conversion buffer flags are set - either the buffer already contains characters, or within quotes or within a REM statement
  16529.  
  16530. L3CF4:  CP   $01          ; Is the Keyword Conversion Buffer empty or the contents marked as being within quotes or within a REM?
  16531.        JR   NZ,L3CED     ; Jump back if so to insert the character since this is either the first character of a new word or is within quotes or within a REM.
  16532.  
  16533. ;C=$01 if not a space, not a letter, not a '#' and not a '$'.
  16534. ;  $02 if a '#' or '$'.
  16535. ;  $03 if a space.
  16536. ;  $06 if a letter.
  16537.  
  16538.        LD   A,C          ; Retrieve the character status value.
  16539.        AND  $01          ; Is it a letter or a '#' or a '$'?
  16540.        JR   Z,L3CB8      ; Jump if so to simply insert the character.
  16541.  
  16542. ;The character is a space, or is not a letter and not a '#' and not a '$', i.e. the last character was the end of a potential keyword
  16543.  
  16544.        PUSH BC           ; Save the next character to insert and the character status value.
  16545.  
  16546. L3CFE:  CALL L3F7E        ; Attempt to identify the string in Keyword Conversion Buffer.
  16547.        POP  BC           ; Retrieve the next character to insert and the character status value.
  16548.        JR   C,L3D7D      ; Jump if keyword identified.
  16549.  
  16550. ;The string in the Keyword Conversion Buffer was not identified as a keyword
  16551.  
  16552.        LD   HL,($FD7F)   ; Fetch the address of the space character between words within the Keyword Conversion Buffer.
  16553.        LD   A,H          ;
  16554.        OR   L            ; Is there an address set, i.e. a space between words?
  16555.        JR   NZ,L3D1E     ; Jump if there is a space character.
  16556.  
  16557.        LD   A,C          ; Retrieve the character status value.
  16558.        AND  $02          ; Is it a space?
  16559.        JR   Z,L3CCC      ; Jump if not to copy Keyword Conversion Buffer into the workspace since it is not a keyword.
  16560.  
  16561. ;Character is a space. Allow this as the keyword could be DEF FN, GO TO, GO SUB, etc.
  16562.  
  16563.        CALL L3DE9        ; Insert the character into the Keyword Conversion Buffer.
  16564.        JR   NC,L3CC4     ; Jump back if no room to insert the character, i.e. not a keyword since too large.
  16565.  
  16566.        LD   HL,($FD7D)   ; Fetch the next location address.
  16567.        DEC  HL           ; Point back to the last character.
  16568.        LD   ($FD7F),HL   ; Store as the address of the space character. This is used for double keywords such as DEF FN.
  16569.        JR   L3CA1        ; Jump back to fetch and process the next character.
  16570.  
  16571. ;The string in the Keyword Conversion Buffer contains two words separated by a space that do not form a
  16572. ;valid double keyword (such as DEF FN, GO SUB, GO TO, etc).
  16573. ;For a BASIC line such as 'IF FLAG THEN' the Keyword Conversion Buffer holds the characters 'FLAG THEN'.
  16574. ;The 'FLAG' characters get moved to the workspace and the 'THEN' characters are shifted to the start of the
  16575. ;Keyword Conversion Buffer before being re-evaluated to see if they form a keyword.
  16576.  
  16577. L3D1E:  PUSH BC           ; Save the character to insert and the character status value.
  16578.  
  16579.        LD   HL,$FD74     ; Point to the start address of the Keyword Conversion Buffer.
  16580.        LD   DE,($FD7F)   ; Fetch the address of the space character between words within the Keyword Conversion Buffer.
  16581.        LD   A,D          ;
  16582.        CP   H            ; Is the space possibly at the start of the buffer?
  16583.        JR   NZ,L3D2F     ; Jump if not.
  16584.  
  16585.        LD   A,E          ;
  16586.        CP   L            ; Is the space at the start of the buffer?
  16587.        JR   NZ,L3D2F     ; Jump if not.
  16588.  
  16589.        INC  DE           ; Point to the next location within the buffer, counter-acting the following decrement.
  16590.  
  16591. L3D2F:  DEC  DE           ; Point to the previous location within the buffer.
  16592.        JR   L3D33        ; Jump ahead to copy all characters to the BASIC line workspace.
  16593.  
  16594. ;Copy all characters from the Keyword Conversion Buffer prior to the space into the BASIC line workspace
  16595.  
  16596. L3D32:  INC  HL           ; Point to the next location within the Keyword Conversion Buffer.
  16597.  
  16598. L3D33:  LD   A,(HL)       ; Fetch a character from the Keyword Conversion Buffer.
  16599.        AND  $7F          ; Mask off the terminator bit.
  16600.        PUSH HL           ; HL=Location within Keyword Conversion Buffer.
  16601.        PUSH DE           ; DE=Location of last character within the Keyword conversion Buffer.
  16602.        CALL L3E16        ; Insert character into BASIC line workspace, including a stored '<' or '>' character.
  16603.        POP  DE           ;
  16604.        POP  HL           ;
  16605.  
  16606.        LD   A,H          ;
  16607.        CP   D            ; Possibly reached the character prior to the space?
  16608.        JR   NZ,L3D32     ; Jump back if not to copy the next character.
  16609.  
  16610.        LD   A,L          ;
  16611.        CP   E            ; Reached the character prior to the space?
  16612.        JR   NZ,L3D32     ; Jump back if not to copy the next character.
  16613.  
  16614. ;Now proceed to handle the next word
  16615.  
  16616.        LD   DE,($FD7F)   ; DE=Address of the space character between words.
  16617.        LD   HL,$FD74     ;
  16618.        LD   ($FD7F),HL   ; Set the address of the space character to be the start of the buffer.
  16619.  
  16620.        LD   BC,($FD7D)   ; BC=Next location within the Keyword Conversion Buffer.
  16621.        DEC  BC           ; Point to the last used location.
  16622.  
  16623.        LD   A,D          ;
  16624.        CP   H            ; Is the space possibly at the start of the buffer?
  16625.        JR   NZ,L3D70     ; Jump if not.
  16626.  
  16627.        LD   A,E          ;
  16628.        CP   L            ; Is the space at the start of the buffer?
  16629.        JR   NZ,L3D70     ; Jump if not.
  16630.  
  16631. ;The space character is at the start of the Keyword Conversion Buffer
  16632.  
  16633.        INC  DE           ; DE=Address after the space character within the Keyword Conversion Buffer.
  16634.        PUSH HL           ; HL=Start address of the Keyword Conversion Buffer.
  16635.        LD   HL,$0000     ;
  16636.        LD   ($FD7F),HL   ; Signal no space character between words.
  16637.        POP  HL           ; HL=Start address of the Keyword Conversion Buffer.
  16638.  
  16639.        LD   A,B          ;
  16640.        CP   H            ; Is the space possibly the last character in the buffer?
  16641.        JR   NZ,L3D70     ; Jump if not.
  16642.  
  16643.        LD   A,C          ;
  16644.        CP   L            ; Is the space the last character in the buffer?
  16645.        JR   NZ,L3D70     ; Jump if not.
  16646.  
  16647.        POP  BC           ; Retrieve the character to insert and the character status value.
  16648.        JR   L3D8F        ; Jump ahead to continue.
  16649.  
  16650. ;The space is not at the start of the Keyword Conversion Buffer, i.e. the buffer contains another word after the space.
  16651. ;The first word has already been copied to the BASIC line workspace so now copy the second word to the start of the Keyword Conversion Buffer
  16652. ;and then see if it is a valid keyword. [It is not recommended to name a variable as per a keyword since statements such as 'PRINT then' will
  16653. ;fail the syntax check since the variable 'then' is interpreted as the keyword 'THEN' and so the statement is seen as 'PRINT THEN', which in
  16654. ;this case is invalid.]
  16655.  
  16656. ;HL points to the start of the Keyword Conversion Buffer.
  16657. ;DE points to the space between the two words.
  16658.  
  16659. L3D70:  LD   A,(DE)       ; Fetch a character from the second word.
  16660.        LD   (HL),A       ; Store it at the beginning of the buffer.
  16661.        INC  HL           ;
  16662.        INC  DE           ;
  16663.        AND  $80          ; Reached the last character in the buffer, i.e. the terminator bit set?
  16664.        JR   Z,L3D70      ; Jump if not to copy the next character.
  16665.  
  16666.        LD   ($FD7D),HL   ; Store the new address of the next free location.
  16667.        JR   L3CFE        ; Jump back to attempt identification of the 'second' word as a keyword.
  16668.  
  16669. ;The string in the Keyword Conversion Buffer was identified as a keyword, so insert the token character code of the
  16670. ;keyword into the BASIC line workspace.
  16671. ;A=Character code of identified token.
  16672.  
  16673. L3D7D:  PUSH BC           ; Save the next character to insert and the character status value.
  16674.        CALL L3E16        ; Insert character held in A into BASIC line workspace.
  16675.        POP  BC           ; Retrieve the next character to insert and the character status value.
  16676.  
  16677. ;The token has been inserted into the BASIC line workspace so reset the Keyword Conversion Buffer
  16678.  
  16679.        LD   HL,$0000     ;
  16680.        LD   ($FD7F),HL   ; Indicate no space character between words in the Keyword Conversion Buffer.
  16681.  
  16682.        LD   A,($FD81)    ; Fetch the flag bits.
  16683.        CP   $04          ; Within a REM statement?
  16684.        JR   Z,L3D94      ; Jump if so to retain the 'within a REM' flag bit.
  16685.  
  16686. L3D8F:  LD   A,$00        ;
  16687.        LD   ($FD81),A    ; Signal no characters within the Keyword Conversion Buffer.
  16688.  
  16689. L3D94:  LD   HL,$FD74     ; Start address of the Keyword Conversion Buffer.
  16690.        LD   ($FD7D),HL   ; Store this as the next location within the buffer.
  16691.        JP   L3CB3        ; Jump back to insert the next character either into the Keyword Conversion Buffer or the BASIC line workspace.
  16692.  
  16693. ; -------------------------------------------------------------------
  16694. ; Fetch Next Character and Character Status from BASIC Line to Insert
  16695. ; -------------------------------------------------------------------
  16696. ; Fetch the next character from the BASIC line being inserted and check whether a letter, a space, a '#' or a '$'.
  16697. ; Exit: B=Character.
  16698. ;       A=$01 if not a space, not a letter, not a '#' and not a '$'.
  16699. ;         $02 if a '#' or '$'.
  16700. ;         $03 if a space.
  16701. ;         $06 if a letter.
  16702.  
  16703. L3D9D:  CALL L2D54        ; Fetch the next character from the BASIC line being inserted.
  16704.        LD   B,A          ; Save the character.
  16705.        CP   '?'          ; $3F. Is it below '?' (the error marker)?
  16706.        JR   C,L3DAF      ; Jump if so.
  16707.  
  16708.        OR   $20          ; Make lowercase.
  16709.        CALL L3DC6        ; Is it a letter?
  16710.        JR   C,L3DC3      ; Jump if so.
  16711.  
  16712. L3DAC:  LD   A,$01        ; Indicate not space, not letter, not '#' and not '$'.
  16713.        RET               ;
  16714.  
  16715. L3DAF:  CP   $20          ; Is it a space?
  16716.        JR   Z,L3DC0      ; Jump if so.
  16717.  
  16718.        CP   '#'          ; $23. Is it '#'?
  16719.        JR   Z,L3DBD      ; Jump if so.
  16720.  
  16721.        JR   C,L3DAC      ; Jump if below '#'.
  16722.  
  16723.        CP   '$'          ; $24. Is it '$'?
  16724.        JR   NZ,L3DAC     ; Jump if not.
  16725.  
  16726. L3DBD:  LD   A,$02        ; Indicate a '#' or '$'.
  16727.        RET               ;
  16728.  
  16729. L3DC0:  LD   A,$03        ; Indicate a space.
  16730.        RET               ;
  16731.  
  16732. L3DC3:  LD   A,$06        ; Indicate a letter.
  16733.        RET               ;
  16734.  
  16735. ; --------------------
  16736. ; Is Lowercase Letter?
  16737. ; --------------------
  16738. ; Entry: A=Character code.
  16739. ; Exit : Carry flag set is a lowercase letter.
  16740.  
  16741. L3DC6:  CP   $7B          ; Is the character above 'z'?
  16742.        RET  NC           ; Return with carry flag reset if above 'z'.
  16743.  
  16744.        CP   $61          ; Is the character below 'a'?
  16745.        CCF               ; Return with carry flag reset if below 'a'.
  16746.        RET               ;
  16747.  
  16748. ; -----------------------------------------------------------------
  16749. ; Copy Keyword Conversion Buffer Contents into BASIC Line Workspace
  16750. ; -----------------------------------------------------------------
  16751.  
  16752. L3DCD:
  16753.  
  16754. ; [To fix the error marker bug at $3EFB (ROM 0), the code below up until the instruction at $3DDA (ROM 0) should have been as follows]
  16755. ;
  16756. ;       LD   HL,$FD74     ; Start address of the Keyword Conversion Buffer.
  16757. ;       CALL $3DDA (ROM 0) ; Copy all characters into the BASIC line workspace.
  16758. ;       LD   HL,$FD74     ; Start address of the Keyword Conversion Buffer.
  16759. ;       LD   ($FD7D),HL   ; Store the next available location.
  16760. ;       SUB  A            ; A=0.
  16761. ;       LD   ($FD7F),A    ;
  16762. ;       LD   ($FD80),A    ; Signal no space character between words in the Keyword Conversion Buffer.
  16763. ;       RET
  16764.  
  16765.        LD   HL,$FD74     ; Start address of the Keyword Conversion Buffer.
  16766.        LD   ($FD7D),HL   ; Store the next available location.
  16767.        SUB  A            ; A=0.
  16768.        LD   ($FD7F),A    ;
  16769.        LD   ($FD80),A    ; Signal no space character between words in the Keyword Conversion Buffer.
  16770.  
  16771. L3DDA:  LD   A,(HL)       ; Fetch a character from the buffer.
  16772.        AND  $7F          ; Mask off the terminator bit.
  16773.  
  16774.        PUSH HL           ; Save buffer location.
  16775.        CALL L3E9C        ; Insert the character into the BASIC line workspace, suppressing spaces as required.
  16776.        POP  HL           ; Retrieve buffer location.
  16777.  
  16778.        LD   A,(HL)       ; Re-fetch the character from the buffer.
  16779.        AND  $80          ; Is it the terminator character?
  16780.        RET  NZ           ; Return if so.
  16781.  
  16782.        INC  HL           ; Point to the next character in the buffer.
  16783.        JR   L3DDA        ; Jump back to handle next buffer character.
  16784.  
  16785. ; -----------------------------------------------
  16786. ; Insert Character into Keyword Conversion Buffer
  16787. ; -----------------------------------------------
  16788. ; Entry; B=Character to insert.
  16789. ; Exit : Carry flag reset if no room to insert the character within the buffer.
  16790.  
  16791. L3DE9:  LD   HL,($FD7D)   ; Fetch address within Keyword Conversion Buffer.
  16792.        LD   DE,$FD7D     ; Address after Keyword Conversion Buffer.
  16793.        LD   A,D          ;
  16794.        CP   H            ; Has end of buffer possibly been reached?
  16795.        JR   NZ,L3DF8     ; Jump if not.
  16796.  
  16797.        LD   A,E          ;
  16798.        CP   L            ; Has end of buffer been reached?
  16799.        JP   Z,L3E13      ; Jump if so. [Could have saved a byte by using JR instead of JP]
  16800.  
  16801. ;End of buffer not reached
  16802.  
  16803. L3DF8:  LD   DE,$FD74     ; Start address of Keyword Conversion Buffer.
  16804.        LD   A,D          ;
  16805.        CP   H            ; Possibly at the start of the buffer?
  16806.        JR   NZ,L3E03     ; Jump if not.
  16807.  
  16808.        LD   A,E          ;
  16809.        CP   L            ; At the start of the buffer?
  16810.        JR   Z,L3E09      ; Jump if so to simply store the character.
  16811.  
  16812. ;Not at the start of the buffer so need to remove terminator bit from the previous character
  16813.  
  16814. L3E03:  DEC  HL           ; Point to the last character.
  16815.        LD   A,(HL)       ;
  16816.        AND  $7F          ; Clear the terminator bit from the last character.
  16817.        LD   (HL),A       ;
  16818.        INC  HL           ; Point back at the current location.
  16819.  
  16820. L3E09:  LD   A,B          ; Retrieve the new character.
  16821.        OR   $80          ; Set the terminator bit.
  16822.        LD   (HL),A       ; Store the character in the buffer.
  16823.        INC  HL           ; Point to the next location.
  16824.        LD   ($FD7D),HL   ; Store the address of the next location.
  16825.  
  16826.        SCF               ; Signal character inserted.
  16827.        RET               ;
  16828.  
  16829. ;End of buffer reached
  16830.  
  16831. L3E13:  SCF               ;
  16832.        CCF               ; Clear the carry flag to indicate no room to insert the character within the buffer.
  16833.        RET               ;
  16834.  
  16835. ; ----------------------------------------------------------------
  16836. ; Insert Character into BASIC Line Workspace, Handling '>' and '<'
  16837. ; ----------------------------------------------------------------
  16838. ; This routine inserts a character into the BASIC line workspace, tokenizing '>=', '<=' and '<>'.
  16839. ; Entry: A=Character to insert.
  16840. ; Exit : If tokenizing a BASIC line then returns with carry flag reset if tokenizing is complete.
  16841. ;        If searching for the error marker location then returns with the carry flag set if the error marker has not been found,
  16842. ;        otherwise a return is made to the main calling routine with BC holding the number of characters in the typed BASIC line,
  16843. ;        i.e. the error marker location is at the end of the line.
  16844.  
  16845. L3E16:  PUSH AF           ; Save the character to insert.
  16846.  
  16847. ; [*BUG* - The string characters "<>", "<=" and ">=" get tokenized to a single character '<>', '<=' and '>=' respectively
  16848. ;          even within quotes or a REM statement. Credit: Paul Collins (+3), Paul Farrow (128)]
  16849. ;
  16850. ; [*BUG* - 128 BASIC mode handles a colon character found following a REM statement differently to 48K mode. In 48K mode, typing
  16851. ;          a colon returns the cursor into 'K' mode and hence the next key press inserts a keyword token. In 128K mode, typing a colon
  16852. ;          does not cause the characters following it to be interpreted as a possible keyword. There is no noticeable difference when
  16853. ;          executing the REM statement since subsequent statements are ignored following a REM command. However, for consistency the
  16854. ;          128K mode editor ought to generate identical BASIC lines to those that would be created from 48K mode. Credit: Paul Farrow]
  16855. ;
  16856. ; [The following instructions would be required fix the two bugs described above. Credit: Paul Farrow.
  16857. ;
  16858. ;       LD   A,($FD81)    ;
  16859. ;       BIT  1,A          ; Within quotes?
  16860. ;       JR   NZ,WITHIN    ; Jump forward if within quotes.
  16861. ;
  16862. ;       BIT  2,A          ; Within a REM statement?
  16863. ;       JR   Z,NOT_WITHIN ; Jump forward if not within a REM statement.
  16864. ;
  16865. ;       POP  AF           ;
  16866. ;       PUSH AF           ;
  16867. ;       CP   ':'          ;
  16868. ;       JR   NZ,WITHIN    ; Jump if not a colon.
  16869. ;
  16870. ;       LD   A,($FD81)    ;
  16871. ;       AND  $FB          ; Signal not within a REM statement.
  16872. ;       LD   ($FD81),A    ;
  16873. ;
  16874. ;WITHIN:
  16875. ;       POP  AF           ; Retrieve the character to insert.
  16876. ;       JP   $3E64 (ROM 0) ; Simply insert the character into the BASIC line workspace.
  16877. ;
  16878. ;NOT_WITHIN:              ; ]
  16879.  
  16880.        LD   A,($FD89)    ; Was the previous character '<' or '>'?
  16881.        OR   A            ;
  16882.        JR   NZ,L3E2F     ; Jump if so.
  16883.  
  16884.        POP  AF           ; Retrieve the character to insert.
  16885.        CP   '>'          ; $3E. Is it '>'?
  16886.        JR   Z,L3E2A      ; Jump if so to store for special treatment later.
  16887.  
  16888.        CP   '<'          ; $3C. Is it '<'?
  16889.        JR   Z,L3E2A      ; Jump if so to store for special treatment later.
  16890.  
  16891. L3E26:  CALL L3E64        ; Insert the character into the BASIC line workspace.
  16892.        RET               ; [Could have saved 1 byte by using JP $3E64 (ROM 0)]
  16893.  
  16894. ;The character was '<' or '>'
  16895.  
  16896. L3E2A:  LD   ($FD89),A    ; Store '<' or '>'.
  16897.        SCF               ; Signal tokenizing not complete or error marker not found.
  16898.        RET               ;
  16899.  
  16900. ;The previous character was '<' or '>'
  16901.  
  16902. L3E2F:  CP   '<'          ; $3C. Was the previous character '<'?
  16903.        LD   A,$00        ; Reset the indicator that the previous
  16904.        LD   ($FD89),A    ; character was '<' or '>'.
  16905.        JR   NZ,L3E52     ; Jump ahead if not '<'.
  16906.  
  16907. ;Previous character was '<'
  16908.  
  16909.        POP  AF           ; Retrieve the character to insert.
  16910.        CP   '>'          ; $3E. Is it '>'?
  16911.        JR   NZ,L3E41     ; Jump ahead if not.
  16912.  
  16913.        LD   A,$C9        ; Tokenize to the single character '<>'.
  16914.        JR   L3E26        ; Jump back to insert the character and return.
  16915.  
  16916. L3E41:  CP   '='          ; $3D. Is it '='?
  16917.        JR   NZ,L3E49     ; Jump ahead if not.
  16918.  
  16919.        LD   A,$C7        ; Tokenize to '<='.
  16920.        JR   L3E26        ; Jump back to insert the character and return.
  16921.  
  16922. ;Previous character was '<' and new character is '<'
  16923.  
  16924. L3E49:  PUSH AF           ; Save the current character to insert.
  16925.        LD   A,'<'        ; $3C.
  16926.        CALL L3E64        ; Put the preceding '<' character into the line.
  16927.        POP  AF           ; Retrieve the character to insert.
  16928.        JR   L3E26        ; Jump back to insert the character and return.
  16929.  
  16930. ;Previous character was '>'
  16931.  
  16932. L3E52:  POP  AF           ; Retrieve the character to insert.
  16933.        CP   '='          ; $3D. Is it '='?
  16934.        JR   NZ,L3E5B     ; Jump ahead if not.
  16935.  
  16936.        LD   A,$C8        ; Tokenize to '>='.
  16937.        JR   L3E26        ; Jump back to insert the character and return.
  16938.  
  16939. ;Previous character was '>' and new character is '>'
  16940.  
  16941. L3E5B:  PUSH AF           ; Save the current character to insert.
  16942.        LD   A,'>'        ; $3E.
  16943.        CALL L3E64        ; Put the preceding '>' character into the line.
  16944.        POP  AF           ; Retrieve the character to insert.
  16945.        JR   L3E26        ; Jump back to insert the character and return.
  16946.  
  16947. ; ---------------------------------------------------------------------
  16948. ; Insert Character into BASIC Line Workspace, Handling 'REM' and Quotes
  16949. ; ---------------------------------------------------------------------
  16950. ; This routine inserts a character into the BASIC line workspace, with special handling of a 'REM' command
  16951. ; and strings contained within quotes.
  16952. ; Entry: A=Character to insert.
  16953. ; Exit : If tokenizing a BASIC line then returns with carry flag reset if tokenizing is complete.
  16954. ;        If searching for the error marker location then returns with the carry flag set if the error marker has not been found,
  16955. ;        otherwise a return is made directly to the main calling routine with BC holding the number of characters in the typed BASIC line,
  16956. ;        i.e. the error marker location is at the end of the line.
  16957.  
  16958. L3E64:  CP   $0D          ; Is it 'ENTER'?
  16959.        JR   Z,L3E88      ; Jump ahead if so.
  16960.  
  16961.        CP   $EA          ; Is it 'REM'?
  16962.        LD   B,A          ; Save the character.
  16963.        JR   NZ,L3E74     ; Jump ahead if not REM.
  16964.  
  16965. ;It is a 'REM' character
  16966.  
  16967.        LD   A,$04        ; Indicate that within a REM statement.
  16968.        LD   ($FD81),A    ;
  16969.        JR   L3E82        ; Jump ahead to insert the character into the BASIC line workspace.
  16970.  
  16971. L3E74:  CP   $22          ; Is it a quote?
  16972.        JR   NZ,L3E82     ; Jump ahead if not.
  16973.  
  16974. ;It is a quote character
  16975.  
  16976.        LD   A,($FD81)    ;
  16977.        AND  $FE          ; Signal last character was not a keyword.
  16978.        XOR  $02          ; Toggle the 'within quotes' flag. Will be 1 for an opening quote, then 0 for a closing quote.
  16979.        LD   ($FD81),A    ;
  16980.  
  16981. L3E82:  LD   A,B          ; Retrieve the character.
  16982.        CALL L3E9C        ; Insert the character into the BASIC line workspace, suppressing spaces as required.
  16983.  
  16984.        SCF               ; Indicate BASIC line tokenization not complete.
  16985.        RET               ;
  16986.  
  16987. ;It is an 'ENTER' character
  16988.  
  16989. ; [*BUG* - At this point a check should be made to see whether the last character was a space. If it was then it will not have
  16990. ;          been inserted but instead the flag in $FD84 (ROM 0) will have been set. The purpose of the flag is to filter out double
  16991. ;          spaces caused by the leading/trailing spaces of tokens. Only if the following character is not a space will the previous
  16992. ;          character, the space, be inserted. When the end of the line is found, there is no attempt to insert this space.
  16993. ;          The bug can be fixed by the two modifications shown below. Credit: Paul Farrow]
  16994.  
  16995. L3E88:  LD   A,($FD8A)    ; Fetch the 'locate error marker' flag.
  16996.        CP   $00          ; Searching for the error marker following a syntax error? [Could have saved 1 byte by using AND A]
  16997.        JR   Z,L3E99      ; Jump if tokenizing the BASIC line.
  16998.  
  16999. ;The end of the line was reached and no error marker was found so assume the error marker exists at the end of the typed line
  17000.  
  17001.        LD   BC,($FD85)   ; BC=Count of number of the characters in the typed BASIC line being inserted.
  17002.        LD   HL,($FD8B)   ;
  17003.  
  17004. ; [The first part of the fix for the trailing space bug is as follows:
  17005. ;
  17006. ;       LD   A,($FD84)    ; Fetch the BASIC line insertion flags.
  17007. ;       AND  $02          ; Was the last character a space?
  17008. ;       JR   Z,GOT_COUNT  ; Jump if not.
  17009. ;
  17010. ;       INC  BC           ; Increment to account for the final space.
  17011. ;
  17012. ;GOT_COUNT:               ; ]
  17013.  
  17014.        LD   SP,HL        ; Restore the stack pointer.
  17015.        SCF               ; Indicate the error marker was not found within the tokenized BASIC line.
  17016.        RET               ; Return back to the top level calling routine, to $2D04 (ROM 0).
  17017.  
  17018. ;Tokenizing the BASIC line
  17019.  
  17020. L3E99:
  17021.  
  17022. ; [The second part of the fix for the trailing space bug is as follows:
  17023. ;
  17024. ;       LD   A,($FD84)    ; Fetch the BASIC line insertion flags.
  17025. ;       AND  $02          ; Was the last character a space?
  17026. ;       LD   A,$20        ; Insert a space into the line.
  17027. ;       CALL NZ,$3EFB (ROM 0) ; If so then insert the character into the BASIC line workspace.]
  17028.  
  17029.        SCF               ;
  17030.        CCF               ; Carry flag reset to indicate tokenizing complete.
  17031.        RET               ;
  17032.  
  17033. ; -----------------------------------------------------------------
  17034. ; Insert Character into BASIC Line Workspace With Space Suppression
  17035. ; -----------------------------------------------------------------
  17036. ; This routine is called to insert a character into the BASIC line workspace, suppressing both leading and trailing spaces
  17037. ; around tokens, e.g. 'PRINT 10' does not require a space stored between 'PRINT' and '10' within the BASIC line.
  17038. ; The routine maintains two flags which indicate whether the last character was a space or was a token. Whenever a space
  17039. ; is encountered, it is noted but not inserted straight away. It is only after the subsequent character is examined that
  17040. ; the routine can determine whether the space should or should not be inserted.
  17041. ; Entry: A=Character to insert.
  17042. ; Exit : A=Updated BASIC line insertion flags.
  17043.  
  17044. L3E9C:  LD   E,A          ; Save the character to insert in E.
  17045.  
  17046.        LD   A,($FD84)    ;
  17047.        LD   D,A          ; D=BASIC line insertion flags.
  17048.  
  17049.        LD   A,E          ; Restore character to insert back to A.
  17050.        CP   $20          ; Is it a space?
  17051.        JR   NZ,L3EC6     ; Jump ahead if not.
  17052.  
  17053. ;Character to insert is a space
  17054.  
  17055.        LD   A,D          ; A=BASIC line insertion flags.
  17056.        AND  $01          ; Was the last character a token?
  17057.        JR   NZ,L3EBF     ; Jump ahead if so.
  17058.  
  17059.        LD   A,D          ; A=BASIC line insertion flags.
  17060.        AND  $02          ; Was the last character a space?
  17061.        JR   NZ,L3EB7     ; Jump ahead if so.
  17062.  
  17063. ;Character to insert is a space and the last character was not a space/token. This could be the start of a new keyword
  17064. ;so note the space but do not insert it now.
  17065.  
  17066.        LD   A,D          ; A=BASIC line insertion flags.
  17067.        OR   $02          ; Signal the last character was a space.
  17068.        LD   ($FD84),A    ; Store the updated BASIC line insertion flags.
  17069.        RET               ;
  17070.  
  17071. ;Character to insert is a space and the last character was a space. The new space could be the start of a new keyword
  17072. ;so keep the 'last character was a space' flag set but insert a space for the previous space that was noted.
  17073.  
  17074. L3EB7:  LD   A,E          ; Retrieve the character to insert.
  17075.        CALL L3EFB        ; Insert the character into the BASIC line workspace.
  17076.        LD   A,($FD84)    ; A=BASIC line insertion flags.
  17077.        RET               ;
  17078.  
  17079. ;Character to insert is a space and the last character was a token. Do not insert trailing spaces for tokens.
  17080.  
  17081. L3EBF:  LD   A,D          ; A=BASIC line insertion flags.
  17082.        AND  $FE          ; Signal last character was not a token.
  17083.        LD   ($FD84),A    ; Store the updated BASIC line insertion flags.
  17084.        RET               ; [Could have saved 2 bytes by using JR $3EB3 (ROM 0)]
  17085.  
  17086. ;Character to insert is not a space
  17087.  
  17088. L3EC6:  CP   $A3          ; Compare against the token 'SPECTRUM' (the first 128K keyword).
  17089.        JR   NC,L3EEE     ; Jump ahead if a token.
  17090.  
  17091. ;Character to insert is not a space and not a token
  17092.  
  17093.        LD   A,D          ; A=BASIC line insertion flags.
  17094.        AND  $02          ; Was the last character a space?
  17095.        JR   NZ,L3EDA     ; Jump ahead if it was.
  17096.  
  17097. ;Character to insert is not a space and not a token and the last character inserted was not a space, so just insert the character
  17098.  
  17099.        LD   A,D          ; A=BASIC line insertion flags.
  17100.        AND  $FE          ; Signal last character was not a keyword.
  17101.        LD   ($FD84),A    ; Store the new flags.
  17102.  
  17103.        LD   A,E          ; Retrieve the character to insert.
  17104.        CALL L3EFB        ; Insert the character into the BASIC line workspace.
  17105.        RET               ; [Could have saved one byte by using JP $3EFB (ROM 0)]
  17106.  
  17107. ;Character to insert is not a space and not a token and the last character was a space. Since the new character is not a token, the previous
  17108. ;space was not the start of a new keyword so insert a space and then the new character.
  17109.  
  17110. L3EDA:  PUSH DE           ; Save the BASIC line insertion flags.
  17111.        LD   A,$20        ; Insert a space into the line.
  17112.        CALL L3EFB        ; Insert the character into the BASIC line workspace.
  17113.        POP  DE           ; Retrieve the flags.
  17114.  
  17115.        LD   A,D          ; A=BASIC line insertion flags.
  17116.        AND  $FE          ; Signal last character was not a keyword.
  17117.        AND  $FD          ; Signal last character was not a space.
  17118.        LD   ($FD84),A    ; Store the updated BASIC line insertion flags. [Could have saved 6 bytes by using JR $3ED2 (ROM 0)]
  17119.  
  17120.        LD   A,E          ; Retrieve the character to insert.
  17121.        CALL L3EFB        ; Insert the character into the BASIC line workspace.
  17122.        RET               ;
  17123.  
  17124. ;Character to insert is a token. Clear any previously noted space since leading spaces are not required for tokens.
  17125.  
  17126. L3EEE:  LD   A,D          ; A=BASIC line insertion flags.
  17127.        AND  $FD          ; Signal last character was not a space.
  17128.        OR   $01          ; Signal last character was a keyword.
  17129.        LD   ($FD84),A    ; Store the updated BASIC line insertion flags. [Could have saved 6 bytes by using JR $3ED2 (ROM 0)]
  17130.  
  17131.        LD   A,E          ; Retrieve the character to insert.
  17132.        CALL L3EFB        ; Insert the character into the BASIC line workspace.
  17133.        RET               ;
  17134.  
  17135. ; --------------------------------------------
  17136. ; Insert a Character into BASIC Line Workspace
  17137. ; --------------------------------------------
  17138. ; This routine is called for two purposes. The first use is for inserting a character or token into the BASIC line workspace (situated at E_LINE).
  17139. ; The second use is after a syntax error has been identified within the tokenized BASIC line in the workspace and the location of the error marker needs to be
  17140. ; established. For the second case, the system variable X_PTR holds the address of where the error occurred within the tokenized BASIC line in the workspace.
  17141. ; The Editor needs to identify how many characters there are before the equivalent error position is reached within the typed BASIC line. To locate it, the typed BASIC
  17142. ; line is re-parsed but this time without inserting any characters into the BASIC line workspace, since this still contains the tokenized line from before. This tokenized line
  17143. ; will now also include embedded floating point numbers for any numeric literals contained within the BASIC line. As the typed line is re-parsed, a count of the characters
  17144. ; examined so far is kept and instead of inserting tokenized characters within the BASIC line workspace, a check is made to see whether the insertion location has
  17145. ; reached the address of the error marker. If it has then the parsing of the BASIC line terminates and the count of the typed line characters indicates the equivalent
  17146. ; position within it of the error. However, should the last character have been a token then the typed line count will also include the number of characters that form
  17147. ; the keyword, and so this must be subtracted from the count.
  17148. ; Entry: A=Character to insert.
  17149. ;        DE=Address of insertion position within the BASIC line workspace.
  17150. ; Exit : If searching for the error marker position and it is found then a return is made directly to the top level calling routine with BC holding the number of characters in
  17151. ;        the typed BASIC line prior to the equivalent error marker position.
  17152.  
  17153. L3EFB:  LD   HL,($FD87)   ;
  17154.        INC  HL           ; Increment the count of the number of characters in the tokenized BASIC line.
  17155.        LD   ($FD87),HL   ;
  17156.  
  17157.        LD   HL,($FD82)   ; HL=Address of next insertion position in the BASIC line workspace.
  17158.        LD   B,A          ; Save the character to insert.
  17159.  
  17160.        LD   A,($FD8A)    ; Fetch the 'locate error marker' flag.
  17161.        CP   $00          ; Searching for the error marker following a syntax error? [Could have saved 1 byte by using AND A]
  17162.        LD   A,B          ; A=Character to insert.
  17163.        JR   Z,L3F33      ; Jump if tokenizing the BASIC line.
  17164.  
  17165. ;Locating the error marker
  17166.  
  17167.        LD   DE,($5C5F)   ; X_PTR. Fetch the address of the character after the error marker.
  17168.        LD   A,H          ;
  17169.        CP   D            ; Has the error marker position possibly been reached?
  17170.        JR   NZ,L3F30     ; Jump ahead if not.
  17171.  
  17172.        LD   A,L          ;
  17173.        CP   E            ; Has the error marker position been reached?
  17174.        JR   NZ,L3F30     ; Jump ahead if not.
  17175.  
  17176. ;The error marker has been reached
  17177.  
  17178. ; [*BUG* - The desired character count until the error marker is held at address $FD85 and needs the length of the last character to be removed from it,
  17179. ;          which for a token would be several bytes. However, the routine simply returns the lower of the tokenized and typed counts, and this yields
  17180. ;          very unhelpful error marker positions shown within the typed BASIC line. Credit: Ian Collier (+3), Andrew Owen (128)]
  17181.  
  17182. ; [The code below up until the instruction at $3F2A (ROM 0) should have been as follows. Changes to the code at $3DCD (ROM 0) are also required. Credit: Paul Farrow.
  17183. ;
  17184. ;       LD   HL,($FD7D)   ; Fetch the next address within the Keyword Conversion Buffer.
  17185. ;       LD   DE,$FD74     ; Fetch the start address of the Keyword Conversion Buffer.
  17186. ;       AND  A            ;
  17187. ;       SBC  HL,DE        ; HL=Length of the keyword (excluding leading or trailing spaces).
  17188. ;       EX   DE,HL        ; DE=Length of the keyword (excluding leading or trailing spaces).
  17189. ;       LD   HL,($FD85)   ; BC=Count of the number of characters in the typed BASIC line until the error marker location was found.
  17190. ;       SBC  HL,DE        ; Subtract the number of characters in the keyword text.
  17191. ;       LD   B,H          ;
  17192. ;       LD   C,L          ; Transfer the result to BC, and then return via the instructions at $3F2A (ROM 0) onwards.]
  17193.  
  17194.        LD   BC,($FD85)   ; Count of the number of characters in the typed BASIC line until the error marker location was found.
  17195.        LD   HL,($FD87)   ; Count of the number of characters in the tokenized BASIC line until the error marker location.
  17196.        AND  A            ;
  17197.        SBC  HL,BC        ;
  17198.        JR   NC,L3F2A     ; Jump if the tokenized version is longer than the typed version.
  17199.  
  17200.        LD   BC,($FD87)   ; Count of the number of characters in the tokenized version of the BASIC line until the error marker location.
  17201.  
  17202. L3F2A:  LD   HL,($FD8B)   ; Fetch the saved stack pointer.
  17203.        LD   SP,HL        ; Restore the stack pointer.
  17204.        SCF               ; Set the carry flag to indicate the error marker has been located.
  17205.        RET               ; Return back to the top level calling routine, to $2D04 (ROM 0).
  17206.  
  17207. ;The error marker has not yet been reached
  17208.  
  17209. L3F30:  SCF               ; Set the carry flag to indicate error marker locating mode.
  17210.        JR   L3F35        ; Jump ahead to continue.
  17211.  
  17212. ;Tokenizing the BASIC line
  17213.  
  17214. L3F33:  SCF               ;
  17215.        CCF               ; Reset carry flag to signal BASIC line tokenizing mode.
  17216.  
  17217. L3F35:  CALL L1F20        ; Use Normal RAM Configuration (physical RAM bank 0).
  17218.  
  17219.        JR   NC,L3F47     ; Jump if tokenizing the BASIC line.
  17220.  
  17221. ;Searching for the error marker so need to consider embedded floating point numbers
  17222.  
  17223. ; [*BUG* - This should fetch the next character from the tokenized BASIC line and not the current character. This routine
  17224. ;          is called to process every visible character in the BASIC line, but is not called for embedded floating point numbers.
  17225. ;          It must therefore test whether the current character is followed by an embedded floating point number and if so to skip
  17226. ;          over it. The routine does make an attempt to detect embedded floating point numbers but incorrectly performs the test
  17227. ;          on the visible character and not the character that follows it. The bug can be fixed as replacing the LD A,(HL) instruction
  17228. ;          with the following instructions. Credit: Paul Farrow.
  17229. ;
  17230. ;       INC  HL           ; Advance to the next character in the tokenized BASIC line.
  17231. ;       LD   A,(HL)       ; Fetch the next character in the tokenized BASIC line.
  17232. ;       DEC  HL           ; Point back to the current character in the tokenized BASIC line.]
  17233.  
  17234.        LD   A,(HL)       ; Fetch the current character in the tokenized BASIC line.
  17235.        EX   DE,HL        ; DE=Insert position within the tokenized BASIC line.
  17236.        CP   $0E          ; Is it the 'number' marker?
  17237.        JR   NZ,L3F5D     ; Jump ahead if not.
  17238.  
  17239.        INC  DE           ; Skip over the 5 byte hidden number representation.
  17240.        INC  DE           ; [*BUG* - There should be another INC DE instruction here to take into account the character that the tokenizer would
  17241.        INC  DE           ; have inserted. As a result, the attempt to locate the error marker location will drift off by one byte for every numeric
  17242.        INC  DE           ; literal within the BASIC statement, and if there are many numeric literals in the statement then the error marker location
  17243.        INC  DE           ; may never be found before the end of the statement is parsed. Credit: Ian Collier (+3), Andrew Owen (128)]
  17244.        JR   L3F5D        ; Jump ahead to continue.
  17245.  
  17246. ;Come here if tokenizing the BASIC line
  17247.  
  17248. L3F47:  PUSH AF           ; Save the character to insert and the carry flag reset.
  17249.  
  17250.        LD   BC,$0001     ; Request to insert 1 byte.
  17251.        PUSH HL           ;
  17252.        PUSH DE           ;
  17253.        CALL L3F66        ; Check that there is memory available for 1 byte,
  17254.        POP  DE           ; automatically producing error '4' if not.
  17255.        POP  HL           ;
  17256.        RST  28H          ; BC=Number of bytes. HL=Address location before the position.
  17257.        DEFW POINTERS     ; $1664. Update all system variables due to the insertion. Exit with DE pointing to old STKEND position, BC with number of bytes 'shifted'.
  17258.        LD   HL,($5C65)   ; STKEND. Fetch the start of the spare memory.
  17259.        EX   DE,HL        ; DE=Address of spare memory. HL=Address of character in the BASIC line.
  17260.        LDDR              ; Shift up all affected bytes to make the room for the new character.
  17261.  
  17262.        POP  AF           ; Retrieve the character to insert and the flags. The carry flag will be reset and hence will indicate that tokenizing the BASIC line is not complete.
  17263.        LD   (DE),A       ; Store the character in the BASIC line workspace.
  17264.  
  17265. L3F5D:  INC  DE           ; Advance to the next character in the BASIC line.
  17266.  
  17267.        CALL L1F45        ; Use Workspace RAM configuration (physical RAM bank 7).
  17268.  
  17269.        LD   ($FD82),DE   ; Store the address of the next insertion position within the BASIC line workspace.
  17270.        RET               ;
  17271.  
  17272. ; ------------------
  17273. ; Room for BC Bytes?
  17274. ; ------------------
  17275. ; Test whether there is room for the specified number of bytes in the spare memory,
  17276. ; producing error "4 Out of memory" if not.
  17277. ; Entry: BC=Number of bytes required.
  17278. ; Exit : Returns if the room requested room is available else an error '4' is produced.
  17279.  
  17280. L3F66:  LD   HL,($5C65)   ; STKEND.
  17281.        ADD  HL,BC        ; Would adding the specified number of bytes overflow the RAM area?
  17282.        JR   C,L3F76      ; Jump to produce an error if so.
  17283.  
  17284.        EX   DE,HL        ; DE=New end address.
  17285.        LD   HL,$0082     ; Would there be at least 130 bytes at the top of RAM?
  17286.        ADD  HL,DE        ;
  17287.        JR   C,L3F76      ; Jump to produce an error if not.
  17288.  
  17289.        SBC  HL,SP        ; If the stack is lower in memory, would there still be enough room?
  17290.        RET  C            ; Return if there would.
  17291.  
  17292. L3F76:  LD   A,$03        ;
  17293.        LD   ($5C3A),A    ; ERR_NR. Signal error "4 Out of Memory".
  17294.        JP   L0321        ; Jump to error handler routine.
  17295.  
  17296. ; ----------------
  17297. ; Identify Keyword
  17298. ; ----------------
  17299. ; This routine identifies the string within the Keyword Conversion Buffer and returns
  17300. ; the token character code. The last character of the string has bit 7 set.
  17301. ; The routine attempts to identify 48K mode keywords, 128K mode keywords and a number of
  17302. ; mis-spelled keywords (those that require a space within them).
  17303. ; Exit: Carry flag set if a keyword was identified.
  17304. ;       A=Token character code.
  17305.  
  17306. L3F7E:  CALL $FD2E        ; Attempt to identify 48K mode keyword.
  17307.        RET  C            ; Return if keyword identified.
  17308.  
  17309. ;Attempt to identify 128K mode keywords and mis-spelled keywords.
  17310.  
  17311.        LD   B,$F9        ; Base character code (results in codes $F9-$FF).
  17312.        LD   DE,$FD74     ; DE=Address of Keyword Conversion Buffer.
  17313.        LD   HL,L3594     ; HL=Keywords string table.
  17314.        CALL $FD3B        ; Attempt to identify 128K mode/mis-spelled keyword.
  17315.        RET  NC           ; Return if no keyword identified.
  17316.  
  17317. ;Attempt to convert mis-spelled keywords
  17318.  
  17319.        CP   $FF          ; Was it "CLOSE#"?
  17320.        JR   NZ,L3F96     ;
  17321.  
  17322.        LD   A,$D4        ; Use character code for 'CLOSE #'.
  17323.        JR   L3FB8        ; Jump ahead to continue.
  17324.  
  17325. L3F96:  CP   $FE          ; Was it "OPEN#"?
  17326.        JR   NZ,L3F9E     ; Jump if not.
  17327.  
  17328.        LD   A,$D3        ; Use character code for 'OPEN #'.
  17329.        JR   L3FB8        ; Jump ahead to continue.
  17330.  
  17331. L3F9E:  CP   $FD          ; Was it "DEFFN"?
  17332.        JR   NZ,L3FA6     ; Jump if not.
  17333.  
  17334.        LD   A,$CE        ; Use character code for 'DEF FN'.
  17335.        JR   L3FB8        ; Jump ahead to continue.
  17336.  
  17337. L3FA6:  CP   $FC          ; Was it "GOSUB"?
  17338.        JR   NZ,L3FAE     ; Jump if not.
  17339.  
  17340.        LD   A,$ED        ; Use character code for 'GO SUB'.
  17341.        JR   L3FB8        ; Jump ahead to continue.
  17342.  
  17343. L3FAE:  CP   $FB          ; Was it "GOTO"?
  17344.        JR   NZ,L3FB6     ; Jump if not.
  17345.  
  17346.        LD   A,$EC        ; Use character code for 'GO TO'.
  17347.        JR   L3FB8        ; Jump ahead to continue.
  17348.  
  17349. L3FB6:  SUB  $56          ; Reduce to $A3 for 'SPECTRUM' and $A4 for 'PLAY'.
  17350.  
  17351. L3FB8:  SCF               ; Signal keyword identified.
  17352.        RET               ;
  17353.  
  17354. ; ---------------
  17355. ; Copy Data Block
  17356. ; ---------------
  17357. ; This routine is used on 8 occasions to copy a block of default data.
  17358. ; Entry: DE=Destination address.
  17359. ;        HL=Address of source data table, which starts with the number of bytes to copy
  17360. ;           followed by the bytes themselves.
  17361.  
  17362. L3FBA:  LD   B,(HL)       ; Get number of bytes to copy.
  17363.        INC  HL           ; Point to the first byte to copy.
  17364.  
  17365. L3FBC:  LD   A,(HL)       ; Fetch the byte from the source
  17366.        LD   (DE),A       ; and copy it to the destination.
  17367.        INC  DE           ; Increment destination address.
  17368.        INC  HL           ; Increment source address.
  17369.        DJNZ L3FBC        ; Repeat for all bytes.
  17370.  
  17371.        RET               ;
  17372.  
  17373. ; -------------------------------------
  17374. ; Get Numeric Value for ASCII Character
  17375. ; -------------------------------------
  17376. ; Exit: Carry flag set if character was numeric and A holding value.
  17377. ;
  17378. ; [Never called by this ROM]
  17379.  
  17380. L3FC3:  CP   '0'          ; $30. Test against '0'.
  17381.        CCF               ;
  17382.        RET  NC           ; Return with carry flag reset if not numeric character.
  17383.  
  17384.        CP   ':'          ; $3A. Test against ':'.
  17385.        RET  NC           ; Return with carry flag reset if not numeric character.
  17386.  
  17387.        SUB  '0'          ; $30. Get numeric value.
  17388.        SCF               ; Return with carry flag set to indicate a numeric character.
  17389.        RET               ;
  17390.  
  17391. ; ---------------------------
  17392. ; Call Action Handler Routine
  17393. ; ---------------------------
  17394. ; If the code in A matches an entry in the table pointed to by HL
  17395. ; then execute the action specified by the entry's routine address.
  17396. ; Entry: A=Code.
  17397. ;        HL=Address of action table.
  17398. ; Exit : Zero flag reset if no match found.
  17399. ;        Carry flag reset if an error beep is required, or to signal no suitable action handler found.
  17400. ;        HL=Address of next table entry if a match was found.
  17401.  
  17402. L3FCE:  PUSH BC           ; Save registers.
  17403.         PUSH DE           ;
  17404.  
  17405.         LD   B,(HL)       ; Fetch number of table entries.
  17406.         INC  HL           ; Point to first entry.
  17407.  
  17408. L3FD2:  CP   (HL)         ; Possible match for A?
  17409.         INC  HL           ;
  17410.         LD   E,(HL)       ;
  17411.         INC  HL           ;
  17412.         LD   D,(HL)       ; DE=Address to call if a match.
  17413.         JR   Z,L3FE1      ; Jump if a match.
  17414.  
  17415.         INC  HL           ; Next table entry.
  17416.         DJNZ L3FD2        ; Repeat for next table entry.
  17417.  
  17418. ;No match found
  17419.  
  17420.         SCF               ; Return with carry flag reset to signal an error beep is required
  17421.         CCF               ; and with the zero flag reset to signal a match was not found.
  17422.  
  17423.         POP  DE           ; Restore registers.
  17424.         POP  BC           ;
  17425.         RET               ;
  17426.  
  17427. ;Found a match
  17428.  
  17429. L3FE1:  EX   DE,HL        ; HL=Action routine to call.
  17430.  
  17431.         POP  DE           ;
  17432.         POP  BC           ;
  17433.  
  17434.         CALL L3FEE        ; Indirectly call the action handler routine.
  17435.         JR   C,L3FEB      ; Jump if no error beep is required.
  17436.  
  17437.         CP   A            ; Set zero flag to indicate a match was found.
  17438.         RET               ; Exit with carry flag reset to indicate error beep required.
  17439.  
  17440. L3FEB:  CP   A            ; Set zero flag to indicate a match was found.
  17441.         SCF               ; Signal no error beep required.
  17442.         RET               ;
  17443.  
  17444. L3FEE:  JP   (HL)         ; Jump to the action handler routine.
  17445.  
  17446.  
  17447. ; =====================
  17448. ; PROGRAMMERS' INITIALS
  17449. ; =====================
  17450. ; [Provided by Andrew Owen]
  17451.  
  17452. L3FEF           DB $00
  17453.                 DB "MB"         ;DEFM "MB"        ; Martin Brennan.
  17454.                 DB $00
  17455.                 DB "SB"         ;DEFM "SB"        ; Steve Berry.
  17456.                 DB $00
  17457.                 DB "AC"         ;DEFM "AC"        ; Andrew Cummins.
  17458.                 DB $00
  17459.                 DB "RG"         ;DEFM "RG"        ; Rupert Goodwins.
  17460.                 DB $00
  17461.                 DB "KM"         ;DEFM "KM"        ; Kevin Males.
  17462.                 DB $00
  17463.  
  17464.  
  17465. ; =================
  17466. ; END OF ROM MARKER
  17467. ; =================
  17468.  
  17469. L3FFF:  DB $01         ;
  17470.  
  17471. ;        END
  17472.  
  17473.  
  17474. ; ==============================
  17475. ; REFERENCE INFORMATION - PART 2
  17476. ; ==============================
  17477.  
  17478. ; ==================================
  17479. ; Routines Copied/Constructed in RAM
  17480. ; ==================================
  17481.  
  17482. ; --------------------------------
  17483. ; Construct Keyword Representation
  17484. ; --------------------------------
  17485. ; This routine copies a keyword string from ROM 1 into the BASIC Line Construction Buffer,
  17486. ; terminating it with an 'end of BASIC line' marker (code ' '+$80). Only standard Spectrum
  17487. ; keywords are handled by this routine (SPECTRUM and PLAY are processed elsewhere).
  17488. ; The routine is run from RAM bank 7 at $FCAE so that access to both ROMs is available.
  17489. ; Depending on the value of A (which should be the ASCII code less $A5,
  17490. ; e.g. 'RND', the first (48K) keyword, has A=0), a different index into the
  17491. ; token table is taken. This is to allow speedier lookup since there are never more
  17492. ; than 15 keywords to advance through.
  17493. ; Entry: A=Keyword character code-$A5 (range $00-$5A).
  17494. ;        DE=Insertion address within BASIC Line Construction Buffer.
  17495. ;
  17496. ; Copied to physical RAM bank 7 at $FCAE-$FCFC by routine at $335F (ROM 0).
  17497. ;
  17498. ;$FCAE  DI                ; Disable interrupts whilst paging.
  17499. ;
  17500. ;       LD   BC,$7FFD     ;
  17501. ;       LD   D,$17        ; Page in ROM 1, SCREEN 0, no locking, RAM bank 7.
  17502. ;       OUT  (C),D        ;
  17503. ;
  17504. ;       CP   $50          ; Was the token $F5 or above?
  17505. ;       JR   NC,$FCEB     ;
  17506. ;
  17507. ;       CP   $40          ; Was the token $E5 or above?
  17508. ;       JR   NC,$FCE4     ;
  17509. ;
  17510. ;       CP   $30          ; Was the token $D5 or above?
  17511. ;       JR   NC,$FCDD     ;
  17512. ;
  17513. ;       CP   $20          ; Was the token $C5 or above?
  17514. ;       JR   NC,$FCD6     ;
  17515. ;
  17516. ;       CP   $10          ; Was the token $B5 or above?
  17517. ;       JR   NC,$FCCF     ;
  17518. ;
  17519. ;Used for token range $A5-$B4 ($00 <= A <= $0F)
  17520. ;
  17521. ;       LD   HL,$0096     ; Token table entry 'RND' in ROM 1.
  17522. ;       JR   $FCF0        ;
  17523. ;
  17524. ;Used for token range $B5-$C4 ($10 <= A <= $1F)
  17525. ;
  17526. ;$FCCF  SUB  $10          ;
  17527. ;       LD   HL,$00CF     ; Token table entry 'ASN' in ROM 1.
  17528. ;       JR   $FCF0        ;
  17529. ;
  17530. ;Used for token range $C5-$D4 ($20 <= A <= $2F)
  17531. ;
  17532. ;$FCD6  SUB  $20          ;
  17533. ;       LD   HL,$0100     ; Token table entry 'OR' in ROM 1.
  17534. ;       JR   $FCF0        ;
  17535. ;
  17536. ;Used for token range $D5-$E4 ($30 <= A <= $3F)
  17537. ;
  17538. ;$FCDD  SUB  $30          ;
  17539. ;       LD   HL,$013E     ; Token table entry 'MERGE' in ROM 1.
  17540. ;       JR   $FCF0        ;
  17541. ;
  17542. ;Used for token range $E5-$F4 ($40 <= A <= $4F)
  17543. ;
  17544. ;$FCE4  SUB  $40          ;
  17545. ;       LD   HL,$018B     ; Token table entry 'RESTORE' in ROM 1.
  17546. ;       JR   $FCF0        ;
  17547. ;
  17548. ;Used for token range $F5-$FF (A >= $50)
  17549. ;
  17550. ;$FCEB  SUB  $50          ;
  17551. ;       LD   HL,$01D4     ; Token table entry 'PRINT' in ROM 1.
  17552. ;
  17553. ;$FCF0  LD   B,A          ; Take a copy of the index value.
  17554. ;       OR   A            ; If A=0 then already have the entry address.
  17555. ;
  17556. ;$FCF2  JR   Z,$FCFD      ; If indexed item found then jump ahead to copy the characters of the token.
  17557. ;
  17558. ;$FCF4  LD   A,(HL)       ; Fetch a character.
  17559. ;       INC  HL           ; Point to next character.
  17560. ;       AND  $80          ; Has end of token marker been found?
  17561. ;       JR   Z,$FCF4      ; Loop back for next character if not.
  17562. ;
  17563. ;       DEC  B            ; Count down the index of the required token.
  17564. ;$FCFC  JR   $FCF2        ; Jump back to test whether the required token has been reached.
  17565.  
  17566. ; -----------------------
  17567. ; Copy Keyword Characters
  17568. ; -----------------------
  17569. ; This routine copies a keyword string from ROM 1 into the BASIC Line Construction Buffer,
  17570. ; terminating it with an 'end of BASIC line' marker (code ' '+$80).
  17571. ; The routine is run from RAM bank 7 so that access to both ROMs is available.
  17572. ; Entry: HL=Address of keyword string in ROM 1.
  17573. ;        DE=Insertion address within BASIC Line Construction Buffer.
  17574. ;
  17575. ; Copied to physical RAM bank 7 at $FCFD-$FD2D by subroutine at $335F (ROM 0).
  17576. ;
  17577. ;$FCFD  LD   DE,$FCA3     ; DE=Keyword Construction Buffer.
  17578. ;       LD   ($FCA1),DE   ; Store the start address of the constructed keyword.
  17579. ;
  17580. ;       LD   A,($FC9E)    ; Print a leading space?
  17581. ;       OR   A            ;
  17582. ;       LD   A,$00        ;
  17583. ;       LD   ($FC9E),A    ; Signal leading space not required.
  17584. ;       JR   NZ,$FD13     ; Jump if leading space not required.
  17585. ;
  17586. ;       LD   A,$20        ; Print a leading space.
  17587. ;       LD   (DE),A       ; Insert a leading space.
  17588. ;       INC  DE           ; Advance to next buffer position.
  17589. ;
  17590. ;$FD13  LD   A,(HL)       ; Fetch a character of the keyword.
  17591. ;       LD   B,A          ; Store it.
  17592. ;       INC  HL           ; Advance to next keyword character.
  17593. ;       LD   (DE),A       ; Store the keyword character in the BASIC line buffer.
  17594. ;       INC  DE           ; Advance to the next buffer position.
  17595. ;       AND  $80          ; Test if the end of the keyword string.
  17596. ;       JR   Z,$FD13      ; Jump back if not to repeat for all characters of the keyword.
  17597. ;
  17598. ;       LD   A,B          ; Get keyword character back.
  17599. ;       AND  $7F          ; Mask of bit 7 which indicates the end of string marker.
  17600. ;       DEC  DE           ; Point back at the last character of the keyword copied into the buffer
  17601. ;       LD   (DE),A       ; and store it.
  17602. ;
  17603. ;       INC  DE           ; Advance to the position in the buffer after the last character of the keyword.
  17604. ;       LD   A,' '+$80    ; $A0. ' ' + end marker
  17605. ;       LD   (DE),A       ; Store an 'end of BASIC line so far' marker.
  17606. ;
  17607. ;       LD   A,$07        ;
  17608. ;       LD   BC,$7FFD     ;
  17609. ;       OUT  (C),A        ; Page in ROM 0, SCREEN 0, no locking, RAM bank 7.
  17610. ;       EI                ; Re-enable interrupts.
  17611. ;$FD2D  RET               ;
  17612.  
  17613. ; --------------
  17614. ; Identify Token
  17615. ; --------------
  17616. ; This routine identifies the string within the Keyword Conversion Buffer and returns
  17617. ; the character code. The last character of the string to identify has bit 7 set.
  17618. ; Exit: Carry flag set if token identified.
  17619. ;       B=Character code.
  17620. ;
  17621. ; Copied to physical RAM bank 7 at $FD2E-$FD69 by subroutine at $335F (ROM 0).
  17622. ;
  17623. ;$FD2E  DI                ; Disable interrupts whilst paging.
  17624. ;       LD   BC,$7FFD     ;
  17625. ;       LD   D,$17        ; Select ROM 1, SCREEN 0, RAM bank 7.
  17626. ;       OUT  (C),D        ;
  17627. ;
  17628. ;       LD   HL,$0096     ; Address of token table in ROM 1.
  17629. ;       LD   B,$A5        ; Character code of the first token - 'RND'.
  17630. ;
  17631. ;Entry point here used to match 128K mode tokens and mis-spelled tokens
  17632. ;
  17633. ;$FD3B  LD   DE,$FD74     ; Keyword Conversion Buffer holds the text to match against.
  17634. ;
  17635. ;$FD3E  LD   A,(DE)       ; Fetch a character from the buffer.
  17636. ;       AND  $7F          ; Mask off terminator bit.
  17637. ;       CP   $61          ; Is it lowercase?
  17638. ;       LD   A,(DE)       ; Fetch the character again from the buffer.
  17639. ;       JR   C,$FD48      ; Jump if uppercase.
  17640. ;
  17641. ;       AND  $DF          ; Make the character uppercase.
  17642. ;
  17643. ;$FD48  CP   (HL)         ; Does the character match the current item in the token table?
  17644. ;       JR   NZ,$FD54     ; Jump if it does not.
  17645. ;
  17646. ;       INC  HL           ; Point to the next character in the buffer.
  17647. ;       INC  DE           ; Point to the next character in the token table.
  17648. ;       AND  $80          ; Has the terminator been reached?
  17649. ;       JR   Z,$FD3E      ; Jump back if not to test the next character in the token.
  17650. ;
  17651. ;A match was found
  17652. ;
  17653. ;       SCF               ; Signal a match was found.
  17654. ;       JR   $FD60        ; Jump ahead to continue.
  17655. ;
  17656. ;$FD54  INC  B            ; The next character code to test against.
  17657. ;       JR   Z,$FD5F      ; Jump if all character codes tested.
  17658. ;
  17659. ;The token does not match so skip to the next entry in the token table
  17660. ;
  17661. ;$FD57  LD   A,(HL)       ; Fetch the character from the token table.
  17662. ;       AND  $80          ; Has the end terminator been found?
  17663. ;       INC  HL           ; Point to the next character.
  17664. ;       JR   Z,$FD57      ; Jump back if no terminator found.
  17665. ;
  17666. ;       JR   $FD3B        ; Jump back to test against the next token.
  17667. ;
  17668. ;All character codes tested and no match found
  17669. ;
  17670. ;$FD5F  OR   A            ; Clear the carry flag to indicate no match found.
  17671. ;
  17672. ;The common exit point
  17673. ;
  17674. ;$FD60  LD   A,B          ; Fetch the character code of the matching token ($00 for no match).
  17675. ;
  17676. ;       LD   D,$07        ; Select ROM 0, SCREEN 0, RAM bank 7.
  17677. ;       LD   BC,$7FFD     ;
  17678. ;       OUT  (C),D        ;
  17679. ;       EI                ; Re-enable interrupts.
  17680. ;$FD69  RET               ;
  17681.  
  17682. ; ----------------------------------
  17683. ; Insert Character into Display File
  17684. ; ----------------------------------
  17685. ; Copy a character into the display file.
  17686. ; Entry: HL=Character data.
  17687. ;        DE=Display file address.
  17688. ; This routine is constructed from three segments and stitched together in physical RAM bank 7 to form a single routine.
  17689. ;
  17690. ; Created in physical RAM Bank 7 at $FF28-$FF60 by routine at $246F (ROM 0). [Construction routine never actually called by the ROM]
  17691. ;
  17692. ;$FF28  PUSH BC           ; Save BC
  17693. ;
  17694. ;       DI                ; Disable interrupts whilst paging.
  17695. ;
  17696. ;       LD   BC,$7FFD     ;
  17697. ;       LD   A,(BANK_M)   ; $5B5C. Fetch current paging configuration.
  17698. ;       XOR  $10          ; Toggle ROMs.
  17699. ;       OUT  (C),A        ; Perform paging.
  17700. ;       EI                ; Re-enable interrupts.
  17701. ;       EX   AF,AF'       ; Save the new configuration in A'.
  17702. ;
  17703. ;       LD   C,D          ; Save D.
  17704. ;
  17705. ;       LD   A,(HL)       ;
  17706. ;       LD   (DE),A       ; Copy byte 1.
  17707. ;
  17708. ;       INC  HL           ;
  17709. ;       INC  D            ;
  17710. ;       LD   A,(HL)       ;
  17711. ;       LD   (DE),A       ; Copy byte 2.
  17712. ;
  17713. ;       INC  HL           ;
  17714. ;       INC  D            ;
  17715. ;       LD   A,(HL)       ;
  17716. ;       LD   (DE),A       ; Copy byte 3.
  17717. ;
  17718. ;       INC  HL           ;
  17719. ;       INC  D            ;
  17720. ;       LD   A,(HL)       ;
  17721. ;       LD   (DE),A       ; Copy byte 4.
  17722. ;
  17723. ;       INC  HL           ;
  17724. ;       INC  D            ;
  17725. ;       LD   A,(HL)       ;
  17726. ;       LD   (DE),A       ; Copy byte 5.
  17727. ;
  17728. ;       INC  HL           ;
  17729. ;       INC  D            ;
  17730. ;       LD   A,(HL)       ;
  17731. ;       LD   (DE),A       ; Copy byte 6.
  17732. ;
  17733. ;       INC  HL           ;
  17734. ;       INC  D            ;
  17735. ;       LD   A,(HL)       ;
  17736. ;       LD   (DE),A       ; Copy byte 7.
  17737. ;
  17738. ;       INC  HL           ;
  17739. ;       INC  D            ;
  17740. ;       LD   A,(HL)       ;
  17741. ;       LD   (DE),A       ; Copy byte 8.
  17742. ;
  17743. ;       LD   D,C          ; Restore D.
  17744. ;
  17745. ;       EX   AF,AF'       ; Retrieve current paging configuration.
  17746. ;       DI                ; Disable interrupts whilst paging.
  17747. ;       LD   C,$FD        ; Restore Paging I/O port number.
  17748. ;       XOR  $10          ; Toggle ROMs.
  17749. ;       OUT  (C),A        ; Perform paging.
  17750. ;       EI                ; Re-enable interrupts.
  17751. ;
  17752. ;       POP  BC           ; Restore BC.
  17753. ;$FF60  RET               ;
  17754.  
  17755.  
  17756. ; ===========================
  17757. ; Standard Error Report Codes
  17758. ; ===========================
  17759.  
  17760. ; 0 - OK                      Successful completion, or jump to a line number bigger than any existing.
  17761. ; 1 - NEXT without FOR        The control variable does not exist (it has not been set up by a FOR statement),
  17762. ;                             but there is an ordinary variable with the same name.
  17763. ; 2 - Variable not found      For a simple variable, this will happen if the variable is used before it has been assigned
  17764. ;                             to by a LET, READ or INPUT statement, loaded from disk (or tape), or set up in a FOR statement.
  17765. ;                             For a subscripted variable, it will happen if the variable is used before it has been
  17766. ;                             dimensioned in a DIM statement, or loaded from disk (or tape).
  17767. ; 3 - Subscript wrong         A subscript is beyond the dimension of the array or there are the wrong number of subscripts.
  17768. ; 4 - Out of memory           There is not enough room in the computer for what you are trying to do.
  17769. ; 5 - Out of screen           An INPUT statement has tried to generate more than 23 lines in the lower half of the screen.
  17770. ;                             Also occurs with 'PRINT AT 22,xx'.
  17771. ; 6 - Number too big          Calculations have yielded a number greater than approximately 10^38.
  17772. ; 7 - RETURN without GO SUB   There has been one more RETURN than there were GO SUBs.
  17773. ; 8 - End of file             Input returned unacceptable character code.
  17774. ; 9 - STOP statement          After this, CONTINUE will not repeat the STOP but carries on with the statement after.
  17775. ; A - Invalid argument        The argument for a function is unsuitable.
  17776. ; B - Integer out of range    When an integer is required, the floating point argument is rounded to the nearest integer.
  17777. ;                             If this is outside a suitable range, then this error results.
  17778. ; C - Nonsense in BASIC       The text of the (string) argument does not form a valid expression.
  17779. ; D - BREAK - CONT repeats    BREAK was pressed during some peripheral operation.
  17780. ; E - Out of DATA             You have tried to READ past the end of the DATA list.
  17781. ; F - Invalid file name       SAVE with filename empty or longer than 10 characters.
  17782. ; G - No room for line        There is not enough room left in memory to accommodate the new program line.
  17783. ; H - STOP in INPUT           Some INPUT data started with STOP.
  17784. ; I - FOR without NEXT        A FOR loop was to be executed no times (e.g. FOR n=1 TO 0) and corresponding NEXT statement could not be found.
  17785. ; J - Invalid I/O device      Attempting to input characters from or output characters to a device that doesn't support it.
  17786. ; K - Invalid colour          The number specified is not an appropriate value.
  17787. ; L - BREAK into program      BREAK pressed. This is detected between two statements.
  17788. ; M - RAMTOP no good          The number specified for RAMTOP is either too big or too small.
  17789. ; N - Statement lost          Jump to a statement that no longer exists.
  17790. ; O - Invalid Stream          Trying to input from or output to a stream that isn't open or that is out of range (0...15),
  17791. ;                             or trying to open a stream that is out of range.
  17792. ; P - FN without DEF          User-defined function used without a corresponding DEF in the program.
  17793. ; Q - Parameter error         Wrong number of arguments, or one of them is the wrong type.
  17794. ; R - Tape loading error      A file on tape was found but for some reason could not be read in, or would not verify.
  17795.  
  17796.  
  17797. ; =========================
  17798. ; Standard System Variables
  17799. ; =========================
  17800. ; These occupy addresses $5C00-$5CB5.
  17801. ;
  17802. ; KSTATE   $5C00   8   IY-$3A   Used in reading the keyboard.
  17803. ; LASTK    $5C08   1   IY-$32   Stores newly pressed key.
  17804. ; REPDEL   $5C09   1   IY-$31   Time (in 50ths of a second) that a key must be held down before it repeats. This starts off at 35.
  17805. ; REPPER   $5C0A   1   IY-$30   Delay (in 50ths of a second) between successive repeats of a key held down - initially 5.
  17806. ; DEFADD   $5C0B   2   IY-$2F   Address of arguments of user defined function (if one is being evaluated), otherwise 0.
  17807. ; K_DATA   $5C0D   1   IY-$2D   Stores second byte of colour controls entered from keyboard.
  17808. ; TVDATA   $5C0E   2   IY-$2C   Stores bytes of colour, AT and TAB controls going to TV.
  17809. ; STRMS    $5C10  38   IY-$2A   Addresses of channels attached to streams.
  17810. ; CHARS    $5C36   2   IY-$04   256 less than address of character set, which starts with ' ' and carries on to '(c)'.
  17811. ; RASP     $5C38   1   IY-$02   Length of warning buzz.
  17812. ; PIP      $5C39   1   IY-$01   Length of keyboard click.
  17813. ; ERR_NR   $5C3A   1   IY+$00   1 less than the report code. Starts off at 255 (for -1) so 'PEEK 23610' gives 255.
  17814. ; FLAGS    $5C3B   1   IY+$01   Various flags to control the BASIC system:
  17815. ;                                 Bit 0: 1=Suppress leading space.
  17816. ;                                 Bit 1: 1=Using printer, 0=Using screen.
  17817. ;                                 Bit 2: 1=Print in L-Mode, 0=Print in K-Mode.
  17818. ;                                 Bit 3: 1=L-Mode, 0=K-Mode.
  17819. ;                                 Bit 4: 1=128K Mode, 0=48K Mode. [Always 0 on 48K Spectrum]
  17820. ;                                 Bit 5: 1=New key press code available in LAST_K.
  17821. ;                                 Bit 6: 1=Numeric variable, 0=String variable.
  17822. ;                                 Bit 7: 1=Line execution, 0=Syntax checking.
  17823. ; TVFLAG   $5C3C   1   IY+$02   Flags associated with the TV:
  17824. ;                                 Bit 0  : 1=Using lower editing area, 0=Using main screen.
  17825. ;                                 Bit 1-2: Not used (always 0).
  17826. ;                                 Bit 3  : 1=Mode might have changed.
  17827. ;                                 Bit 4  : 1=Automatic listing in main screen, 0=Ordinary listing in main screen.
  17828. ;                                 Bit 5  : 1=Lower screen requires clearing after a key press.
  17829. ;                                 Bit 6  : 1=Tape Loader option selected (set but never tested). [Always 0 on 48K Spectrum]
  17830. ;                                 Bit 7  : Not used (always 0).
  17831. ; ERR_SP   $5C3D   2   IY+$03   Address of item on machine stack to be used as error return.
  17832. ; LISTSP   $5C3F   2   IY+$05   Address of return address from automatic listing.
  17833. ; MODE     $5C41   1   IY+$07   Specifies cursor type:
  17834. ;                                 $00='L' or 'C'.
  17835. ;                                 $01='E'.
  17836. ;                                 $02='G'.
  17837. ;                                 $04='K'.
  17838. ; NEWPPC   $5C42   2   IY+$08   Line to be jumped to.
  17839. ; NSPPC    $5C44   1   IY+$0A   Statement number in line to be jumped to.
  17840. ; PPC      $5C45   2   IY+$0B   Line number of statement currently being executed.
  17841. ; SUBPPC   $5C47   1   IY+$0D   Number within line of statement currently being executed.
  17842. ; BORDCR   $5C48   1   IY+$0E   Border colour multiplied by 8; also contains the attributes normally used for the lower half
  17843. ;                               of the screen.
  17844. ; E_PPC    $5C49   2   IY+$0F   Number of current line (with program cursor).
  17845. ; VARS     $5C4B   2   IY+$11   Address of variables.
  17846. ; DEST     $5C4D   2   IY+$13   Address of variable in assignment.
  17847. ; CHANS    $5C4F   2   IY+$15   Address of channel data.
  17848. ; CURCHL   $5C51   2   IY+$17   Address of information currently being used for input and output.
  17849. ; PROG     $5C53   2   IY+$19   Address of BASIC program.
  17850. ; NXTLIN   $5C55   2   IY+$1B   Address of next line in program.
  17851. ; DATADD   $5C57   2   IY+$1D   Address of terminator of last DATA item.
  17852. ; E_LINE   $5C59   2   IY+$1F   Address of command being typed in.
  17853. ; K_CUR    $5C5B   2   IY+$21   Address of cursor.
  17854. ; CH_ADD   $5C5D   2   IY+$23   Address of the next character to be interpreted - the character after the argument of PEEK,
  17855. ;                               or the NEWLINE at the end of a POKE statement.
  17856. ; X_PTR    $5C5F   2   IY+$25   Address of the character after the '?' marker.
  17857. ; WORKSP   $5C61   2   IY+$27   Address of temporary work space.
  17858. ; STKBOT   $5C63   2   IY+$29   Address of bottom of calculator stack.
  17859. ; STKEND   $5C65   2   IY+$2B   Address of start of spare space.
  17860. ; BREG     $5C67   1   IY+$2D   Calculator's B register.
  17861. ; MEM      $5C68   2   IY+$2E   Address of area used for calculator's memory (usually MEMBOT, but not always).
  17862. ; FLAGS2   $5C6A   1   IY+$30   Flags:
  17863. ;                                 Bit 0  : 1=Screen requires clearing.
  17864. ;                                 Bit 1  : 1=Printer buffer contains data.
  17865. ;                                 Bit 2  : 1=In quotes.
  17866. ;                                 Bit 3  : 1=CAPS LOCK on.
  17867. ;                                 Bit 4  : 1=Using channel 'K'.
  17868. ;                                 Bit 5-7: Not used (always 0).
  17869. ; DF_SZ    $5C6B   1   IY+$31   The number of lines (including one blank line) in the lower part of the screen.
  17870. ; S_TOP    $5C6C   2   IY+$32   The number of the top program line in automatic listings.
  17871. ; OLDPPC   $5C6E   2   IY+$34   Line number to which CONTINUE jumps.
  17872. ; OSPPC    $5C70   1   IY+$36   Number within line of statement to which CONTINUE jumps.
  17873. ; FLAGX    $5C71   1   IY+$37   Flags:
  17874. ;                                 Bit 0  : 1=Simple string complete so delete old copy.
  17875. ;                                 Bit 1  : 1=Indicates new variable, 0=Variable exists.
  17876. ;                                 Bit 2-4: Not used (always 0).
  17877. ;                                 Bit 5  : 1=INPUT mode.
  17878. ;                                 Bit 6  : 1=Numeric variable, 0=String variable. Holds nature of existing variable.
  17879. ;                                 Bit 7  : 1=Using INPUT LINE.
  17880. ; STRLEN   $5C72   2   IY+$38   Length of string type destination in assignment.
  17881. ; T_ADDR   $5C74   2   IY+$3A   Address of next item in syntax table.
  17882. ; SEED     $5C76   2   IY+$3C   The seed for RND. Set by RANDOMIZE.
  17883. ; FRAMES   $5C78   3   IY+$3E   3 byte (least significant byte first), frame counter incremented every 20ms.
  17884. ; UDG      $5C7B   2   IY+$41   Address of first user-defined graphic. Can be changed to save space by having fewer
  17885. ;                               user-defined characters.
  17886. ; COORDS   $5C7D   1   IY+$43   X-coordinate of last point plotted.
  17887. ;          $5C7E   1   IY+$44   Y-coordinate of last point plotted.
  17888. ; P_POSN   $5C7F   1   IY+$45   33-column number of printer position.
  17889. ; PRCC     $5C80   2   IY+$46   Full address of next position for LPRINT to print at (in ZX Printer buffer).
  17890. ;                               Legal values $5B00 - $5B1F. [Not used in 128K mode]
  17891. ; ECHO_E   $5C82   2   IY+$48   33-column number and 24-line number (in lower half) of end of input buffer.
  17892. ; DF_CC    $5C84   2   IY+$4A   Address in display file of PRINT position.
  17893. ; DF_CCL   $5C86   2   IY+$4C   Like DF CC for lower part of screen.
  17894. ; S_POSN   $5C88   1   IY+$4E   33-column number for PRINT position.
  17895. ;          $5C89   1   IY+$4F   24-line number for PRINT position.
  17896. ; SPOSNL   $5C8A   2   IY+$50   Like S_POSN for lower part.
  17897. ; SCR_CT   $5C8C   1   IY+$52   Counts scrolls - it is always 1 more than the number of scrolls that will be done before
  17898. ;                               stopping with 'scroll?'.
  17899. ; ATTR_P   $5C8D   1   IY+$53   Permanent current colours, etc, as set up by colour statements.
  17900. ; MASK_P   $5C8E   1   IY+$54   Used for transparent colours, etc. Any bit that is 1 shows that the corresponding attribute
  17901. ;                               bit is taken not from ATTR_P, but from what is already on the screen.
  17902. ; ATTR_T   $5C8F   1   IY+$55   Temporary current colours (as set up by colour items).
  17903. ; MASK_T   $5C90   1   IY+$56   Like MASK_P, but temporary.
  17904. ; P_FLAG   $5C91   1   IY+$57   Flags:
  17905. ;                                 Bit 0: 1=OVER 1, 0=OVER 0.
  17906. ;                                 Bit 1: Not used (always 0).
  17907. ;                                 Bit 2: 1=INVERSE 1, 0=INVERSE 0.
  17908. ;                                 Bit 3: Not used (always 0).
  17909. ;                                 Bit 4: 1=Using INK 9.
  17910. ;                                 Bit 5: Not used (always 0).
  17911. ;                                 Bit 6: 1=Using PAPER 9.
  17912. ;                                 Bit 7: Not used (always 0).
  17913. ; MEMBOT   $5C92  30   IY+$58   Calculator's memory area - used to store numbers that cannot conveniently be put on the
  17914. ;                               calculator stack.
  17915. ;          $5CB0   2   IY+$76   Not used on standard Spectrum. [Used by ZX Interface 1 Edition 2 for printer WIDTH]
  17916. ; RAMTOP   $5CB2   2   IY+$78   Address of last byte of BASIC system area.
  17917. ; P_RAMT   $5CB4   2   IY+$7A   Address of last byte of physical RAM.
  17918.  
  17919.  
  17920. ; ==========
  17921. ; Memory Map
  17922. ; ==========
  17923. ; The conventional memory is used as follows:
  17924. ;
  17925. ; +---------+-----------+------------+--------------+-------------+--
  17926. ; | BASIC   |  Display  | Attributes |  New System  |   System    |
  17927. ; |  ROM    |   File    |    File    |  Variables   |  Variables  |
  17928. ; +---------+-----------+------------+--------------+-------------+--
  17929. ; ^         ^           ^            ^              ^             ^
  17930. ; $0000   $4000       $5800        $5B00          $5C00         $5CB6 = CHANS
  17931. ;
  17932. ;
  17933. ;  --+----------+---+---------+-----------+---+------------+--+---+--
  17934. ;    | Channel  |$80|  BASIC  | Variables |$80| Edit Line  |NL|$80|
  17935. ;    |   Info   |   | Program |   Area    |   | or Command |  |   |
  17936. ;  --+----------+---+---------+-----------+---+------------+--+---+--
  17937. ;    ^              ^         ^               ^                   ^
  17938. ;  CHANS           PROG      VARS           E_LINE              WORKSP
  17939. ;
  17940. ;
  17941. ;                             ------>         <-------  <------
  17942. ;  --+-------+--+------------+-------+-------+---------+-------+-+---+------+
  17943. ;    | INPUT |NL| Temporary  | Calc. | Spare | Machine | GOSUB |?|$3E| UDGs |
  17944. ;    | data  |  | Work Space | Stack |       |  Stack  | Stack | |   |      |
  17945. ;  --+-------+--+------------+-------+-------+---------+-------+-+---+------+
  17946. ;    ^                       ^       ^       ^                   ^   ^      ^
  17947. ;  WORKSP                  STKBOT  STKEND   SP               RAMTOP UDG  P_RAMT
  17948.  
  17949.  
  17950. ; ==========
  17951. ; I Register
  17952. ; ==========
  17953. ; The I register is used along with the R register by the Z80 for automatic memory refreshing. Setting the I register to a value between $40 and $7F
  17954. ; causes memory refreshes to occur to the lower 16K RAM. This RAM is contended with the ULA which uses it for the generation of the video display.
  17955. ; The memory refreshes get interpreted by the ULA as the CPU requesting to access the lower 16K RAM bank very rapidly and very often. The ULA is not
  17956. ; able to handle reads at such a high frequency, with the consequence that it fails to fetch and output the next screen byte. Instead it uses re-uses
  17957. ; the byte previously read. This causes a visible corruption to the video display output, often referred to a 'snow', although no actual corruption
  17958. ; occurs to the video display RAM. This also happens when the I register is set to a value between $C0 and $FF when a contended RAM bank is paged in
  17959. ; and, unlike the Spectrum 16K/48K, can lead to a machine crash.
  17960.  
  17961.  
  17962. ; ===================
  17963. ; Extending 128 BASIC
  17964. ; ===================
  17965. ; Full details on the mechanism and an example program with source code listing is available for download at www.fruitcake.plus.com.
  17966. ;
  17967. ; The new system variable RAMRST normally contains a RST $08 instruction and is used with the following byte in RAMERR to allow
  17968. ; 128 BASIC mode to produce a standard Spectrum error report via ROM 1. Replacing the RST $08 instruction with a JP instruction
  17969. ; allows control to be passed to a user routine when certain 128 BASIC errors occur. The low byte of the jump destination
  17970. ; address is held in the RAMERR system variable, and so this will hold the error code value ranging from $00 to $FF. The high
  17971. ; byte of the destination address will be taken from system variable BAUD, and so this must be requisitioned for use by
  17972. ; the extended BASIC parser. This means that whilst the extended BASIC mechanism is active, the Spectrum 128 RS232 commands
  17973. ; cannot be used. This limitation can be overcome by temporarily disabling the paging mechanism by restoring the RST $08 instruction
  17974. ; in RAMRST and restoring the baud rate constant in BAUD, then executing the required RS232 commands. Afterwards, the extended
  17975. ; BASIC parser can be re-enabled by resetting the BAUD and RAMRST system variables.
  17976. ;
  17977. ; When an error occurs, RAMERR will be set by ROM 0 before calling RAMRST. With a JP instruction installed at RAMRST, the
  17978. ; destination address could in theory range from any address within a page of memory (256 bytes). In practice, ROM 0
  17979. ; only uses the RAMRST routine for 13 error codes, and then only for certain situations. Most of these errors are produced
  17980. ; for very obscure scenarios but fortunately ROM 0 will produce error "C Nonsense in BASIC" when it cannot identify the first
  17981. ; keyword of a BASIC statement. This will cause the extended BASIC mechanism to be invoked and it can then have a go at parsing
  17982. ; the unknown word. Since all keywords in 128 BASIC mode have to be typed in letter by letter, the extended BASIC parser can support
  17983. ; meaningful command names and is not limited to extensions of standard keywords as is the case with the mechanism offer by the
  17984. ; ZX Interface 1.
  17985.  
  17986.  
  17987. ; ===================
  17988. ; Screen File Formats
  17989. ; ===================
  17990. ; The two screens available on the Spectrum 128, the normal screen in RAM bank 5 ($4000-$5AFF) and the shadow screen in
  17991. ; RAM bank 7 ($C000-$FFFF), both use the same file format.
  17992. ;
  17993. ; ------------
  17994. ; Display File
  17995. ; ------------
  17996. ; The display file consists of 3 areas, each consisting of 8 characters rows, with each row consisting of 8 pixel lines.
  17997. ; Each pixel line consists of 32 cell columns, with each cell consisting of a byte that represents 8 pixels.
  17998. ;
  17999. ; The address of a particular cell is formed as follows:
  18000. ;
  18001. ;      +---+---+---+---+---+---+---+---+  +---+---+---+---+---+---+---+---+
  18002. ;      | s | 1 | 0 | a | a | l | l | l |  | r | r | r | c | c | c | c | c |
  18003. ;      +---+---+---+---+---+---+---+---+  +---+---+---+---+---+---+---+---+
  18004. ; Bit:  15  14  13  12  11  10   9   8      7   6   5   4   3   2   1   0
  18005. ;
  18006. ; where: s     = Screen (0-1: 0=Normal screen, 1=Shadow Screen)
  18007. ;        aa    = Area   (0-2)
  18008. ;        rrr   = Row    (0-7)
  18009. ;        lll   = Line   (0-7)
  18010. ;        ccccc = Column (0-31)
  18011. ;
  18012. ; An area value of 3 denotes the attributes file, which consists of a different format.
  18013. ;
  18014. ; ---------------
  18015. ; Attributes File
  18016. ; ---------------
  18017. ; The attributes file consists of 24 characters rows, with each row consisting of 32 cell columns.
  18018. ; Each cell consisting of a byte that holds the colour information.
  18019. ;
  18020. ; The address of a particular cell is formed as follows:
  18021. ;
  18022. ;      +---+---+---+---+---+---+---+---+  +---+---+---+---+---+---+---+---+
  18023. ;      | s | 1 | 0 | 1 | 1 | 0 | r | r |  | r | r | r | c | c | c | c | c |
  18024. ;      +---+---+---+---+---+---+---+---+  +---+---+---+---+---+---+---+---+
  18025. ; Bit:  15  14  13  12  11  10   9   8      7   6   5   4   3   2   1   0
  18026. ;
  18027. ; where: s     = Screen (0-1: 0=Normal screen, 1=Shadow Screen)
  18028. ;        rrrrr = Row    (0-23)
  18029. ;        ccccc = Column (0-31)
  18030. ;
  18031. ;
  18032. ; Each cell holds a byte of colour information:
  18033. ;
  18034. ;      +---+---+---+---+---+---+---+---+
  18035. ;      | f | b | p | p | p | i | i | i |
  18036. ;      +---+---+---+---+---+---+---+---+
  18037. ; Bit:   7   6   5   4   3   2   1   0
  18038. ;
  18039. ; where: f   = Flash  (0-1: 0=Off, 1=On)
  18040. ;        b   = Bright (0-1: 0=Off, 1=On)
  18041. ;        ppp = Paper  (0-7: 0=Black, 1=Blue, 2=Red, 3=Magenta, 4=Green, 5=Cyan, 6=Yellow, 7=White)
  18042. ;        iii = Ink    (0-7: 0=Black, 1=Blue, 2=Red, 3=Magenta, 4=Green, 5=Cyan, 6=Yellow, 7=White)
  18043. ;
  18044. ; -----------------------------------------------------------
  18045. ; Address Conversion Between Display File and Attributes File
  18046. ; -----------------------------------------------------------
  18047. ; The address of the attribute cell corresponding to an address in the display file can be constructed by moving bits 11 to 12 (the area value)
  18048. ; to bit positions 8 to 9, setting bit 10 to 0 and setting bits 11 to 12 to 1.
  18049. ;
  18050. ; The address of the display file character cell corresponding to an address in the attributes file can be constructed by moving bits 8 to 9 (the row value)
  18051. ; to bit positions 11 to 12, and then setting bits 8 to 9 to 0.
  18052.  
  18053.  
  18054. ; ==================
  18055. ; Standard I/O Ports
  18056. ; ==================
  18057.  
  18058. ; --------
  18059. ; Port $FE
  18060. ; --------
  18061. ; This controls the cassette interface, the speaker, the border colour and is used to read the keyboard.
  18062. ; Since it is the ULA that controls these facilities, it will introduce a delay when accessing the port if
  18063. ; it is busy at the time, and hence I/O port $FE is subject to contention.
  18064. ;
  18065. ; OUTPUT:
  18066. ;
  18067. ; Bit 0-2: Border colour  (0=Black, 1=Blue, 2=Red, 3=Magenta, 4=Green, 5=Cyan, 6=Yellow, 7=White).
  18068. ; Bit 3  : MIC output     (1=Off, 0=On).
  18069. ; Bit 4  : Speaker output (1=On, 0=Off).
  18070. ; Bit 5-7: Not used.
  18071. ;
  18072. ; INPUT:
  18073. ;
  18074. ; Upper byte selects keyboard row to read.
  18075. ;
  18076. ;          Bit0  Bit1  Bit2  Bit3  Bit4    Bit4  Bit3  Bit2  Bit1  Bit0
  18077. ;          ----  ----  ----  ----  ----    ----  ----  ----  ----  ----
  18078. ; $F7FE =    1     2     3     4     5       6     7     8     9     0   = $EFFE
  18079. ; $FBFE =    Q     W     E     R     T       Y     U     I     O     P   = $DFFE
  18080. ; $FDFE =    A     S     D     F     G       H     J     K     L   ENTER = $BFFE
  18081. ; $FEFE =  SHIFT   Z     X     C     V       B     N     M    SYM  SPACE = $7FFE
  18082. ;
  18083. ; Bit 5: Not used (always 1).
  18084. ; Bit 6: EAR input.
  18085. ; Bit 7: Not used (always 1).
  18086.  
  18087.  
  18088. ; ======================
  18089. ; Cassette Header Format
  18090. ; ======================
  18091. ;
  18092. ; A file consists of a header block followed by a data block. Each block begins with a flag that
  18093. ; indicates whether it is a header block or a data block. Next are the header or data bytes,
  18094. ; and finally a checksum of the flag and header/data bytes.
  18095. ;
  18096. ; Flag     - A value of $00 for a header and $FF for a data block.
  18097. ; Bytes    - The bytes forming the header information or the file data.
  18098. ; Checksum - An XOR checksum of the Flag and Bytes fields.
  18099. ;
  18100. ; The header information consists of 17 bytes and these describe the size and type of data that the
  18101. ; data block contains.
  18102. ;
  18103. ; The header bytes have the following meaning:
  18104. ;   Byte  $00    : File type - $00=Program, $01=Numeric array, $02=Character array, $03=Code/Screen$.
  18105. ;   Bytes $01-$0A: File name, padding with trailing spaces.
  18106. ;   Bytes $0B-$0C: Length of program/code block/screen$/array ($1B00 for screen$).
  18107. ;   Bytes $0D-$0E: For a program, it holds the auto-run line number ($80 in byte $0E if no auto-run).
  18108. ;                  For code block/screen$ it holds the start address ($4000 for screen$).
  18109. ;                  For an array, it holds the variable name in byte $0E.
  18110. ;   Bytes $0F-$10: Offset to the variables (i.e. length of program) if a program.
  18111.  
  18112.  
  18113. ; ================================================
  18114. ; AY-3-8912 Programmable Sound Generator Registers
  18115. ; ================================================
  18116. ; This is controlled through output I/O port $FFFD. It is driven from a 1.77345MHz clock.
  18117. ;
  18118. ; -----------------
  18119. ; Registers 0 and 1 (Channel A Tone Generator)
  18120. ; -----------------
  18121. ; Forms a 12 bit pitch control for sound channel A. The basic unit of tone is the clock
  18122. ; frequency divided by 16, i.e. 110.841KHz. With a 12 bit counter range, 4095 different
  18123. ; frequencies from 27.067Hz to 110.841KHz (in increments of 27.067Hz) can be generated.
  18124. ;
  18125. ;   Bits 0-7  : Contents of register 0.
  18126. ;   Bits 8-11 : Contents of lower nibble of register 1.
  18127. ;   Bits 12-15: Not used.
  18128. ;
  18129. ; -----------------
  18130. ; Registers 2 and 3 (Channel B Tone Generator)
  18131. ; -----------------
  18132. ; Forms a 12 bit pitch control for sound channel B.
  18133. ;
  18134. ;   Bits 0-7  : Contents of register 2.
  18135. ;   Bits 8-11 : Contents of lower nibble of register 3.
  18136. ;   Bits 12-15: Not used.
  18137. ;
  18138. ; -----------------
  18139. ; Registers 4 and 5 (Channel C Tone Generator)
  18140. ; -----------------
  18141. ; Forms a 12 bit pitch control for sound channel C.
  18142. ;
  18143. ;   Bits 0-7  : Contents of register 4.
  18144. ;   Bits 8-11 : Contents of lower nibble of register 5.
  18145. ;   Bits 12-15: Not used.
  18146. ;
  18147. ; ----------
  18148. ; Register 6 (Noise Generator)
  18149. ; ----------
  18150. ; The frequency of the noise is obtained in the PSG by first counting down the input
  18151. ; clock by 16 (i.e. 110.841KHz), then by further counting down the result by the programmed
  18152. ; 5 bit noise period value held in bits 0-4 of register 6. With a 5 bit counter range, 31 different
  18153. ; frequencies from 3.576KHz to 110.841KHz (in increments of 3.576KHz) can be generated.
  18154. ;
  18155. ; ----------
  18156. ; Register 7 (Mixer - I/O Enable)
  18157. ; ----------
  18158. ; This controls the enable status of the noise and tone mixers for the three channels,
  18159. ; and also controls the I/O port used to drive the RS232 and Keypad sockets.
  18160. ;
  18161. ; Bit 0: Channel A Tone Enable (0=enabled).
  18162. ; Bit 1: Channel B Tone Enable (0=enabled).
  18163. ; Bit 2: Channel C Tone Enable (0=enabled).
  18164. ; Bit 3: Channel A Noise Enable (0=enabled).
  18165. ; Bit 4: Channel B Noise Enable (0=enabled).
  18166. ; Bit 5: Channel C Noise Enable (0=enabled).
  18167. ; Bit 6: I/O Port Enable (0=input, 1=output).
  18168. ; Bit 7: Not used.
  18169. ;
  18170. ; ----------
  18171. ; Register 8 (Channel A Volume)
  18172. ; ----------
  18173. ; This controls the volume of channel A.
  18174. ;
  18175. ; Bits 0-4: Channel A volume level.
  18176. ; Bit 5   : 1=Use envelope defined by register 13 and ignore the volume setting.
  18177. ; Bits 6-7: Not used.
  18178. ;
  18179. ; ----------
  18180. ; Register 9 (Channel B Volume)
  18181. ; ----------
  18182. ; This controls the volume of channel B.
  18183. ;
  18184. ; Bits 0-4: Channel B volume level.
  18185. ; Bit 5   : 1=Use envelope defined by register 13 and ignore the volume setting.
  18186. ; Bits 6-7: Not used.
  18187. ;
  18188. ; -----------
  18189. ; Register 10 (Channel C Volume)
  18190. ; -----------
  18191. ; This controls the volume of channel C.
  18192. ;
  18193. ; Bits 0-4: Channel C volume level.
  18194. ; Bit 5   : 1=Use envelope defined by register 13 and ignore the volume setting.
  18195. ; Bits 6-7: Not used.
  18196. ;
  18197. ; ------------------
  18198. ; Register 11 and 12 (Envelope Period)
  18199. ; ------------------
  18200. ; These registers allow the frequency of the envelope to be selected.
  18201. ; The frequency of the envelope is obtained in the PSG by first counting down
  18202. ; the input clock by 256 (6.927KHz), then further counting down the result by the programmed
  18203. ; 16 bit envelope period value. With a 16 bit counter range, 65535 different
  18204. ; frequencies from 1.691Hz to 110.841KHz (in increments of 1.691Hz) can be generated.
  18205. ;
  18206. ; Bits 0-7 : Contents of register 11.
  18207. ; Bits 8-15: Contents of register 12.
  18208. ;
  18209. ; -----------
  18210. ; Register 13 (Envelope Shape)
  18211. ; -----------
  18212. ; This register allows the shape of the envelope to be selected.
  18213. ; The envelope generator further counts down the envelope frequency by 16, producing
  18214. ; a 16-state per cycle envelope pattern. The particular shape and cycle pattern of any
  18215. ; desired envelope is accomplished by controlling the count pattern of the 4 bit counter
  18216. ; and by defining a single cycle or repeat cycle pattern.
  18217. ;
  18218. ; Bit 0   : Hold.
  18219. ; Bit 1   : Alternate.
  18220. ; Bit 2   : Attack.
  18221. ; Bit 3   : Continue.
  18222. ; Bits 4-7: Not used.
  18223. ;
  18224. ; These control bits can produce the following envelope waveforms:
  18225. ;
  18226. ; Bit: 3 2 1 0
  18227. ;      -------
  18228. ;
  18229. ;      0 0 X X  \                         Single decay then off.
  18230. ;                \______________________  Used by W0 PLAY command.
  18231. ;
  18232. ;
  18233. ;      0 1 X X   /|                       Single attack then off.
  18234. ;               / |_____________________  Used by W1 PLAY command.
  18235. ;
  18236. ;
  18237. ;      1 0 0 0  \ |\ |\ |\ |\ |\ |\ |\ |  Repeated decay.
  18238. ;                \| \| \| \| \| \| \| \|  Used by W4 PLAY command.
  18239. ;
  18240. ;
  18241. ;      1 0 0 1  \                         Single decay then off.
  18242. ;                \______________________  Not used PLAY command (use W0 instead).
  18243. ;
  18244. ;
  18245. ;      1 0 1 0  \  /\  /\  /\  /\  /\  /  Repeated decay-attack.
  18246. ;                \/  \/  \/  \/  \/  \/   Used by W7 PLAY command.
  18247. ;
  18248. ;                  _____________________
  18249. ;      1 0 1 1  \ |                       Single decay then hold.
  18250. ;                \|                       Used by W2 PLAY command.
  18251. ;
  18252. ;
  18253. ;      1 1 0 0   /| /| /| /| /| /| /| /|  Repeated attack.
  18254. ;               / |/ |/ |/ |/ |/ |/ |/ |  Used by W5 PLAY command.
  18255. ;
  18256. ;                 ______________________
  18257. ;      1 1 0 1   /                        Single attack then hold.
  18258. ;               /                         Used by W3 PLAY command.
  18259. ;
  18260. ;
  18261. ;      1 1 1 0   /\  /\  /\  /\  /\  /\   Repeated attack-decay.
  18262. ;               /  \/  \/  \/  \/  \/  \  Used by W6 PLAY command.
  18263. ;
  18264. ;
  18265. ;      1 1 1 1   /|                       Single attack then off.
  18266. ;               / |_____________________  Not used by PLAY command (use W1 instead).
  18267. ;
  18268. ;
  18269. ;           -->|  |<--  Envelope Period
  18270. ;
  18271. ; -----------
  18272. ; Register 14 (I/O Port)
  18273. ; -----------
  18274. ; This controls the RS232 and Keypad sockets.
  18275. ; Once the register has been selected, it can be read via port $FFFD and written via port $BFFD.
  18276. ;
  18277. ; Bit 0: KEYPAD CTS (out) - 0=Spectrum ready to receive, 1=Busy
  18278. ; Bit 1: KEYPAD RXD (out) - 0=Transmit high bit,         1=Transmit low bit
  18279. ; Bit 2: RS232  CTS (out) - 0=Spectrum ready to receive, 1=Busy
  18280. ; Bit 3: RS232  RXD (out) - 0=Transmit high bit,         1=Transmit low bit
  18281. ; Bit 4: KEYPAD DTR (in)  - 0=Keypad ready for data,     1=Busy
  18282. ; Bit 5: KEYPAD TXD (in)  - 0=Receive high bit,          1=Receive low bit
  18283. ; Bit 6: RS232  DTR (in)  - 0=Device ready for data,     1=Busy
  18284. ; Bit 7: RS232  TXD (in)  - 0=Receive high bit,          1=Receive low bit
  18285. ;
  18286. ; The RS232 port also doubles up as a MIDI port, with communications to MIDI devices occurring at 31250 baud.
  18287. ; Commands and data can be sent to MIDI devices. Command bytes have the most significant bit set, whereas data bytes have it reset.
  18288.  
  18289.  
  18290. ; ===============
  18291. ; Socket Pin Outs
  18292. ; ===============
  18293.  
  18294. ; -----------------
  18295. ; RS232/MIDI Socket
  18296. ; -----------------
  18297. ; The RS232/MIDI socket is controlled by register 14 of the AY-3-8912 sound generator.
  18298. ;    _____________
  18299. ;  _|             |
  18300. ; |               | Front View
  18301. ; |_  6 5 4 3 2 1 |
  18302. ;   |_|_|_|_|_|_|_|
  18303. ;
  18304. ; Pin   Signal
  18305. ; ---   ------
  18306. ; 1     0V
  18307. ; 2     TXD - In  (Bit 7)
  18308. ; 3     RXD - Out (Bit 3)
  18309. ; 4     DTR - In  (Bit 6)
  18310. ; 5     CTS - Out (Bit 2)
  18311. ; 6     12V
  18312.  
  18313. ; -------------
  18314. ; Keypad Socket
  18315. ; -------------
  18316. ; The keypad socket is controlled by register 14 of the AY-3-8912 sound generator.
  18317. ; Only bits 0 and 5 are used for communications with the keypad (pins 2 and 5).
  18318. ; Writing a 1 to bit 0 (pin 2) will eventually force the keypad to reset.
  18319. ; Summary information about the keypad and its communications protocol can be found in the Spectrum 128 Service Manual and
  18320. ; detailed description can be found at www.fruitcake.plus.com.
  18321. ;    _____________
  18322. ;  _|             |
  18323. ; |               | Front View
  18324. ; |_  6 5 4 3 2 1 |
  18325. ;   |_|_|_|_|_|_|_|
  18326. ;
  18327. ; Pin   Signal
  18328. ; ---   ------
  18329. ; 1     0V
  18330. ; 2     OUT - Out (Bit 0)
  18331. ; 3     n/u - In  (Bit 4)
  18332. ; 4     n/u - Out (Bit 1)
  18333. ; 5     IN  - In  (Bit 5)
  18334. ; 6     12V
  18335. ;
  18336. ; n/u = Not used for keypad communications.
  18337. ;
  18338. ; The keypad socket was later used by Amstrad to support a lightgun. There are no routines within the ROMs to handle communications
  18339. ; to the lightgun so each game has to implement its own control software. Only bits 4 and 5 are used for communications with the lightgun (pins 3 and 5).
  18340. ; The connections to the lightgun are as follows:
  18341. ;
  18342. ; Pin   Signal
  18343. ; ---   ------
  18344. ; 1     0V
  18345. ; 2     n/u     - Out (Bit 0)
  18346. ; 3     SENSOR  - In  (Bit 4)
  18347. ; 4     n/u     - Out (Bit 1)
  18348. ; 5     TRIGGER - In  (Bit 5)
  18349. ; 6     12V
  18350. ;
  18351. ; n/u = Not used for lightgun communications.
  18352.  
  18353. ; --------------
  18354. ; Monitor Socket
  18355. ; --------------
  18356. ;
  18357. ;         *******
  18358. ;      ***       ***
  18359. ;    **             **
  18360. ;   * --7--     --6-- *
  18361. ;  *         |         *
  18362. ; *  --3--   8   --1--  *  Front View
  18363. ; *          |          *
  18364. ; *      /       \      *
  18365. ;  *    5    |    4    *
  18366. ;   *  /     2     \  *
  18367. ;    **      |      **
  18368. ;      ***       ***
  18369. ;         *******
  18370. ;
  18371. ; Pin   Signal           Level
  18372. ; ---   ------           -----
  18373. ; 1     Composite PAL    1.2V pk-pk (75 Ohms)
  18374. ; 2     0 Volts          0V
  18375. ; 3     Bright Output    TTL
  18376. ; 4     Composite Sync   TTL
  18377. ; 5     Vertical Sync    TTL
  18378. ; 6     Green            TTL
  18379. ; 7     Red              TTL
  18380. ; 8     Blue             TTL
  18381. ;
  18382. ; A detailed description of the monitor socket and circuitry, and how to construct a suitable RGB SCART cable
  18383. ; can be found at www.fruitcake.plus.com.
  18384.  
  18385. ; --------------
  18386. ; Edge Connector
  18387. ; --------------
  18388. ;
  18389. ; Pin   Side A   Side B
  18390. ; ---   ------   ------
  18391. ; 1     A15      A14
  18392. ; 2     A13      A12
  18393. ; 3     D7       +5V
  18394. ; 4     n/u      +9V
  18395. ; 5     Slot     Slot
  18396. ; 6     D0       0V
  18397. ; 7     D1       0V
  18398. ; 8     D2       /CLK
  18399. ; 9     D6       A0
  18400. ; 10    D5       A1
  18401. ; 11    D3       A2
  18402. ; 12    D4       A3
  18403. ; 13    /INT     /IORQULA
  18404. ; 14    /NMI     0V
  18405. ; 15    /HALT    n/u (On 48K Spectrum = VIDEO)
  18406. ; 16    /MREQ    n/u (On 48K Spectrum = /Y)
  18407. ; 17    /IORQ    n/u (On 48K Spectrum = V)
  18408. ; 18    /RD      n/u (On 48K Spectrum = U)
  18409. ; 19    /WR      /BUSREQ
  18410. ; 20    -5V      /RESET
  18411. ; 21    /WAIT    A7
  18412. ; 22    +12V     A6
  18413. ; 23    -12V     A5
  18414. ; 24    /M1      A4
  18415. ; 25    /RFSH    /ROMCS
  18416. ; 26    A8       /BUSACK
  18417. ; 27    A10      A9
  18418. ; 28    n/u      A11
  18419. ;
  18420. ; Side A=Component Side, Side B=Underside.
  18421. ; n/u = Not used.
  18422.  
  18423.