Subversion Repositories pentevo

Rev

Rev 550 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
384 savelij 1
 
403 savelij 2
;www.fruitcake.plus.com
3
 
596 savelij 4
;LAST UPDATE: 10.02.2013 savelij
403 savelij 5
 
384 savelij 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.
596 savelij 1051
        DEFW KP_SCAN-$0100 ; $3B01. [*BUG* - The address jumps into the middle of the keypad decode routine in ROM 1. It
384 savelij 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
 
596 savelij 7337
        LD   HL,0X13;3    ; $0003. Address of a $FF byte within ROM 1, used to generate error report "0 OK".
384 savelij 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