1 |
8 |
gdevic |
;************************************************************************
|
2 |
|
|
;** An Assembly File Listing to generate a 16K ROM for the ZX Spectrum **
|
3 |
|
|
;************************************************************************
|
4 |
|
|
;
|
5 |
|
|
; 11-10-2014:
|
6 |
|
|
; This version has been updated to correctly handle the NMI jump.
|
7 |
|
|
;
|
8 |
|
|
; -------------------------
|
9 |
|
|
; Last updated: 13-DEC-2004
|
10 |
|
|
; -------------------------
|
11 |
|
|
|
12 |
|
|
; TASM cross-assembler directives.
|
13 |
|
|
; ( comment out, perhaps, for other assemblers - see Notes at end.)
|
14 |
|
|
|
15 |
|
|
#define DEFB .BYTE
|
16 |
|
|
#define DEFW .WORD
|
17 |
|
|
#define DEFM .TEXT
|
18 |
|
|
#define ORG .ORG
|
19 |
|
|
#define EQU .EQU
|
20 |
|
|
#define equ .EQU
|
21 |
|
|
|
22 |
|
|
; It is always a good idea to anchor, using ORGs, important sections such as
|
23 |
|
|
; the character bitmaps so that they don't move as code is added and removed.
|
24 |
|
|
|
25 |
|
|
; Generally most approaches try to maintain main entry points as they are
|
26 |
|
|
; often used by third-party software.
|
27 |
|
|
|
28 |
|
|
ORG 0000
|
29 |
|
|
|
30 |
|
|
;*****************************************
|
31 |
|
|
;** Part 1. RESTART ROUTINES AND TABLES **
|
32 |
|
|
;*****************************************
|
33 |
|
|
|
34 |
|
|
; -----------
|
35 |
|
|
; THE 'START'
|
36 |
|
|
; -----------
|
37 |
|
|
; At switch on, the Z80 chip is in Interrupt Mode 0.
|
38 |
|
|
; The Spectrum uses Interrupt Mode 1.
|
39 |
|
|
; This location can also be 'called' to reset the machine.
|
40 |
|
|
; Typically with PRINT USR 0.
|
41 |
|
|
|
42 |
|
|
;; START
|
43 |
|
|
L0000: DI ; Disable Interrupts.
|
44 |
|
|
XOR A ; Signal coming from START.
|
45 |
|
|
LD DE,$FFFF ; Set pointer to top of possible physical RAM.
|
46 |
|
|
JP L11CB ; Jump forward to common code at START-NEW.
|
47 |
|
|
|
48 |
|
|
; -------------------
|
49 |
|
|
; THE 'ERROR' RESTART
|
50 |
|
|
; -------------------
|
51 |
|
|
; The error pointer is made to point to the position of the error to enable
|
52 |
|
|
; the editor to highlight the error position if it occurred during syntax
|
53 |
|
|
; checking. It is used at 37 places in the program. An instruction fetch
|
54 |
|
|
; on address $0008 may page in a peripheral ROM such as the Sinclair
|
55 |
|
|
; Interface 1 or Disciple Disk Interface. This was not an original design
|
56 |
|
|
; concept and not all errors pass through here.
|
57 |
|
|
|
58 |
|
|
;; ERROR-1
|
59 |
|
|
L0008: LD HL,($5C5D) ; Fetch the character address from CH_ADD.
|
60 |
|
|
LD ($5C5F),HL ; Copy it to the error pointer X_PTR.
|
61 |
|
|
JR L0053 ; Forward to continue at ERROR-2.
|
62 |
|
|
|
63 |
|
|
; -----------------------------
|
64 |
|
|
; THE 'PRINT CHARACTER' RESTART
|
65 |
|
|
; -----------------------------
|
66 |
|
|
; The A register holds the code of the character that is to be sent to
|
67 |
|
|
; the output stream of the current channel. The alternate register set is
|
68 |
|
|
; used to output a character in the A register so there is no need to
|
69 |
|
|
; preserve any of the current main registers (HL, DE, BC).
|
70 |
|
|
; This restart is used 21 times.
|
71 |
|
|
|
72 |
|
|
;; PRINT-A
|
73 |
|
|
L0010: JP L15F2 ; Jump forward to continue at PRINT-A-2.
|
74 |
|
|
|
75 |
|
|
; ---
|
76 |
|
|
|
77 |
|
|
DEFB $FF, $FF, $FF ; Five unused locations.
|
78 |
|
|
DEFB $FF, $FF ;
|
79 |
|
|
|
80 |
|
|
; -------------------------------
|
81 |
|
|
; THE 'COLLECT CHARACTER' RESTART
|
82 |
|
|
; -------------------------------
|
83 |
|
|
; The contents of the location currently addressed by CH_ADD are fetched.
|
84 |
|
|
; A return is made if the value represents a character that has
|
85 |
|
|
; relevance to the BASIC parser. Otherwise CH_ADD is incremented and the
|
86 |
|
|
; tests repeated. CH_ADD will be addressing somewhere -
|
87 |
|
|
; 1) in the BASIC program area during line execution.
|
88 |
|
|
; 2) in workspace if evaluating, for example, a string expression.
|
89 |
|
|
; 3) in the edit buffer if parsing a direct command or a new BASIC line.
|
90 |
|
|
; 4) in workspace if accepting input but not that from INPUT LINE.
|
91 |
|
|
|
92 |
|
|
;; GET-CHAR
|
93 |
|
|
L0018: LD HL,($5C5D) ; fetch the address from CH_ADD.
|
94 |
|
|
LD A,(HL) ; use it to pick up current character.
|
95 |
|
|
|
96 |
|
|
;; TEST-CHAR
|
97 |
|
|
L001C: CALL L007D ; routine SKIP-OVER tests if the character is
|
98 |
|
|
; relevant.
|
99 |
|
|
RET NC ; Return if it is significant.
|
100 |
|
|
|
101 |
|
|
; ------------------------------------
|
102 |
|
|
; THE 'COLLECT NEXT CHARACTER' RESTART
|
103 |
|
|
; ------------------------------------
|
104 |
|
|
; As the BASIC commands and expressions are interpreted, this routine is
|
105 |
|
|
; called repeatedly to step along the line. It is used 83 times.
|
106 |
|
|
|
107 |
|
|
;; NEXT-CHAR
|
108 |
|
|
L0020: CALL L0074 ; routine CH-ADD+1 fetches the next immediate
|
109 |
|
|
; character.
|
110 |
|
|
JR L001C ; jump back to TEST-CHAR until a valid
|
111 |
|
|
; character is found.
|
112 |
|
|
|
113 |
|
|
; ---
|
114 |
|
|
|
115 |
|
|
DEFB $FF, $FF, $FF ; unused
|
116 |
|
|
|
117 |
|
|
; -----------------------
|
118 |
|
|
; THE 'CALCULATE' RESTART
|
119 |
|
|
; -----------------------
|
120 |
|
|
; This restart enters the Spectrum's internal, floating-point, stack-based,
|
121 |
|
|
; FORTH-like language.
|
122 |
|
|
; It is further used recursively from within the calculator.
|
123 |
|
|
; It is used on 77 occasions.
|
124 |
|
|
|
125 |
|
|
;; FP-CALC
|
126 |
|
|
L0028: JP L335B ; jump forward to the CALCULATE routine.
|
127 |
|
|
|
128 |
|
|
; ---
|
129 |
|
|
|
130 |
|
|
DEFB $FF, $FF, $FF ; spare - note that on the ZX81, space being a
|
131 |
|
|
DEFB $FF, $FF ; little cramped, these same locations were
|
132 |
|
|
; used for the five-byte end-calc literal.
|
133 |
|
|
|
134 |
|
|
; ------------------------------
|
135 |
|
|
; THE 'CREATE BC SPACES' RESTART
|
136 |
|
|
; ------------------------------
|
137 |
|
|
; This restart is used on only 12 occasions to create BC spaces
|
138 |
|
|
; between workspace and the calculator stack.
|
139 |
|
|
|
140 |
|
|
;; BC-SPACES
|
141 |
|
|
L0030: PUSH BC ; Save number of spaces.
|
142 |
|
|
LD HL,($5C61) ; Fetch WORKSP.
|
143 |
|
|
PUSH HL ; Save address of workspace.
|
144 |
|
|
JP L169E ; Jump forward to continuation code RESERVE.
|
145 |
|
|
|
146 |
|
|
; --------------------------------
|
147 |
|
|
; THE 'MASKABLE INTERRUPT' ROUTINE
|
148 |
|
|
; --------------------------------
|
149 |
|
|
; This routine increments the Spectrum's three-byte FRAMES counter fifty
|
150 |
|
|
; times a second (sixty times a second in the USA ).
|
151 |
|
|
; Both this routine and the called KEYBOARD subroutine use the IY register
|
152 |
|
|
; to access system variables and flags so a user-written program must
|
153 |
|
|
; disable interrupts to make use of the IY register.
|
154 |
|
|
|
155 |
|
|
;; MASK-INT
|
156 |
|
|
L0038: PUSH AF ; Save the registers that will be used but not
|
157 |
|
|
PUSH HL ; the IY register unfortunately.
|
158 |
|
|
LD HL,($5C78) ; Fetch the first two bytes at FRAMES1.
|
159 |
|
|
INC HL ; Increment lowest two bytes of counter.
|
160 |
|
|
LD ($5C78),HL ; Place back in FRAMES1.
|
161 |
|
|
LD A,H ; Test if the result was zero.
|
162 |
|
|
OR L ;
|
163 |
|
|
JR NZ,L0048 ; Forward, if not, to KEY-INT
|
164 |
|
|
|
165 |
|
|
INC (IY+$40) ; otherwise increment FRAMES3 the third byte.
|
166 |
|
|
|
167 |
|
|
; Now save the rest of the main registers and read and decode the keyboard.
|
168 |
|
|
|
169 |
|
|
;; KEY-INT
|
170 |
|
|
L0048: PUSH BC ; Save the other main registers.
|
171 |
|
|
PUSH DE ;
|
172 |
|
|
|
173 |
|
|
CALL L02BF ; Routine KEYBOARD executes a stage in the
|
174 |
|
|
; process of reading a key-press.
|
175 |
|
|
POP DE ;
|
176 |
|
|
POP BC ; Restore registers.
|
177 |
|
|
|
178 |
|
|
POP HL ;
|
179 |
|
|
POP AF ;
|
180 |
|
|
|
181 |
|
|
EI ; Enable Interrupts.
|
182 |
|
|
RET ; Return.
|
183 |
|
|
|
184 |
|
|
; ---------------------
|
185 |
|
|
; THE 'ERROR-2' ROUTINE
|
186 |
|
|
; ---------------------
|
187 |
|
|
; A continuation of the code at 0008.
|
188 |
|
|
; The error code is stored and after clearing down stacks, an indirect jump
|
189 |
|
|
; is made to MAIN-4, etc. to handle the error.
|
190 |
|
|
|
191 |
|
|
;; ERROR-2
|
192 |
|
|
L0053: POP HL ; drop the return address - the location
|
193 |
|
|
; after the RST 08H instruction.
|
194 |
|
|
LD L,(HL) ; fetch the error code that follows.
|
195 |
|
|
; (nice to see this instruction used.)
|
196 |
|
|
|
197 |
|
|
; Note. this entry point is used when out of memory at REPORT-4.
|
198 |
|
|
; The L register has been loaded with the report code but X-PTR is not
|
199 |
|
|
; updated.
|
200 |
|
|
|
201 |
|
|
;; ERROR-3
|
202 |
|
|
L0055: LD (IY+$00),L ; Store it in the system variable ERR_NR.
|
203 |
|
|
LD SP,($5C3D) ; ERR_SP points to an error handler on the
|
204 |
|
|
; machine stack. There may be a hierarchy
|
205 |
|
|
; of routines.
|
206 |
|
|
; To MAIN-4 initially at base.
|
207 |
|
|
; or REPORT-G on line entry.
|
208 |
|
|
; or ED-ERROR when editing.
|
209 |
|
|
; or ED-FULL during ed-enter.
|
210 |
|
|
; or IN-VAR-1 during runtime input etc.
|
211 |
|
|
|
212 |
|
|
JP L16C5 ; Jump to SET-STK to clear the calculator stack
|
213 |
|
|
; and reset MEM to usual place in the systems
|
214 |
|
|
; variables area and then indirectly to MAIN-4,
|
215 |
|
|
; etc.
|
216 |
|
|
|
217 |
|
|
; ---
|
218 |
|
|
|
219 |
|
|
DEFB $FF, $FF, $FF ; Unused locations
|
220 |
|
|
DEFB $FF, $FF, $FF ; before the fixed-position
|
221 |
|
|
DEFB $FF ; NMI routine.
|
222 |
|
|
|
223 |
|
|
; ------------------------------------
|
224 |
|
|
; THE 'NON-MASKABLE INTERRUPT' ROUTINE
|
225 |
|
|
; ------------------------------------
|
226 |
|
|
;
|
227 |
|
|
; There is no NMI switch on the standard Spectrum or its peripherals.
|
228 |
|
|
; When the NMI line is held low, then no matter what the Z80 was doing at
|
229 |
|
|
; the time, it will now execute the code at 66 Hex.
|
230 |
|
|
; This Interrupt Service Routine will jump to location zero if the contents
|
231 |
|
|
; of the system variable NMIADD are zero or return if the location holds a
|
232 |
|
|
; non-zero address. So attaching a simple switch to the NMI as in the book
|
233 |
|
|
; "Spectrum Hardware Manual" causes a reset. The logic was obviously
|
234 |
|
|
; intended to work the other way. Sinclair Research said that, since they
|
235 |
|
|
; had never advertised the NMI, they had no plans to fix the error "until
|
236 |
|
|
; the opportunity arose".
|
237 |
|
|
;
|
238 |
|
|
; Note. The location NMIADD was, in fact, later used by Sinclair Research
|
239 |
|
|
; to enhance the text channel on the ZX Interface 1.
|
240 |
|
|
; On later Amstrad-made Spectrums, and the Brazilian Spectrum, the logic of
|
241 |
|
|
; this routine was indeed reversed but not as at first intended.
|
242 |
|
|
;
|
243 |
|
|
; It can be deduced by looking elsewhere in this ROM that the NMIADD system
|
244 |
|
|
; variable pointed to L121C and that this enabled a Warm Restart to be
|
245 |
|
|
; performed at any time, even while playing machine code games, or while
|
246 |
|
|
; another Spectrum has been allowed to gain control of this one.
|
247 |
|
|
;
|
248 |
|
|
; Software houses would have been able to protect their games from attack by
|
249 |
|
|
; placing two zeros in the NMIADD system variable.
|
250 |
|
|
|
251 |
|
|
;; RESET
|
252 |
|
|
L0066: PUSH AF ; save the
|
253 |
|
|
PUSH HL ; registers.
|
254 |
|
|
LD HL,($5CB0) ; fetch the system variable NMIADD.
|
255 |
|
|
LD A,H ; test address
|
256 |
|
|
OR L ; for zero.
|
257 |
|
|
|
258 |
|
|
; JR NZ,L0070 ; skip to NO-RESET if NOT ZERO
|
259 |
|
|
JR Z,L0070 ; **FIXED**
|
260 |
|
|
|
261 |
|
|
JP (HL) ; jump to routine ( i.e. L0000 )
|
262 |
|
|
|
263 |
|
|
;; NO-RESET
|
264 |
|
|
L0070: POP HL ; restore the
|
265 |
|
|
POP AF ; registers.
|
266 |
|
|
RETN ; return to previous interrupt state.
|
267 |
|
|
|
268 |
|
|
; ---------------------------
|
269 |
|
|
; THE 'CH ADD + 1' SUBROUTINE
|
270 |
|
|
; ---------------------------
|
271 |
|
|
; This subroutine is called from RST 20, and three times from elsewhere
|
272 |
|
|
; to fetch the next immediate character following the current valid character
|
273 |
|
|
; address and update the associated system variable.
|
274 |
|
|
; The entry point TEMP-PTR1 is used from the SCANNING routine.
|
275 |
|
|
; Both TEMP-PTR1 and TEMP-PTR2 are used by the READ command routine.
|
276 |
|
|
|
277 |
|
|
;; CH-ADD+1
|
278 |
|
|
L0074: LD HL,($5C5D) ; fetch address from CH_ADD.
|
279 |
|
|
|
280 |
|
|
;; TEMP-PTR1
|
281 |
|
|
L0077: INC HL ; increase the character address by one.
|
282 |
|
|
|
283 |
|
|
;; TEMP-PTR2
|
284 |
|
|
L0078: LD ($5C5D),HL ; update CH_ADD with character address.
|
285 |
|
|
|
286 |
|
|
X007B: LD A,(HL) ; load character to A from HL.
|
287 |
|
|
RET ; and return.
|
288 |
|
|
|
289 |
|
|
; --------------------------
|
290 |
|
|
; THE 'SKIP OVER' SUBROUTINE
|
291 |
|
|
; --------------------------
|
292 |
|
|
; This subroutine is called once from RST 18 to skip over white-space and
|
293 |
|
|
; other characters irrelevant to the parsing of a BASIC line etc. .
|
294 |
|
|
; Initially the A register holds the character to be considered
|
295 |
|
|
; and HL holds its address which will not be within quoted text
|
296 |
|
|
; when a BASIC line is parsed.
|
297 |
|
|
; Although the 'tab' and 'at' characters will not appear in a BASIC line,
|
298 |
|
|
; they could be present in a string expression, and in other situations.
|
299 |
|
|
; Note. although white-space is usually placed in a program to indent loops
|
300 |
|
|
; and make it more readable, it can also be used for the opposite effect and
|
301 |
|
|
; spaces may appear in variable names although the parser never sees them.
|
302 |
|
|
; It is this routine that helps make the variables 'Anum bEr5 3BUS' and
|
303 |
|
|
; 'a number 53 bus' appear the same to the parser.
|
304 |
|
|
|
305 |
|
|
;; SKIP-OVER
|
306 |
|
|
L007D: CP $21 ; test if higher than space.
|
307 |
|
|
RET NC ; return with carry clear if so.
|
308 |
|
|
|
309 |
|
|
CP $0D ; carriage return ?
|
310 |
|
|
RET Z ; return also with carry clear if so.
|
311 |
|
|
|
312 |
|
|
; all other characters have no relevance
|
313 |
|
|
; to the parser and must be returned with
|
314 |
|
|
; carry set.
|
315 |
|
|
|
316 |
|
|
CP $10 ; test if 0-15d
|
317 |
|
|
RET C ; return, if so, with carry set.
|
318 |
|
|
|
319 |
|
|
CP $18 ; test if 24-32d
|
320 |
|
|
CCF ; complement carry flag.
|
321 |
|
|
RET C ; return with carry set if so.
|
322 |
|
|
|
323 |
|
|
; now leaves 16d-23d
|
324 |
|
|
|
325 |
|
|
INC HL ; all above have at least one extra character
|
326 |
|
|
; to be stepped over.
|
327 |
|
|
|
328 |
|
|
CP $16 ; controls 22d ('at') and 23d ('tab') have two.
|
329 |
|
|
JR C,L0090 ; forward to SKIPS with ink, paper, flash,
|
330 |
|
|
; bright, inverse or over controls.
|
331 |
|
|
; Note. the high byte of tab is for RS232 only.
|
332 |
|
|
; it has no relevance on this machine.
|
333 |
|
|
|
334 |
|
|
INC HL ; step over the second character of 'at'/'tab'.
|
335 |
|
|
|
336 |
|
|
;; SKIPS
|
337 |
|
|
L0090: SCF ; set the carry flag
|
338 |
|
|
LD ($5C5D),HL ; update the CH_ADD system variable.
|
339 |
|
|
RET ; return with carry set.
|
340 |
|
|
|
341 |
|
|
|
342 |
|
|
; ------------------
|
343 |
|
|
; THE 'TOKEN' TABLES
|
344 |
|
|
; ------------------
|
345 |
|
|
; The tokenized characters 134d (RND) to 255d (COPY) are expanded using
|
346 |
|
|
; this table. The last byte of a token is inverted to denote the end of
|
347 |
|
|
; the word. The first is an inverted step-over byte.
|
348 |
|
|
|
349 |
|
|
;; TKN-TABLE
|
350 |
|
|
L0095: DEFB '?'+$80
|
351 |
|
|
DEFM "RN"
|
352 |
|
|
DEFB 'D'+$80
|
353 |
|
|
DEFM "INKEY"
|
354 |
|
|
DEFB '$'+$80
|
355 |
|
|
DEFB 'P','I'+$80
|
356 |
|
|
DEFB 'F','N'+$80
|
357 |
|
|
DEFM "POIN"
|
358 |
|
|
DEFB 'T'+$80
|
359 |
|
|
DEFM "SCREEN"
|
360 |
|
|
DEFB '$'+$80
|
361 |
|
|
DEFM "ATT"
|
362 |
|
|
DEFB 'R'+$80
|
363 |
|
|
DEFB 'A','T'+$80
|
364 |
|
|
DEFM "TA"
|
365 |
|
|
DEFB 'B'+$80
|
366 |
|
|
DEFM "VAL"
|
367 |
|
|
DEFB '$'+$80
|
368 |
|
|
DEFM "COD"
|
369 |
|
|
DEFB 'E'+$80
|
370 |
|
|
DEFM "VA"
|
371 |
|
|
DEFB 'L'+$80
|
372 |
|
|
DEFM "LE"
|
373 |
|
|
DEFB 'N'+$80
|
374 |
|
|
DEFM "SI"
|
375 |
|
|
DEFB 'N'+$80
|
376 |
|
|
DEFM "CO"
|
377 |
|
|
DEFB 'S'+$80
|
378 |
|
|
DEFM "TA"
|
379 |
|
|
DEFB 'N'+$80
|
380 |
|
|
DEFM "AS"
|
381 |
|
|
DEFB 'N'+$80
|
382 |
|
|
DEFM "AC"
|
383 |
|
|
DEFB 'S'+$80
|
384 |
|
|
DEFM "AT"
|
385 |
|
|
DEFB 'N'+$80
|
386 |
|
|
DEFB 'L','N'+$80
|
387 |
|
|
DEFM "EX"
|
388 |
|
|
DEFB 'P'+$80
|
389 |
|
|
DEFM "IN"
|
390 |
|
|
DEFB 'T'+$80
|
391 |
|
|
DEFM "SQ"
|
392 |
|
|
DEFB 'R'+$80
|
393 |
|
|
DEFM "SG"
|
394 |
|
|
DEFB 'N'+$80
|
395 |
|
|
DEFM "AB"
|
396 |
|
|
DEFB 'S'+$80
|
397 |
|
|
DEFM "PEE"
|
398 |
|
|
DEFB 'K'+$80
|
399 |
|
|
DEFB 'I','N'+$80
|
400 |
|
|
DEFM "US"
|
401 |
|
|
DEFB 'R'+$80
|
402 |
|
|
DEFM "STR"
|
403 |
|
|
DEFB '$'+$80
|
404 |
|
|
DEFM "CHR"
|
405 |
|
|
DEFB '$'+$80
|
406 |
|
|
DEFM "NO"
|
407 |
|
|
DEFB 'T'+$80
|
408 |
|
|
DEFM "BI"
|
409 |
|
|
DEFB 'N'+$80
|
410 |
|
|
|
411 |
|
|
; The previous 32 function-type words are printed without a leading space
|
412 |
|
|
; The following have a leading space if they begin with a letter
|
413 |
|
|
|
414 |
|
|
DEFB 'O','R'+$80
|
415 |
|
|
DEFM "AN"
|
416 |
|
|
DEFB 'D'+$80
|
417 |
|
|
DEFB $3C,'='+$80 ; <=
|
418 |
|
|
DEFB $3E,'='+$80 ; >=
|
419 |
|
|
DEFB $3C,$3E+$80 ; <>
|
420 |
|
|
DEFM "LIN"
|
421 |
|
|
DEFB 'E'+$80
|
422 |
|
|
DEFM "THE"
|
423 |
|
|
DEFB 'N'+$80
|
424 |
|
|
DEFB 'T','O'+$80
|
425 |
|
|
DEFM "STE"
|
426 |
|
|
DEFB 'P'+$80
|
427 |
|
|
DEFM "DEF F"
|
428 |
|
|
DEFB 'N'+$80
|
429 |
|
|
DEFM "CA"
|
430 |
|
|
DEFB 'T'+$80
|
431 |
|
|
DEFM "FORMA"
|
432 |
|
|
DEFB 'T'+$80
|
433 |
|
|
DEFM "MOV"
|
434 |
|
|
DEFB 'E'+$80
|
435 |
|
|
DEFM "ERAS"
|
436 |
|
|
DEFB 'E'+$80
|
437 |
|
|
DEFM "OPEN "
|
438 |
|
|
DEFB '#'+$80
|
439 |
|
|
DEFM "CLOSE "
|
440 |
|
|
DEFB '#'+$80
|
441 |
|
|
DEFM "MERG"
|
442 |
|
|
DEFB 'E'+$80
|
443 |
|
|
DEFM "VERIF"
|
444 |
|
|
DEFB 'Y'+$80
|
445 |
|
|
DEFM "BEE"
|
446 |
|
|
DEFB 'P'+$80
|
447 |
|
|
DEFM "CIRCL"
|
448 |
|
|
DEFB 'E'+$80
|
449 |
|
|
DEFM "IN"
|
450 |
|
|
DEFB 'K'+$80
|
451 |
|
|
DEFM "PAPE"
|
452 |
|
|
DEFB 'R'+$80
|
453 |
|
|
DEFM "FLAS"
|
454 |
|
|
DEFB 'H'+$80
|
455 |
|
|
DEFM "BRIGH"
|
456 |
|
|
DEFB 'T'+$80
|
457 |
|
|
DEFM "INVERS"
|
458 |
|
|
DEFB 'E'+$80
|
459 |
|
|
DEFM "OVE"
|
460 |
|
|
DEFB 'R'+$80
|
461 |
|
|
DEFM "OU"
|
462 |
|
|
DEFB 'T'+$80
|
463 |
|
|
DEFM "LPRIN"
|
464 |
|
|
DEFB 'T'+$80
|
465 |
|
|
DEFM "LLIS"
|
466 |
|
|
DEFB 'T'+$80
|
467 |
|
|
DEFM "STO"
|
468 |
|
|
DEFB 'P'+$80
|
469 |
|
|
DEFM "REA"
|
470 |
|
|
DEFB 'D'+$80
|
471 |
|
|
DEFM "DAT"
|
472 |
|
|
DEFB 'A'+$80
|
473 |
|
|
DEFM "RESTOR"
|
474 |
|
|
DEFB 'E'+$80
|
475 |
|
|
DEFM "NE"
|
476 |
|
|
DEFB 'W'+$80
|
477 |
|
|
DEFM "BORDE"
|
478 |
|
|
DEFB 'R'+$80
|
479 |
|
|
DEFM "CONTINU"
|
480 |
|
|
DEFB 'E'+$80
|
481 |
|
|
DEFM "DI"
|
482 |
|
|
DEFB 'M'+$80
|
483 |
|
|
DEFM "RE"
|
484 |
|
|
DEFB 'M'+$80
|
485 |
|
|
DEFM "FO"
|
486 |
|
|
DEFB 'R'+$80
|
487 |
|
|
DEFM "GO T"
|
488 |
|
|
DEFB 'O'+$80
|
489 |
|
|
DEFM "GO SU"
|
490 |
|
|
DEFB 'B'+$80
|
491 |
|
|
DEFM "INPU"
|
492 |
|
|
DEFB 'T'+$80
|
493 |
|
|
DEFM "LOA"
|
494 |
|
|
DEFB 'D'+$80
|
495 |
|
|
DEFM "LIS"
|
496 |
|
|
DEFB 'T'+$80
|
497 |
|
|
DEFM "LE"
|
498 |
|
|
DEFB 'T'+$80
|
499 |
|
|
DEFM "PAUS"
|
500 |
|
|
DEFB 'E'+$80
|
501 |
|
|
DEFM "NEX"
|
502 |
|
|
DEFB 'T'+$80
|
503 |
|
|
DEFM "POK"
|
504 |
|
|
DEFB 'E'+$80
|
505 |
|
|
DEFM "PRIN"
|
506 |
|
|
DEFB 'T'+$80
|
507 |
|
|
DEFM "PLO"
|
508 |
|
|
DEFB 'T'+$80
|
509 |
|
|
DEFM "RU"
|
510 |
|
|
DEFB 'N'+$80
|
511 |
|
|
DEFM "SAV"
|
512 |
|
|
DEFB 'E'+$80
|
513 |
|
|
DEFM "RANDOMIZ"
|
514 |
|
|
DEFB 'E'+$80
|
515 |
|
|
DEFB 'I','F'+$80
|
516 |
|
|
DEFM "CL"
|
517 |
|
|
DEFB 'S'+$80
|
518 |
|
|
DEFM "DRA"
|
519 |
|
|
DEFB 'W'+$80
|
520 |
|
|
DEFM "CLEA"
|
521 |
|
|
DEFB 'R'+$80
|
522 |
|
|
DEFM "RETUR"
|
523 |
|
|
DEFB 'N'+$80
|
524 |
|
|
DEFM "COP"
|
525 |
|
|
DEFB 'Y'+$80
|
526 |
|
|
|
527 |
|
|
; ----------------
|
528 |
|
|
; THE 'KEY' TABLES
|
529 |
|
|
; ----------------
|
530 |
|
|
; These six look-up tables are used by the keyboard reading routine
|
531 |
|
|
; to decode the key values.
|
532 |
|
|
;
|
533 |
|
|
; The first table contains the maps for the 39 keys of the standard
|
534 |
|
|
; 40-key Spectrum keyboard. The remaining key [SHIFT $27] is read directly.
|
535 |
|
|
; The keys consist of the 26 upper-case alphabetic characters, the 10 digit
|
536 |
|
|
; keys and the space, ENTER and symbol shift key.
|
537 |
|
|
; Unshifted alphabetic keys have $20 added to the value.
|
538 |
|
|
; The keywords for the main alphabetic keys are obtained by adding $A5 to
|
539 |
|
|
; the values obtained from this table.
|
540 |
|
|
|
541 |
|
|
;; MAIN-KEYS
|
542 |
|
|
L0205: DEFB $42 ; B
|
543 |
|
|
DEFB $48 ; H
|
544 |
|
|
DEFB $59 ; Y
|
545 |
|
|
DEFB $36 ; 6
|
546 |
|
|
DEFB $35 ; 5
|
547 |
|
|
DEFB $54 ; T
|
548 |
|
|
DEFB $47 ; G
|
549 |
|
|
DEFB $56 ; V
|
550 |
|
|
DEFB $4E ; N
|
551 |
|
|
DEFB $4A ; J
|
552 |
|
|
DEFB $55 ; U
|
553 |
|
|
DEFB $37 ; 7
|
554 |
|
|
DEFB $34 ; 4
|
555 |
|
|
DEFB $52 ; R
|
556 |
|
|
DEFB $46 ; F
|
557 |
|
|
DEFB $43 ; C
|
558 |
|
|
DEFB $4D ; M
|
559 |
|
|
DEFB $4B ; K
|
560 |
|
|
DEFB $49 ; I
|
561 |
|
|
DEFB $38 ; 8
|
562 |
|
|
DEFB $33 ; 3
|
563 |
|
|
DEFB $45 ; E
|
564 |
|
|
DEFB $44 ; D
|
565 |
|
|
DEFB $58 ; X
|
566 |
|
|
DEFB $0E ; SYMBOL SHIFT
|
567 |
|
|
DEFB $4C ; L
|
568 |
|
|
DEFB $4F ; O
|
569 |
|
|
DEFB $39 ; 9
|
570 |
|
|
DEFB $32 ; 2
|
571 |
|
|
DEFB $57 ; W
|
572 |
|
|
DEFB $53 ; S
|
573 |
|
|
DEFB $5A ; Z
|
574 |
|
|
DEFB $20 ; SPACE
|
575 |
|
|
DEFB $0D ; ENTER
|
576 |
|
|
DEFB $50 ; P
|
577 |
|
|
DEFB $30 ; 0
|
578 |
|
|
DEFB $31 ; 1
|
579 |
|
|
DEFB $51 ; Q
|
580 |
|
|
DEFB $41 ; A
|
581 |
|
|
|
582 |
|
|
|
583 |
|
|
;; E-UNSHIFT
|
584 |
|
|
; The 26 unshifted extended mode keys for the alphabetic characters.
|
585 |
|
|
; The green keywords on the original keyboard.
|
586 |
|
|
L022C: DEFB $E3 ; READ
|
587 |
|
|
DEFB $C4 ; BIN
|
588 |
|
|
DEFB $E0 ; LPRINT
|
589 |
|
|
DEFB $E4 ; DATA
|
590 |
|
|
DEFB $B4 ; TAN
|
591 |
|
|
DEFB $BC ; SGN
|
592 |
|
|
DEFB $BD ; ABS
|
593 |
|
|
DEFB $BB ; SQR
|
594 |
|
|
DEFB $AF ; CODE
|
595 |
|
|
DEFB $B0 ; VAL
|
596 |
|
|
DEFB $B1 ; LEN
|
597 |
|
|
DEFB $C0 ; USR
|
598 |
|
|
DEFB $A7 ; PI
|
599 |
|
|
DEFB $A6 ; INKEY$
|
600 |
|
|
DEFB $BE ; PEEK
|
601 |
|
|
DEFB $AD ; TAB
|
602 |
|
|
DEFB $B2 ; SIN
|
603 |
|
|
DEFB $BA ; INT
|
604 |
|
|
DEFB $E5 ; RESTORE
|
605 |
|
|
DEFB $A5 ; RND
|
606 |
|
|
DEFB $C2 ; CHR$
|
607 |
|
|
DEFB $E1 ; LLIST
|
608 |
|
|
DEFB $B3 ; COS
|
609 |
|
|
DEFB $B9 ; EXP
|
610 |
|
|
DEFB $C1 ; STR$
|
611 |
|
|
DEFB $B8 ; LN
|
612 |
|
|
|
613 |
|
|
|
614 |
|
|
;; EXT-SHIFT
|
615 |
|
|
; The 26 shifted extended mode keys for the alphabetic characters.
|
616 |
|
|
; The red keywords below keys on the original keyboard.
|
617 |
|
|
L0246: DEFB $7E ; ~
|
618 |
|
|
DEFB $DC ; BRIGHT
|
619 |
|
|
DEFB $DA ; PAPER
|
620 |
|
|
DEFB $5C ; \
|
621 |
|
|
DEFB $B7 ; ATN
|
622 |
|
|
DEFB $7B ; {
|
623 |
|
|
DEFB $7D ; }
|
624 |
|
|
DEFB $D8 ; CIRCLE
|
625 |
|
|
DEFB $BF ; IN
|
626 |
|
|
DEFB $AE ; VAL$
|
627 |
|
|
DEFB $AA ; SCREEN$
|
628 |
|
|
DEFB $AB ; ATTR
|
629 |
|
|
DEFB $DD ; INVERSE
|
630 |
|
|
DEFB $DE ; OVER
|
631 |
|
|
DEFB $DF ; OUT
|
632 |
|
|
DEFB $7F ; (Copyright character)
|
633 |
|
|
DEFB $B5 ; ASN
|
634 |
|
|
DEFB $D6 ; VERIFY
|
635 |
|
|
DEFB $7C ; |
|
636 |
|
|
DEFB $D5 ; MERGE
|
637 |
|
|
DEFB $5D ; ]
|
638 |
|
|
DEFB $DB ; FLASH
|
639 |
|
|
DEFB $B6 ; ACS
|
640 |
|
|
DEFB $D9 ; INK
|
641 |
|
|
DEFB $5B ; [
|
642 |
|
|
DEFB $D7 ; BEEP
|
643 |
|
|
|
644 |
|
|
|
645 |
|
|
;; CTL-CODES
|
646 |
|
|
; The ten control codes assigned to the top line of digits when the shift
|
647 |
|
|
; key is pressed.
|
648 |
|
|
L0260: DEFB $0C ; DELETE
|
649 |
|
|
DEFB $07 ; EDIT
|
650 |
|
|
DEFB $06 ; CAPS LOCK
|
651 |
|
|
DEFB $04 ; TRUE VIDEO
|
652 |
|
|
DEFB $05 ; INVERSE VIDEO
|
653 |
|
|
DEFB $08 ; CURSOR LEFT
|
654 |
|
|
DEFB $0A ; CURSOR DOWN
|
655 |
|
|
DEFB $0B ; CURSOR UP
|
656 |
|
|
DEFB $09 ; CURSOR RIGHT
|
657 |
|
|
DEFB $0F ; GRAPHICS
|
658 |
|
|
|
659 |
|
|
|
660 |
|
|
;; SYM-CODES
|
661 |
|
|
; The 26 red symbols assigned to the alphabetic characters of the keyboard.
|
662 |
|
|
; The ten single-character digit symbols are converted without the aid of
|
663 |
|
|
; a table using subtraction and minor manipulation.
|
664 |
|
|
L026A: DEFB $E2 ; STOP
|
665 |
|
|
DEFB $2A ; *
|
666 |
|
|
DEFB $3F ; ?
|
667 |
|
|
DEFB $CD ; STEP
|
668 |
|
|
DEFB $C8 ; >=
|
669 |
|
|
DEFB $CC ; TO
|
670 |
|
|
DEFB $CB ; THEN
|
671 |
|
|
DEFB $5E ; ^
|
672 |
|
|
DEFB $AC ; AT
|
673 |
|
|
DEFB $2D ; -
|
674 |
|
|
DEFB $2B ; +
|
675 |
|
|
DEFB $3D ; =
|
676 |
|
|
DEFB $2E ; .
|
677 |
|
|
DEFB $2C ; ,
|
678 |
|
|
DEFB $3B ; ;
|
679 |
|
|
DEFB $22 ; "
|
680 |
|
|
DEFB $C7 ; <=
|
681 |
|
|
DEFB $3C ; <
|
682 |
|
|
DEFB $C3 ; NOT
|
683 |
|
|
DEFB $3E ; >
|
684 |
|
|
DEFB $C5 ; OR
|
685 |
|
|
DEFB $2F ; /
|
686 |
|
|
DEFB $C9 ; <>
|
687 |
|
|
DEFB $60 ; pound
|
688 |
|
|
DEFB $C6 ; AND
|
689 |
|
|
DEFB $3A ; :
|
690 |
|
|
|
691 |
|
|
;; E-DIGITS
|
692 |
|
|
; The ten keywords assigned to the digits in extended mode.
|
693 |
|
|
; The remaining red keywords below the keys.
|
694 |
|
|
L0284: DEFB $D0 ; FORMAT
|
695 |
|
|
DEFB $CE ; DEF FN
|
696 |
|
|
DEFB $A8 ; FN
|
697 |
|
|
DEFB $CA ; LINE
|
698 |
|
|
DEFB $D3 ; OPEN #
|
699 |
|
|
DEFB $D4 ; CLOSE #
|
700 |
|
|
DEFB $D1 ; MOVE
|
701 |
|
|
DEFB $D2 ; ERASE
|
702 |
|
|
DEFB $A9 ; POINT
|
703 |
|
|
DEFB $CF ; CAT
|
704 |
|
|
|
705 |
|
|
|
706 |
|
|
;*******************************
|
707 |
|
|
;** Part 2. KEYBOARD ROUTINES **
|
708 |
|
|
;*******************************
|
709 |
|
|
|
710 |
|
|
; Using shift keys and a combination of modes the Spectrum 40-key keyboard
|
711 |
|
|
; can be mapped to 256 input characters
|
712 |
|
|
|
713 |
|
|
; ---------------------------------------------------------------------------
|
714 |
|
|
;
|
715 |
|
|
; 0 1 2 3 4 -Bits- 4 3 2 1 0
|
716 |
|
|
; PORT PORT
|
717 |
|
|
;
|
718 |
|
|
; F7FE [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] | [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 0 ] EFFE
|
719 |
|
|
; ^ | v
|
720 |
|
|
; FBFE [ Q ] [ W ] [ E ] [ R ] [ T ] | [ Y ] [ U ] [ I ] [ O ] [ P ] DFFE
|
721 |
|
|
; ^ | v
|
722 |
|
|
; FDFE [ A ] [ S ] [ D ] [ F ] [ G ] | [ H ] [ J ] [ K ] [ L ] [ ENT ] BFFE
|
723 |
|
|
; ^ | v
|
724 |
|
|
; FEFE [SHI] [ Z ] [ X ] [ C ] [ V ] | [ B ] [ N ] [ M ] [sym] [ SPC ] 7FFE
|
725 |
|
|
; ^ $27 $18 v
|
726 |
|
|
; Start End
|
727 |
|
|
; 00100111 00011000
|
728 |
|
|
;
|
729 |
|
|
; ---------------------------------------------------------------------------
|
730 |
|
|
; The above map may help in reading.
|
731 |
|
|
; The neat arrangement of ports means that the B register need only be
|
732 |
|
|
; rotated left to work up the left hand side and then down the right
|
733 |
|
|
; hand side of the keyboard. When the reset bit drops into the carry
|
734 |
|
|
; then all 8 half-rows have been read. Shift is the first key to be
|
735 |
|
|
; read. The lower six bits of the shifts are unambiguous.
|
736 |
|
|
|
737 |
|
|
; -------------------------------
|
738 |
|
|
; THE 'KEYBOARD SCANNING' ROUTINE
|
739 |
|
|
; -------------------------------
|
740 |
|
|
; From keyboard and s-inkey$
|
741 |
|
|
; Returns 1 or 2 keys in DE, most significant shift first if any
|
742 |
|
|
; key values 0-39 else 255
|
743 |
|
|
|
744 |
|
|
;; KEY-SCAN
|
745 |
|
|
L028E: LD L,$2F ; initial key value
|
746 |
|
|
; valid values are obtained by subtracting
|
747 |
|
|
; eight five times.
|
748 |
|
|
LD DE,$FFFF ; a buffer to receive 2 keys.
|
749 |
|
|
|
750 |
|
|
LD BC,$FEFE ; the commencing port address
|
751 |
|
|
; B holds 11111110 initially and is also
|
752 |
|
|
; used to count the 8 half-rows
|
753 |
|
|
;; KEY-LINE
|
754 |
|
|
L0296: IN A,(C) ; read the port to A - bits will be reset
|
755 |
|
|
; if a key is pressed else set.
|
756 |
|
|
CPL ; complement - pressed key-bits are now set
|
757 |
|
|
AND $1F ; apply 00011111 mask to pick up the
|
758 |
|
|
; relevant set bits.
|
759 |
|
|
|
760 |
|
|
JR Z,L02AB ; forward to KEY-DONE if zero and therefore
|
761 |
|
|
; no keys pressed in row at all.
|
762 |
|
|
|
763 |
|
|
LD H,A ; transfer row bits to H
|
764 |
|
|
LD A,L ; load the initial key value to A
|
765 |
|
|
|
766 |
|
|
;; KEY-3KEYS
|
767 |
|
|
L029F: INC D ; now test the key buffer
|
768 |
|
|
RET NZ ; if we have collected 2 keys already
|
769 |
|
|
; then too many so quit.
|
770 |
|
|
|
771 |
|
|
;; KEY-BITS
|
772 |
|
|
L02A1: SUB $08 ; subtract 8 from the key value
|
773 |
|
|
; cycling through key values (top = $27)
|
774 |
|
|
; e.g. 2F> 27>1F>17>0F>07
|
775 |
|
|
; 2E> 26>1E>16>0E>06
|
776 |
|
|
SRL H ; shift key bits right into carry.
|
777 |
|
|
JR NC,L02A1 ; back to KEY-BITS if not pressed
|
778 |
|
|
; but if pressed we have a value (0-39d)
|
779 |
|
|
|
780 |
|
|
LD D,E ; transfer a possible previous key to D
|
781 |
|
|
LD E,A ; transfer the new key to E
|
782 |
|
|
JR NZ,L029F ; back to KEY-3KEYS if there were more
|
783 |
|
|
; set bits - H was not yet zero.
|
784 |
|
|
|
785 |
|
|
;; KEY-DONE
|
786 |
|
|
L02AB: DEC L ; cycles 2F>2E>2D>2C>2B>2A>29>28 for
|
787 |
|
|
; each half-row.
|
788 |
|
|
RLC B ; form next port address e.g. FEFE > FDFE
|
789 |
|
|
JR C,L0296 ; back to KEY-LINE if still more rows to do.
|
790 |
|
|
|
791 |
|
|
LD A,D ; now test if D is still FF ?
|
792 |
|
|
INC A ; if it is zero we have at most 1 key
|
793 |
|
|
; range now $01-$28 (1-40d)
|
794 |
|
|
RET Z ; return if one key or no key.
|
795 |
|
|
|
796 |
|
|
CP $28 ; is it capsshift (was $27) ?
|
797 |
|
|
RET Z ; return if so.
|
798 |
|
|
|
799 |
|
|
CP $19 ; is it symbol shift (was $18) ?
|
800 |
|
|
RET Z ; return also
|
801 |
|
|
|
802 |
|
|
LD A,E ; now test E
|
803 |
|
|
LD E,D ; but first switch
|
804 |
|
|
LD D,A ; the two keys.
|
805 |
|
|
CP $18 ; is it symbol shift ?
|
806 |
|
|
RET ; return (with zero set if it was).
|
807 |
|
|
; but with symbol shift now in D
|
808 |
|
|
|
809 |
|
|
; ----------------------
|
810 |
|
|
; THE 'KEYBOARD' ROUTINE
|
811 |
|
|
; ----------------------
|
812 |
|
|
; Called from the interrupt 50 times a second.
|
813 |
|
|
;
|
814 |
|
|
|
815 |
|
|
;; KEYBOARD
|
816 |
|
|
L02BF: CALL L028E ; routine KEY-SCAN
|
817 |
|
|
RET NZ ; return if invalid combinations
|
818 |
|
|
|
819 |
|
|
; then decrease the counters within the two key-state maps
|
820 |
|
|
; as this could cause one to become free.
|
821 |
|
|
; if the keyboard has not been pressed during the last five interrupts
|
822 |
|
|
; then both sets will be free.
|
823 |
|
|
|
824 |
|
|
|
825 |
|
|
LD HL,$5C00 ; point to KSTATE-0
|
826 |
|
|
|
827 |
|
|
;; K-ST-LOOP
|
828 |
|
|
L02C6: BIT 7,(HL) ; is it free ? (i.e. $FF)
|
829 |
|
|
JR NZ,L02D1 ; forward to K-CH-SET if so
|
830 |
|
|
|
831 |
|
|
INC HL ; address the 5-counter
|
832 |
|
|
DEC (HL) ; decrease the counter
|
833 |
|
|
DEC HL ; step back
|
834 |
|
|
|
835 |
|
|
JR NZ,L02D1 ; forward to K-CH-SET if not at end of count
|
836 |
|
|
|
837 |
|
|
LD (HL),$FF ; else mark this particular map free.
|
838 |
|
|
|
839 |
|
|
;; K-CH-SET
|
840 |
|
|
L02D1: LD A,L ; make a copy of the low address byte.
|
841 |
|
|
LD HL,$5C04 ; point to KSTATE-4
|
842 |
|
|
; (ld l,$04 would do)
|
843 |
|
|
CP L ; have both sets been considered ?
|
844 |
|
|
JR NZ,L02C6 ; back to K-ST-LOOP to consider this 2nd set
|
845 |
|
|
|
846 |
|
|
; now the raw key (0-38d) is converted to a main key (uppercase).
|
847 |
|
|
|
848 |
|
|
CALL L031E ; routine K-TEST to get main key in A
|
849 |
|
|
|
850 |
|
|
RET NC ; return if just a single shift
|
851 |
|
|
|
852 |
|
|
LD HL,$5C00 ; point to KSTATE-0
|
853 |
|
|
CP (HL) ; does the main key code match ?
|
854 |
|
|
JR Z,L0310 ; forward to K-REPEAT if so
|
855 |
|
|
|
856 |
|
|
; if not consider the second key map.
|
857 |
|
|
|
858 |
|
|
EX DE,HL ; save kstate-0 in de
|
859 |
|
|
LD HL,$5C04 ; point to KSTATE-4
|
860 |
|
|
CP (HL) ; does the main key code match ?
|
861 |
|
|
JR Z,L0310 ; forward to K-REPEAT if so
|
862 |
|
|
|
863 |
|
|
; having excluded a repeating key we can now consider a new key.
|
864 |
|
|
; the second set is always examined before the first.
|
865 |
|
|
|
866 |
|
|
BIT 7,(HL) ; is the key map free ?
|
867 |
|
|
JR NZ,L02F1 ; forward to K-NEW if so.
|
868 |
|
|
|
869 |
|
|
EX DE,HL ; bring back KSTATE-0
|
870 |
|
|
BIT 7,(HL) ; is it free ?
|
871 |
|
|
RET Z ; return if not.
|
872 |
|
|
; as we have a key but nowhere to put it yet.
|
873 |
|
|
|
874 |
|
|
; continue or jump to here if one of the buffers was free.
|
875 |
|
|
|
876 |
|
|
;; K-NEW
|
877 |
|
|
L02F1: LD E,A ; store key in E
|
878 |
|
|
LD (HL),A ; place in free location
|
879 |
|
|
INC HL ; advance to the interrupt counter
|
880 |
|
|
LD (HL),$05 ; and initialize counter to 5
|
881 |
|
|
INC HL ; advance to the delay
|
882 |
|
|
LD A,($5C09) ; pick up the system variable REPDEL
|
883 |
|
|
LD (HL),A ; and insert that for first repeat delay.
|
884 |
|
|
INC HL ; advance to last location of state map.
|
885 |
|
|
|
886 |
|
|
LD C,(IY+$07) ; pick up MODE (3 bytes)
|
887 |
|
|
LD D,(IY+$01) ; pick up FLAGS (3 bytes)
|
888 |
|
|
PUSH HL ; save state map location
|
889 |
|
|
; Note. could now have used, to avoid IY,
|
890 |
|
|
; ld l,$41; ld c,(hl); ld l,$3B; ld d,(hl).
|
891 |
|
|
; six and two threes of course.
|
892 |
|
|
|
893 |
|
|
CALL L0333 ; routine K-DECODE
|
894 |
|
|
|
895 |
|
|
POP HL ; restore map pointer
|
896 |
|
|
LD (HL),A ; put the decoded key in last location of map.
|
897 |
|
|
|
898 |
|
|
;; K-END
|
899 |
|
|
L0308: LD ($5C08),A ; update LASTK system variable.
|
900 |
|
|
SET 5,(IY+$01) ; update FLAGS - signal a new key.
|
901 |
|
|
RET ; return to interrupt routine.
|
902 |
|
|
|
903 |
|
|
; -----------------------
|
904 |
|
|
; THE 'REPEAT KEY' BRANCH
|
905 |
|
|
; -----------------------
|
906 |
|
|
; A possible repeat has been identified. HL addresses the raw key.
|
907 |
|
|
; The last location of the key map holds the decoded key from the first
|
908 |
|
|
; context. This could be a keyword and, with the exception of NOT a repeat
|
909 |
|
|
; is syntactically incorrect and not really desirable.
|
910 |
|
|
|
911 |
|
|
;; K-REPEAT
|
912 |
|
|
L0310: INC HL ; increment the map pointer to second location.
|
913 |
|
|
LD (HL),$05 ; maintain interrupt counter at 5.
|
914 |
|
|
INC HL ; now point to third location.
|
915 |
|
|
DEC (HL) ; decrease the REPDEL value which is used to
|
916 |
|
|
; time the delay of a repeat key.
|
917 |
|
|
|
918 |
|
|
RET NZ ; return if not yet zero.
|
919 |
|
|
|
920 |
|
|
LD A,($5C0A) ; fetch the system variable value REPPER.
|
921 |
|
|
LD (HL),A ; for subsequent repeats REPPER will be used.
|
922 |
|
|
|
923 |
|
|
INC HL ; advance
|
924 |
|
|
;
|
925 |
|
|
LD A,(HL) ; pick up the key decoded possibly in another
|
926 |
|
|
; context.
|
927 |
|
|
; Note. should compare with $A5 (RND) and make
|
928 |
|
|
; a simple return if this is a keyword.
|
929 |
|
|
; e.g. cp $a5; ret nc; (3 extra bytes)
|
930 |
|
|
JR L0308 ; back to K-END
|
931 |
|
|
|
932 |
|
|
; ----------------------
|
933 |
|
|
; THE 'KEY-TEST' ROUTINE
|
934 |
|
|
; ----------------------
|
935 |
|
|
; also called from s-inkey$
|
936 |
|
|
; begin by testing for a shift with no other.
|
937 |
|
|
|
938 |
|
|
;; K-TEST
|
939 |
|
|
L031E: LD B,D ; load most significant key to B
|
940 |
|
|
; will be $FF if not shift.
|
941 |
|
|
LD D,$00 ; and reset D to index into main table
|
942 |
|
|
LD A,E ; load least significant key from E
|
943 |
|
|
CP $27 ; is it higher than 39d i.e. FF
|
944 |
|
|
RET NC ; return with just a shift (in B now)
|
945 |
|
|
|
946 |
|
|
CP $18 ; is it symbol shift ?
|
947 |
|
|
JR NZ,L032C ; forward to K-MAIN if not
|
948 |
|
|
|
949 |
|
|
; but we could have just symbol shift and no other
|
950 |
|
|
|
951 |
|
|
BIT 7,B ; is other key $FF (ie not shift)
|
952 |
|
|
RET NZ ; return with solitary symbol shift
|
953 |
|
|
|
954 |
|
|
|
955 |
|
|
;; K-MAIN
|
956 |
|
|
L032C: LD HL,L0205 ; address: MAIN-KEYS
|
957 |
|
|
ADD HL,DE ; add offset 0-38
|
958 |
|
|
LD A,(HL) ; pick up main key value
|
959 |
|
|
SCF ; set carry flag
|
960 |
|
|
RET ; return (B has other key still)
|
961 |
|
|
|
962 |
|
|
; ----------------------------------
|
963 |
|
|
; THE 'KEYBOARD DECODING' SUBROUTINE
|
964 |
|
|
; ----------------------------------
|
965 |
|
|
; also called from s-inkey$
|
966 |
|
|
|
967 |
|
|
;; K-DECODE
|
968 |
|
|
L0333: LD A,E ; pick up the stored main key
|
969 |
|
|
CP $3A ; an arbitrary point between digits and letters
|
970 |
|
|
JR C,L0367 ; forward to K-DIGIT with digits, space, enter.
|
971 |
|
|
|
972 |
|
|
DEC C ; decrease MODE ( 0='KLC', 1='E', 2='G')
|
973 |
|
|
|
974 |
|
|
JP M,L034F ; to K-KLC-LET if was zero
|
975 |
|
|
|
976 |
|
|
JR Z,L0341 ; to K-E-LET if was 1 for extended letters.
|
977 |
|
|
|
978 |
|
|
; proceed with graphic codes.
|
979 |
|
|
; Note. should selectively drop return address if code > 'U' ($55).
|
980 |
|
|
; i.e. abort the KEYBOARD call.
|
981 |
|
|
; e.g. cp 'V'; jr c,addit; pop af ;pop af ;;addit etc. (6 extra bytes).
|
982 |
|
|
; (s-inkey$ never gets into graphics mode.)
|
983 |
|
|
|
984 |
|
|
;; addit
|
985 |
|
|
ADD A,$4F ; add offset to augment 'A' to graphics A say.
|
986 |
|
|
RET ; return.
|
987 |
|
|
; Note. ( but [GRAPH] V gives RND, etc ).
|
988 |
|
|
|
989 |
|
|
; ---
|
990 |
|
|
|
991 |
|
|
; the jump was to here with extended mode with uppercase A-Z.
|
992 |
|
|
|
993 |
|
|
;; K-E-LET
|
994 |
|
|
L0341: LD HL,L022C-$41 ; base address of E-UNSHIFT L022c.
|
995 |
|
|
; ( $01EB in standard ROM ).
|
996 |
|
|
INC B ; test B is it empty i.e. not a shift.
|
997 |
|
|
JR Z,L034A ; forward to K-LOOK-UP if neither shift.
|
998 |
|
|
|
999 |
|
|
LD HL,L0246-$41 ; Address: $0205 L0246-$41 EXT-SHIFT base
|
1000 |
|
|
|
1001 |
|
|
;; K-LOOK-UP
|
1002 |
|
|
L034A: LD D,$00 ; prepare to index.
|
1003 |
|
|
ADD HL,DE ; add the main key value.
|
1004 |
|
|
LD A,(HL) ; pick up other mode value.
|
1005 |
|
|
RET ; return.
|
1006 |
|
|
|
1007 |
|
|
; ---
|
1008 |
|
|
|
1009 |
|
|
; the jump was here with mode = 0
|
1010 |
|
|
|
1011 |
|
|
;; K-KLC-LET
|
1012 |
|
|
L034F: LD HL,L026A-$41 ; prepare base of sym-codes
|
1013 |
|
|
BIT 0,B ; shift=$27 sym-shift=$18
|
1014 |
|
|
JR Z,L034A ; back to K-LOOK-UP with symbol-shift
|
1015 |
|
|
|
1016 |
|
|
BIT 3,D ; test FLAGS is it 'K' mode (from OUT-CURS)
|
1017 |
|
|
JR Z,L0364 ; skip to K-TOKENS if so
|
1018 |
|
|
|
1019 |
|
|
BIT 3,(IY+$30) ; test FLAGS2 - consider CAPS LOCK ?
|
1020 |
|
|
RET NZ ; return if so with main code.
|
1021 |
|
|
|
1022 |
|
|
INC B ; is shift being pressed ?
|
1023 |
|
|
; result zero if not
|
1024 |
|
|
RET NZ ; return if shift pressed.
|
1025 |
|
|
|
1026 |
|
|
ADD A,$20 ; else convert the code to lower case.
|
1027 |
|
|
RET ; return.
|
1028 |
|
|
|
1029 |
|
|
; ---
|
1030 |
|
|
|
1031 |
|
|
; the jump was here for tokens
|
1032 |
|
|
|
1033 |
|
|
;; K-TOKENS
|
1034 |
|
|
L0364: ADD A,$A5 ; add offset to main code so that 'A'
|
1035 |
|
|
; becomes 'NEW' etc.
|
1036 |
|
|
|
1037 |
|
|
RET ; return.
|
1038 |
|
|
|
1039 |
|
|
; ---
|
1040 |
|
|
|
1041 |
|
|
; the jump was here with digits, space, enter and symbol shift (< $xx)
|
1042 |
|
|
|
1043 |
|
|
;; K-DIGIT
|
1044 |
|
|
L0367: CP $30 ; is it '0' or higher ?
|
1045 |
|
|
RET C ; return with space, enter and symbol-shift
|
1046 |
|
|
|
1047 |
|
|
DEC C ; test MODE (was 0='KLC', 1='E', 2='G')
|
1048 |
|
|
JP M,L039D ; jump to K-KLC-DGT if was 0.
|
1049 |
|
|
|
1050 |
|
|
JR NZ,L0389 ; forward to K-GRA-DGT if mode was 2.
|
1051 |
|
|
|
1052 |
|
|
; continue with extended digits 0-9.
|
1053 |
|
|
|
1054 |
|
|
LD HL,L0284-$30 ; $0254 - base of E-DIGITS
|
1055 |
|
|
BIT 5,B ; test - shift=$27 sym-shift=$18
|
1056 |
|
|
JR Z,L034A ; to K-LOOK-UP if sym-shift
|
1057 |
|
|
|
1058 |
|
|
CP $38 ; is character '8' ?
|
1059 |
|
|
JR NC,L0382 ; to K-8-&-9 if greater than '7'
|
1060 |
|
|
|
1061 |
|
|
SUB $20 ; reduce to ink range $10-$17
|
1062 |
|
|
INC B ; shift ?
|
1063 |
|
|
RET Z ; return if not.
|
1064 |
|
|
|
1065 |
|
|
ADD A,$08 ; add 8 to give paper range $18 - $1F
|
1066 |
|
|
RET ; return
|
1067 |
|
|
|
1068 |
|
|
; ---
|
1069 |
|
|
|
1070 |
|
|
; 89
|
1071 |
|
|
|
1072 |
|
|
;; K-8-&-9
|
1073 |
|
|
L0382: SUB $36 ; reduce to 02 and 03 bright codes
|
1074 |
|
|
INC B ; test if shift pressed.
|
1075 |
|
|
RET Z ; return if not.
|
1076 |
|
|
|
1077 |
|
|
ADD A,$FE ; subtract 2 setting carry
|
1078 |
|
|
RET ; to give 0 and 1 flash codes.
|
1079 |
|
|
|
1080 |
|
|
; ---
|
1081 |
|
|
|
1082 |
|
|
; graphics mode with digits
|
1083 |
|
|
|
1084 |
|
|
;; K-GRA-DGT
|
1085 |
|
|
L0389: LD HL,L0260-$30 ; $0230 base address of CTL-CODES
|
1086 |
|
|
|
1087 |
|
|
CP $39 ; is key '9' ?
|
1088 |
|
|
JR Z,L034A ; back to K-LOOK-UP - changed to $0F, GRAPHICS.
|
1089 |
|
|
|
1090 |
|
|
CP $30 ; is key '0' ?
|
1091 |
|
|
JR Z,L034A ; back to K-LOOK-UP - changed to $0C, delete.
|
1092 |
|
|
|
1093 |
|
|
; for keys '0' - '7' we assign a mosaic character depending on shift.
|
1094 |
|
|
|
1095 |
|
|
AND $07 ; convert character to number. 0 - 7.
|
1096 |
|
|
ADD A,$80 ; add offset - they start at $80
|
1097 |
|
|
|
1098 |
|
|
INC B ; destructively test for shift
|
1099 |
|
|
RET Z ; and return if not pressed.
|
1100 |
|
|
|
1101 |
|
|
XOR $0F ; toggle bits becomes range $88-$8F
|
1102 |
|
|
RET ; return.
|
1103 |
|
|
|
1104 |
|
|
; ---
|
1105 |
|
|
|
1106 |
|
|
; now digits in 'KLC' mode
|
1107 |
|
|
|
1108 |
|
|
;; K-KLC-DGT
|
1109 |
|
|
L039D: INC B ; return with digit codes if neither
|
1110 |
|
|
RET Z ; shift key pressed.
|
1111 |
|
|
|
1112 |
|
|
BIT 5,B ; test for caps shift.
|
1113 |
|
|
|
1114 |
|
|
LD HL,L0260-$30 ; prepare base of table CTL-CODES.
|
1115 |
|
|
JR NZ,L034A ; back to K-LOOK-UP if shift pressed.
|
1116 |
|
|
|
1117 |
|
|
; must have been symbol shift
|
1118 |
|
|
|
1119 |
|
|
SUB $10 ; for ASCII most will now be correct
|
1120 |
|
|
; on a standard typewriter.
|
1121 |
|
|
|
1122 |
|
|
CP $22 ; but '@' is not - see below.
|
1123 |
|
|
JR Z,L03B2 ; forward to K-@-CHAR if so
|
1124 |
|
|
|
1125 |
|
|
CP $20 ; '_' is the other one that fails
|
1126 |
|
|
RET NZ ; return if not.
|
1127 |
|
|
|
1128 |
|
|
LD A,$5F ; substitute ASCII '_'
|
1129 |
|
|
RET ; return.
|
1130 |
|
|
|
1131 |
|
|
; ---
|
1132 |
|
|
|
1133 |
|
|
;; K-@-CHAR
|
1134 |
|
|
L03B2: LD A,$40 ; substitute ASCII '@'
|
1135 |
|
|
RET ; return.
|
1136 |
|
|
|
1137 |
|
|
|
1138 |
|
|
; ------------------------------------------------------------------------
|
1139 |
|
|
; The Spectrum Input character keys. One or two are abbreviated.
|
1140 |
|
|
; From $00 Flash 0 to $FF COPY. The routine above has decoded all these.
|
1141 |
|
|
|
1142 |
|
|
; | 00 Fl0| 01 Fl1| 02 Br0| 03 Br1| 04 In0| 05 In1| 06 CAP| 07 EDT|
|
1143 |
|
|
; | 08 LFT| 09 RIG| 0A DWN| 0B UP | 0C DEL| 0D ENT| 0E SYM| 0F GRA|
|
1144 |
|
|
; | 10 Ik0| 11 Ik1| 12 Ik2| 13 Ik3| 14 Ik4| 15 Ik5| 16 Ik6| 17 Ik7|
|
1145 |
|
|
; | 18 Pa0| 19 Pa1| 1A Pa2| 1B Pa3| 1C Pa4| 1D Pa5| 1E Pa6| 1F Pa7|
|
1146 |
|
|
; | 20 SP | 21 ! | 22 " | 23 # | 24 $ | 25 % | 26 & | 27 ' |
|
1147 |
|
|
; | 28 ( | 29 ) | 2A * | 2B + | 2C , | 2D - | 2E . | 2F / |
|
1148 |
|
|
; | 30 0 | 31 1 | 32 2 | 33 3 | 34 4 | 35 5 | 36 6 | 37 7 |
|
1149 |
|
|
; | 38 8 | 39 9 | 3A : | 3B ; | 3C < | 3D = | 3E > | 3F ? |
|
1150 |
|
|
; | 40 @ | 41 A | 42 B | 43 C | 44 D | 45 E | 46 F | 47 G |
|
1151 |
|
|
; | 48 H | 49 I | 4A J | 4B K | 4C L | 4D M | 4E N | 4F O |
|
1152 |
|
|
; | 50 P | 51 Q | 52 R | 53 S | 54 T | 55 U | 56 V | 57 W |
|
1153 |
|
|
; | 58 X | 59 Y | 5A Z | 5B [ | 5C \ | 5D ] | 5E ^ | 5F _ |
|
1154 |
|
|
; | 60 £ | 61 a | 62 b | 63 c | 64 d | 65 e | 66 f | 67 g |
|
1155 |
|
|
; | 68 h | 69 i | 6A j | 6B k | 6C l | 6D m | 6E n | 6F o |
|
1156 |
|
|
; | 70 p | 71 q | 72 r | 73 s | 74 t | 75 u | 76 v | 77 w |
|
1157 |
|
|
; | 78 x | 79 y | 7A z | 7B { | 7C | | 7D } | 7E ~ | 7F © |
|
1158 |
|
|
; | 80 128| 81 129| 82 130| 83 131| 84 132| 85 133| 86 134| 87 135|
|
1159 |
|
|
; | 88 136| 89 137| 8A 138| 8B 139| 8C 140| 8D 141| 8E 142| 8F 143|
|
1160 |
|
|
; | 90 [A]| 91 [B]| 92 [C]| 93 [D]| 94 [E]| 95 [F]| 96 [G]| 97 [H]|
|
1161 |
|
|
; | 98 [I]| 99 [J]| 9A [K]| 9B [L]| 9C [M]| 9D [N]| 9E [O]| 9F [P]|
|
1162 |
|
|
; | A0 [Q]| A1 [R]| A2 [S]| A3 [T]| A4 [U]| A5 RND| A6 IK$| A7 PI |
|
1163 |
|
|
; | A8 FN | A9 PNT| AA SC$| AB ATT| AC AT | AD TAB| AE VL$| AF COD|
|
1164 |
|
|
; | B0 VAL| B1 LEN| B2 SIN| B3 COS| B4 TAN| B5 ASN| B6 ACS| B7 ATN|
|
1165 |
|
|
; | B8 LN | B9 EXP| BA INT| BB SQR| BC SGN| BD ABS| BE PEK| BF IN |
|
1166 |
|
|
; | C0 USR| C1 ST$| C2 CH$| C3 NOT| C4 BIN| C5 OR | C6 AND| C7 <= |
|
1167 |
|
|
; | C8 >= | C9 <> | CA LIN| CB THN| CC TO | CD STP| CE DEF| CF CAT|
|
1168 |
|
|
; | D0 FMT| D1 MOV| D2 ERS| D3 OPN| D4 CLO| D5 MRG| D6 VFY| D7 BEP|
|
1169 |
|
|
; | D8 CIR| D9 INK| DA PAP| DB FLA| DC BRI| DD INV| DE OVR| DF OUT|
|
1170 |
|
|
; | E0 LPR| E1 LLI| E2 STP| E3 REA| E4 DAT| E5 RES| E6 NEW| E7 BDR|
|
1171 |
|
|
; | E8 CON| E9 DIM| EA REM| EB FOR| EC GTO| ED GSB| EE INP| EF LOA|
|
1172 |
|
|
; | F0 LIS| F1 LET| F2 PAU| F3 NXT| F4 POK| F5 PRI| F6 PLO| F7 RUN|
|
1173 |
|
|
; | F8 SAV| F9 RAN| FA IF | FB CLS| FC DRW| FD CLR| FE RET| FF CPY|
|
1174 |
|
|
|
1175 |
|
|
; Note that for simplicity, Sinclair have located all the control codes
|
1176 |
|
|
; below the space character.
|
1177 |
|
|
; ASCII DEL, $7F, has been made a copyright symbol.
|
1178 |
|
|
; Also $60, '`', not used in BASIC but used in other languages, has been
|
1179 |
|
|
; allocated the local currency symbol for the relevant country -
|
1180 |
|
|
; £ in most Spectrums.
|
1181 |
|
|
|
1182 |
|
|
; ------------------------------------------------------------------------
|
1183 |
|
|
|
1184 |
|
|
|
1185 |
|
|
;**********************************
|
1186 |
|
|
;** Part 3. LOUDSPEAKER ROUTINES **
|
1187 |
|
|
;**********************************
|
1188 |
|
|
|
1189 |
|
|
; Documented by Alvin Albrecht.
|
1190 |
|
|
|
1191 |
|
|
; ------------------------------
|
1192 |
|
|
; Routine to control loudspeaker
|
1193 |
|
|
; ------------------------------
|
1194 |
|
|
; Outputs a square wave of given duration and frequency
|
1195 |
|
|
; to the loudspeaker.
|
1196 |
|
|
; Enter with: DE = #cycles - 1
|
1197 |
|
|
; HL = tone period as described next
|
1198 |
|
|
;
|
1199 |
|
|
; The tone period is measured in T states and consists of
|
1200 |
|
|
; three parts: a coarse part (H register), a medium part
|
1201 |
|
|
; (bits 7..2 of L) and a fine part (bits 1..0 of L) which
|
1202 |
|
|
; contribute to the waveform timing as follows:
|
1203 |
|
|
;
|
1204 |
|
|
; coarse medium fine
|
1205 |
|
|
; duration of low = 118 + 1024*H + 16*(L>>2) + 4*(L&0x3)
|
1206 |
|
|
; duration of hi = 118 + 1024*H + 16*(L>>2) + 4*(L&0x3)
|
1207 |
|
|
; Tp = tone period = 236 + 2048*H + 32*(L>>2) + 8*(L&0x3)
|
1208 |
|
|
; = 236 + 2048*H + 8*L = 236 + 8*HL
|
1209 |
|
|
;
|
1210 |
|
|
; As an example, to output five seconds of middle C (261.624 Hz):
|
1211 |
|
|
; (a) Tone period = 1/261.624 = 3.822ms
|
1212 |
|
|
; (b) Tone period in T-States = 3.822ms*fCPU = 13378
|
1213 |
|
|
; where fCPU = clock frequency of the CPU = 3.5MHz
|
1214 |
|
|
; © Find H and L for desired tone period:
|
1215 |
|
|
; HL = (Tp - 236) / 8 = (13378 - 236) / 8 = 1643 = 0x066B
|
1216 |
|
|
; (d) Tone duration in cycles = 5s/3.822ms = 1308 cycles
|
1217 |
|
|
; DE = 1308 - 1 = 0x051B
|
1218 |
|
|
;
|
1219 |
|
|
; The resulting waveform has a duty ratio of exactly 50%.
|
1220 |
|
|
;
|
1221 |
|
|
;
|
1222 |
|
|
;; BEEPER
|
1223 |
|
|
L03B5: DI ; Disable Interrupts so they don't disturb timing
|
1224 |
|
|
LD A,L ;
|
1225 |
|
|
SRL L ;
|
1226 |
|
|
SRL L ; L = medium part of tone period
|
1227 |
|
|
CPL ;
|
1228 |
|
|
AND $03 ; A = 3 - fine part of tone period
|
1229 |
|
|
LD C,A ;
|
1230 |
|
|
LD B,$00 ;
|
1231 |
|
|
LD IX,L03D1 ; Address: BE-IX+3
|
1232 |
|
|
ADD IX,BC ; IX holds address of entry into the loop
|
1233 |
|
|
; the loop will contain 0-3 NOPs, implementing
|
1234 |
|
|
; the fine part of the tone period.
|
1235 |
|
|
LD A,($5C48) ; BORDCR
|
1236 |
|
|
AND $38 ; bits 5..3 contain border colour
|
1237 |
|
|
RRCA ; border colour bits moved to 2..0
|
1238 |
|
|
RRCA ; to match border bits on port #FE
|
1239 |
|
|
RRCA ;
|
1240 |
|
|
OR $08 ; bit 3 set (tape output bit on port #FE)
|
1241 |
|
|
; for loud sound output
|
1242 |
|
|
;; BE-IX+3
|
1243 |
|
|
L03D1: NOP ;(4) ; optionally executed NOPs for small
|
1244 |
|
|
; adjustments to tone period
|
1245 |
|
|
;; BE-IX+2
|
1246 |
|
|
L03D2: NOP ;(4) ;
|
1247 |
|
|
|
1248 |
|
|
;; BE-IX+1
|
1249 |
|
|
L03D3: NOP ;(4) ;
|
1250 |
|
|
|
1251 |
|
|
;; BE-IX+0
|
1252 |
|
|
L03D4: INC B ;(4) ;
|
1253 |
|
|
INC C ;(4) ;
|
1254 |
|
|
|
1255 |
|
|
;; BE-H&L-LP
|
1256 |
|
|
L03D6: DEC C ;(4) ; timing loop for duration of
|
1257 |
|
|
JR NZ,L03D6 ;(12/7); high or low pulse of waveform
|
1258 |
|
|
|
1259 |
|
|
LD C,$3F ;(7) ;
|
1260 |
|
|
DEC B ;(4) ;
|
1261 |
|
|
JP NZ,L03D6 ;(10) ; to BE-H&L-LP
|
1262 |
|
|
|
1263 |
|
|
XOR $10 ;(7) ; toggle output beep bit
|
1264 |
|
|
OUT ($FE),A ;(11) ; output pulse
|
1265 |
|
|
LD B,H ;(4) ; B = coarse part of tone period
|
1266 |
|
|
LD C,A ;(4) ; save port #FE output byte
|
1267 |
|
|
BIT 4,A ;(8) ; if new output bit is high, go
|
1268 |
|
|
JR NZ,L03F2 ;(12/7); to BE-AGAIN
|
1269 |
|
|
|
1270 |
|
|
LD A,D ;(4) ; one cycle of waveform has completed
|
1271 |
|
|
OR E ;(4) ; (low->low). if cycle countdown = 0
|
1272 |
|
|
JR Z,L03F6 ;(12/7); go to BE-END
|
1273 |
|
|
|
1274 |
|
|
LD A,C ;(4) ; restore output byte for port #FE
|
1275 |
|
|
LD C,L ;(4) ; C = medium part of tone period
|
1276 |
|
|
DEC DE ;(6) ; decrement cycle count
|
1277 |
|
|
JP (IX) ;(8) ; do another cycle
|
1278 |
|
|
|
1279 |
|
|
;; BE-AGAIN ; halfway through cycle
|
1280 |
|
|
L03F2: LD C,L ;(4) ; C = medium part of tone period
|
1281 |
|
|
INC C ;(4) ; adds 16 cycles to make duration of high = duration of low
|
1282 |
|
|
JP (IX) ;(8) ; do high pulse of tone
|
1283 |
|
|
|
1284 |
|
|
;; BE-END
|
1285 |
|
|
L03F6: EI ; Enable Interrupts
|
1286 |
|
|
RET ;
|
1287 |
|
|
|
1288 |
|
|
|
1289 |
|
|
; ------------------
|
1290 |
|
|
; THE 'BEEP' COMMAND
|
1291 |
|
|
; ------------------
|
1292 |
|
|
; BASIC interface to BEEPER subroutine.
|
1293 |
|
|
; Invoked in BASIC with:
|
1294 |
|
|
; BEEP dur, pitch
|
1295 |
|
|
; where dur = duration in seconds
|
1296 |
|
|
; pitch = # of semitones above/below middle C
|
1297 |
|
|
;
|
1298 |
|
|
; Enter with: pitch on top of calculator stack
|
1299 |
|
|
; duration next on calculator stack
|
1300 |
|
|
;
|
1301 |
|
|
;; beep
|
1302 |
|
|
L03F8: RST 28H ;; FP-CALC
|
1303 |
|
|
DEFB $31 ;;duplicate ; duplicate pitch
|
1304 |
|
|
DEFB $27 ;;int ; convert to integer
|
1305 |
|
|
DEFB $C0 ;;st-mem-0 ; store integer pitch to memory 0
|
1306 |
|
|
DEFB $03 ;;subtract ; calculate fractional part of pitch = fp_pitch - int_pitch
|
1307 |
|
|
DEFB $34 ;;stk-data ; push constant
|
1308 |
|
|
DEFB $EC ;;Exponent: $7C, Bytes: 4 ; constant = 0.05762265
|
1309 |
|
|
DEFB $6C,$98,$1F,$F5 ;;($6C,$98,$1F,$F5)
|
1310 |
|
|
DEFB $04 ;;multiply ; compute:
|
1311 |
|
|
DEFB $A1 ;;stk-one ; 1 + 0.05762265 * fraction_part(pitch)
|
1312 |
|
|
DEFB $0F ;;addition
|
1313 |
|
|
DEFB $38 ;;end-calc ; leave on calc stack
|
1314 |
|
|
|
1315 |
|
|
LD HL,$5C92 ; MEM-0: number stored here is in 16 bit integer format (pitch)
|
1316 |
|
|
; 0, 0/FF (pos/neg), LSB, MSB, 0
|
1317 |
|
|
; LSB/MSB is stored in two's complement
|
1318 |
|
|
; In the following, the pitch is checked if it is in the range -128<=p<=127
|
1319 |
|
|
LD A,(HL) ; First byte must be zero, otherwise
|
1320 |
|
|
AND A ; error in integer conversion
|
1321 |
|
|
JR NZ,L046C ; to REPORT-B
|
1322 |
|
|
|
1323 |
|
|
INC HL ;
|
1324 |
|
|
LD C,(HL) ; C = pos/neg flag = 0/FF
|
1325 |
|
|
INC HL ;
|
1326 |
|
|
LD B,(HL) ; B = LSB, two's complement
|
1327 |
|
|
LD A,B ;
|
1328 |
|
|
RLA ;
|
1329 |
|
|
SBC A,A ; A = 0/FF if B is pos/neg
|
1330 |
|
|
CP C ; must be the same as C if the pitch is -128<=p<=127
|
1331 |
|
|
JR NZ,L046C ; if no, error REPORT-B
|
1332 |
|
|
|
1333 |
|
|
INC HL ; if -128<=p<=127, MSB will be 0/FF if B is pos/neg
|
1334 |
|
|
CP (HL) ; verify this
|
1335 |
|
|
JR NZ,L046C ; if no, error REPORT-B
|
1336 |
|
|
; now we know -128<=p<=127
|
1337 |
|
|
LD A,B ; A = pitch + 60
|
1338 |
|
|
ADD A,$3C ; if -60<=pitch<=67,
|
1339 |
|
|
JP P,L0425 ; goto BE-i-OK
|
1340 |
|
|
|
1341 |
|
|
JP PO,L046C ; if pitch <= 67 goto REPORT-B
|
1342 |
|
|
; lower bound of pitch set at -60
|
1343 |
|
|
|
1344 |
|
|
;; BE-I-OK ; here, -60<=pitch<=127
|
1345 |
|
|
; and A=pitch+60 -> 0<=A<=187
|
1346 |
|
|
|
1347 |
|
|
L0425: LD B,$FA ; 6 octaves below middle C
|
1348 |
|
|
|
1349 |
|
|
;; BE-OCTAVE ; A=# semitones above 5 octaves below middle C
|
1350 |
|
|
L0427: INC B ; increment octave
|
1351 |
|
|
SUB $0C ; 12 semitones = one octave
|
1352 |
|
|
JR NC,L0427 ; to BE-OCTAVE
|
1353 |
|
|
|
1354 |
|
|
ADD A,$0C ; A = # semitones above C (0-11)
|
1355 |
|
|
PUSH BC ; B = octave displacement from middle C, 2's complement: -5<=B<=10
|
1356 |
|
|
LD HL,L046E ; Address: semi-tone
|
1357 |
|
|
CALL L3406 ; routine LOC-MEM
|
1358 |
|
|
; HL = 5*A + $046E
|
1359 |
|
|
CALL L33B4 ; routine STACK-NUM
|
1360 |
|
|
; read FP value (freq) from semitone table (HL) and push onto calc stack
|
1361 |
|
|
|
1362 |
|
|
RST 28H ;; FP-CALC
|
1363 |
|
|
DEFB $04 ;;multiply mult freq by 1 + 0.0576 * fraction_part(pitch) stacked earlier
|
1364 |
|
|
;; thus taking into account fractional part of pitch.
|
1365 |
|
|
;; the number 0.0576*frequency is the distance in Hz to the next
|
1366 |
|
|
;; note (verify with the frequencies recorded in the semitone
|
1367 |
|
|
;; table below) so that the fraction_part of the pitch does
|
1368 |
|
|
;; indeed represent a fractional distance to the next note.
|
1369 |
|
|
DEFB $38 ;;end-calc HL points to first byte of fp num on stack = middle frequency to generate
|
1370 |
|
|
|
1371 |
|
|
POP AF ; A = octave displacement from middle C, 2's complement: -5<=A<=10
|
1372 |
|
|
ADD A,(HL) ; increase exponent by A (equivalent to multiplying by 2^A)
|
1373 |
|
|
LD (HL),A ;
|
1374 |
|
|
|
1375 |
|
|
RST 28H ;; FP-CALC
|
1376 |
|
|
DEFB $C0 ;;st-mem-0 ; store frequency in memory 0
|
1377 |
|
|
DEFB $02 ;;delete ; remove from calc stack
|
1378 |
|
|
DEFB $31 ;;duplicate ; duplicate duration (seconds)
|
1379 |
|
|
DEFB $38 ;;end-calc
|
1380 |
|
|
|
1381 |
|
|
CALL L1E94 ; routine FIND-INT1 ; FP duration to A
|
1382 |
|
|
CP $0B ; if dur > 10 seconds,
|
1383 |
|
|
JR NC,L046C ; goto REPORT-B
|
1384 |
|
|
|
1385 |
|
|
;;; The following calculation finds the tone period for HL and the cycle count
|
1386 |
|
|
;;; for DE expected in the BEEPER subroutine. From the example in the BEEPER comments,
|
1387 |
|
|
;;;
|
1388 |
|
|
;;; HL = ((fCPU / f) - 236) / 8 = fCPU/8/f - 236/8 = 437500/f -29.5
|
1389 |
|
|
;;; DE = duration * frequency - 1
|
1390 |
|
|
;;;
|
1391 |
|
|
;;; Note the different constant (30.125) used in the calculation of HL
|
1392 |
|
|
;;; below. This is probably an error.
|
1393 |
|
|
|
1394 |
|
|
RST 28H ;; FP-CALC
|
1395 |
|
|
DEFB $E0 ;;get-mem-0 ; push frequency
|
1396 |
|
|
DEFB $04 ;;multiply ; result1: #cycles = duration * frequency
|
1397 |
|
|
DEFB $E0 ;;get-mem-0 ; push frequency
|
1398 |
|
|
DEFB $34 ;;stk-data ; push constant
|
1399 |
|
|
DEFB $80 ;;Exponent $93, Bytes: 3 ; constant = 437500
|
1400 |
|
|
DEFB $43,$55,$9F,$80 ;;($55,$9F,$80,$00)
|
1401 |
|
|
DEFB $01 ;;exchange ; frequency on top
|
1402 |
|
|
DEFB $05 ;;division ; 437500 / frequency
|
1403 |
|
|
DEFB $34 ;;stk-data ; push constant
|
1404 |
|
|
DEFB $35 ;;Exponent: $85, Bytes: 1 ; constant = 30.125
|
1405 |
|
|
DEFB $71 ;;($71,$00,$00,$00)
|
1406 |
|
|
DEFB $03 ;;subtract ; result2: tone_period(HL) = 437500 / freq - 30.125
|
1407 |
|
|
DEFB $38 ;;end-calc
|
1408 |
|
|
|
1409 |
|
|
CALL L1E99 ; routine FIND-INT2
|
1410 |
|
|
PUSH BC ; BC = tone_period(HL)
|
1411 |
|
|
CALL L1E99 ; routine FIND-INT2, BC = #cycles to generate
|
1412 |
|
|
POP HL ; HL = tone period
|
1413 |
|
|
LD D,B ;
|
1414 |
|
|
LD E,C ; DE = #cycles
|
1415 |
|
|
LD A,D ;
|
1416 |
|
|
OR E ;
|
1417 |
|
|
RET Z ; if duration = 0, skip BEEP and avoid 65536 cycle
|
1418 |
|
|
; boondoggle that would occur next
|
1419 |
|
|
DEC DE ; DE = #cycles - 1
|
1420 |
|
|
JP L03B5 ; to BEEPER
|
1421 |
|
|
|
1422 |
|
|
; ---
|
1423 |
|
|
|
1424 |
|
|
|
1425 |
|
|
;; REPORT-B
|
1426 |
|
|
L046C: RST 08H ; ERROR-1
|
1427 |
|
|
DEFB $0A ; Error Report: Integer out of range
|
1428 |
|
|
|
1429 |
|
|
|
1430 |
|
|
|
1431 |
|
|
; ---------------------
|
1432 |
|
|
; THE 'SEMI-TONE' TABLE
|
1433 |
|
|
; ---------------------
|
1434 |
|
|
;
|
1435 |
|
|
; Holds frequencies corresponding to semitones in middle octave.
|
1436 |
|
|
; To move n octaves higher or lower, frequencies are multiplied by 2^n.
|
1437 |
|
|
|
1438 |
|
|
;; semi-tone five byte fp decimal freq note (middle)
|
1439 |
|
|
L046E: DEFB $89, $02, $D0, $12, $86; 261.625565290 C
|
1440 |
|
|
DEFB $89, $0A, $97, $60, $75; 277.182631135 C#
|
1441 |
|
|
DEFB $89, $12, $D5, $17, $1F; 293.664768100 D
|
1442 |
|
|
DEFB $89, $1B, $90, $41, $02; 311.126983881 D#
|
1443 |
|
|
DEFB $89, $24, $D0, $53, $CA; 329.627557039 E
|
1444 |
|
|
DEFB $89, $2E, $9D, $36, $B1; 349.228231549 F
|
1445 |
|
|
DEFB $89, $38, $FF, $49, $3E; 369.994422674 F#
|
1446 |
|
|
DEFB $89, $43, $FF, $6A, $73; 391.995436072 G
|
1447 |
|
|
DEFB $89, $4F, $A7, $00, $54; 415.304697513 G#
|
1448 |
|
|
DEFB $89, $5C, $00, $00, $00; 440.000000000 A
|
1449 |
|
|
DEFB $89, $69, $14, $F6, $24; 466.163761616 A#
|
1450 |
|
|
DEFB $89, $76, $F1, $10, $05; 493.883301378 B
|
1451 |
|
|
|
1452 |
|
|
|
1453 |
|
|
; "Music is the hidden mathematical endeavour of a soul unconscious it
|
1454 |
|
|
; is calculating" - Gottfried Wilhelm Liebnitz 1646 - 1716
|
1455 |
|
|
|
1456 |
|
|
|
1457 |
|
|
;****************************************
|
1458 |
|
|
;** Part 4. CASSETTE HANDLING ROUTINES **
|
1459 |
|
|
;****************************************
|
1460 |
|
|
|
1461 |
|
|
; These routines begin with the service routines followed by a single
|
1462 |
|
|
; command entry point.
|
1463 |
|
|
; The first of these service routines is a curiosity.
|
1464 |
|
|
|
1465 |
|
|
; -----------------------
|
1466 |
|
|
; THE 'ZX81 NAME' ROUTINE
|
1467 |
|
|
; -----------------------
|
1468 |
|
|
; This routine fetches a filename in ZX81 format and is not used by the
|
1469 |
|
|
; cassette handling routines in this ROM.
|
1470 |
|
|
|
1471 |
|
|
;; zx81-name
|
1472 |
|
|
L04AA: CALL L24FB ; routine SCANNING to evaluate expression.
|
1473 |
|
|
LD A,($5C3B) ; fetch system variable FLAGS.
|
1474 |
|
|
ADD A,A ; test bit 7 - syntax, bit 6 - result type.
|
1475 |
|
|
JP M,L1C8A ; to REPORT-C if not string result
|
1476 |
|
|
; 'Nonsense in BASIC'.
|
1477 |
|
|
|
1478 |
|
|
POP HL ; drop return address.
|
1479 |
|
|
RET NC ; return early if checking syntax.
|
1480 |
|
|
|
1481 |
|
|
PUSH HL ; re-save return address.
|
1482 |
|
|
CALL L2BF1 ; routine STK-FETCH fetches string parameters.
|
1483 |
|
|
LD H,D ; transfer start of filename
|
1484 |
|
|
LD L,E ; to the HL register.
|
1485 |
|
|
DEC C ; adjust to point to last character and
|
1486 |
|
|
RET M ; return if the null string.
|
1487 |
|
|
; or multiple of 256!
|
1488 |
|
|
|
1489 |
|
|
ADD HL,BC ; find last character of the filename.
|
1490 |
|
|
; and also clear carry.
|
1491 |
|
|
SET 7,(HL) ; invert it.
|
1492 |
|
|
RET ; return.
|
1493 |
|
|
|
1494 |
|
|
; =========================================
|
1495 |
|
|
;
|
1496 |
|
|
; PORT 254 ($FE)
|
1497 |
|
|
;
|
1498 |
|
|
; spk mic { border }
|
1499 |
|
|
; ___ ___ ___ ___ ___ ___ ___ ___
|
1500 |
|
|
; PORT | | | | | | | | |
|
1501 |
|
|
; 254 | | | | | | | | |
|
1502 |
|
|
; $FE |___|___|___|___|___|___|___|___|
|
1503 |
|
|
; 7 6 5 4 3 2 1 0
|
1504 |
|
|
;
|
1505 |
|
|
|
1506 |
|
|
; ----------------------------------
|
1507 |
|
|
; Save header and program/data bytes
|
1508 |
|
|
; ----------------------------------
|
1509 |
|
|
; This routine saves a section of data. It is called from SA-CTRL to save the
|
1510 |
|
|
; seventeen bytes of header data. It is also the exit route from that routine
|
1511 |
|
|
; when it is set up to save the actual data.
|
1512 |
|
|
; On entry -
|
1513 |
|
|
; HL points to start of data.
|
1514 |
|
|
; IX points to descriptor.
|
1515 |
|
|
; The accumulator is set to $00 for a header, $FF for data.
|
1516 |
|
|
|
1517 |
|
|
;; SA-BYTES
|
1518 |
|
|
L04C2: LD HL,L053F ; address: SA/LD-RET
|
1519 |
|
|
PUSH HL ; is pushed as common exit route.
|
1520 |
|
|
; however there is only one non-terminal exit
|
1521 |
|
|
; point.
|
1522 |
|
|
|
1523 |
|
|
LD HL,$1F80 ; a timing constant H=$1F, L=$80
|
1524 |
|
|
; inner and outer loop counters
|
1525 |
|
|
; a five second lead-in is used for a header.
|
1526 |
|
|
|
1527 |
|
|
BIT 7,A ; test one bit of accumulator.
|
1528 |
|
|
; (AND A ?)
|
1529 |
|
|
JR Z,L04D0 ; skip to SA-FLAG if a header is being saved.
|
1530 |
|
|
|
1531 |
|
|
; else is data bytes and a shorter lead-in is used.
|
1532 |
|
|
|
1533 |
|
|
LD HL,$0C98 ; another timing value H=$0C, L=$98.
|
1534 |
|
|
; a two second lead-in is used for the data.
|
1535 |
|
|
|
1536 |
|
|
|
1537 |
|
|
;; SA-FLAG
|
1538 |
|
|
L04D0: EX AF,AF' ; save flag
|
1539 |
|
|
INC DE ; increase length by one.
|
1540 |
|
|
DEC IX ; decrease start.
|
1541 |
|
|
|
1542 |
|
|
DI ; disable interrupts
|
1543 |
|
|
|
1544 |
|
|
LD A,$02 ; select red for border, microphone bit on.
|
1545 |
|
|
LD B,A ; also does as an initial slight counter value.
|
1546 |
|
|
|
1547 |
|
|
;; SA-LEADER
|
1548 |
|
|
L04D8: DJNZ L04D8 ; self loop to SA-LEADER for delay.
|
1549 |
|
|
; after initial loop, count is $A4 (or $A3)
|
1550 |
|
|
|
1551 |
|
|
OUT ($FE),A ; output byte $02/$0D to tape port.
|
1552 |
|
|
|
1553 |
|
|
XOR $0F ; switch from RED (mic on) to CYAN (mic off).
|
1554 |
|
|
|
1555 |
|
|
LD B,$A4 ; hold count. also timed instruction.
|
1556 |
|
|
|
1557 |
|
|
DEC L ; originally $80 or $98.
|
1558 |
|
|
; but subsequently cycles 256 times.
|
1559 |
|
|
JR NZ,L04D8 ; back to SA-LEADER until L is zero.
|
1560 |
|
|
|
1561 |
|
|
; the outer loop is counted by H
|
1562 |
|
|
|
1563 |
|
|
DEC B ; decrement count
|
1564 |
|
|
DEC H ; originally twelve or thirty-one.
|
1565 |
|
|
JP P,L04D8 ; back to SA-LEADER until H becomes $FF
|
1566 |
|
|
|
1567 |
|
|
; now send a sync pulse. At this stage mic is off and A holds value
|
1568 |
|
|
; for mic on.
|
1569 |
|
|
; A sync pulse is much shorter than the steady pulses of the lead-in.
|
1570 |
|
|
|
1571 |
|
|
LD B,$2F ; another short timed delay.
|
1572 |
|
|
|
1573 |
|
|
;; SA-SYNC-1
|
1574 |
|
|
L04EA: DJNZ L04EA ; self loop to SA-SYNC-1
|
1575 |
|
|
|
1576 |
|
|
OUT ($FE),A ; switch to mic on and red.
|
1577 |
|
|
LD A,$0D ; prepare mic off - cyan
|
1578 |
|
|
LD B,$37 ; another short timed delay.
|
1579 |
|
|
|
1580 |
|
|
;; SA-SYNC-2
|
1581 |
|
|
L04F2: DJNZ L04F2 ; self loop to SA-SYNC-2
|
1582 |
|
|
|
1583 |
|
|
OUT ($FE),A ; output mic off, cyan border.
|
1584 |
|
|
LD BC,$3B0E ; B=$3B time(*), C=$0E, YELLOW, MIC OFF.
|
1585 |
|
|
|
1586 |
|
|
;
|
1587 |
|
|
|
1588 |
|
|
EX AF,AF' ; restore saved flag
|
1589 |
|
|
; which is 1st byte to be saved.
|
1590 |
|
|
|
1591 |
|
|
LD L,A ; and transfer to L.
|
1592 |
|
|
; the initial parity is A, $FF or $00.
|
1593 |
|
|
JP L0507 ; JUMP forward to SA-START ->
|
1594 |
|
|
; the mid entry point of loop.
|
1595 |
|
|
|
1596 |
|
|
; -------------------------
|
1597 |
|
|
; During the save loop a parity byte is maintained in H.
|
1598 |
|
|
; the save loop begins by testing if reduced length is zero and if so
|
1599 |
|
|
; the final parity byte is saved reducing count to $FFFF.
|
1600 |
|
|
|
1601 |
|
|
;; SA-LOOP
|
1602 |
|
|
L04FE: LD A,D ; fetch high byte
|
1603 |
|
|
OR E ; test against low byte.
|
1604 |
|
|
JR Z,L050E ; forward to SA-PARITY if zero.
|
1605 |
|
|
|
1606 |
|
|
LD L,(IX+$00) ; load currently addressed byte to L.
|
1607 |
|
|
|
1608 |
|
|
;; SA-LOOP-P
|
1609 |
|
|
L0505: LD A,H ; fetch parity byte.
|
1610 |
|
|
XOR L ; exclusive or with new byte.
|
1611 |
|
|
|
1612 |
|
|
; -> the mid entry point of loop.
|
1613 |
|
|
|
1614 |
|
|
;; SA-START
|
1615 |
|
|
L0507: LD H,A ; put parity byte in H.
|
1616 |
|
|
LD A,$01 ; prepare blue, mic=on.
|
1617 |
|
|
SCF ; set carry flag ready to rotate in.
|
1618 |
|
|
JP L0525 ; JUMP forward to SA-8-BITS -8->
|
1619 |
|
|
|
1620 |
|
|
; ---
|
1621 |
|
|
|
1622 |
|
|
;; SA-PARITY
|
1623 |
|
|
L050E: LD L,H ; transfer the running parity byte to L and
|
1624 |
|
|
JR L0505 ; back to SA-LOOP-P
|
1625 |
|
|
; to output that byte before quitting normally.
|
1626 |
|
|
|
1627 |
|
|
; ---
|
1628 |
|
|
|
1629 |
|
|
; The entry point to save yellow part of bit.
|
1630 |
|
|
; A bit consists of a period with mic on and blue border followed by
|
1631 |
|
|
; a period of mic off with yellow border.
|
1632 |
|
|
; Note. since the DJNZ instruction does not affect flags, the zero flag is
|
1633 |
|
|
; used to indicate which of the two passes is in effect and the carry
|
1634 |
|
|
; maintains the state of the bit to be saved.
|
1635 |
|
|
|
1636 |
|
|
;; SA-BIT-2
|
1637 |
|
|
L0511: LD A,C ; fetch 'mic on and yellow' which is
|
1638 |
|
|
; held permanently in C.
|
1639 |
|
|
BIT 7,B ; set the zero flag. B holds $3E.
|
1640 |
|
|
|
1641 |
|
|
; The entry point to save 1 entire bit. For first bit B holds $3B(*).
|
1642 |
|
|
; Carry is set if saved bit is 1. zero is reset NZ on entry.
|
1643 |
|
|
|
1644 |
|
|
;; SA-BIT-1
|
1645 |
|
|
L0514: DJNZ L0514 ; self loop for delay to SA-BIT-1
|
1646 |
|
|
|
1647 |
|
|
JR NC,L051C ; forward to SA-OUT if bit is 0.
|
1648 |
|
|
|
1649 |
|
|
; but if bit is 1 then the mic state is held for longer.
|
1650 |
|
|
|
1651 |
|
|
LD B,$42 ; set timed delay. (66 decimal)
|
1652 |
|
|
|
1653 |
|
|
;; SA-SET
|
1654 |
|
|
L051A: DJNZ L051A ; self loop to SA-SET
|
1655 |
|
|
; (roughly an extra 66*13 clock cycles)
|
1656 |
|
|
|
1657 |
|
|
;; SA-OUT
|
1658 |
|
|
L051C: OUT ($FE),A ; blue and mic on OR yellow and mic off.
|
1659 |
|
|
|
1660 |
|
|
LD B,$3E ; set up delay
|
1661 |
|
|
JR NZ,L0511 ; back to SA-BIT-2 if zero reset NZ (first pass)
|
1662 |
|
|
|
1663 |
|
|
; proceed when the blue and yellow bands have been output.
|
1664 |
|
|
|
1665 |
|
|
DEC B ; change value $3E to $3D.
|
1666 |
|
|
XOR A ; clear carry flag (ready to rotate in).
|
1667 |
|
|
INC A ; reset zero flag i.e. NZ.
|
1668 |
|
|
|
1669 |
|
|
; -8->
|
1670 |
|
|
|
1671 |
|
|
;; SA-8-BITS
|
1672 |
|
|
L0525: RL L ; rotate left through carry
|
1673 |
|
|
; C<76543210
|
1674 |
|
|
JP NZ,L0514 ; JUMP back to SA-BIT-1
|
1675 |
|
|
; until all 8 bits done.
|
1676 |
|
|
|
1677 |
|
|
; when the initial set carry is passed out again then a byte is complete.
|
1678 |
|
|
|
1679 |
|
|
DEC DE ; decrease length
|
1680 |
|
|
INC IX ; increase byte pointer
|
1681 |
|
|
LD B,$31 ; set up timing.
|
1682 |
|
|
|
1683 |
|
|
LD A,$7F ; test the space key and
|
1684 |
|
|
IN A,($FE) ; return to common exit (to restore border)
|
1685 |
|
|
RRA ; if a space is pressed
|
1686 |
|
|
RET NC ; return to SA/LD-RET. - - >
|
1687 |
|
|
|
1688 |
|
|
; now test if byte counter has reached $FFFF.
|
1689 |
|
|
|
1690 |
|
|
LD A,D ; fetch high byte
|
1691 |
|
|
INC A ; increment.
|
1692 |
|
|
JP NZ,L04FE ; JUMP to SA-LOOP if more bytes.
|
1693 |
|
|
|
1694 |
|
|
LD B,$3B ; a final delay.
|
1695 |
|
|
|
1696 |
|
|
;; SA-DELAY
|
1697 |
|
|
L053C: DJNZ L053C ; self loop to SA-DELAY
|
1698 |
|
|
|
1699 |
|
|
RET ; return - - >
|
1700 |
|
|
|
1701 |
|
|
; ------------------------------
|
1702 |
|
|
; THE 'SAVE/LOAD RETURN' ROUTINE
|
1703 |
|
|
; ------------------------------
|
1704 |
|
|
; The address of this routine is pushed on the stack prior to any load/save
|
1705 |
|
|
; operation and it handles normal completion with the restoration of the
|
1706 |
|
|
; border and also abnormal termination when the break key, or to be more
|
1707 |
|
|
; precise the space key is pressed during a tape operation.
|
1708 |
|
|
;
|
1709 |
|
|
; - - >
|
1710 |
|
|
|
1711 |
|
|
;; SA/LD-RET
|
1712 |
|
|
L053F: PUSH AF ; preserve accumulator throughout.
|
1713 |
|
|
LD A,($5C48) ; fetch border colour from BORDCR.
|
1714 |
|
|
AND $38 ; mask off paper bits.
|
1715 |
|
|
RRCA ; rotate
|
1716 |
|
|
RRCA ; to the
|
1717 |
|
|
RRCA ; range 0-7.
|
1718 |
|
|
|
1719 |
|
|
OUT ($FE),A ; change the border colour.
|
1720 |
|
|
|
1721 |
|
|
LD A,$7F ; read from port address $7FFE the
|
1722 |
|
|
IN A,($FE) ; row with the space key at outside.
|
1723 |
|
|
|
1724 |
|
|
RRA ; test for space key pressed.
|
1725 |
|
|
EI ; enable interrupts
|
1726 |
|
|
JR C,L0554 ; forward to SA/LD-END if not
|
1727 |
|
|
|
1728 |
|
|
|
1729 |
|
|
;; REPORT-Da
|
1730 |
|
|
L0552: RST 08H ; ERROR-1
|
1731 |
|
|
DEFB $0C ; Error Report: BREAK - CONT repeats
|
1732 |
|
|
|
1733 |
|
|
; ---
|
1734 |
|
|
|
1735 |
|
|
;; SA/LD-END
|
1736 |
|
|
L0554: POP AF ; restore the accumulator.
|
1737 |
|
|
RET ; return.
|
1738 |
|
|
|
1739 |
|
|
; ------------------------------------
|
1740 |
|
|
; Load header or block of information
|
1741 |
|
|
; ------------------------------------
|
1742 |
|
|
; This routine is used to load bytes and on entry A is set to $00 for a
|
1743 |
|
|
; header or to $FF for data. IX points to the start of receiving location
|
1744 |
|
|
; and DE holds the length of bytes to be loaded. If, on entry the carry flag
|
1745 |
|
|
; is set then data is loaded, if reset then it is verified.
|
1746 |
|
|
|
1747 |
|
|
;; LD-BYTES
|
1748 |
|
|
L0556: INC D ; reset the zero flag without disturbing carry.
|
1749 |
|
|
EX AF,AF' ; preserve entry flags.
|
1750 |
|
|
DEC D ; restore high byte of length.
|
1751 |
|
|
|
1752 |
|
|
DI ; disable interrupts
|
1753 |
|
|
|
1754 |
|
|
LD A,$0F ; make the border white and mic off.
|
1755 |
|
|
OUT ($FE),A ; output to port.
|
1756 |
|
|
|
1757 |
|
|
LD HL,L053F ; Address: SA/LD-RET
|
1758 |
|
|
PUSH HL ; is saved on stack as terminating routine.
|
1759 |
|
|
|
1760 |
|
|
; the reading of the EAR bit (D6) will always be preceded by a test of the
|
1761 |
|
|
; space key (D0), so store the initial post-test state.
|
1762 |
|
|
|
1763 |
|
|
IN A,($FE) ; read the ear state - bit 6.
|
1764 |
|
|
RRA ; rotate to bit 5.
|
1765 |
|
|
AND $20 ; isolate this bit.
|
1766 |
|
|
OR $02 ; combine with red border colour.
|
1767 |
|
|
LD C,A ; and store initial state long-term in C.
|
1768 |
|
|
CP A ; set the zero flag.
|
1769 |
|
|
|
1770 |
|
|
;
|
1771 |
|
|
|
1772 |
|
|
;; LD-BREAK
|
1773 |
|
|
L056B: RET NZ ; return if at any time space is pressed.
|
1774 |
|
|
|
1775 |
|
|
;; LD-START
|
1776 |
|
|
L056C: CALL L05E7 ; routine LD-EDGE-1
|
1777 |
|
|
JR NC,L056B ; back to LD-BREAK with time out and no
|
1778 |
|
|
; edge present on tape.
|
1779 |
|
|
|
1780 |
|
|
; but continue when a transition is found on tape.
|
1781 |
|
|
|
1782 |
|
|
LD HL,$0415 ; set up 16-bit outer loop counter for
|
1783 |
|
|
; approx 1 second delay.
|
1784 |
|
|
|
1785 |
|
|
;; LD-WAIT
|
1786 |
|
|
L0574: DJNZ L0574 ; self loop to LD-WAIT (for 256 times)
|
1787 |
|
|
|
1788 |
|
|
DEC HL ; decrease outer loop counter.
|
1789 |
|
|
LD A,H ; test for
|
1790 |
|
|
OR L ; zero.
|
1791 |
|
|
JR NZ,L0574 ; back to LD-WAIT, if not zero, with zero in B.
|
1792 |
|
|
|
1793 |
|
|
; continue after delay with H holding zero and B also.
|
1794 |
|
|
; sample 256 edges to check that we are in the middle of a lead-in section.
|
1795 |
|
|
|
1796 |
|
|
CALL L05E3 ; routine LD-EDGE-2
|
1797 |
|
|
JR NC,L056B ; back to LD-BREAK
|
1798 |
|
|
; if no edges at all.
|
1799 |
|
|
|
1800 |
|
|
;; LD-LEADER
|
1801 |
|
|
L0580: LD B,$9C ; set timing value.
|
1802 |
|
|
CALL L05E3 ; routine LD-EDGE-2
|
1803 |
|
|
JR NC,L056B ; back to LD-BREAK if time-out
|
1804 |
|
|
|
1805 |
|
|
LD A,$C6 ; two edges must be spaced apart.
|
1806 |
|
|
CP B ; compare
|
1807 |
|
|
JR NC,L056C ; back to LD-START if too close together for a
|
1808 |
|
|
; lead-in.
|
1809 |
|
|
|
1810 |
|
|
INC H ; proceed to test 256 edged sample.
|
1811 |
|
|
JR NZ,L0580 ; back to LD-LEADER while more to do.
|
1812 |
|
|
|
1813 |
|
|
; sample indicates we are in the middle of a two or five second lead-in.
|
1814 |
|
|
; Now test every edge looking for the terminal sync signal.
|
1815 |
|
|
|
1816 |
|
|
;; LD-SYNC
|
1817 |
|
|
L058F: LD B,$C9 ; initial timing value in B.
|
1818 |
|
|
CALL L05E7 ; routine LD-EDGE-1
|
1819 |
|
|
JR NC,L056B ; back to LD-BREAK with time-out.
|
1820 |
|
|
|
1821 |
|
|
LD A,B ; fetch augmented timing value from B.
|
1822 |
|
|
CP $D4 ; compare
|
1823 |
|
|
JR NC,L058F ; back to LD-SYNC if gap too big, that is,
|
1824 |
|
|
; a normal lead-in edge gap.
|
1825 |
|
|
|
1826 |
|
|
; but a short gap will be the sync pulse.
|
1827 |
|
|
; in which case another edge should appear before B rises to $FF
|
1828 |
|
|
|
1829 |
|
|
CALL L05E7 ; routine LD-EDGE-1
|
1830 |
|
|
RET NC ; return with time-out.
|
1831 |
|
|
|
1832 |
|
|
; proceed when the sync at the end of the lead-in is found.
|
1833 |
|
|
; We are about to load data so change the border colours.
|
1834 |
|
|
|
1835 |
|
|
LD A,C ; fetch long-term mask from C
|
1836 |
|
|
XOR $03 ; and make blue/yellow.
|
1837 |
|
|
|
1838 |
|
|
LD C,A ; store the new long-term byte.
|
1839 |
|
|
|
1840 |
|
|
LD H,$00 ; set up parity byte as zero.
|
1841 |
|
|
LD B,$B0 ; timing.
|
1842 |
|
|
JR L05C8 ; forward to LD-MARKER
|
1843 |
|
|
; the loop mid entry point with the alternate
|
1844 |
|
|
; zero flag reset to indicate first byte
|
1845 |
|
|
; is discarded.
|
1846 |
|
|
|
1847 |
|
|
; --------------
|
1848 |
|
|
; the loading loop loads each byte and is entered at the mid point.
|
1849 |
|
|
|
1850 |
|
|
;; LD-LOOP
|
1851 |
|
|
L05A9: EX AF,AF' ; restore entry flags and type in A.
|
1852 |
|
|
JR NZ,L05B3 ; forward to LD-FLAG if awaiting initial flag
|
1853 |
|
|
; which is to be discarded.
|
1854 |
|
|
|
1855 |
|
|
JR NC,L05BD ; forward to LD-VERIFY if not to be loaded.
|
1856 |
|
|
|
1857 |
|
|
LD (IX+$00),L ; place loaded byte at memory location.
|
1858 |
|
|
JR L05C2 ; forward to LD-NEXT
|
1859 |
|
|
|
1860 |
|
|
; ---
|
1861 |
|
|
|
1862 |
|
|
;; LD-FLAG
|
1863 |
|
|
L05B3: RL C ; preserve carry (verify) flag in long-term
|
1864 |
|
|
; state byte. Bit 7 can be lost.
|
1865 |
|
|
|
1866 |
|
|
XOR L ; compare type in A with first byte in L.
|
1867 |
|
|
RET NZ ; return if no match e.g. CODE vs. DATA.
|
1868 |
|
|
|
1869 |
|
|
; continue when data type matches.
|
1870 |
|
|
|
1871 |
|
|
LD A,C ; fetch byte with stored carry
|
1872 |
|
|
RRA ; rotate it to carry flag again
|
1873 |
|
|
LD C,A ; restore long-term port state.
|
1874 |
|
|
|
1875 |
|
|
INC DE ; increment length ??
|
1876 |
|
|
JR L05C4 ; forward to LD-DEC.
|
1877 |
|
|
; but why not to location after ?
|
1878 |
|
|
|
1879 |
|
|
; ---
|
1880 |
|
|
; for verification the byte read from tape is compared with that in memory.
|
1881 |
|
|
|
1882 |
|
|
;; LD-VERIFY
|
1883 |
|
|
L05BD: LD A,(IX+$00) ; fetch byte from memory.
|
1884 |
|
|
XOR L ; compare with that on tape
|
1885 |
|
|
RET NZ ; return if not zero.
|
1886 |
|
|
|
1887 |
|
|
;; LD-NEXT
|
1888 |
|
|
L05C2: INC IX ; increment byte pointer.
|
1889 |
|
|
|
1890 |
|
|
;; LD-DEC
|
1891 |
|
|
L05C4: DEC DE ; decrement length.
|
1892 |
|
|
EX AF,AF' ; store the flags.
|
1893 |
|
|
LD B,$B2 ; timing.
|
1894 |
|
|
|
1895 |
|
|
; when starting to read 8 bits the receiving byte is marked with bit at right.
|
1896 |
|
|
; when this is rotated out again then 8 bits have been read.
|
1897 |
|
|
|
1898 |
|
|
;; LD-MARKER
|
1899 |
|
|
L05C8: LD L,$01 ; initialize as %00000001
|
1900 |
|
|
|
1901 |
|
|
;; LD-8-BITS
|
1902 |
|
|
L05CA: CALL L05E3 ; routine LD-EDGE-2 increments B relative to
|
1903 |
|
|
; gap between 2 edges.
|
1904 |
|
|
RET NC ; return with time-out.
|
1905 |
|
|
|
1906 |
|
|
LD A,$CB ; the comparison byte.
|
1907 |
|
|
CP B ; compare to incremented value of B.
|
1908 |
|
|
; if B is higher then bit on tape was set.
|
1909 |
|
|
; if <= then bit on tape is reset.
|
1910 |
|
|
|
1911 |
|
|
RL L ; rotate the carry bit into L.
|
1912 |
|
|
|
1913 |
|
|
LD B,$B0 ; reset the B timer byte.
|
1914 |
|
|
JP NC,L05CA ; JUMP back to LD-8-BITS
|
1915 |
|
|
|
1916 |
|
|
; when carry set then marker bit has been passed out and byte is complete.
|
1917 |
|
|
|
1918 |
|
|
LD A,H ; fetch the running parity byte.
|
1919 |
|
|
XOR L ; include the new byte.
|
1920 |
|
|
LD H,A ; and store back in parity register.
|
1921 |
|
|
|
1922 |
|
|
LD A,D ; check length of
|
1923 |
|
|
OR E ; expected bytes.
|
1924 |
|
|
JR NZ,L05A9 ; back to LD-LOOP
|
1925 |
|
|
; while there are more.
|
1926 |
|
|
|
1927 |
|
|
; when all bytes loaded then parity byte should be zero.
|
1928 |
|
|
|
1929 |
|
|
LD A,H ; fetch parity byte.
|
1930 |
|
|
CP $01 ; set carry if zero.
|
1931 |
|
|
RET ; return
|
1932 |
|
|
; in no carry then error as checksum disagrees.
|
1933 |
|
|
|
1934 |
|
|
; -------------------------
|
1935 |
|
|
; Check signal being loaded
|
1936 |
|
|
; -------------------------
|
1937 |
|
|
; An edge is a transition from one mic state to another.
|
1938 |
|
|
; More specifically a change in bit 6 of value input from port $FE.
|
1939 |
|
|
; Graphically it is a change of border colour, say, blue to yellow.
|
1940 |
|
|
; The first entry point looks for two adjacent edges. The second entry point
|
1941 |
|
|
; is used to find a single edge.
|
1942 |
|
|
; The B register holds a count, up to 256, within which the edge (or edges)
|
1943 |
|
|
; must be found. The gap between two edges will be more for a '1' than a '0'
|
1944 |
|
|
; so the value of B denotes the state of the bit (two edges) read from tape.
|
1945 |
|
|
|
1946 |
|
|
; ->
|
1947 |
|
|
|
1948 |
|
|
;; LD-EDGE-2
|
1949 |
|
|
L05E3: CALL L05E7 ; call routine LD-EDGE-1 below.
|
1950 |
|
|
RET NC ; return if space pressed or time-out.
|
1951 |
|
|
; else continue and look for another adjacent
|
1952 |
|
|
; edge which together represent a bit on the
|
1953 |
|
|
; tape.
|
1954 |
|
|
|
1955 |
|
|
; ->
|
1956 |
|
|
; this entry point is used to find a single edge from above but also
|
1957 |
|
|
; when detecting a read-in signal on the tape.
|
1958 |
|
|
|
1959 |
|
|
;; LD-EDGE-1
|
1960 |
|
|
L05E7: LD A,$16 ; a delay value of twenty two.
|
1961 |
|
|
|
1962 |
|
|
;; LD-DELAY
|
1963 |
|
|
L05E9: DEC A ; decrement counter
|
1964 |
|
|
JR NZ,L05E9 ; loop back to LD-DELAY 22 times.
|
1965 |
|
|
|
1966 |
|
|
AND A ; clear carry.
|
1967 |
|
|
|
1968 |
|
|
;; LD-SAMPLE
|
1969 |
|
|
L05ED: INC B ; increment the time-out counter.
|
1970 |
|
|
RET Z ; return with failure when $FF passed.
|
1971 |
|
|
|
1972 |
|
|
LD A,$7F ; prepare to read keyboard and EAR port
|
1973 |
|
|
IN A,($FE) ; row $7FFE. bit 6 is EAR, bit 0 is SPACE key.
|
1974 |
|
|
RRA ; test outer key the space. (bit 6 moves to 5)
|
1975 |
|
|
RET NC ; return if space pressed. >>>
|
1976 |
|
|
|
1977 |
|
|
XOR C ; compare with initial long-term state.
|
1978 |
|
|
AND $20 ; isolate bit 5
|
1979 |
|
|
JR Z,L05ED ; back to LD-SAMPLE if no edge.
|
1980 |
|
|
|
1981 |
|
|
; but an edge, a transition of the EAR bit, has been found so switch the
|
1982 |
|
|
; long-term comparison byte containing both border colour and EAR bit.
|
1983 |
|
|
|
1984 |
|
|
LD A,C ; fetch comparison value.
|
1985 |
|
|
CPL ; switch the bits
|
1986 |
|
|
LD C,A ; and put back in C for long-term.
|
1987 |
|
|
|
1988 |
|
|
AND $07 ; isolate new colour bits.
|
1989 |
|
|
OR $08 ; set bit 3 - MIC off.
|
1990 |
|
|
OUT ($FE),A ; send to port to effect the change of colour.
|
1991 |
|
|
|
1992 |
|
|
SCF ; set carry flag signaling edge found within
|
1993 |
|
|
; time allowed.
|
1994 |
|
|
RET ; return.
|
1995 |
|
|
|
1996 |
|
|
; ---------------------------------
|
1997 |
|
|
; Entry point for all tape commands
|
1998 |
|
|
; ---------------------------------
|
1999 |
|
|
; This is the single entry point for the four tape commands.
|
2000 |
|
|
; The routine first determines in what context it has been called by examining
|
2001 |
|
|
; the low byte of the Syntax table entry which was stored in T_ADDR.
|
2002 |
|
|
; Subtracting $EO (the present arrangement) gives a value of
|
2003 |
|
|
; $00 - SAVE
|
2004 |
|
|
; $01 - LOAD
|
2005 |
|
|
; $02 - VERIFY
|
2006 |
|
|
; $03 - MERGE
|
2007 |
|
|
; As with all commands the address STMT-RET is on the stack.
|
2008 |
|
|
|
2009 |
|
|
;; SAVE-ETC
|
2010 |
|
|
L0605: POP AF ; discard address STMT-RET.
|
2011 |
|
|
LD A,($5C74) ; fetch T_ADDR
|
2012 |
|
|
|
2013 |
|
|
; Now reduce the low byte of the Syntax table entry to give command.
|
2014 |
|
|
; Note. For ZASM use SUB $E0 as next instruction.
|
2015 |
|
|
|
2016 |
|
|
L0609: SUB L1ADF + 1 % 256 ; subtract the known offset.
|
2017 |
|
|
; ( is SUB $E0 in standard ROM )
|
2018 |
|
|
|
2019 |
|
|
LD ($5C74),A ; and put back in T_ADDR as 0,1,2, or 3
|
2020 |
|
|
; for future reference.
|
2021 |
|
|
|
2022 |
|
|
CALL L1C8C ; routine EXPT-EXP checks that a string
|
2023 |
|
|
; expression follows and stacks the
|
2024 |
|
|
; parameters in run-time.
|
2025 |
|
|
|
2026 |
|
|
CALL L2530 ; routine SYNTAX-Z
|
2027 |
|
|
JR Z,L0652 ; forward to SA-DATA if checking syntax.
|
2028 |
|
|
|
2029 |
|
|
LD BC,$0011 ; presume seventeen bytes for a header.
|
2030 |
|
|
LD A,($5C74) ; fetch command from T_ADDR.
|
2031 |
|
|
AND A ; test for zero - SAVE.
|
2032 |
|
|
JR Z,L0621 ; forward to SA-SPACE if so.
|
2033 |
|
|
|
2034 |
|
|
LD C,$22 ; else double length to thirty four.
|
2035 |
|
|
|
2036 |
|
|
;; SA-SPACE
|
2037 |
|
|
L0621: RST 30H ; BC-SPACES creates 17/34 bytes in workspace.
|
2038 |
|
|
|
2039 |
|
|
PUSH DE ; transfer the start of new space to
|
2040 |
|
|
POP IX ; the available index register.
|
2041 |
|
|
|
2042 |
|
|
; ten spaces are required for the default filename but it is simpler to
|
2043 |
|
|
; overwrite the first file-type indicator byte as well.
|
2044 |
|
|
|
2045 |
|
|
LD B,$0B ; set counter to eleven.
|
2046 |
|
|
LD A,$20 ; prepare a space.
|
2047 |
|
|
|
2048 |
|
|
;; SA-BLANK
|
2049 |
|
|
L0629: LD (DE),A ; set workspace location to space.
|
2050 |
|
|
INC DE ; next location.
|
2051 |
|
|
DJNZ L0629 ; loop back to SA-BLANK till all eleven done.
|
2052 |
|
|
|
2053 |
|
|
LD (IX+$01),$FF ; set first byte of ten character filename
|
2054 |
|
|
; to $FF as a default to signal null string.
|
2055 |
|
|
|
2056 |
|
|
CALL L2BF1 ; routine STK-FETCH fetches the filename
|
2057 |
|
|
; parameters from the calculator stack.
|
2058 |
|
|
; length of string in BC.
|
2059 |
|
|
; start of string in DE.
|
2060 |
|
|
|
2061 |
|
|
LD HL,$FFF6 ; prepare the value minus ten.
|
2062 |
|
|
DEC BC ; decrement length.
|
2063 |
|
|
; ten becomes nine, zero becomes $FFFF.
|
2064 |
|
|
ADD HL,BC ; trial addition.
|
2065 |
|
|
INC BC ; restore true length.
|
2066 |
|
|
JR NC,L064B ; forward to SA-NAME if length is one to ten.
|
2067 |
|
|
|
2068 |
|
|
; the filename is more than ten characters in length or the null string.
|
2069 |
|
|
|
2070 |
|
|
LD A,($5C74) ; fetch command from T_ADDR.
|
2071 |
|
|
AND A ; test for zero - SAVE.
|
2072 |
|
|
JR NZ,L0644 ; forward to SA-NULL if not the SAVE command.
|
2073 |
|
|
|
2074 |
|
|
; but no more than ten characters are allowed for SAVE.
|
2075 |
|
|
; The first ten characters of any other command parameter are acceptable.
|
2076 |
|
|
; Weird, but necessary, if saving to sectors.
|
2077 |
|
|
; Note. the golden rule that there are no restriction on anything is broken.
|
2078 |
|
|
|
2079 |
|
|
;; REPORT-Fa
|
2080 |
|
|
L0642: RST 08H ; ERROR-1
|
2081 |
|
|
DEFB $0E ; Error Report: Invalid file name
|
2082 |
|
|
|
2083 |
|
|
; continue with LOAD, MERGE, VERIFY and also SAVE within ten character limit.
|
2084 |
|
|
|
2085 |
|
|
;; SA-NULL
|
2086 |
|
|
L0644: LD A,B ; test length of filename
|
2087 |
|
|
OR C ; for zero.
|
2088 |
|
|
JR Z,L0652 ; forward to SA-DATA if so using the 255
|
2089 |
|
|
; indicator followed by spaces.
|
2090 |
|
|
|
2091 |
|
|
LD BC,$000A ; else trim length to ten.
|
2092 |
|
|
|
2093 |
|
|
; other paths rejoin here with BC holding length in range 1 - 10.
|
2094 |
|
|
|
2095 |
|
|
;; SA-NAME
|
2096 |
|
|
L064B: PUSH IX ; push start of file descriptor.
|
2097 |
|
|
POP HL ; and pop into HL.
|
2098 |
|
|
|
2099 |
|
|
INC HL ; HL now addresses first byte of filename.
|
2100 |
|
|
EX DE,HL ; transfer destination address to DE, start
|
2101 |
|
|
; of string in command to HL.
|
2102 |
|
|
LDIR ; copy up to ten bytes
|
2103 |
|
|
; if less than ten then trailing spaces follow.
|
2104 |
|
|
|
2105 |
|
|
; the case for the null string rejoins here.
|
2106 |
|
|
|
2107 |
|
|
;; SA-DATA
|
2108 |
|
|
L0652: RST 18H ; GET-CHAR
|
2109 |
|
|
CP $E4 ; is character after filename the token 'DATA' ?
|
2110 |
|
|
JR NZ,L06A0 ; forward to SA-SCR$ to consider SCREEN$ if
|
2111 |
|
|
; not.
|
2112 |
|
|
|
2113 |
|
|
; continue to consider DATA.
|
2114 |
|
|
|
2115 |
|
|
LD A,($5C74) ; fetch command from T_ADDR
|
2116 |
|
|
CP $03 ; is it 'VERIFY' ?
|
2117 |
|
|
JP Z,L1C8A ; jump forward to REPORT-C if so.
|
2118 |
|
|
; 'Nonsense in BASIC'
|
2119 |
|
|
; VERIFY "d" DATA is not allowed.
|
2120 |
|
|
|
2121 |
|
|
; continue with SAVE, LOAD, MERGE of DATA.
|
2122 |
|
|
|
2123 |
|
|
RST 20H ; NEXT-CHAR
|
2124 |
|
|
CALL L28B2 ; routine LOOK-VARS searches variables area
|
2125 |
|
|
; returning with carry reset if found or
|
2126 |
|
|
; checking syntax.
|
2127 |
|
|
SET 7,C ; this converts a simple string to a
|
2128 |
|
|
; string array. The test for an array or string
|
2129 |
|
|
; comes later.
|
2130 |
|
|
JR NC,L0672 ; forward to SA-V-OLD if variable found.
|
2131 |
|
|
|
2132 |
|
|
LD HL,$0000 ; set destination to zero as not fixed.
|
2133 |
|
|
LD A,($5C74) ; fetch command from T_ADDR
|
2134 |
|
|
DEC A ; test for 1 - LOAD
|
2135 |
|
|
JR Z,L0685 ; forward to SA-V-NEW with LOAD DATA.
|
2136 |
|
|
; to load a new array.
|
2137 |
|
|
|
2138 |
|
|
; otherwise the variable was not found in run-time with SAVE/MERGE.
|
2139 |
|
|
|
2140 |
|
|
;; REPORT-2a
|
2141 |
|
|
L0670: RST 08H ; ERROR-1
|
2142 |
|
|
DEFB $01 ; Error Report: Variable not found
|
2143 |
|
|
|
2144 |
|
|
; continue with SAVE/LOAD DATA
|
2145 |
|
|
|
2146 |
|
|
;; SA-V-OLD
|
2147 |
|
|
L0672: JP NZ,L1C8A ; to REPORT-C if not an array variable.
|
2148 |
|
|
; or erroneously a simple string.
|
2149 |
|
|
; 'Nonsense in BASIC'
|
2150 |
|
|
|
2151 |
|
|
|
2152 |
|
|
CALL L2530 ; routine SYNTAX-Z
|
2153 |
|
|
JR Z,L0692 ; forward to SA-DATA-1 if checking syntax.
|
2154 |
|
|
|
2155 |
|
|
INC HL ; step past single character variable name.
|
2156 |
|
|
LD A,(HL) ; fetch low byte of length.
|
2157 |
|
|
LD (IX+$0B),A ; place in descriptor.
|
2158 |
|
|
INC HL ; point to high byte.
|
2159 |
|
|
LD A,(HL) ; and transfer that
|
2160 |
|
|
LD (IX+$0C),A ; to descriptor.
|
2161 |
|
|
INC HL ; increase pointer within variable.
|
2162 |
|
|
|
2163 |
|
|
;; SA-V-NEW
|
2164 |
|
|
L0685: LD (IX+$0E),C ; place character array name in header.
|
2165 |
|
|
LD A,$01 ; default to type numeric.
|
2166 |
|
|
BIT 6,C ; test result from look-vars.
|
2167 |
|
|
JR Z,L068F ; forward to SA-V-TYPE if numeric.
|
2168 |
|
|
|
2169 |
|
|
INC A ; set type to 2 - string array.
|
2170 |
|
|
|
2171 |
|
|
;; SA-V-TYPE
|
2172 |
|
|
L068F: LD (IX+$00),A ; place type 0, 1 or 2 in descriptor.
|
2173 |
|
|
|
2174 |
|
|
;; SA-DATA-1
|
2175 |
|
|
L0692: EX DE,HL ; save var pointer in DE
|
2176 |
|
|
|
2177 |
|
|
RST 20H ; NEXT-CHAR
|
2178 |
|
|
CP $29 ; is character ')' ?
|
2179 |
|
|
JR NZ,L0672 ; back if not to SA-V-OLD to report
|
2180 |
|
|
; 'Nonsense in BASIC'
|
2181 |
|
|
|
2182 |
|
|
RST 20H ; NEXT-CHAR advances character address.
|
2183 |
|
|
CALL L1BEE ; routine CHECK-END errors if not end of
|
2184 |
|
|
; the statement.
|
2185 |
|
|
|
2186 |
|
|
EX DE,HL ; bring back variables data pointer.
|
2187 |
|
|
JP L075A ; jump forward to SA-ALL
|
2188 |
|
|
|
2189 |
|
|
; ---
|
2190 |
|
|
; the branch was here to consider a 'SCREEN$', the display file.
|
2191 |
|
|
|
2192 |
|
|
;; SA-SCR$
|
2193 |
|
|
L06A0: CP $AA ; is character the token 'SCREEN$' ?
|
2194 |
|
|
JR NZ,L06C3 ; forward to SA-CODE if not.
|
2195 |
|
|
|
2196 |
|
|
LD A,($5C74) ; fetch command from T_ADDR
|
2197 |
|
|
CP $03 ; is it MERGE ?
|
2198 |
|
|
JP Z,L1C8A ; jump to REPORT-C if so.
|
2199 |
|
|
; 'Nonsense in BASIC'
|
2200 |
|
|
|
2201 |
|
|
; continue with SAVE/LOAD/VERIFY SCREEN$.
|
2202 |
|
|
|
2203 |
|
|
RST 20H ; NEXT-CHAR
|
2204 |
|
|
CALL L1BEE ; routine CHECK-END errors if not at end of
|
2205 |
|
|
; statement.
|
2206 |
|
|
|
2207 |
|
|
; continue in runtime.
|
2208 |
|
|
|
2209 |
|
|
LD (IX+$0B),$00 ; set descriptor length
|
2210 |
|
|
LD (IX+$0C),$1B ; to $1b00 to include bitmaps and attributes.
|
2211 |
|
|
|
2212 |
|
|
LD HL,$4000 ; set start to display file start.
|
2213 |
|
|
LD (IX+$0D),L ; place start in
|
2214 |
|
|
LD (IX+$0E),H ; the descriptor.
|
2215 |
|
|
JR L0710 ; forward to SA-TYPE-3
|
2216 |
|
|
|
2217 |
|
|
; ---
|
2218 |
|
|
; the branch was here to consider CODE.
|
2219 |
|
|
|
2220 |
|
|
;; SA-CODE
|
2221 |
|
|
L06C3: CP $AF ; is character the token 'CODE' ?
|
2222 |
|
|
JR NZ,L0716 ; forward if not to SA-LINE to consider an
|
2223 |
|
|
; auto-started BASIC program.
|
2224 |
|
|
|
2225 |
|
|
LD A,($5C74) ; fetch command from T_ADDR
|
2226 |
|
|
CP $03 ; is it MERGE ?
|
2227 |
|
|
JP Z,L1C8A ; jump forward to REPORT-C if so.
|
2228 |
|
|
; 'Nonsense in BASIC'
|
2229 |
|
|
|
2230 |
|
|
|
2231 |
|
|
RST 20H ; NEXT-CHAR advances character address.
|
2232 |
|
|
CALL L2048 ; routine PR-ST-END checks if a carriage
|
2233 |
|
|
; return or ':' follows.
|
2234 |
|
|
JR NZ,L06E1 ; forward to SA-CODE-1 if there are parameters.
|
2235 |
|
|
|
2236 |
|
|
LD A,($5C74) ; else fetch the command from T_ADDR.
|
2237 |
|
|
AND A ; test for zero - SAVE without a specification.
|
2238 |
|
|
JP Z,L1C8A ; jump to REPORT-C if so.
|
2239 |
|
|
; 'Nonsense in BASIC'
|
2240 |
|
|
|
2241 |
|
|
; for LOAD/VERIFY put zero on stack to signify handle at location saved from.
|
2242 |
|
|
|
2243 |
|
|
CALL L1CE6 ; routine USE-ZERO
|
2244 |
|
|
JR L06F0 ; forward to SA-CODE-2
|
2245 |
|
|
|
2246 |
|
|
; ---
|
2247 |
|
|
|
2248 |
|
|
; if there are more characters after CODE expect start and possibly length.
|
2249 |
|
|
|
2250 |
|
|
;; SA-CODE-1
|
2251 |
|
|
L06E1: CALL L1C82 ; routine EXPT-1NUM checks for numeric
|
2252 |
|
|
; expression and stacks it in run-time.
|
2253 |
|
|
|
2254 |
|
|
RST 18H ; GET-CHAR
|
2255 |
|
|
CP $2C ; does a comma follow ?
|
2256 |
|
|
JR Z,L06F5 ; forward if so to SA-CODE-3
|
2257 |
|
|
|
2258 |
|
|
; else allow saved code to be loaded to a specified address.
|
2259 |
|
|
|
2260 |
|
|
LD A,($5C74) ; fetch command from T_ADDR.
|
2261 |
|
|
AND A ; is the command SAVE which requires length ?
|
2262 |
|
|
JP Z,L1C8A ; jump to REPORT-C if so.
|
2263 |
|
|
; 'Nonsense in BASIC'
|
2264 |
|
|
|
2265 |
|
|
; the command LOAD code may rejoin here with zero stacked as start.
|
2266 |
|
|
|
2267 |
|
|
;; SA-CODE-2
|
2268 |
|
|
L06F0: CALL L1CE6 ; routine USE-ZERO stacks zero for length.
|
2269 |
|
|
JR L06F9 ; forward to SA-CODE-4
|
2270 |
|
|
|
2271 |
|
|
; ---
|
2272 |
|
|
; the branch was here with SAVE CODE start,
|
2273 |
|
|
|
2274 |
|
|
;; SA-CODE-3
|
2275 |
|
|
L06F5: RST 20H ; NEXT-CHAR advances character address.
|
2276 |
|
|
CALL L1C82 ; routine EXPT-1NUM checks for expression
|
2277 |
|
|
; and stacks in run-time.
|
2278 |
|
|
|
2279 |
|
|
; paths converge here and nothing must follow.
|
2280 |
|
|
|
2281 |
|
|
;; SA-CODE-4
|
2282 |
|
|
L06F9: CALL L1BEE ; routine CHECK-END errors with extraneous
|
2283 |
|
|
; characters and quits if checking syntax.
|
2284 |
|
|
|
2285 |
|
|
; in run-time there are two 16-bit parameters on the calculator stack.
|
2286 |
|
|
|
2287 |
|
|
CALL L1E99 ; routine FIND-INT2 gets length.
|
2288 |
|
|
LD (IX+$0B),C ; place length
|
2289 |
|
|
LD (IX+$0C),B ; in descriptor.
|
2290 |
|
|
CALL L1E99 ; routine FIND-INT2 gets start.
|
2291 |
|
|
LD (IX+$0D),C ; place start
|
2292 |
|
|
LD (IX+$0E),B ; in descriptor.
|
2293 |
|
|
LD H,B ; transfer the
|
2294 |
|
|
LD L,C ; start to HL also.
|
2295 |
|
|
|
2296 |
|
|
;; SA-TYPE-3
|
2297 |
|
|
L0710: LD (IX+$00),$03 ; place type 3 - code in descriptor.
|
2298 |
|
|
JR L075A ; forward to SA-ALL.
|
2299 |
|
|
|
2300 |
|
|
; ---
|
2301 |
|
|
; the branch was here with BASIC to consider an optional auto-start line
|
2302 |
|
|
; number.
|
2303 |
|
|
|
2304 |
|
|
;; SA-LINE
|
2305 |
|
|
L0716: CP $CA ; is character the token 'LINE' ?
|
2306 |
|
|
JR Z,L0723 ; forward to SA-LINE-1 if so.
|
2307 |
|
|
|
2308 |
|
|
; else all possibilities have been considered and nothing must follow.
|
2309 |
|
|
|
2310 |
|
|
CALL L1BEE ; routine CHECK-END
|
2311 |
|
|
|
2312 |
|
|
; continue in run-time to save BASIC without auto-start.
|
2313 |
|
|
|
2314 |
|
|
LD (IX+$0E),$80 ; place high line number in descriptor to
|
2315 |
|
|
; disable auto-start.
|
2316 |
|
|
JR L073A ; forward to SA-TYPE-0 to save program.
|
2317 |
|
|
|
2318 |
|
|
; ---
|
2319 |
|
|
; the branch was here to consider auto-start.
|
2320 |
|
|
|
2321 |
|
|
;; SA-LINE-1
|
2322 |
|
|
L0723: LD A,($5C74) ; fetch command from T_ADDR
|
2323 |
|
|
AND A ; test for SAVE.
|
2324 |
|
|
JP NZ,L1C8A ; jump forward to REPORT-C with anything else.
|
2325 |
|
|
; 'Nonsense in BASIC'
|
2326 |
|
|
|
2327 |
|
|
;
|
2328 |
|
|
|
2329 |
|
|
RST 20H ; NEXT-CHAR
|
2330 |
|
|
CALL L1C82 ; routine EXPT-1NUM checks for numeric
|
2331 |
|
|
; expression and stacks in run-time.
|
2332 |
|
|
CALL L1BEE ; routine CHECK-END quits if syntax path.
|
2333 |
|
|
CALL L1E99 ; routine FIND-INT2 fetches the numeric
|
2334 |
|
|
; expression.
|
2335 |
|
|
LD (IX+$0D),C ; place the auto-start
|
2336 |
|
|
LD (IX+$0E),B ; line number in the descriptor.
|
2337 |
|
|
|
2338 |
|
|
; Note. this isn't checked, but is subsequently handled by the system.
|
2339 |
|
|
; If the user typed 40000 instead of 4000 then it won't auto-start
|
2340 |
|
|
; at line 4000, or indeed, at all.
|
2341 |
|
|
|
2342 |
|
|
; continue to save program and any variables.
|
2343 |
|
|
|
2344 |
|
|
;; SA-TYPE-0
|
2345 |
|
|
L073A: LD (IX+$00),$00 ; place type zero - program in descriptor.
|
2346 |
|
|
LD HL,($5C59) ; fetch E_LINE to HL.
|
2347 |
|
|
LD DE,($5C53) ; fetch PROG to DE.
|
2348 |
|
|
SCF ; set carry flag to calculate from end of
|
2349 |
|
|
; variables E_LINE -1.
|
2350 |
|
|
SBC HL,DE ; subtract to give total length.
|
2351 |
|
|
|
2352 |
|
|
LD (IX+$0B),L ; place total length
|
2353 |
|
|
LD (IX+$0C),H ; in descriptor.
|
2354 |
|
|
LD HL,($5C4B) ; load HL from system variable VARS
|
2355 |
|
|
SBC HL,DE ; subtract to give program length.
|
2356 |
|
|
LD (IX+$0F),L ; place length of program
|
2357 |
|
|
LD (IX+$10),H ; in the descriptor.
|
2358 |
|
|
EX DE,HL ; start to HL, length to DE.
|
2359 |
|
|
|
2360 |
|
|
;; SA-ALL
|
2361 |
|
|
L075A: LD A,($5C74) ; fetch command from T_ADDR
|
2362 |
|
|
AND A ; test for zero - SAVE.
|
2363 |
|
|
JP Z,L0970 ; jump forward to SA-CONTRL with SAVE ->
|
2364 |
|
|
|
2365 |
|
|
; ---
|
2366 |
|
|
; continue with LOAD, MERGE and VERIFY.
|
2367 |
|
|
|
2368 |
|
|
PUSH HL ; save start.
|
2369 |
|
|
LD BC,$0011 ; prepare to add seventeen
|
2370 |
|
|
ADD IX,BC ; to point IX at second descriptor.
|
2371 |
|
|
|
2372 |
|
|
;; LD-LOOK-H
|
2373 |
|
|
L0767: PUSH IX ; save IX
|
2374 |
|
|
LD DE,$0011 ; seventeen bytes
|
2375 |
|
|
XOR A ; reset zero flag
|
2376 |
|
|
SCF ; set carry flag
|
2377 |
|
|
CALL L0556 ; routine LD-BYTES loads a header from tape
|
2378 |
|
|
; to second descriptor.
|
2379 |
|
|
POP IX ; restore IX.
|
2380 |
|
|
JR NC,L0767 ; loop back to LD-LOOK-H until header found.
|
2381 |
|
|
|
2382 |
|
|
LD A,$FE ; select system channel 'S'
|
2383 |
|
|
CALL L1601 ; routine CHAN-OPEN opens it.
|
2384 |
|
|
|
2385 |
|
|
LD (IY+$52),$03 ; set SCR_CT to 3 lines.
|
2386 |
|
|
|
2387 |
|
|
LD C,$80 ; C has bit 7 set to indicate type mismatch as
|
2388 |
|
|
; a default startpoint.
|
2389 |
|
|
|
2390 |
|
|
LD A,(IX+$00) ; fetch loaded header type to A
|
2391 |
|
|
CP (IX-$11) ; compare with expected type.
|
2392 |
|
|
JR NZ,L078A ; forward to LD-TYPE with mis-match.
|
2393 |
|
|
|
2394 |
|
|
LD C,$F6 ; set C to minus ten - will count characters
|
2395 |
|
|
; up to zero.
|
2396 |
|
|
|
2397 |
|
|
;; LD-TYPE
|
2398 |
|
|
L078A: CP $04 ; check if type in acceptable range 0 - 3.
|
2399 |
|
|
JR NC,L0767 ; back to LD-LOOK-H with 4 and over.
|
2400 |
|
|
|
2401 |
|
|
; else A indicates type 0-3.
|
2402 |
|
|
|
2403 |
|
|
LD DE,L09C0 ; address base of last 4 tape messages
|
2404 |
|
|
PUSH BC ; save BC
|
2405 |
|
|
CALL L0C0A ; routine PO-MSG outputs relevant message.
|
2406 |
|
|
; Note. all messages have a leading newline.
|
2407 |
|
|
POP BC ; restore BC
|
2408 |
|
|
|
2409 |
|
|
PUSH IX ; transfer IX,
|
2410 |
|
|
POP DE ; the 2nd descriptor, to DE.
|
2411 |
|
|
LD HL,$FFF0 ; prepare minus seventeen.
|
2412 |
|
|
ADD HL,DE ; add to point HL to 1st descriptor.
|
2413 |
|
|
LD B,$0A ; the count will be ten characters for the
|
2414 |
|
|
; filename.
|
2415 |
|
|
|
2416 |
|
|
LD A,(HL) ; fetch first character and test for
|
2417 |
|
|
INC A ; value 255.
|
2418 |
|
|
JR NZ,L07A6 ; forward to LD-NAME if not the wildcard.
|
2419 |
|
|
|
2420 |
|
|
; but if it is the wildcard, then add ten to C which is minus ten for a type
|
2421 |
|
|
; match or -128 for a type mismatch. Although characters have to be counted
|
2422 |
|
|
; bit 7 of C will not alter from state set here.
|
2423 |
|
|
|
2424 |
|
|
LD A,C ; transfer $F6 or $80 to A
|
2425 |
|
|
ADD A,B ; add $0A
|
2426 |
|
|
LD C,A ; place result, zero or -118, in C.
|
2427 |
|
|
|
2428 |
|
|
; At this point we have either a type mismatch, a wildcard match or ten
|
2429 |
|
|
; characters to be counted. The characters must be shown on the screen.
|
2430 |
|
|
|
2431 |
|
|
;; LD-NAME
|
2432 |
|
|
L07A6: INC DE ; address next input character
|
2433 |
|
|
LD A,(DE) ; fetch character
|
2434 |
|
|
CP (HL) ; compare to expected
|
2435 |
|
|
INC HL ; address next expected character
|
2436 |
|
|
JR NZ,L07AD ; forward to LD-CH-PR with mismatch
|
2437 |
|
|
|
2438 |
|
|
INC C ; increment matched character count
|
2439 |
|
|
|
2440 |
|
|
;; LD-CH-PR
|
2441 |
|
|
L07AD: RST 10H ; PRINT-A prints character
|
2442 |
|
|
DJNZ L07A6 ; loop back to LD-NAME for ten characters.
|
2443 |
|
|
|
2444 |
|
|
; if ten characters matched and the types previously matched then C will
|
2445 |
|
|
; now hold zero.
|
2446 |
|
|
|
2447 |
|
|
BIT 7,C ; test if all matched
|
2448 |
|
|
JR NZ,L0767 ; back to LD-LOOK-H if not
|
2449 |
|
|
|
2450 |
|
|
; else print a terminal carriage return.
|
2451 |
|
|
|
2452 |
|
|
LD A,$0D ; prepare carriage return.
|
2453 |
|
|
RST 10H ; PRINT-A outputs it.
|
2454 |
|
|
|
2455 |
|
|
; The various control routines for LOAD, VERIFY and MERGE are executed
|
2456 |
|
|
; during the one-second gap following the header on tape.
|
2457 |
|
|
|
2458 |
|
|
POP HL ; restore xx
|
2459 |
|
|
LD A,(IX+$00) ; fetch incoming type
|
2460 |
|
|
CP $03 ; compare with CODE
|
2461 |
|
|
JR Z,L07CB ; forward to VR-CONTRL if it is CODE.
|
2462 |
|
|
|
2463 |
|
|
; type is a program or an array.
|
2464 |
|
|
|
2465 |
|
|
LD A,($5C74) ; fetch command from T_ADDR
|
2466 |
|
|
DEC A ; was it LOAD ?
|
2467 |
|
|
JP Z,L0808 ; JUMP forward to LD-CONTRL if so to
|
2468 |
|
|
; load BASIC or variables.
|
2469 |
|
|
|
2470 |
|
|
CP $02 ; was command MERGE ?
|
2471 |
|
|
JP Z,L08B6 ; jump forward to ME-CONTRL if so.
|
2472 |
|
|
|
2473 |
|
|
; else continue into VERIFY control routine to verify.
|
2474 |
|
|
|
2475 |
|
|
; ----------------------------
|
2476 |
|
|
; THE 'VERIFY CONTROL' ROUTINE
|
2477 |
|
|
; ----------------------------
|
2478 |
|
|
; There are two branches to this routine.
|
2479 |
|
|
; 1) From above to verify a program or array
|
2480 |
|
|
; 2) from earlier with no carry to load or verify code.
|
2481 |
|
|
|
2482 |
|
|
;; VR-CONTRL
|
2483 |
|
|
L07CB: PUSH HL ; save pointer to data.
|
2484 |
|
|
LD L,(IX-$06) ; fetch length of old data
|
2485 |
|
|
LD H,(IX-$05) ; to HL.
|
2486 |
|
|
LD E,(IX+$0B) ; fetch length of new data
|
2487 |
|
|
LD D,(IX+$0C) ; to DE.
|
2488 |
|
|
LD A,H ; check length of old
|
2489 |
|
|
OR L ; for zero.
|
2490 |
|
|
JR Z,L07E9 ; forward to VR-CONT-1 if length unspecified
|
2491 |
|
|
; e.g. LOAD "x" CODE
|
2492 |
|
|
|
2493 |
|
|
; as opposed to, say, LOAD 'x' CODE 32768,300.
|
2494 |
|
|
|
2495 |
|
|
SBC HL,DE ; subtract the two lengths.
|
2496 |
|
|
JR C,L0806 ; forward to REPORT-R if the length on tape is
|
2497 |
|
|
; larger than that specified in command.
|
2498 |
|
|
; 'Tape loading error'
|
2499 |
|
|
|
2500 |
|
|
JR Z,L07E9 ; forward to VR-CONT-1 if lengths match.
|
2501 |
|
|
|
2502 |
|
|
; a length on tape shorter than expected is not allowed for CODE
|
2503 |
|
|
|
2504 |
|
|
LD A,(IX+$00) ; else fetch type from tape.
|
2505 |
|
|
CP $03 ; is it CODE ?
|
2506 |
|
|
JR NZ,L0806 ; forward to REPORT-R if so
|
2507 |
|
|
; 'Tape loading error'
|
2508 |
|
|
|
2509 |
|
|
;; VR-CONT-1
|
2510 |
|
|
L07E9: POP HL ; pop pointer to data
|
2511 |
|
|
LD A,H ; test for zero
|
2512 |
|
|
OR L ; e.g. LOAD 'x' CODE
|
2513 |
|
|
JR NZ,L07F4 ; forward to VR-CONT-2 if destination specified.
|
2514 |
|
|
|
2515 |
|
|
LD L,(IX+$0D) ; else use the destination in the header
|
2516 |
|
|
LD H,(IX+$0E) ; and load code at address saved from.
|
2517 |
|
|
|
2518 |
|
|
;; VR-CONT-2
|
2519 |
|
|
L07F4: PUSH HL ; push pointer to start of data block.
|
2520 |
|
|
POP IX ; transfer to IX.
|
2521 |
|
|
LD A,($5C74) ; fetch reduced command from T_ADDR
|
2522 |
|
|
CP $02 ; is it VERIFY ?
|
2523 |
|
|
SCF ; prepare a set carry flag
|
2524 |
|
|
JR NZ,L0800 ; skip to VR-CONT-3 if not
|
2525 |
|
|
|
2526 |
|
|
AND A ; clear carry flag for VERIFY so that
|
2527 |
|
|
; data is not loaded.
|
2528 |
|
|
|
2529 |
|
|
;; VR-CONT-3
|
2530 |
|
|
L0800: LD A,$FF ; signal data block to be loaded
|
2531 |
|
|
|
2532 |
|
|
; -----------------
|
2533 |
|
|
; Load a data block
|
2534 |
|
|
; -----------------
|
2535 |
|
|
; This routine is called from 3 places other than above to load a data block.
|
2536 |
|
|
; In all cases the accumulator is first set to $FF so the routine could be
|
2537 |
|
|
; called at the previous instruction.
|
2538 |
|
|
|
2539 |
|
|
;; LD-BLOCK
|
2540 |
|
|
L0802: CALL L0556 ; routine LD-BYTES
|
2541 |
|
|
RET C ; return if successful.
|
2542 |
|
|
|
2543 |
|
|
|
2544 |
|
|
;; REPORT-R
|
2545 |
|
|
L0806: RST 08H ; ERROR-1
|
2546 |
|
|
DEFB $1A ; Error Report: Tape loading error
|
2547 |
|
|
|
2548 |
|
|
; --------------------------
|
2549 |
|
|
; THE 'LOAD CONTROL' ROUTINE
|
2550 |
|
|
; --------------------------
|
2551 |
|
|
; This branch is taken when the command is LOAD with type 0, 1 or 2.
|
2552 |
|
|
|
2553 |
|
|
;; LD-CONTRL
|
2554 |
|
|
L0808: LD E,(IX+$0B) ; fetch length of found data block
|
2555 |
|
|
LD D,(IX+$0C) ; from 2nd descriptor.
|
2556 |
|
|
PUSH HL ; save destination
|
2557 |
|
|
LD A,H ; test for zero
|
2558 |
|
|
OR L ;
|
2559 |
|
|
JR NZ,L0819 ; forward if not to LD-CONT-1
|
2560 |
|
|
|
2561 |
|
|
INC DE ; increase length
|
2562 |
|
|
INC DE ; for letter name
|
2563 |
|
|
INC DE ; and 16-bit length
|
2564 |
|
|
EX DE,HL ; length to HL,
|
2565 |
|
|
JR L0825 ; forward to LD-CONT-2
|
2566 |
|
|
|
2567 |
|
|
; ---
|
2568 |
|
|
|
2569 |
|
|
;; LD-CONT-1
|
2570 |
|
|
L0819: LD L,(IX-$06) ; fetch length from
|
2571 |
|
|
LD H,(IX-$05) ; the first header.
|
2572 |
|
|
EX DE,HL ;
|
2573 |
|
|
SCF ; set carry flag
|
2574 |
|
|
SBC HL,DE ;
|
2575 |
|
|
JR C,L082E ; to LD-DATA
|
2576 |
|
|
|
2577 |
|
|
;; LD-CONT-2
|
2578 |
|
|
L0825: LD DE,$0005 ; allow overhead of five bytes.
|
2579 |
|
|
ADD HL,DE ; add in the difference in data lengths.
|
2580 |
|
|
LD B,H ; transfer to
|
2581 |
|
|
LD C,L ; the BC register pair
|
2582 |
|
|
CALL L1F05 ; routine TEST-ROOM fails if not enough room.
|
2583 |
|
|
|
2584 |
|
|
;; LD-DATA
|
2585 |
|
|
L082E: POP HL ; pop destination
|
2586 |
|
|
LD A,(IX+$00) ; fetch type 0, 1 or 2.
|
2587 |
|
|
AND A ; test for program and variables.
|
2588 |
|
|
JR Z,L0873 ; forward if so to LD-PROG
|
2589 |
|
|
|
2590 |
|
|
; the type is a numeric or string array.
|
2591 |
|
|
|
2592 |
|
|
LD A,H ; test the destination for zero
|
2593 |
|
|
OR L ; indicating variable does not already exist.
|
2594 |
|
|
JR Z,L084C ; forward if so to LD-DATA-1
|
2595 |
|
|
|
2596 |
|
|
; else the destination is the first dimension within the array structure
|
2597 |
|
|
|
2598 |
|
|
DEC HL ; address high byte of total length
|
2599 |
|
|
LD B,(HL) ; transfer to B.
|
2600 |
|
|
DEC HL ; address low byte of total length.
|
2601 |
|
|
LD C,(HL) ; transfer to C.
|
2602 |
|
|
DEC HL ; point to letter of variable.
|
2603 |
|
|
INC BC ; adjust length to
|
2604 |
|
|
INC BC ; include these
|
2605 |
|
|
INC BC ; three bytes also.
|
2606 |
|
|
LD ($5C5F),IX ; save header pointer in X_PTR.
|
2607 |
|
|
CALL L19E8 ; routine RECLAIM-2 reclaims the old variable
|
2608 |
|
|
; sliding workspace including the two headers
|
2609 |
|
|
; downwards.
|
2610 |
|
|
LD IX,($5C5F) ; reload IX from X_PTR which will have been
|
2611 |
|
|
; adjusted down by POINTERS routine.
|
2612 |
|
|
|
2613 |
|
|
;; LD-DATA-1
|
2614 |
|
|
L084C: LD HL,($5C59) ; address E_LINE
|
2615 |
|
|
DEC HL ; now point to the $80 variables end-marker.
|
2616 |
|
|
LD C,(IX+$0B) ; fetch new data length
|
2617 |
|
|
LD B,(IX+$0C) ; from 2nd header.
|
2618 |
|
|
PUSH BC ; * save it.
|
2619 |
|
|
INC BC ; adjust the
|
2620 |
|
|
INC BC ; length to include
|
2621 |
|
|
INC BC ; letter name and total length.
|
2622 |
|
|
LD A,(IX-$03) ; fetch letter name from old header.
|
2623 |
|
|
PUSH AF ; preserve accumulator though not corrupted.
|
2624 |
|
|
|
2625 |
|
|
CALL L1655 ; routine MAKE-ROOM creates space for variable
|
2626 |
|
|
; sliding workspace up. IX no longer addresses
|
2627 |
|
|
; anywhere meaningful.
|
2628 |
|
|
INC HL ; point to first new location.
|
2629 |
|
|
|
2630 |
|
|
POP AF ; fetch back the letter name.
|
2631 |
|
|
LD (HL),A ; place in first new location.
|
2632 |
|
|
POP DE ; * pop the data length.
|
2633 |
|
|
INC HL ; address 2nd location
|
2634 |
|
|
LD (HL),E ; store low byte of length.
|
2635 |
|
|
INC HL ; address next.
|
2636 |
|
|
LD (HL),D ; store high byte.
|
2637 |
|
|
INC HL ; address start of data.
|
2638 |
|
|
PUSH HL ; transfer address
|
2639 |
|
|
POP IX ; to IX register pair.
|
2640 |
|
|
SCF ; set carry flag indicating load not verify.
|
2641 |
|
|
LD A,$FF ; signal data not header.
|
2642 |
|
|
JP L0802 ; JUMP back to LD-BLOCK
|
2643 |
|
|
|
2644 |
|
|
; -----------------
|
2645 |
|
|
; the branch is here when a program as opposed to an array is to be loaded.
|
2646 |
|
|
|
2647 |
|
|
;; LD-PROG
|
2648 |
|
|
L0873: EX DE,HL ; transfer dest to DE.
|
2649 |
|
|
LD HL,($5C59) ; address E_LINE
|
2650 |
|
|
DEC HL ; now variables end-marker.
|
2651 |
|
|
LD ($5C5F),IX ; place the IX header pointer in X_PTR
|
2652 |
|
|
LD C,(IX+$0B) ; get new length
|
2653 |
|
|
LD B,(IX+$0C) ; from 2nd header
|
2654 |
|
|
PUSH BC ; and save it.
|
2655 |
|
|
|
2656 |
|
|
CALL L19E5 ; routine RECLAIM-1 reclaims program and vars.
|
2657 |
|
|
; adjusting X-PTR.
|
2658 |
|
|
|
2659 |
|
|
POP BC ; restore new length.
|
2660 |
|
|
PUSH HL ; * save start
|
2661 |
|
|
PUSH BC ; ** and length.
|
2662 |
|
|
|
2663 |
|
|
CALL L1655 ; routine MAKE-ROOM creates the space.
|
2664 |
|
|
|
2665 |
|
|
LD IX,($5C5F) ; reload IX from adjusted X_PTR
|
2666 |
|
|
INC HL ; point to start of new area.
|
2667 |
|
|
LD C,(IX+$0F) ; fetch length of BASIC on tape
|
2668 |
|
|
LD B,(IX+$10) ; from 2nd descriptor
|
2669 |
|
|
ADD HL,BC ; add to address the start of variables.
|
2670 |
|
|
LD ($5C4B),HL ; set system variable VARS
|
2671 |
|
|
|
2672 |
|
|
LD H,(IX+$0E) ; fetch high byte of autostart line number.
|
2673 |
|
|
LD A,H ; transfer to A
|
2674 |
|
|
AND $C0 ; test if greater than $3F.
|
2675 |
|
|
JR NZ,L08AD ; forward to LD-PROG-1 if so with no autostart.
|
2676 |
|
|
|
2677 |
|
|
LD L,(IX+$0D) ; else fetch the low byte.
|
2678 |
|
|
LD ($5C42),HL ; set system variable to line number NEWPPC
|
2679 |
|
|
LD (IY+$0A),$00 ; set statement NSPPC to zero.
|
2680 |
|
|
|
2681 |
|
|
;; LD-PROG-1
|
2682 |
|
|
L08AD: POP DE ; ** pop the length
|
2683 |
|
|
POP IX ; * and start.
|
2684 |
|
|
SCF ; set carry flag
|
2685 |
|
|
LD A,$FF ; signal data as opposed to a header.
|
2686 |
|
|
JP L0802 ; jump back to LD-BLOCK
|
2687 |
|
|
|
2688 |
|
|
; ---------------------------
|
2689 |
|
|
; THE 'MERGE CONTROL' ROUTINE
|
2690 |
|
|
; ---------------------------
|
2691 |
|
|
; the branch was here to merge a program and its variables or an array.
|
2692 |
|
|
;
|
2693 |
|
|
|
2694 |
|
|
;; ME-CONTRL
|
2695 |
|
|
L08B6: LD C,(IX+$0B) ; fetch length
|
2696 |
|
|
LD B,(IX+$0C) ; of data block on tape.
|
2697 |
|
|
PUSH BC ; save it.
|
2698 |
|
|
INC BC ; one for the pot.
|
2699 |
|
|
|
2700 |
|
|
RST 30H ; BC-SPACES creates room in workspace.
|
2701 |
|
|
; HL addresses last new location.
|
2702 |
|
|
LD (HL),$80 ; place end-marker at end.
|
2703 |
|
|
EX DE,HL ; transfer first location to HL.
|
2704 |
|
|
POP DE ; restore length to DE.
|
2705 |
|
|
PUSH HL ; save start.
|
2706 |
|
|
|
2707 |
|
|
PUSH HL ; and transfer it
|
2708 |
|
|
POP IX ; to IX register.
|
2709 |
|
|
SCF ; set carry flag to load data on tape.
|
2710 |
|
|
LD A,$FF ; signal data not a header.
|
2711 |
|
|
CALL L0802 ; routine LD-BLOCK loads to workspace.
|
2712 |
|
|
POP HL ; restore first location in workspace to HL.
|
2713 |
|
|
X08CE LD DE,($5C53) ; set DE from system variable PROG.
|
2714 |
|
|
|
2715 |
|
|
; now enter a loop to merge the data block in workspace with the program and
|
2716 |
|
|
; variables.
|
2717 |
|
|
|
2718 |
|
|
;; ME-NEW-LP
|
2719 |
|
|
L08D2: LD A,(HL) ; fetch next byte from workspace.
|
2720 |
|
|
AND $C0 ; compare with $3F.
|
2721 |
|
|
JR NZ,L08F0 ; forward to ME-VAR-LP if a variable or
|
2722 |
|
|
; end-marker.
|
2723 |
|
|
|
2724 |
|
|
; continue when HL addresses a BASIC line number.
|
2725 |
|
|
|
2726 |
|
|
;; ME-OLD-LP
|
2727 |
|
|
L08D7: LD A,(DE) ; fetch high byte from program area.
|
2728 |
|
|
INC DE ; bump prog address.
|
2729 |
|
|
CP (HL) ; compare with that in workspace.
|
2730 |
|
|
INC HL ; bump workspace address.
|
2731 |
|
|
JR NZ,L08DF ; forward to ME-OLD-L1 if high bytes don't match
|
2732 |
|
|
|
2733 |
|
|
LD A,(DE) ; fetch the low byte of program line number.
|
2734 |
|
|
CP (HL) ; compare with that in workspace.
|
2735 |
|
|
|
2736 |
|
|
;; ME-OLD-L1
|
2737 |
|
|
L08DF: DEC DE ; point to start of
|
2738 |
|
|
DEC HL ; respective lines again.
|
2739 |
|
|
JR NC,L08EB ; forward to ME-NEW-L2 if line number in
|
2740 |
|
|
; workspace is less than or equal to current
|
2741 |
|
|
; program line as has to be added to program.
|
2742 |
|
|
|
2743 |
|
|
PUSH HL ; else save workspace pointer.
|
2744 |
|
|
EX DE,HL ; transfer prog pointer to HL
|
2745 |
|
|
CALL L19B8 ; routine NEXT-ONE finds next line in DE.
|
2746 |
|
|
POP HL ; restore workspace pointer
|
2747 |
|
|
JR L08D7 ; back to ME-OLD-LP until destination position
|
2748 |
|
|
; in program area found.
|
2749 |
|
|
|
2750 |
|
|
; ---
|
2751 |
|
|
; the branch was here with an insertion or replacement point.
|
2752 |
|
|
|
2753 |
|
|
;; ME-NEW-L2
|
2754 |
|
|
L08EB: CALL L092C ; routine ME-ENTER enters the line
|
2755 |
|
|
JR L08D2 ; loop back to ME-NEW-LP.
|
2756 |
|
|
|
2757 |
|
|
; ---
|
2758 |
|
|
; the branch was here when the location in workspace held a variable.
|
2759 |
|
|
|
2760 |
|
|
;; ME-VAR-LP
|
2761 |
|
|
L08F0: LD A,(HL) ; fetch first byte of workspace variable.
|
2762 |
|
|
LD C,A ; copy to C also.
|
2763 |
|
|
CP $80 ; is it the end-marker ?
|
2764 |
|
|
RET Z ; return if so as complete. >>>>>
|
2765 |
|
|
|
2766 |
|
|
PUSH HL ; save workspace area pointer.
|
2767 |
|
|
LD HL,($5C4B) ; load HL with VARS - start of variables area.
|
2768 |
|
|
|
2769 |
|
|
;; ME-OLD-VP
|
2770 |
|
|
L08F9: LD A,(HL) ; fetch first byte.
|
2771 |
|
|
CP $80 ; is it the end-marker ?
|
2772 |
|
|
JR Z,L0923 ; forward if so to ME-VAR-L2 to add
|
2773 |
|
|
; variable at end of variables area.
|
2774 |
|
|
|
2775 |
|
|
CP C ; compare with variable in workspace area.
|
2776 |
|
|
JR Z,L0909 ; forward to ME-OLD-V2 if a match to replace.
|
2777 |
|
|
|
2778 |
|
|
; else entire variables area has to be searched.
|
2779 |
|
|
|
2780 |
|
|
;; ME-OLD-V1
|
2781 |
|
|
L0901: PUSH BC ; save character in C.
|
2782 |
|
|
CALL L19B8 ; routine NEXT-ONE gets following variable
|
2783 |
|
|
; address in DE.
|
2784 |
|
|
POP BC ; restore character in C
|
2785 |
|
|
EX DE,HL ; transfer next address to HL.
|
2786 |
|
|
JR L08F9 ; loop back to ME-OLD-VP
|
2787 |
|
|
|
2788 |
|
|
; ---
|
2789 |
|
|
; the branch was here when first characters of name matched.
|
2790 |
|
|
|
2791 |
|
|
;; ME-OLD-V2
|
2792 |
|
|
L0909: AND $E0 ; keep bits 11100000
|
2793 |
|
|
CP $A0 ; compare 10100000 - a long-named variable.
|
2794 |
|
|
|
2795 |
|
|
JR NZ,L0921 ; forward to ME-VAR-L1 if just one-character.
|
2796 |
|
|
|
2797 |
|
|
; but long-named variables have to be matched character by character.
|
2798 |
|
|
|
2799 |
|
|
POP DE ; fetch workspace 1st character pointer
|
2800 |
|
|
PUSH DE ; and save it on the stack again.
|
2801 |
|
|
PUSH HL ; save variables area pointer on stack.
|
2802 |
|
|
|
2803 |
|
|
;; ME-OLD-V3
|
2804 |
|
|
L0912: INC HL ; address next character in vars area.
|
2805 |
|
|
INC DE ; address next character in workspace area.
|
2806 |
|
|
LD A,(DE) ; fetch workspace character.
|
2807 |
|
|
CP (HL) ; compare to variables character.
|
2808 |
|
|
JR NZ,L091E ; forward to ME-OLD-V4 with a mismatch.
|
2809 |
|
|
|
2810 |
|
|
RLA ; test if the terminal inverted character.
|
2811 |
|
|
JR NC,L0912 ; loop back to ME-OLD-V3 if more to test.
|
2812 |
|
|
|
2813 |
|
|
; otherwise the long name matches in its entirety.
|
2814 |
|
|
|
2815 |
|
|
POP HL ; restore pointer to first character of variable
|
2816 |
|
|
JR L0921 ; forward to ME-VAR-L1
|
2817 |
|
|
|
2818 |
|
|
; ---
|
2819 |
|
|
; the branch is here when two characters don't match
|
2820 |
|
|
|
2821 |
|
|
;; ME-OLD-V4
|
2822 |
|
|
L091E: POP HL ; restore the prog/vars pointer.
|
2823 |
|
|
JR L0901 ; back to ME-OLD-V1 to resume search.
|
2824 |
|
|
|
2825 |
|
|
; ---
|
2826 |
|
|
; branch here when variable is to replace an existing one
|
2827 |
|
|
|
2828 |
|
|
;; ME-VAR-L1
|
2829 |
|
|
L0921: LD A,$FF ; indicate a replacement.
|
2830 |
|
|
|
2831 |
|
|
; this entry point is when A holds $80 indicating a new variable.
|
2832 |
|
|
|
2833 |
|
|
;; ME-VAR-L2
|
2834 |
|
|
L0923: POP DE ; pop workspace pointer.
|
2835 |
|
|
EX DE,HL ; now make HL workspace pointer, DE vars pointer
|
2836 |
|
|
INC A ; zero flag set if replacement.
|
2837 |
|
|
SCF ; set carry flag indicating a variable not a
|
2838 |
|
|
; program line.
|
2839 |
|
|
CALL L092C ; routine ME-ENTER copies variable in.
|
2840 |
|
|
JR L08F0 ; loop back to ME-VAR-LP
|
2841 |
|
|
|
2842 |
|
|
; ------------------------
|
2843 |
|
|
; Merge a Line or Variable
|
2844 |
|
|
; ------------------------
|
2845 |
|
|
; A BASIC line or variable is inserted at the current point. If the line
|
2846 |
|
|
; number or variable names match (zero flag set) then a replacement takes
|
2847 |
|
|
; place.
|
2848 |
|
|
|
2849 |
|
|
;; ME-ENTER
|
2850 |
|
|
L092C: JR NZ,L093E ; forward to ME-ENT-1 for insertion only.
|
2851 |
|
|
|
2852 |
|
|
; but the program line or variable matches so old one is reclaimed.
|
2853 |
|
|
|
2854 |
|
|
EX AF,AF' ; save flag??
|
2855 |
|
|
LD ($5C5F),HL ; preserve workspace pointer in dynamic X_PTR
|
2856 |
|
|
EX DE,HL ; transfer program dest pointer to HL.
|
2857 |
|
|
CALL L19B8 ; routine NEXT-ONE finds following location
|
2858 |
|
|
; in program or variables area.
|
2859 |
|
|
CALL L19E8 ; routine RECLAIM-2 reclaims the space between.
|
2860 |
|
|
EX DE,HL ; transfer program dest pointer back to DE.
|
2861 |
|
|
LD HL,($5C5F) ; fetch adjusted workspace pointer from X_PTR
|
2862 |
|
|
EX AF,AF' ; restore flags.
|
2863 |
|
|
|
2864 |
|
|
; now the new line or variable is entered.
|
2865 |
|
|
|
2866 |
|
|
;; ME-ENT-1
|
2867 |
|
|
L093E: EX AF,AF' ; save or re-save flags.
|
2868 |
|
|
PUSH DE ; save dest pointer in prog/vars area.
|
2869 |
|
|
CALL L19B8 ; routine NEXT-ONE finds next in workspace.
|
2870 |
|
|
; gets next in DE, difference in BC.
|
2871 |
|
|
; prev addr in HL
|
2872 |
|
|
LD ($5C5F),HL ; store pointer in X_PTR
|
2873 |
|
|
LD HL,($5C53) ; load HL from system variable PROG
|
2874 |
|
|
EX (SP),HL ; swap with prog/vars pointer on stack.
|
2875 |
|
|
PUSH BC ; ** save length of new program line/variable.
|
2876 |
|
|
EX AF,AF' ; fetch flags back.
|
2877 |
|
|
JR C,L0955 ; skip to ME-ENT-2 if variable
|
2878 |
|
|
|
2879 |
|
|
DEC HL ; address location before pointer
|
2880 |
|
|
CALL L1655 ; routine MAKE-ROOM creates room for BASIC line
|
2881 |
|
|
INC HL ; address next.
|
2882 |
|
|
JR L0958 ; forward to ME-ENT-3
|
2883 |
|
|
|
2884 |
|
|
; ---
|
2885 |
|
|
|
2886 |
|
|
;; ME-ENT-2
|
2887 |
|
|
L0955: CALL L1655 ; routine MAKE-ROOM creates room for variable.
|
2888 |
|
|
|
2889 |
|
|
;; ME-ENT-3
|
2890 |
|
|
L0958: INC HL ; address next?
|
2891 |
|
|
|
2892 |
|
|
POP BC ; ** pop length
|
2893 |
|
|
POP DE ; * pop value for PROG which may have been
|
2894 |
|
|
; altered by POINTERS if first line.
|
2895 |
|
|
LD ($5C53),DE ; set PROG to original value.
|
2896 |
|
|
LD DE,($5C5F) ; fetch adjusted workspace pointer from X_PTR
|
2897 |
|
|
PUSH BC ; save length
|
2898 |
|
|
PUSH DE ; and workspace pointer
|
2899 |
|
|
EX DE,HL ; make workspace pointer source, prog/vars
|
2900 |
|
|
; pointer the destination
|
2901 |
|
|
LDIR ; copy bytes of line or variable into new area.
|
2902 |
|
|
POP HL ; restore workspace pointer.
|
2903 |
|
|
POP BC ; restore length.
|
2904 |
|
|
PUSH DE ; save new prog/vars pointer.
|
2905 |
|
|
CALL L19E8 ; routine RECLAIM-2 reclaims the space used
|
2906 |
|
|
; by the line or variable in workspace block
|
2907 |
|
|
; as no longer required and space could be
|
2908 |
|
|
; useful for adding more lines.
|
2909 |
|
|
POP DE ; restore the prog/vars pointer
|
2910 |
|
|
RET ; return.
|
2911 |
|
|
|
2912 |
|
|
; --------------------------
|
2913 |
|
|
; THE 'SAVE CONTROL' ROUTINE
|
2914 |
|
|
; --------------------------
|
2915 |
|
|
; A branch from the main SAVE-ETC routine at SAVE-ALL.
|
2916 |
|
|
; First the header data is saved. Then after a wait of 1 second
|
2917 |
|
|
; the data itself is saved.
|
2918 |
|
|
; HL points to start of data.
|
2919 |
|
|
; IX points to start of descriptor.
|
2920 |
|
|
|
2921 |
|
|
;; SA-CONTRL
|
2922 |
|
|
L0970: PUSH HL ; save start of data
|
2923 |
|
|
|
2924 |
|
|
LD A,$FD ; select system channel 'S'
|
2925 |
|
|
CALL L1601 ; routine CHAN-OPEN
|
2926 |
|
|
|
2927 |
|
|
XOR A ; clear to address table directly
|
2928 |
|
|
LD DE,L09A1 ; address: tape-msgs
|
2929 |
|
|
CALL L0C0A ; routine PO-MSG -
|
2930 |
|
|
; 'Start tape then press any key.'
|
2931 |
|
|
|
2932 |
|
|
SET 5,(IY+$02) ; TV_FLAG - Signal lower screen requires
|
2933 |
|
|
; clearing
|
2934 |
|
|
CALL L15D4 ; routine WAIT-KEY
|
2935 |
|
|
|
2936 |
|
|
PUSH IX ; save pointer to descriptor.
|
2937 |
|
|
LD DE,$0011 ; there are seventeen bytes.
|
2938 |
|
|
XOR A ; signal a header.
|
2939 |
|
|
CALL L04C2 ; routine SA-BYTES
|
2940 |
|
|
|
2941 |
|
|
POP IX ; restore descriptor pointer.
|
2942 |
|
|
|
2943 |
|
|
LD B,$32 ; wait for a second - 50 interrupts.
|
2944 |
|
|
|
2945 |
|
|
;; SA-1-SEC
|
2946 |
|
|
L0991: HALT ; wait for interrupt
|
2947 |
|
|
DJNZ L0991 ; back to SA-1-SEC until pause complete.
|
2948 |
|
|
|
2949 |
|
|
LD E,(IX+$0B) ; fetch length of bytes from the
|
2950 |
|
|
LD D,(IX+$0C) ; descriptor.
|
2951 |
|
|
|
2952 |
|
|
LD A,$FF ; signal data bytes.
|
2953 |
|
|
|
2954 |
|
|
POP IX ; retrieve pointer to start
|
2955 |
|
|
JP L04C2 ; jump back to SA-BYTES
|
2956 |
|
|
|
2957 |
|
|
|
2958 |
|
|
; Arrangement of two headers in workspace.
|
2959 |
|
|
; Originally IX addresses first location and only one header is required
|
2960 |
|
|
; when saving.
|
2961 |
|
|
;
|
2962 |
|
|
; OLD NEW PROG DATA DATA CODE
|
2963 |
|
|
; HEADER HEADER num chr NOTES.
|
2964 |
|
|
; ------ ------ ---- ---- ---- ---- -----------------------------
|
2965 |
|
|
; IX-$11 IX+$00 0 1 2 3 Type.
|
2966 |
|
|
; IX-$10 IX+$01 x x x x F ($FF if filename is null).
|
2967 |
|
|
; IX-$0F IX+$02 x x x x i
|
2968 |
|
|
; IX-$0E IX+$03 x x x x l
|
2969 |
|
|
; IX-$0D IX+$04 x x x x e
|
2970 |
|
|
; IX-$0C IX+$05 x x x x n
|
2971 |
|
|
; IX-$0B IX+$06 x x x x a
|
2972 |
|
|
; IX-$0A IX+$07 x x x x m
|
2973 |
|
|
; IX-$09 IX+$08 x x x x e
|
2974 |
|
|
; IX-$08 IX+$09 x x x x .
|
2975 |
|
|
; IX-$07 IX+$0A x x x x (terminal spaces).
|
2976 |
|
|
; IX-$06 IX+$0B lo lo lo lo Total
|
2977 |
|
|
; IX-$05 IX+$0C hi hi hi hi Length of datablock.
|
2978 |
|
|
; IX-$04 IX+$0D Auto - - Start Various
|
2979 |
|
|
; IX-$03 IX+$0E Start a-z a-z addr ($80 if no autostart).
|
2980 |
|
|
; IX-$02 IX+$0F lo - - - Length of Program
|
2981 |
|
|
; IX-$01 IX+$10 hi - - - only i.e. without variables.
|
2982 |
|
|
;
|
2983 |
|
|
|
2984 |
|
|
|
2985 |
|
|
; ------------------------
|
2986 |
|
|
; Canned cassette messages
|
2987 |
|
|
; ------------------------
|
2988 |
|
|
; The last-character-inverted Cassette messages.
|
2989 |
|
|
; Starts with normal initial step-over byte.
|
2990 |
|
|
|
2991 |
|
|
;; tape-msgs
|
2992 |
|
|
L09A1: DEFB $80
|
2993 |
|
|
DEFM "Start tape, then press any key"
|
2994 |
|
|
L09C0: DEFB '.'+$80
|
2995 |
|
|
DEFB $0D
|
2996 |
|
|
DEFM "Program:"
|
2997 |
|
|
DEFB ' '+$80
|
2998 |
|
|
DEFB $0D
|
2999 |
|
|
DEFM "Number array:"
|
3000 |
|
|
DEFB ' '+$80
|
3001 |
|
|
DEFB $0D
|
3002 |
|
|
DEFM "Character array:"
|
3003 |
|
|
DEFB ' '+$80
|
3004 |
|
|
DEFB $0D
|
3005 |
|
|
DEFM "Bytes:"
|
3006 |
|
|
DEFB ' '+$80
|
3007 |
|
|
|
3008 |
|
|
|
3009 |
|
|
;**************************************************
|
3010 |
|
|
;** Part 5. SCREEN AND PRINTER HANDLING ROUTINES **
|
3011 |
|
|
;**************************************************
|
3012 |
|
|
|
3013 |
|
|
; --------------------------
|
3014 |
|
|
; THE 'PRINT OUTPUT' ROUTINE
|
3015 |
|
|
; --------------------------
|
3016 |
|
|
; This is the routine most often used by the RST 10 restart although the
|
3017 |
|
|
; subroutine is on two occasions called directly when it is known that
|
3018 |
|
|
; output will definitely be to the lower screen.
|
3019 |
|
|
|
3020 |
|
|
;; PRINT-OUT
|
3021 |
|
|
L09F4: CALL L0B03 ; routine PO-FETCH fetches print position
|
3022 |
|
|
; to HL register pair.
|
3023 |
|
|
CP $20 ; is character a space or higher ?
|
3024 |
|
|
JP NC,L0AD9 ; jump forward to PO-ABLE if so.
|
3025 |
|
|
|
3026 |
|
|
CP $06 ; is character in range 00-05 ?
|
3027 |
|
|
JR C,L0A69 ; to PO-QUEST to print '?' if so.
|
3028 |
|
|
|
3029 |
|
|
CP $18 ; is character in range 24d - 31d ?
|
3030 |
|
|
JR NC,L0A69 ; to PO-QUEST to also print '?' if so.
|
3031 |
|
|
|
3032 |
|
|
LD HL,L0A11 - 6 ; address 0A0B - the base address of control
|
3033 |
|
|
; character table - where zero would be.
|
3034 |
|
|
LD E,A ; control character 06 - 23d
|
3035 |
|
|
LD D,$00 ; is transferred to DE.
|
3036 |
|
|
|
3037 |
|
|
ADD HL,DE ; index into table.
|
3038 |
|
|
|
3039 |
|
|
LD E,(HL) ; fetch the offset to routine.
|
3040 |
|
|
ADD HL,DE ; add to make HL the address.
|
3041 |
|
|
PUSH HL ; push the address.
|
3042 |
|
|
|
3043 |
|
|
JP L0B03 ; Jump forward to PO-FETCH,
|
3044 |
|
|
; as the screen/printer position has been
|
3045 |
|
|
; disturbed, and then indirectly to the PO-STORE
|
3046 |
|
|
; routine on stack.
|
3047 |
|
|
|
3048 |
|
|
; -----------------------------
|
3049 |
|
|
; THE 'CONTROL CHARACTER' TABLE
|
3050 |
|
|
; -----------------------------
|
3051 |
|
|
; For control characters in the range 6 - 23d the following table
|
3052 |
|
|
; is indexed to provide an offset to the handling routine that
|
3053 |
|
|
; follows the table.
|
3054 |
|
|
|
3055 |
|
|
;; ctlchrtab
|
3056 |
|
|
L0A11: DEFB L0A5F - $ ; 06d offset $4E to Address: PO-COMMA
|
3057 |
|
|
DEFB L0A69 - $ ; 07d offset $57 to Address: PO-QUEST
|
3058 |
|
|
DEFB L0A23 - $ ; 08d offset $10 to Address: PO-BACK-1
|
3059 |
|
|
DEFB L0A3D - $ ; 09d offset $29 to Address: PO-RIGHT
|
3060 |
|
|
DEFB L0A69 - $ ; 10d offset $54 to Address: PO-QUEST
|
3061 |
|
|
DEFB L0A69 - $ ; 11d offset $53 to Address: PO-QUEST
|
3062 |
|
|
DEFB L0A69 - $ ; 12d offset $52 to Address: PO-QUEST
|
3063 |
|
|
DEFB L0A4F - $ ; 13d offset $37 to Address: PO-ENTER
|
3064 |
|
|
DEFB L0A69 - $ ; 14d offset $50 to Address: PO-QUEST
|
3065 |
|
|
DEFB L0A69 - $ ; 15d offset $4F to Address: PO-QUEST
|
3066 |
|
|
DEFB L0A7A - $ ; 16d offset $5F to Address: PO-1-OPER
|
3067 |
|
|
DEFB L0A7A - $ ; 17d offset $5E to Address: PO-1-OPER
|
3068 |
|
|
DEFB L0A7A - $ ; 18d offset $5D to Address: PO-1-OPER
|
3069 |
|
|
DEFB L0A7A - $ ; 19d offset $5C to Address: PO-1-OPER
|
3070 |
|
|
DEFB L0A7A - $ ; 20d offset $5B to Address: PO-1-OPER
|
3071 |
|
|
DEFB L0A7A - $ ; 21d offset $5A to Address: PO-1-OPER
|
3072 |
|
|
DEFB L0A75 - $ ; 22d offset $54 to Address: PO-2-OPER
|
3073 |
|
|
DEFB L0A75 - $ ; 23d offset $53 to Address: PO-2-OPER
|
3074 |
|
|
|
3075 |
|
|
|
3076 |
|
|
; -------------------------
|
3077 |
|
|
; THE 'CURSOR LEFT' ROUTINE
|
3078 |
|
|
; -------------------------
|
3079 |
|
|
; Backspace and up a line if that action is from the left of screen.
|
3080 |
|
|
; For ZX printer backspace up to first column but not beyond.
|
3081 |
|
|
|
3082 |
|
|
;; PO-BACK-1
|
3083 |
|
|
L0A23: INC C ; move left one column.
|
3084 |
|
|
LD A,$22 ; value $21 is leftmost column.
|
3085 |
|
|
CP C ; have we passed ?
|
3086 |
|
|
JR NZ,L0A3A ; to PO-BACK-3 if not and store new position.
|
3087 |
|
|
|
3088 |
|
|
BIT 1,(IY+$01) ; test FLAGS - is printer in use ?
|
3089 |
|
|
JR NZ,L0A38 ; to PO-BACK-2 if so, as we are unable to
|
3090 |
|
|
; backspace from the leftmost position.
|
3091 |
|
|
|
3092 |
|
|
|
3093 |
|
|
INC B ; move up one screen line
|
3094 |
|
|
LD C,$02 ; the rightmost column position.
|
3095 |
|
|
LD A,$18 ; Note. This should be $19
|
3096 |
|
|
; credit. Dr. Frank O'Hara, 1982
|
3097 |
|
|
|
3098 |
|
|
CP B ; has position moved past top of screen ?
|
3099 |
|
|
JR NZ,L0A3A ; to PO-BACK-3 if not and store new position.
|
3100 |
|
|
|
3101 |
|
|
DEC B ; else back to $18.
|
3102 |
|
|
|
3103 |
|
|
;; PO-BACK-2
|
3104 |
|
|
L0A38: LD C,$21 ; the leftmost column position.
|
3105 |
|
|
|
3106 |
|
|
;; PO-BACK-3
|
3107 |
|
|
L0A3A: JP L0DD9 ; to CL-SET and PO-STORE to save new
|
3108 |
|
|
; position in system variables.
|
3109 |
|
|
|
3110 |
|
|
; --------------------------
|
3111 |
|
|
; THE 'CURSOR RIGHT' ROUTINE
|
3112 |
|
|
; --------------------------
|
3113 |
|
|
; This moves the print position to the right leaving a trail in the
|
3114 |
|
|
; current background colour.
|
3115 |
|
|
; "However the programmer has failed to store the new print position
|
3116 |
|
|
; so CHR$ 9 will only work if the next print position is at a newly
|
3117 |
|
|
; defined place.
|
3118 |
|
|
; e.g. PRINT PAPER 2; CHR$ 9; AT 4,0;
|
3119 |
|
|
; does work but is not very helpful"
|
3120 |
|
|
; - Dr. Ian Logan, Understanding Your Spectrum, 1982.
|
3121 |
|
|
|
3122 |
|
|
;; PO-RIGHT
|
3123 |
|
|
L0A3D: LD A,($5C91) ; fetch P_FLAG value
|
3124 |
|
|
PUSH AF ; and save it on stack.
|
3125 |
|
|
|
3126 |
|
|
LD (IY+$57),$01 ; temporarily set P_FLAG 'OVER 1'.
|
3127 |
|
|
LD A,$20 ; prepare a space.
|
3128 |
|
|
CALL L0B65 ; routine PO-CHAR to print it.
|
3129 |
|
|
; Note. could be PO-ABLE which would update
|
3130 |
|
|
; the column position.
|
3131 |
|
|
|
3132 |
|
|
POP AF ; restore the permanent flag.
|
3133 |
|
|
LD ($5C91),A ; and restore system variable P_FLAG
|
3134 |
|
|
|
3135 |
|
|
RET ; return without updating column position
|
3136 |
|
|
|
3137 |
|
|
; -----------------------
|
3138 |
|
|
; Perform carriage return
|
3139 |
|
|
; -----------------------
|
3140 |
|
|
; A carriage return is 'printed' to screen or printer buffer.
|
3141 |
|
|
|
3142 |
|
|
;; PO-ENTER
|
3143 |
|
|
L0A4F: BIT 1,(IY+$01) ; test FLAGS - is printer in use ?
|
3144 |
|
|
JP NZ,L0ECD ; to COPY-BUFF if so, to flush buffer and reset
|
3145 |
|
|
; the print position.
|
3146 |
|
|
|
3147 |
|
|
LD C,$21 ; the leftmost column position.
|
3148 |
|
|
CALL L0C55 ; routine PO-SCR handles any scrolling required.
|
3149 |
|
|
DEC B ; to next screen line.
|
3150 |
|
|
JP L0DD9 ; jump forward to CL-SET to store new position.
|
3151 |
|
|
|
3152 |
|
|
; -----------
|
3153 |
|
|
; Print comma
|
3154 |
|
|
; -----------
|
3155 |
|
|
; The comma control character. The 32 column screen has two 16 character
|
3156 |
|
|
; tabstops. The routine is only reached via the control character table.
|
3157 |
|
|
|
3158 |
|
|
;; PO-COMMA
|
3159 |
|
|
L0A5F: CALL L0B03 ; routine PO-FETCH - seems unnecessary.
|
3160 |
|
|
|
3161 |
|
|
LD A,C ; the column position. $21-$01
|
3162 |
|
|
DEC A ; move right. $20-$00
|
3163 |
|
|
DEC A ; and again $1F-$00 or $FF if trailing
|
3164 |
|
|
AND $10 ; will be $00 or $10.
|
3165 |
|
|
JR L0AC3 ; forward to PO-FILL
|
3166 |
|
|
|
3167 |
|
|
; -------------------
|
3168 |
|
|
; Print question mark
|
3169 |
|
|
; -------------------
|
3170 |
|
|
; This routine prints a question mark which is commonly
|
3171 |
|
|
; used to print an unassigned control character in range 0-31d.
|
3172 |
|
|
; there are a surprising number yet to be assigned.
|
3173 |
|
|
|
3174 |
|
|
;; PO-QUEST
|
3175 |
|
|
L0A69: LD A,$3F ; prepare the character '?'.
|
3176 |
|
|
JR L0AD9 ; forward to PO-ABLE.
|
3177 |
|
|
|
3178 |
|
|
; --------------------------------
|
3179 |
|
|
; Control characters with operands
|
3180 |
|
|
; --------------------------------
|
3181 |
|
|
; Certain control characters are followed by 1 or 2 operands.
|
3182 |
|
|
; The entry points from control character table are PO-2-OPER and PO-1-OPER.
|
3183 |
|
|
; The routines alter the output address of the current channel so that
|
3184 |
|
|
; subsequent RST $10 instructions take the appropriate action
|
3185 |
|
|
; before finally resetting the output address back to PRINT-OUT.
|
3186 |
|
|
|
3187 |
|
|
;; PO-TV-2
|
3188 |
|
|
L0A6D: LD DE,L0A87 ; address: PO-CONT will be next output routine
|
3189 |
|
|
LD ($5C0F),A ; store first operand in TVDATA-hi
|
3190 |
|
|
JR L0A80 ; forward to PO-CHANGE >>
|
3191 |
|
|
|
3192 |
|
|
; ---
|
3193 |
|
|
|
3194 |
|
|
; -> This initial entry point deals with two operands - AT or TAB.
|
3195 |
|
|
|
3196 |
|
|
;; PO-2-OPER
|
3197 |
|
|
L0A75: LD DE,L0A6D ; address: PO-TV-2 will be next output routine
|
3198 |
|
|
JR L0A7D ; forward to PO-TV-1
|
3199 |
|
|
|
3200 |
|
|
; ---
|
3201 |
|
|
|
3202 |
|
|
; -> This initial entry point deals with one operand INK to OVER.
|
3203 |
|
|
|
3204 |
|
|
;; PO-1-OPER
|
3205 |
|
|
L0A7A: LD DE,L0A87 ; address: PO-CONT will be next output routine
|
3206 |
|
|
|
3207 |
|
|
;; PO-TV-1
|
3208 |
|
|
L0A7D: LD ($5C0E),A ; store control code in TVDATA-lo
|
3209 |
|
|
|
3210 |
|
|
;; PO-CHANGE
|
3211 |
|
|
L0A80: LD HL,($5C51) ; use CURCHL to find current output channel.
|
3212 |
|
|
LD (HL),E ; make it
|
3213 |
|
|
INC HL ; the supplied
|
3214 |
|
|
LD (HL),D ; address from DE.
|
3215 |
|
|
RET ; return.
|
3216 |
|
|
|
3217 |
|
|
; ---
|
3218 |
|
|
|
3219 |
|
|
;; PO-CONT
|
3220 |
|
|
L0A87: LD DE,L09F4 ; Address: PRINT-OUT
|
3221 |
|
|
CALL L0A80 ; routine PO-CHANGE to restore normal channel.
|
3222 |
|
|
LD HL,($5C0E) ; TVDATA gives control code and possible
|
3223 |
|
|
; subsequent character
|
3224 |
|
|
LD D,A ; save current character
|
3225 |
|
|
LD A,L ; the stored control code
|
3226 |
|
|
CP $16 ; was it INK to OVER (1 operand) ?
|
3227 |
|
|
JP C,L2211 ; to CO-TEMP-5
|
3228 |
|
|
|
3229 |
|
|
JR NZ,L0AC2 ; to PO-TAB if not 22d i.e. 23d TAB.
|
3230 |
|
|
|
3231 |
|
|
; else must have been 22d AT.
|
3232 |
|
|
LD B,H ; line to H (0-23d)
|
3233 |
|
|
LD C,D ; column to C (0-31d)
|
3234 |
|
|
LD A,$1F ; the value 31d
|
3235 |
|
|
SUB C ; reverse the column number.
|
3236 |
|
|
JR C,L0AAC ; to PO-AT-ERR if C was greater than 31d.
|
3237 |
|
|
|
3238 |
|
|
ADD A,$02 ; transform to system range $02-$21
|
3239 |
|
|
LD C,A ; and place in column register.
|
3240 |
|
|
|
3241 |
|
|
BIT 1,(IY+$01) ; test FLAGS - is printer in use ?
|
3242 |
|
|
JR NZ,L0ABF ; to PO-AT-SET as line can be ignored.
|
3243 |
|
|
|
3244 |
|
|
LD A,$16 ; 22 decimal
|
3245 |
|
|
SUB B ; subtract line number to reverse
|
3246 |
|
|
; 0 - 22 becomes 22 - 0.
|
3247 |
|
|
|
3248 |
|
|
;; PO-AT-ERR
|
3249 |
|
|
L0AAC: JP C,L1E9F ; to REPORT-B if higher than 22 decimal
|
3250 |
|
|
; Integer out of range.
|
3251 |
|
|
|
3252 |
|
|
INC A ; adjust for system range $01-$17
|
3253 |
|
|
LD B,A ; place in line register
|
3254 |
|
|
INC B ; adjust to system range $02-$18
|
3255 |
|
|
BIT 0,(IY+$02) ; TV_FLAG - Lower screen in use ?
|
3256 |
|
|
JP NZ,L0C55 ; exit to PO-SCR to test for scrolling
|
3257 |
|
|
|
3258 |
|
|
CP (IY+$31) ; Compare against DF_SZ
|
3259 |
|
|
JP C,L0C86 ; to REPORT-5 if too low
|
3260 |
|
|
; Out of screen.
|
3261 |
|
|
|
3262 |
|
|
;; PO-AT-SET
|
3263 |
|
|
L0ABF: JP L0DD9 ; print position is valid so exit via CL-SET
|
3264 |
|
|
|
3265 |
|
|
; ---
|
3266 |
|
|
|
3267 |
|
|
; Continue here when dealing with TAB.
|
3268 |
|
|
; Note. In BASIC, TAB is followed by a 16-bit number and was initially
|
3269 |
|
|
; designed to work with any output device.
|
3270 |
|
|
|
3271 |
|
|
;; PO-TAB
|
3272 |
|
|
L0AC2: LD A,H ; transfer parameter to A
|
3273 |
|
|
; Losing current character -
|
3274 |
|
|
; High byte of TAB parameter.
|
3275 |
|
|
|
3276 |
|
|
|
3277 |
|
|
;; PO-FILL
|
3278 |
|
|
L0AC3: CALL L0B03 ; routine PO-FETCH, HL-addr, BC=line/column.
|
3279 |
|
|
; column 1 (right), $21 (left)
|
3280 |
|
|
ADD A,C ; add operand to current column
|
3281 |
|
|
DEC A ; range 0 - 31+
|
3282 |
|
|
AND $1F ; make range 0 - 31d
|
3283 |
|
|
RET Z ; return if result zero
|
3284 |
|
|
|
3285 |
|
|
LD D,A ; Counter to D
|
3286 |
|
|
SET 0,(IY+$01) ; update FLAGS - signal suppress leading space.
|
3287 |
|
|
|
3288 |
|
|
;; PO-SPACE
|
3289 |
|
|
L0AD0: LD A,$20 ; space character.
|
3290 |
|
|
|
3291 |
|
|
CALL L0C3B ; routine PO-SAVE prints the character
|
3292 |
|
|
; using alternate set (normal output routine)
|
3293 |
|
|
|
3294 |
|
|
DEC D ; decrement counter.
|
3295 |
|
|
JR NZ,L0AD0 ; to PO-SPACE until done
|
3296 |
|
|
|
3297 |
|
|
RET ; return
|
3298 |
|
|
|
3299 |
|
|
; ----------------------
|
3300 |
|
|
; Printable character(s)
|
3301 |
|
|
; ----------------------
|
3302 |
|
|
; This routine prints printable characters and continues into
|
3303 |
|
|
; the position store routine
|
3304 |
|
|
|
3305 |
|
|
;; PO-ABLE
|
3306 |
|
|
L0AD9: CALL L0B24 ; routine PO-ANY
|
3307 |
|
|
; and continue into position store routine.
|
3308 |
|
|
|
3309 |
|
|
; ----------------------------
|
3310 |
|
|
; THE 'POSITION STORE' ROUTINE
|
3311 |
|
|
; ----------------------------
|
3312 |
|
|
; This routine updates the system variables associated with the main screen,
|
3313 |
|
|
; the lower screen/input buffer or the ZX printer.
|
3314 |
|
|
|
3315 |
|
|
;; PO-STORE
|
3316 |
|
|
L0ADC: BIT 1,(IY+$01) ; Test FLAGS - is printer in use ?
|
3317 |
|
|
JR NZ,L0AFC ; Forward, if so, to PO-ST-PR
|
3318 |
|
|
|
3319 |
|
|
BIT 0,(IY+$02) ; Test TV_FLAG - is lower screen in use ?
|
3320 |
|
|
JR NZ,L0AF0 ; Forward, if so, to PO-ST-E
|
3321 |
|
|
|
3322 |
|
|
; This section deals with the upper screen.
|
3323 |
|
|
|
3324 |
|
|
LD ($5C88),BC ; Update S_POSN - line/column upper screen
|
3325 |
|
|
LD ($5C84),HL ; Update DF_CC - upper display file address
|
3326 |
|
|
|
3327 |
|
|
RET ; Return.
|
3328 |
|
|
|
3329 |
|
|
; ---
|
3330 |
|
|
|
3331 |
|
|
; This section deals with the lower screen.
|
3332 |
|
|
|
3333 |
|
|
;; PO-ST-E
|
3334 |
|
|
L0AF0: LD ($5C8A),BC ; Update SPOSNL line/column lower screen
|
3335 |
|
|
LD ($5C82),BC ; Update ECHO_E line/column input buffer
|
3336 |
|
|
LD ($5C86),HL ; Update DFCCL lower screen memory address
|
3337 |
|
|
RET ; Return.
|
3338 |
|
|
|
3339 |
|
|
; ---
|
3340 |
|
|
|
3341 |
|
|
; This section deals with the ZX Printer.
|
3342 |
|
|
|
3343 |
|
|
;; PO-ST-PR
|
3344 |
|
|
L0AFC: LD (IY+$45),C ; Update P_POSN column position printer
|
3345 |
|
|
LD ($5C80),HL ; Update PR_CC - full printer buffer memory
|
3346 |
|
|
; address
|
3347 |
|
|
RET ; Return.
|
3348 |
|
|
|
3349 |
|
|
; Note. that any values stored in location 23681 will be overwritten with
|
3350 |
|
|
; the value 91 decimal.
|
3351 |
|
|
; Credit April 1983, Dilwyn Jones. "Delving Deeper into your ZX Spectrum".
|
3352 |
|
|
|
3353 |
|
|
; ----------------------------
|
3354 |
|
|
; THE 'POSITION FETCH' ROUTINE
|
3355 |
|
|
; ----------------------------
|
3356 |
|
|
; This routine fetches the line/column and display file address of the upper
|
3357 |
|
|
; and lower screen or, if the printer is in use, the column position and
|
3358 |
|
|
; absolute memory address.
|
3359 |
|
|
; Note. that PR-CC-hi (23681) is used by this routine and if, in accordance
|
3360 |
|
|
; with the manual (that says this is unused), the location has been used for
|
3361 |
|
|
; other purposes, then subsequent output to the printer buffer could corrupt
|
3362 |
|
|
; a 256-byte section of memory.
|
3363 |
|
|
|
3364 |
|
|
;; PO-FETCH
|
3365 |
|
|
L0B03: BIT 1,(IY+$01) ; Test FLAGS - is printer in use ?
|
3366 |
|
|
JR NZ,L0B1D ; Forward, if so, to PO-F-PR
|
3367 |
|
|
|
3368 |
|
|
; assume upper screen in use and thus optimize for path that requires speed.
|
3369 |
|
|
|
3370 |
|
|
LD BC,($5C88) ; Fetch line/column from S_POSN
|
3371 |
|
|
LD HL,($5C84) ; Fetch DF_CC display file address
|
3372 |
|
|
|
3373 |
|
|
BIT 0,(IY+$02) ; Test TV_FLAG - lower screen in use ?
|
3374 |
|
|
RET Z ; Return if upper screen in use.
|
3375 |
|
|
|
3376 |
|
|
; Overwrite registers with values for lower screen.
|
3377 |
|
|
|
3378 |
|
|
LD BC,($5C8A) ; Fetch line/column from SPOSNL
|
3379 |
|
|
LD HL,($5C86) ; Fetch display file address from DFCCL
|
3380 |
|
|
RET ; Return.
|
3381 |
|
|
|
3382 |
|
|
; ---
|
3383 |
|
|
|
3384 |
|
|
; This section deals with the ZX Printer.
|
3385 |
|
|
|
3386 |
|
|
;; PO-F-PR
|
3387 |
|
|
L0B1D: LD C,(IY+$45) ; Fetch column from P_POSN.
|
3388 |
|
|
LD HL,($5C80) ; Fetch printer buffer address from PR_CC.
|
3389 |
|
|
RET ; Return.
|
3390 |
|
|
|
3391 |
|
|
; ---------------------------------
|
3392 |
|
|
; THE 'PRINT ANY CHARACTER' ROUTINE
|
3393 |
|
|
; ---------------------------------
|
3394 |
|
|
; This routine is used to print any character in range 32d - 255d
|
3395 |
|
|
; It is only called from PO-ABLE which continues into PO-STORE
|
3396 |
|
|
|
3397 |
|
|
;; PO-ANY
|
3398 |
|
|
L0B24: CP $80 ; ASCII ?
|
3399 |
|
|
JR C,L0B65 ; to PO-CHAR is so.
|
3400 |
|
|
|
3401 |
|
|
CP $90 ; test if a block graphic character.
|
3402 |
|
|
JR NC,L0B52 ; to PO-T&UDG to print tokens and UDGs
|
3403 |
|
|
|
3404 |
|
|
; The 16 2*2 mosaic characters 128-143 decimal are formed from
|
3405 |
|
|
; bits 0-3 of the character.
|
3406 |
|
|
|
3407 |
|
|
LD B,A ; save character
|
3408 |
|
|
CALL L0B38 ; routine PO-GR-1 to construct top half
|
3409 |
|
|
; then bottom half.
|
3410 |
|
|
CALL L0B03 ; routine PO-FETCH fetches print position.
|
3411 |
|
|
LD DE,$5C92 ; MEM-0 is location of 8 bytes of character
|
3412 |
|
|
JR L0B7F ; to PR-ALL to print to screen or printer
|
3413 |
|
|
|
3414 |
|
|
; ---
|
3415 |
|
|
|
3416 |
|
|
;; PO-GR-1
|
3417 |
|
|
L0B38: LD HL,$5C92 ; address MEM-0 - a temporary buffer in
|
3418 |
|
|
; systems variables which is normally used
|
3419 |
|
|
; by the calculator.
|
3420 |
|
|
CALL L0B3E ; routine PO-GR-2 to construct top half
|
3421 |
|
|
; and continue into routine to construct
|
3422 |
|
|
; bottom half.
|
3423 |
|
|
|
3424 |
|
|
;; PO-GR-2
|
3425 |
|
|
L0B3E: RR B ; rotate bit 0/2 to carry
|
3426 |
|
|
SBC A,A ; result $00 or $FF
|
3427 |
|
|
AND $0F ; mask off right hand side
|
3428 |
|
|
LD C,A ; store part in C
|
3429 |
|
|
RR B ; rotate bit 1/3 of original chr to carry
|
3430 |
|
|
SBC A,A ; result $00 or $FF
|
3431 |
|
|
AND $F0 ; mask off left hand side
|
3432 |
|
|
OR C ; combine with stored pattern
|
3433 |
|
|
LD C,$04 ; four bytes for top/bottom half
|
3434 |
|
|
|
3435 |
|
|
;; PO-GR-3
|
3436 |
|
|
L0B4C: LD (HL),A ; store bit patterns in temporary buffer
|
3437 |
|
|
INC HL ; next address
|
3438 |
|
|
DEC C ; jump back to
|
3439 |
|
|
JR NZ,L0B4C ; to PO-GR-3 until byte is stored 4 times
|
3440 |
|
|
|
3441 |
|
|
RET ; return
|
3442 |
|
|
|
3443 |
|
|
; ---
|
3444 |
|
|
|
3445 |
|
|
; Tokens and User defined graphics are now separated.
|
3446 |
|
|
|
3447 |
|
|
;; PO-T&UDG
|
3448 |
|
|
L0B52: SUB $A5 ; the 'RND' character
|
3449 |
|
|
JR NC,L0B5F ; to PO-T to print tokens
|
3450 |
|
|
|
3451 |
|
|
ADD A,$15 ; add 21d to restore to 0 - 20
|
3452 |
|
|
PUSH BC ; save current print position
|
3453 |
|
|
LD BC,($5C7B) ; fetch UDG to address bit patterns
|
3454 |
|
|
JR L0B6A ; to PO-CHAR-2 - common code to lay down
|
3455 |
|
|
; a bit patterned character
|
3456 |
|
|
|
3457 |
|
|
; ---
|
3458 |
|
|
|
3459 |
|
|
;; PO-T
|
3460 |
|
|
L0B5F: CALL L0C10 ; routine PO-TOKENS prints tokens
|
3461 |
|
|
JP L0B03 ; exit via a JUMP to PO-FETCH as this routine
|
3462 |
|
|
; must continue into PO-STORE.
|
3463 |
|
|
; A JR instruction could be used.
|
3464 |
|
|
|
3465 |
|
|
; This point is used to print ASCII characters 32d - 127d.
|
3466 |
|
|
|
3467 |
|
|
;; PO-CHAR
|
3468 |
|
|
L0B65: PUSH BC ; save print position
|
3469 |
|
|
LD BC,($5C36) ; address CHARS
|
3470 |
|
|
|
3471 |
|
|
; This common code is used to transfer the character bytes to memory.
|
3472 |
|
|
|
3473 |
|
|
;; PO-CHAR-2
|
3474 |
|
|
L0B6A: EX DE,HL ; transfer destination address to DE
|
3475 |
|
|
LD HL,$5C3B ; point to FLAGS
|
3476 |
|
|
RES 0,(HL) ; allow for leading space
|
3477 |
|
|
CP $20 ; is it a space ?
|
3478 |
|
|
JR NZ,L0B76 ; to PO-CHAR-3 if not
|
3479 |
|
|
|
3480 |
|
|
SET 0,(HL) ; signal no leading space to FLAGS
|
3481 |
|
|
|
3482 |
|
|
;; PO-CHAR-3
|
3483 |
|
|
L0B76: LD H,$00 ; set high byte to 0
|
3484 |
|
|
LD L,A ; character to A
|
3485 |
|
|
; 0-21 UDG or 32-127 ASCII.
|
3486 |
|
|
ADD HL,HL ; multiply
|
3487 |
|
|
ADD HL,HL ; by
|
3488 |
|
|
ADD HL,HL ; eight
|
3489 |
|
|
ADD HL,BC ; HL now points to first byte of character
|
3490 |
|
|
POP BC ; the source address CHARS or UDG
|
3491 |
|
|
EX DE,HL ; character address to DE
|
3492 |
|
|
|
3493 |
|
|
; ----------------------------------
|
3494 |
|
|
; THE 'PRINT ALL CHARACTERS' ROUTINE
|
3495 |
|
|
; ----------------------------------
|
3496 |
|
|
; This entry point entered from above to print ASCII and UDGs but also from
|
3497 |
|
|
; earlier to print mosaic characters.
|
3498 |
|
|
; HL=destination
|
3499 |
|
|
; DE=character source
|
3500 |
|
|
; BC=line/column
|
3501 |
|
|
|
3502 |
|
|
;; PR-ALL
|
3503 |
|
|
L0B7F: LD A,C ; column to A
|
3504 |
|
|
DEC A ; move right
|
3505 |
|
|
LD A,$21 ; pre-load with leftmost position
|
3506 |
|
|
JR NZ,L0B93 ; but if not zero to PR-ALL-1
|
3507 |
|
|
|
3508 |
|
|
DEC B ; down one line
|
3509 |
|
|
LD C,A ; load C with $21
|
3510 |
|
|
BIT 1,(IY+$01) ; test FLAGS - Is printer in use
|
3511 |
|
|
JR Z,L0B93 ; to PR-ALL-1 if not
|
3512 |
|
|
|
3513 |
|
|
PUSH DE ; save source address
|
3514 |
|
|
CALL L0ECD ; routine COPY-BUFF outputs line to printer
|
3515 |
|
|
POP DE ; restore character source address
|
3516 |
|
|
LD A,C ; the new column number ($21) to C
|
3517 |
|
|
|
3518 |
|
|
;; PR-ALL-1
|
3519 |
|
|
L0B93: CP C ; this test is really for screen - new line ?
|
3520 |
|
|
PUSH DE ; save source
|
3521 |
|
|
|
3522 |
|
|
CALL Z,L0C55 ; routine PO-SCR considers scrolling
|
3523 |
|
|
|
3524 |
|
|
POP DE ; restore source
|
3525 |
|
|
PUSH BC ; save line/column
|
3526 |
|
|
PUSH HL ; and destination
|
3527 |
|
|
LD A,($5C91) ; fetch P_FLAG to accumulator
|
3528 |
|
|
LD B,$FF ; prepare OVER mask in B.
|
3529 |
|
|
RRA ; bit 0 set if OVER 1
|
3530 |
|
|
JR C,L0BA4 ; to PR-ALL-2
|
3531 |
|
|
|
3532 |
|
|
INC B ; set OVER mask to 0
|
3533 |
|
|
|
3534 |
|
|
;; PR-ALL-2
|
3535 |
|
|
L0BA4: RRA ; skip bit 1 of P_FLAG
|
3536 |
|
|
RRA ; bit 2 is INVERSE
|
3537 |
|
|
SBC A,A ; will be FF for INVERSE 1 else zero
|
3538 |
|
|
LD C,A ; transfer INVERSE mask to C
|
3539 |
|
|
LD A,$08 ; prepare to count 8 bytes
|
3540 |
|
|
AND A ; clear carry to signal screen
|
3541 |
|
|
BIT 1,(IY+$01) ; test FLAGS - is printer in use ?
|
3542 |
|
|
JR Z,L0BB6 ; to PR-ALL-3 if screen
|
3543 |
|
|
|
3544 |
|
|
SET 1,(IY+$30) ; update FLAGS2 - signal printer buffer has
|
3545 |
|
|
; been used.
|
3546 |
|
|
SCF ; set carry flag to signal printer.
|
3547 |
|
|
|
3548 |
|
|
;; PR-ALL-3
|
3549 |
|
|
L0BB6: EX DE,HL ; now HL=source, DE=destination
|
3550 |
|
|
|
3551 |
|
|
;; PR-ALL-4
|
3552 |
|
|
L0BB7: EX AF,AF' ; save printer/screen flag
|
3553 |
|
|
LD A,(DE) ; fetch existing destination byte
|
3554 |
|
|
AND B ; consider OVER
|
3555 |
|
|
XOR (HL) ; now XOR with source
|
3556 |
|
|
XOR C ; now with INVERSE MASK
|
3557 |
|
|
LD (DE),A ; update screen/printer
|
3558 |
|
|
EX AF,AF' ; restore flag
|
3559 |
|
|
JR C,L0BD3 ; to PR-ALL-6 - printer address update
|
3560 |
|
|
|
3561 |
|
|
INC D ; gives next pixel line down screen
|
3562 |
|
|
|
3563 |
|
|
;; PR-ALL-5
|
3564 |
|
|
L0BC1: INC HL ; address next character byte
|
3565 |
|
|
DEC A ; the byte count is decremented
|
3566 |
|
|
JR NZ,L0BB7 ; back to PR-ALL-4 for all 8 bytes
|
3567 |
|
|
|
3568 |
|
|
EX DE,HL ; destination to HL
|
3569 |
|
|
DEC H ; bring back to last updated screen position
|
3570 |
|
|
BIT 1,(IY+$01) ; test FLAGS - is printer in use ?
|
3571 |
|
|
CALL Z,L0BDB ; if not, call routine PO-ATTR to update
|
3572 |
|
|
; corresponding colour attribute.
|
3573 |
|
|
POP HL ; restore original screen/printer position
|
3574 |
|
|
POP BC ; and line column
|
3575 |
|
|
DEC C ; move column to right
|
3576 |
|
|
INC HL ; increase screen/printer position
|
3577 |
|
|
RET ; return and continue into PO-STORE
|
3578 |
|
|
; within PO-ABLE
|
3579 |
|
|
|
3580 |
|
|
; ---
|
3581 |
|
|
|
3582 |
|
|
; This branch is used to update the printer position by 32 places
|
3583 |
|
|
; Note. The high byte of the address D remains constant (which it should).
|
3584 |
|
|
|
3585 |
|
|
;; PR-ALL-6
|
3586 |
|
|
L0BD3: EX AF,AF' ; save the flag
|
3587 |
|
|
LD A,$20 ; load A with 32 decimal
|
3588 |
|
|
ADD A,E ; add this to E
|
3589 |
|
|
LD E,A ; and store result in E
|
3590 |
|
|
EX AF,AF' ; fetch the flag
|
3591 |
|
|
JR L0BC1 ; back to PR-ALL-5
|
3592 |
|
|
|
3593 |
|
|
; -----------------------------------
|
3594 |
|
|
; THE 'GET ATTRIBUTE ADDRESS' ROUTINE
|
3595 |
|
|
; -----------------------------------
|
3596 |
|
|
; This routine is entered with the HL register holding the last screen
|
3597 |
|
|
; address to be updated by PRINT or PLOT.
|
3598 |
|
|
; The Spectrum screen arrangement leads to the L register holding the correct
|
3599 |
|
|
; value for the attribute file and it is only necessary to manipulate H to
|
3600 |
|
|
; form the correct colour attribute address.
|
3601 |
|
|
|
3602 |
|
|
;; PO-ATTR
|
3603 |
|
|
L0BDB: LD A,H ; fetch high byte $40 - $57
|
3604 |
|
|
RRCA ; shift
|
3605 |
|
|
RRCA ; bits 3 and 4
|
3606 |
|
|
RRCA ; to right.
|
3607 |
|
|
AND $03 ; range is now 0 - 2
|
3608 |
|
|
OR $58 ; form correct high byte for third of screen
|
3609 |
|
|
LD H,A ; HL is now correct
|
3610 |
|
|
LD DE,($5C8F) ; make D hold ATTR_T, E hold MASK-T
|
3611 |
|
|
LD A,(HL) ; fetch existing attribute
|
3612 |
|
|
XOR E ; apply masks
|
3613 |
|
|
AND D ;
|
3614 |
|
|
XOR E ;
|
3615 |
|
|
BIT 6,(IY+$57) ; test P_FLAG - is this PAPER 9 ??
|
3616 |
|
|
JR Z,L0BFA ; skip to PO-ATTR-1 if not.
|
3617 |
|
|
|
3618 |
|
|
AND $C7 ; set paper
|
3619 |
|
|
BIT 2,A ; to contrast with ink
|
3620 |
|
|
JR NZ,L0BFA ; skip to PO-ATTR-1
|
3621 |
|
|
|
3622 |
|
|
XOR $38 ;
|
3623 |
|
|
|
3624 |
|
|
;; PO-ATTR-1
|
3625 |
|
|
L0BFA: BIT 4,(IY+$57) ; test P_FLAG - Is this INK 9 ??
|
3626 |
|
|
JR Z,L0C08 ; skip to PO-ATTR-2 if not
|
3627 |
|
|
|
3628 |
|
|
AND $F8 ; make ink
|
3629 |
|
|
BIT 5,A ; contrast with paper.
|
3630 |
|
|
JR NZ,L0C08 ; to PO-ATTR-2
|
3631 |
|
|
|
3632 |
|
|
XOR $07 ;
|
3633 |
|
|
|
3634 |
|
|
;; PO-ATTR-2
|
3635 |
|
|
L0C08: LD (HL),A ; save the new attribute.
|
3636 |
|
|
RET ; return.
|
3637 |
|
|
|
3638 |
|
|
; ---------------------------------
|
3639 |
|
|
; THE 'MESSAGE PRINTING' SUBROUTINE
|
3640 |
|
|
; ---------------------------------
|
3641 |
|
|
; This entry point is used to print tape, boot-up, scroll? and error messages.
|
3642 |
|
|
; On entry the DE register points to an initial step-over byte or the
|
3643 |
|
|
; inverted end-marker of the previous entry in the table.
|
3644 |
|
|
; Register A contains the message number, often zero to print first message.
|
3645 |
|
|
; (HL has nothing important usually P_FLAG)
|
3646 |
|
|
|
3647 |
|
|
;; PO-MSG
|
3648 |
|
|
L0C0A: PUSH HL ; put hi-byte zero on stack to suppress
|
3649 |
|
|
LD H,$00 ; trailing spaces
|
3650 |
|
|
EX (SP),HL ; ld h,0; push hl would have done ?.
|
3651 |
|
|
JR L0C14 ; forward to PO-TABLE.
|
3652 |
|
|
|
3653 |
|
|
; ---
|
3654 |
|
|
|
3655 |
|
|
; This entry point prints the BASIC keywords, '<>' etc. from alt set
|
3656 |
|
|
|
3657 |
|
|
;; PO-TOKENS
|
3658 |
|
|
L0C10: LD DE,L0095 ; address: TKN-TABLE
|
3659 |
|
|
PUSH AF ; save the token number to control
|
3660 |
|
|
; trailing spaces - see later *
|
3661 |
|
|
|
3662 |
|
|
; ->
|
3663 |
|
|
|
3664 |
|
|
;; PO-TABLE
|
3665 |
|
|
L0C14: CALL L0C41 ; routine PO-SEARCH will set carry for
|
3666 |
|
|
; all messages and function words.
|
3667 |
|
|
|
3668 |
|
|
JR C,L0C22 ; forward to PO-EACH if not a command, '<>' etc.
|
3669 |
|
|
|
3670 |
|
|
LD A,$20 ; prepare leading space
|
3671 |
|
|
BIT 0,(IY+$01) ; test FLAGS - leading space if not set
|
3672 |
|
|
|
3673 |
|
|
CALL Z,L0C3B ; routine PO-SAVE to print a space without
|
3674 |
|
|
; disturbing registers.
|
3675 |
|
|
|
3676 |
|
|
;; PO-EACH
|
3677 |
|
|
L0C22: LD A,(DE) ; Fetch character from the table.
|
3678 |
|
|
AND $7F ; Cancel any inverted bit.
|
3679 |
|
|
|
3680 |
|
|
CALL L0C3B ; Routine PO-SAVE to print using the alternate
|
3681 |
|
|
; set of registers.
|
3682 |
|
|
|
3683 |
|
|
LD A,(DE) ; Re-fetch character from table.
|
3684 |
|
|
INC DE ; Address next character in the table.
|
3685 |
|
|
|
3686 |
|
|
ADD A,A ; Was character inverted ?
|
3687 |
|
|
; (this also doubles character)
|
3688 |
|
|
JR NC,L0C22 ; back to PO-EACH if not.
|
3689 |
|
|
|
3690 |
|
|
POP DE ; * re-fetch trailing space byte to D
|
3691 |
|
|
|
3692 |
|
|
CP $48 ; was the last character '$' ?
|
3693 |
|
|
JR Z,L0C35 ; forward to PO-TR-SP to consider trailing
|
3694 |
|
|
; space if so.
|
3695 |
|
|
|
3696 |
|
|
CP $82 ; was it < 'A' i.e. '#','>','=' from tokens
|
3697 |
|
|
; or ' ','.' (from tape) or '?' from scroll
|
3698 |
|
|
|
3699 |
|
|
RET C ; Return if so as no trailing space required.
|
3700 |
|
|
|
3701 |
|
|
;; PO-TR-SP
|
3702 |
|
|
L0C35: LD A,D ; The trailing space flag (zero if an error msg)
|
3703 |
|
|
|
3704 |
|
|
CP $03 ; Test against RND, INKEY$ and PI which have no
|
3705 |
|
|
; parameters and therefore no trailing space.
|
3706 |
|
|
|
3707 |
|
|
RET C ; Return if no trailing space.
|
3708 |
|
|
|
3709 |
|
|
LD A,$20 ; Prepare the space character and continue to
|
3710 |
|
|
; print and make an indirect return.
|
3711 |
|
|
|
3712 |
|
|
; -----------------------------------
|
3713 |
|
|
; THE 'RECURSIVE PRINTING' SUBROUTINE
|
3714 |
|
|
; -----------------------------------
|
3715 |
|
|
; This routine which is part of PRINT-OUT allows RST $10 to be used
|
3716 |
|
|
; recursively to print tokens and the spaces associated with them.
|
3717 |
|
|
; It is called on three occasions when the value of DE must be preserved.
|
3718 |
|
|
|
3719 |
|
|
;; PO-SAVE
|
3720 |
|
|
L0C3B: PUSH DE ; Save DE value.
|
3721 |
|
|
EXX ; Switch in main set
|
3722 |
|
|
|
3723 |
|
|
RST 10H ; PRINT-A prints using this alternate set.
|
3724 |
|
|
|
3725 |
|
|
EXX ; Switch back to this alternate set.
|
3726 |
|
|
POP DE ; Restore the initial DE value.
|
3727 |
|
|
|
3728 |
|
|
RET ; Return.
|
3729 |
|
|
|
3730 |
|
|
; ------------
|
3731 |
|
|
; Table search
|
3732 |
|
|
; ------------
|
3733 |
|
|
; This subroutine searches a message or the token table for the
|
3734 |
|
|
; message number held in A. DE holds the address of the table.
|
3735 |
|
|
|
3736 |
|
|
;; PO-SEARCH
|
3737 |
|
|
L0C41: PUSH AF ; save the message/token number
|
3738 |
|
|
EX DE,HL ; transfer DE to HL
|
3739 |
|
|
INC A ; adjust for initial step-over byte
|
3740 |
|
|
|
3741 |
|
|
;; PO-STEP
|
3742 |
|
|
L0C44: BIT 7,(HL) ; is character inverted ?
|
3743 |
|
|
INC HL ; address next
|
3744 |
|
|
JR Z,L0C44 ; back to PO-STEP if not inverted.
|
3745 |
|
|
|
3746 |
|
|
DEC A ; decrease counter
|
3747 |
|
|
JR NZ,L0C44 ; back to PO-STEP if not zero
|
3748 |
|
|
|
3749 |
|
|
EX DE,HL ; transfer address to DE
|
3750 |
|
|
POP AF ; restore message/token number
|
3751 |
|
|
CP $20 ; return with carry set
|
3752 |
|
|
RET C ; for all messages and function tokens
|
3753 |
|
|
|
3754 |
|
|
LD A,(DE) ; test first character of token
|
3755 |
|
|
SUB $41 ; and return with carry set
|
3756 |
|
|
RET ; if it is less that 'A'
|
3757 |
|
|
; i.e. '<>', '<=', '>='
|
3758 |
|
|
|
3759 |
|
|
; ---------------
|
3760 |
|
|
; Test for scroll
|
3761 |
|
|
; ---------------
|
3762 |
|
|
; This test routine is called when printing carriage return, when considering
|
3763 |
|
|
; PRINT AT and from the general PRINT ALL characters routine to test if
|
3764 |
|
|
; scrolling is required, prompting the user if necessary.
|
3765 |
|
|
; This is therefore using the alternate set.
|
3766 |
|
|
; The B register holds the current line.
|
3767 |
|
|
|
3768 |
|
|
;; PO-SCR
|
3769 |
|
|
L0C55: BIT 1,(IY+$01) ; test FLAGS - is printer in use ?
|
3770 |
|
|
RET NZ ; return immediately if so.
|
3771 |
|
|
|
3772 |
|
|
LD DE,L0DD9 ; set DE to address: CL-SET
|
3773 |
|
|
PUSH DE ; and push for return address.
|
3774 |
|
|
|
3775 |
|
|
LD A,B ; transfer the line to A.
|
3776 |
|
|
BIT 0,(IY+$02) ; test TV_FLAG - lower screen in use ?
|
3777 |
|
|
JP NZ,L0D02 ; jump forward to PO-SCR-4 if so.
|
3778 |
|
|
|
3779 |
|
|
CP (IY+$31) ; greater than DF_SZ display file size ?
|
3780 |
|
|
JR C,L0C86 ; forward to REPORT-5 if less.
|
3781 |
|
|
; 'Out of screen'
|
3782 |
|
|
|
3783 |
|
|
RET NZ ; return (via CL-SET) if greater
|
3784 |
|
|
|
3785 |
|
|
BIT 4,(IY+$02) ; test TV_FLAG - Automatic listing ?
|
3786 |
|
|
JR Z,L0C88 ; forward to PO-SCR-2 if not.
|
3787 |
|
|
|
3788 |
|
|
LD E,(IY+$2D) ; fetch BREG - the count of scroll lines to E.
|
3789 |
|
|
DEC E ; decrease and jump
|
3790 |
|
|
JR Z,L0CD2 ; to PO-SCR-3 if zero and scrolling required.
|
3791 |
|
|
|
3792 |
|
|
LD A,$00 ; explicit - select channel zero.
|
3793 |
|
|
CALL L1601 ; routine CHAN-OPEN opens it.
|
3794 |
|
|
|
3795 |
|
|
LD SP,($5C3F) ; set stack pointer to LIST_SP
|
3796 |
|
|
|
3797 |
|
|
RES 4,(IY+$02) ; reset TV_FLAG - signal auto listing finished.
|
3798 |
|
|
RET ; return ignoring pushed value, CL-SET
|
3799 |
|
|
; to MAIN or EDITOR without updating
|
3800 |
|
|
; print position >>
|
3801 |
|
|
|
3802 |
|
|
; ---
|
3803 |
|
|
|
3804 |
|
|
|
3805 |
|
|
;; REPORT-5
|
3806 |
|
|
L0C86: RST 08H ; ERROR-1
|
3807 |
|
|
DEFB $04 ; Error Report: Out of screen
|
3808 |
|
|
|
3809 |
|
|
; continue here if not an automatic listing.
|
3810 |
|
|
|
3811 |
|
|
;; PO-SCR-2
|
3812 |
|
|
L0C88: DEC (IY+$52) ; decrease SCR_CT
|
3813 |
|
|
JR NZ,L0CD2 ; forward to PO-SCR-3 to scroll display if
|
3814 |
|
|
; result not zero.
|
3815 |
|
|
|
3816 |
|
|
; now produce prompt.
|
3817 |
|
|
|
3818 |
|
|
LD A,$18 ; reset
|
3819 |
|
|
SUB B ; the
|
3820 |
|
|
LD ($5C8C),A ; SCR_CT scroll count
|
3821 |
|
|
LD HL,($5C8F) ; L=ATTR_T, H=MASK_T
|
3822 |
|
|
PUSH HL ; save on stack
|
3823 |
|
|
LD A,($5C91) ; P_FLAG
|
3824 |
|
|
PUSH AF ; save on stack to prevent lower screen
|
3825 |
|
|
; attributes (BORDCR etc.) being applied.
|
3826 |
|
|
LD A,$FD ; select system channel 'K'
|
3827 |
|
|
CALL L1601 ; routine CHAN-OPEN opens it
|
3828 |
|
|
XOR A ; clear to address message directly
|
3829 |
|
|
LD DE,L0CF8 ; make DE address: scrl-mssg
|
3830 |
|
|
CALL L0C0A ; routine PO-MSG prints to lower screen
|
3831 |
|
|
SET 5,(IY+$02) ; set TV_FLAG - signal lower screen requires
|
3832 |
|
|
; clearing
|
3833 |
|
|
LD HL,$5C3B ; make HL address FLAGS
|
3834 |
|
|
SET 3,(HL) ; signal 'L' mode.
|
3835 |
|
|
RES 5,(HL) ; signal 'no new key'.
|
3836 |
|
|
EXX ; switch to main set.
|
3837 |
|
|
; as calling chr input from alternative set.
|
3838 |
|
|
CALL L15D4 ; routine WAIT-KEY waits for new key
|
3839 |
|
|
; Note. this is the right routine but the
|
3840 |
|
|
; stream in use is unsatisfactory. From the
|
3841 |
|
|
; choices available, it is however the best.
|
3842 |
|
|
|
3843 |
|
|
EXX ; switch back to alternate set.
|
3844 |
|
|
CP $20 ; space is considered as BREAK
|
3845 |
|
|
JR Z,L0D00 ; forward to REPORT-D if so
|
3846 |
|
|
; 'BREAK - CONT repeats'
|
3847 |
|
|
|
3848 |
|
|
CP $E2 ; is character 'STOP' ?
|
3849 |
|
|
JR Z,L0D00 ; forward to REPORT-D if so
|
3850 |
|
|
|
3851 |
|
|
OR $20 ; convert to lower-case
|
3852 |
|
|
CP $6E ; is character 'n' ?
|
3853 |
|
|
JR Z,L0D00 ; forward to REPORT-D if so else scroll.
|
3854 |
|
|
|
3855 |
|
|
LD A,$FE ; select system channel 'S'
|
3856 |
|
|
CALL L1601 ; routine CHAN-OPEN
|
3857 |
|
|
POP AF ; restore original P_FLAG
|
3858 |
|
|
LD ($5C91),A ; and save in P_FLAG.
|
3859 |
|
|
POP HL ; restore original ATTR_T, MASK_T
|
3860 |
|
|
LD ($5C8F),HL ; and reset ATTR_T, MASK-T as 'scroll?' has
|
3861 |
|
|
; been printed.
|
3862 |
|
|
|
3863 |
|
|
;; PO-SCR-3
|
3864 |
|
|
L0CD2: CALL L0DFE ; routine CL-SC-ALL to scroll whole display
|
3865 |
|
|
LD B,(IY+$31) ; fetch DF_SZ to B
|
3866 |
|
|
INC B ; increase to address last line of display
|
3867 |
|
|
LD C,$21 ; set C to $21 (was $21 from above routine)
|
3868 |
|
|
PUSH BC ; save the line and column in BC.
|
3869 |
|
|
|
3870 |
|
|
CALL L0E9B ; routine CL-ADDR finds display address.
|
3871 |
|
|
|
3872 |
|
|
LD A,H ; now find the corresponding attribute byte
|
3873 |
|
|
RRCA ; (this code sequence is used twice
|
3874 |
|
|
RRCA ; elsewhere and is a candidate for
|
3875 |
|
|
RRCA ; a subroutine.)
|
3876 |
|
|
AND $03 ;
|
3877 |
|
|
OR $58 ;
|
3878 |
|
|
LD H,A ;
|
3879 |
|
|
|
3880 |
|
|
LD DE,$5AE0 ; start of last 'line' of attribute area
|
3881 |
|
|
LD A,(DE) ; get attribute for last line
|
3882 |
|
|
LD C,(HL) ; transfer to base line of upper part
|
3883 |
|
|
LD B,$20 ; there are thirty two bytes
|
3884 |
|
|
EX DE,HL ; swap the pointers.
|
3885 |
|
|
|
3886 |
|
|
;; PO-SCR-3A
|
3887 |
|
|
L0CF0: LD (DE),A ; transfer
|
3888 |
|
|
LD (HL),C ; attributes.
|
3889 |
|
|
INC DE ; address next.
|
3890 |
|
|
INC HL ; address next.
|
3891 |
|
|
DJNZ L0CF0 ; loop back to PO-SCR-3A for all adjacent
|
3892 |
|
|
; attribute lines.
|
3893 |
|
|
|
3894 |
|
|
POP BC ; restore the line/column.
|
3895 |
|
|
RET ; return via CL-SET (was pushed on stack).
|
3896 |
|
|
|
3897 |
|
|
; ---
|
3898 |
|
|
|
3899 |
|
|
; The message 'scroll?' appears here with last byte inverted.
|
3900 |
|
|
|
3901 |
|
|
;; scrl-mssg
|
3902 |
|
|
L0CF8: DEFB $80 ; initial step-over byte.
|
3903 |
|
|
DEFM "scroll"
|
3904 |
|
|
DEFB '?'+$80
|
3905 |
|
|
|
3906 |
|
|
;; REPORT-D
|
3907 |
|
|
L0D00: RST 08H ; ERROR-1
|
3908 |
|
|
DEFB $0C ; Error Report: BREAK - CONT repeats
|
3909 |
|
|
|
3910 |
|
|
; continue here if using lower display - A holds line number.
|
3911 |
|
|
|
3912 |
|
|
;; PO-SCR-4
|
3913 |
|
|
L0D02: CP $02 ; is line number less than 2 ?
|
3914 |
|
|
JR C,L0C86 ; to REPORT-5 if so
|
3915 |
|
|
; 'Out of Screen'.
|
3916 |
|
|
|
3917 |
|
|
ADD A,(IY+$31) ; add DF_SZ
|
3918 |
|
|
SUB $19 ;
|
3919 |
|
|
RET NC ; return if scrolling unnecessary
|
3920 |
|
|
|
3921 |
|
|
NEG ; Negate to give number of scrolls required.
|
3922 |
|
|
PUSH BC ; save line/column
|
3923 |
|
|
LD B,A ; count to B
|
3924 |
|
|
LD HL,($5C8F) ; fetch current ATTR_T, MASK_T to HL.
|
3925 |
|
|
PUSH HL ; and save
|
3926 |
|
|
LD HL,($5C91) ; fetch P_FLAG
|
3927 |
|
|
PUSH HL ; and save.
|
3928 |
|
|
; to prevent corruption by input AT
|
3929 |
|
|
|
3930 |
|
|
CALL L0D4D ; routine TEMPS sets to BORDCR etc
|
3931 |
|
|
LD A,B ; transfer scroll number to A.
|
3932 |
|
|
|
3933 |
|
|
;; PO-SCR-4A
|
3934 |
|
|
L0D1C: PUSH AF ; save scroll number.
|
3935 |
|
|
LD HL,$5C6B ; address DF_SZ
|
3936 |
|
|
LD B,(HL) ; fetch old value
|
3937 |
|
|
LD A,B ; transfer to A
|
3938 |
|
|
INC A ; and increment
|
3939 |
|
|
LD (HL),A ; then put back.
|
3940 |
|
|
LD HL,$5C89 ; address S_POSN_hi - line
|
3941 |
|
|
CP (HL) ; compare
|
3942 |
|
|
JR C,L0D2D ; forward to PO-SCR-4B if scrolling required
|
3943 |
|
|
|
3944 |
|
|
INC (HL) ; else increment S_POSN_hi
|
3945 |
|
|
LD B,$18 ; set count to whole display ??
|
3946 |
|
|
; Note. should be $17 and the top line will be
|
3947 |
|
|
; scrolled into the ROM which is harmless on
|
3948 |
|
|
; the standard set up.
|
3949 |
|
|
; credit P.Giblin 1984.
|
3950 |
|
|
|
3951 |
|
|
;; PO-SCR-4B
|
3952 |
|
|
L0D2D: CALL L0E00 ; routine CL-SCROLL scrolls B lines
|
3953 |
|
|
POP AF ; restore scroll counter.
|
3954 |
|
|
DEC A ; decrease
|
3955 |
|
|
JR NZ,L0D1C ; back to PO-SCR-4A until done
|
3956 |
|
|
|
3957 |
|
|
POP HL ; restore original P_FLAG.
|
3958 |
|
|
LD (IY+$57),L ; and overwrite system variable P_FLAG.
|
3959 |
|
|
|
3960 |
|
|
POP HL ; restore original ATTR_T/MASK_T.
|
3961 |
|
|
LD ($5C8F),HL ; and update system variables.
|
3962 |
|
|
|
3963 |
|
|
LD BC,($5C88) ; fetch S_POSN to BC.
|
3964 |
|
|
RES 0,(IY+$02) ; signal to TV_FLAG - main screen in use.
|
3965 |
|
|
CALL L0DD9 ; call routine CL-SET for upper display.
|
3966 |
|
|
|
3967 |
|
|
SET 0,(IY+$02) ; signal to TV_FLAG - lower screen in use.
|
3968 |
|
|
POP BC ; restore line/column
|
3969 |
|
|
RET ; return via CL-SET for lower display.
|
3970 |
|
|
|
3971 |
|
|
; ----------------------
|
3972 |
|
|
; Temporary colour items
|
3973 |
|
|
; ----------------------
|
3974 |
|
|
; This subroutine is called 11 times to copy the permanent colour items
|
3975 |
|
|
; to the temporary ones.
|
3976 |
|
|
|
3977 |
|
|
;; TEMPS
|
3978 |
|
|
L0D4D: XOR A ; clear the accumulator
|
3979 |
|
|
LD HL,($5C8D) ; fetch L=ATTR_P and H=MASK_P
|
3980 |
|
|
BIT 0,(IY+$02) ; test TV_FLAG - is lower screen in use ?
|
3981 |
|
|
JR Z,L0D5B ; skip to TEMPS-1 if not
|
3982 |
|
|
|
3983 |
|
|
LD H,A ; set H, MASK P, to 00000000.
|
3984 |
|
|
LD L,(IY+$0E) ; fetch BORDCR to L which is used for lower
|
3985 |
|
|
; screen.
|
3986 |
|
|
|
3987 |
|
|
;; TEMPS-1
|
3988 |
|
|
L0D5B: LD ($5C8F),HL ; transfer values to ATTR_T and MASK_T
|
3989 |
|
|
|
3990 |
|
|
; for the print flag the permanent values are odd bits, temporary even bits.
|
3991 |
|
|
|
3992 |
|
|
LD HL,$5C91 ; address P_FLAG.
|
3993 |
|
|
JR NZ,L0D65 ; skip to TEMPS-2 if lower screen using A=0.
|
3994 |
|
|
|
3995 |
|
|
LD A,(HL) ; else pick up flag bits.
|
3996 |
|
|
RRCA ; rotate permanent bits to temporary bits.
|
3997 |
|
|
|
3998 |
|
|
;; TEMPS-2
|
3999 |
|
|
L0D65: XOR (HL) ;
|
4000 |
|
|
AND $55 ; BIN 01010101
|
4001 |
|
|
XOR (HL) ; permanent now as original
|
4002 |
|
|
LD (HL),A ; apply permanent bits to temporary bits.
|
4003 |
|
|
RET ; and return.
|
4004 |
|
|
|
4005 |
|
|
; -----------------
|
4006 |
|
|
; THE 'CLS' COMMAND
|
4007 |
|
|
; -----------------
|
4008 |
|
|
; This command clears the display.
|
4009 |
|
|
; The routine is also called during initialization and by the CLEAR command.
|
4010 |
|
|
; If it's difficult to write it should be difficult to read.
|
4011 |
|
|
|
4012 |
|
|
;; CLS
|
4013 |
|
|
L0D6B: CALL L0DAF ; Routine CL-ALL clears the entire display and
|
4014 |
|
|
; sets the attributes to the permanent ones
|
4015 |
|
|
; from ATTR-P.
|
4016 |
|
|
|
4017 |
|
|
; Having cleared all 24 lines of the display area, continue into the
|
4018 |
|
|
; subroutine that clears the lower display area. Note that at the moment
|
4019 |
|
|
; the attributes for the lower lines are the same as upper ones and have
|
4020 |
|
|
; to be changed to match the BORDER colour.
|
4021 |
|
|
|
4022 |
|
|
; --------------------------
|
4023 |
|
|
; THE 'CLS-LOWER' SUBROUTINE
|
4024 |
|
|
; --------------------------
|
4025 |
|
|
; This routine is called from INPUT, and from the MAIN execution loop.
|
4026 |
|
|
; This is very much a housekeeping routine which clears between 2 and 23
|
4027 |
|
|
; lines of the display, setting attributes and correcting situations where
|
4028 |
|
|
; errors have occurred while the normal input and output routines have been
|
4029 |
|
|
; temporarily diverted to deal with, say colour control codes.
|
4030 |
|
|
|
4031 |
|
|
;; CLS-LOWER
|
4032 |
|
|
L0D6E: LD HL,$5C3C ; address System Variable TV_FLAG.
|
4033 |
|
|
RES 5,(HL) ; TV_FLAG - signal do not clear lower screen.
|
4034 |
|
|
SET 0,(HL) ; TV_FLAG - signal lower screen in use.
|
4035 |
|
|
|
4036 |
|
|
CALL L0D4D ; routine TEMPS applies permanent attributes,
|
4037 |
|
|
; in this case BORDCR to ATTR_T.
|
4038 |
|
|
; Note. this seems unnecessary and is repeated
|
4039 |
|
|
; within CL-LINE.
|
4040 |
|
|
|
4041 |
|
|
LD B,(IY+$31) ; fetch lower screen display file size DF_SZ
|
4042 |
|
|
|
4043 |
|
|
CALL L0E44 ; routine CL-LINE clears lines to bottom of the
|
4044 |
|
|
; display and sets attributes from BORDCR while
|
4045 |
|
|
; preserving the B register.
|
4046 |
|
|
|
4047 |
|
|
LD HL,$5AC0 ; set initial attribute address to the leftmost
|
4048 |
|
|
; cell of second line up.
|
4049 |
|
|
|
4050 |
|
|
LD A,($5C8D) ; fetch permanent attribute from ATTR_P.
|
4051 |
|
|
|
4052 |
|
|
DEC B ; decrement lower screen display file size.
|
4053 |
|
|
|
4054 |
|
|
JR L0D8E ; forward to enter the backfill loop at CLS-3
|
4055 |
|
|
; where B is decremented again.
|
4056 |
|
|
|
4057 |
|
|
; ---
|
4058 |
|
|
|
4059 |
|
|
; The backfill loop is entered at midpoint and ensures, if more than 2
|
4060 |
|
|
; lines have been cleared, that any other lines take the permanent screen
|
4061 |
|
|
; attributes.
|
4062 |
|
|
|
4063 |
|
|
;; CLS-1
|
4064 |
|
|
L0D87: LD C,$20 ; set counter to 32 character cells per line
|
4065 |
|
|
|
4066 |
|
|
;; CLS-2
|
4067 |
|
|
L0D89: DEC HL ; decrease attribute address.
|
4068 |
|
|
LD (HL),A ; and place attributes in next line up.
|
4069 |
|
|
DEC C ; decrease the 32 counter.
|
4070 |
|
|
JR NZ,L0D89 ; loop back to CLS-2 until all 32 cells done.
|
4071 |
|
|
|
4072 |
|
|
;; CLS-3
|
4073 |
|
|
L0D8E: DJNZ L0D87 ; decrease B counter and back to CLS-1
|
4074 |
|
|
; if not zero.
|
4075 |
|
|
|
4076 |
|
|
LD (IY+$31),$02 ; now set DF_SZ lower screen to 2
|
4077 |
|
|
|
4078 |
|
|
; This entry point is also called from CL-ALL below to
|
4079 |
|
|
; reset the system channel input and output addresses to normal.
|
4080 |
|
|
|
4081 |
|
|
;; CL-CHAN
|
4082 |
|
|
L0D94: LD A,$FD ; select system channel 'K'
|
4083 |
|
|
|
4084 |
|
|
CALL L1601 ; routine CHAN-OPEN opens it.
|
4085 |
|
|
|
4086 |
|
|
LD HL,($5C51) ; fetch CURCHL to HL to address current channel
|
4087 |
|
|
LD DE,L09F4 ; set address to PRINT-OUT for first pass.
|
4088 |
|
|
AND A ; clear carry for first pass.
|
4089 |
|
|
|
4090 |
|
|
;; CL-CHAN-A
|
4091 |
|
|
L0DA0: LD (HL),E ; Insert the output address on the first pass
|
4092 |
|
|
INC HL ; or the input address on the second pass.
|
4093 |
|
|
LD (HL),D ;
|
4094 |
|
|
INC HL ;
|
4095 |
|
|
|
4096 |
|
|
LD DE,L10A8 ; fetch address KEY-INPUT for second pass
|
4097 |
|
|
CCF ; complement carry flag - will set on pass 1.
|
4098 |
|
|
|
4099 |
|
|
JR C,L0DA0 ; back to CL-CHAN-A if first pass else done.
|
4100 |
|
|
|
4101 |
|
|
LD BC,$1721 ; line 23 for lower screen
|
4102 |
|
|
JR L0DD9 ; exit via CL-SET to set column
|
4103 |
|
|
; for lower display
|
4104 |
|
|
|
4105 |
|
|
; ---------------------------
|
4106 |
|
|
; Clearing whole display area
|
4107 |
|
|
; ---------------------------
|
4108 |
|
|
; This subroutine called from CLS, AUTO-LIST and MAIN-3
|
4109 |
|
|
; clears 24 lines of the display and resets the relevant system variables.
|
4110 |
|
|
; This routine also recovers from an error situation where, for instance, an
|
4111 |
|
|
; invalid colour or position control code has left the output routine addressing
|
4112 |
|
|
; PO-TV-2 or PO-CONT.
|
4113 |
|
|
|
4114 |
|
|
;; CL-ALL
|
4115 |
|
|
L0DAF: LD HL,$0000 ; Initialize plot coordinates.
|
4116 |
|
|
LD ($5C7D),HL ; Set system variable COORDS to 0,0.
|
4117 |
|
|
|
4118 |
|
|
RES 0,(IY+$30) ; update FLAGS2 - signal main screen is clear.
|
4119 |
|
|
|
4120 |
|
|
CALL L0D94 ; routine CL-CHAN makes channel 'K' 'normal'.
|
4121 |
|
|
|
4122 |
|
|
LD A,$FE ; select system channel 'S'
|
4123 |
|
|
CALL L1601 ; routine CHAN-OPEN opens it.
|
4124 |
|
|
|
4125 |
|
|
CALL L0D4D ; routine TEMPS applies permanent attributes,
|
4126 |
|
|
; in this case ATTR_P, to ATTR_T.
|
4127 |
|
|
; Note. this seems unnecessary.
|
4128 |
|
|
|
4129 |
|
|
LD B,$18 ; There are 24 lines.
|
4130 |
|
|
|
4131 |
|
|
CALL L0E44 ; routine CL-LINE clears 24 text lines and sets
|
4132 |
|
|
; attributes from ATTR-P.
|
4133 |
|
|
; This routine preserves B and sets C to $21.
|
4134 |
|
|
|
4135 |
|
|
LD HL,($5C51) ; fetch CURCHL make HL address output routine.
|
4136 |
|
|
|
4137 |
|
|
LD DE,L09F4 ; address: PRINT-OUT
|
4138 |
|
|
LD (HL),E ; is made
|
4139 |
|
|
INC HL ; the normal
|
4140 |
|
|
LD (HL),D ; output address.
|
4141 |
|
|
|
4142 |
|
|
LD (IY+$52),$01 ; set SCR_CT - scroll count - to default.
|
4143 |
|
|
|
4144 |
|
|
; Note. BC already contains $1821.
|
4145 |
|
|
|
4146 |
|
|
LD BC,$1821 ; reset column and line to 0,0
|
4147 |
|
|
; and continue into CL-SET, below, exiting
|
4148 |
|
|
; via PO-STORE (for the upper screen).
|
4149 |
|
|
|
4150 |
|
|
; --------------------
|
4151 |
|
|
; THE 'CL-SET' ROUTINE
|
4152 |
|
|
; --------------------
|
4153 |
|
|
; This important subroutine is used to calculate the character output
|
4154 |
|
|
; address for screens or printer based on the line/column for screens
|
4155 |
|
|
; or the column for printer.
|
4156 |
|
|
|
4157 |
|
|
;; CL-SET
|
4158 |
|
|
L0DD9: LD HL,$5B00 ; the base address of printer buffer
|
4159 |
|
|
BIT 1,(IY+$01) ; test FLAGS - is printer in use ?
|
4160 |
|
|
JR NZ,L0DF4 ; forward to CL-SET-2 if so.
|
4161 |
|
|
|
4162 |
|
|
LD A,B ; transfer line to A.
|
4163 |
|
|
BIT 0,(IY+$02) ; test TV_FLAG - lower screen in use ?
|
4164 |
|
|
JR Z,L0DEE ; skip to CL-SET-1 if handling upper part
|
4165 |
|
|
|
4166 |
|
|
ADD A,(IY+$31) ; add DF_SZ for lower screen
|
4167 |
|
|
SUB $18 ; and adjust.
|
4168 |
|
|
|
4169 |
|
|
;; CL-SET-1
|
4170 |
|
|
L0DEE: PUSH BC ; save the line/column.
|
4171 |
|
|
LD B,A ; transfer line to B
|
4172 |
|
|
; (adjusted if lower screen)
|
4173 |
|
|
|
4174 |
|
|
CALL L0E9B ; routine CL-ADDR calculates address at left
|
4175 |
|
|
; of screen.
|
4176 |
|
|
POP BC ; restore the line/column.
|
4177 |
|
|
|
4178 |
|
|
;; CL-SET-2
|
4179 |
|
|
L0DF4: LD A,$21 ; the column $01-$21 is reversed
|
4180 |
|
|
SUB C ; to range $00 - $20
|
4181 |
|
|
LD E,A ; now transfer to DE
|
4182 |
|
|
LD D,$00 ; prepare for addition
|
4183 |
|
|
ADD HL,DE ; and add to base address
|
4184 |
|
|
|
4185 |
|
|
JP L0ADC ; exit via PO-STORE to update the relevant
|
4186 |
|
|
; system variables.
|
4187 |
|
|
; ----------------
|
4188 |
|
|
; Handle scrolling
|
4189 |
|
|
; ----------------
|
4190 |
|
|
; The routine CL-SC-ALL is called once from PO to scroll all the display
|
4191 |
|
|
; and from the routine CL-SCROLL, once, to scroll part of the display.
|
4192 |
|
|
|
4193 |
|
|
;; CL-SC-ALL
|
4194 |
|
|
L0DFE: LD B,$17 ; scroll 23 lines, after 'scroll?'.
|
4195 |
|
|
|
4196 |
|
|
;; CL-SCROLL
|
4197 |
|
|
L0E00: CALL L0E9B ; routine CL-ADDR gets screen address in HL.
|
4198 |
|
|
LD C,$08 ; there are 8 pixel lines to scroll.
|
4199 |
|
|
|
4200 |
|
|
;; CL-SCR-1
|
4201 |
|
|
L0E05: PUSH BC ; save counters.
|
4202 |
|
|
PUSH HL ; and initial address.
|
4203 |
|
|
LD A,B ; get line count.
|
4204 |
|
|
AND $07 ; will set zero if all third to be scrolled.
|
4205 |
|
|
LD A,B ; re-fetch the line count.
|
4206 |
|
|
JR NZ,L0E19 ; forward to CL-SCR-3 if partial scroll.
|
4207 |
|
|
|
4208 |
|
|
; HL points to top line of third and must be copied to bottom of previous 3rd.
|
4209 |
|
|
; ( so HL = $4800 or $5000 ) ( but also sometimes $4000 )
|
4210 |
|
|
|
4211 |
|
|
;; CL-SCR-2
|
4212 |
|
|
L0E0D: EX DE,HL ; copy HL to DE.
|
4213 |
|
|
LD HL,$F8E0 ; subtract $08 from H and add $E0 to L -
|
4214 |
|
|
ADD HL,DE ; to make destination bottom line of previous
|
4215 |
|
|
; third.
|
4216 |
|
|
EX DE,HL ; restore the source and destination.
|
4217 |
|
|
LD BC,$0020 ; thirty-two bytes are to be copied.
|
4218 |
|
|
DEC A ; decrement the line count.
|
4219 |
|
|
LDIR ; copy a pixel line to previous third.
|
4220 |
|
|
|
4221 |
|
|
;; CL-SCR-3
|
4222 |
|
|
L0E19: EX DE,HL ; save source in DE.
|
4223 |
|
|
LD HL,$FFE0 ; load the value -32.
|
4224 |
|
|
ADD HL,DE ; add to form destination in HL.
|
4225 |
|
|
EX DE,HL ; switch source and destination
|
4226 |
|
|
LD B,A ; save the count in B.
|
4227 |
|
|
AND $07 ; mask to find count applicable to current
|
4228 |
|
|
RRCA ; third and
|
4229 |
|
|
RRCA ; multiply by
|
4230 |
|
|
RRCA ; thirty two (same as 5 RLCAs)
|
4231 |
|
|
|
4232 |
|
|
LD C,A ; transfer byte count to C ($E0 at most)
|
4233 |
|
|
LD A,B ; store line count to A
|
4234 |
|
|
LD B,$00 ; make B zero
|
4235 |
|
|
LDIR ; copy bytes (BC=0, H incremented, L=0)
|
4236 |
|
|
LD B,$07 ; set B to 7, C is zero.
|
4237 |
|
|
ADD HL,BC ; add 7 to H to address next third.
|
4238 |
|
|
AND $F8 ; has last third been done ?
|
4239 |
|
|
JR NZ,L0E0D ; back to CL-SCR-2 if not.
|
4240 |
|
|
|
4241 |
|
|
POP HL ; restore topmost address.
|
4242 |
|
|
INC H ; next pixel line down.
|
4243 |
|
|
POP BC ; restore counts.
|
4244 |
|
|
DEC C ; reduce pixel line count.
|
4245 |
|
|
JR NZ,L0E05 ; back to CL-SCR-1 if all eight not done.
|
4246 |
|
|
|
4247 |
|
|
CALL L0E88 ; routine CL-ATTR gets address in attributes
|
4248 |
|
|
; from current 'ninth line', count in BC.
|
4249 |
|
|
|
4250 |
|
|
LD HL,$FFE0 ; set HL to the 16-bit value -32.
|
4251 |
|
|
ADD HL,DE ; and add to form destination address.
|
4252 |
|
|
EX DE,HL ; swap source and destination addresses.
|
4253 |
|
|
LDIR ; copy bytes scrolling the linear attributes.
|
4254 |
|
|
LD B,$01 ; continue to clear the bottom line.
|
4255 |
|
|
|
4256 |
|
|
; ------------------------------
|
4257 |
|
|
; THE 'CLEAR TEXT LINES' ROUTINE
|
4258 |
|
|
; ------------------------------
|
4259 |
|
|
; This subroutine, called from CL-ALL, CLS-LOWER and AUTO-LIST and above,
|
4260 |
|
|
; clears text lines at bottom of display.
|
4261 |
|
|
; The B register holds on entry the number of lines to be cleared 1-24.
|
4262 |
|
|
|
4263 |
|
|
;; CL-LINE
|
4264 |
|
|
L0E44: PUSH BC ; save line count
|
4265 |
|
|
CALL L0E9B ; routine CL-ADDR gets top address
|
4266 |
|
|
LD C,$08 ; there are eight screen lines to a text line.
|
4267 |
|
|
|
4268 |
|
|
;; CL-LINE-1
|
4269 |
|
|
L0E4A: PUSH BC ; save pixel line count
|
4270 |
|
|
PUSH HL ; and save the address
|
4271 |
|
|
LD A,B ; transfer the line to A (1-24).
|
4272 |
|
|
|
4273 |
|
|
;; CL-LINE-2
|
4274 |
|
|
L0E4D: AND $07 ; mask 0-7 to consider thirds at a time
|
4275 |
|
|
RRCA ; multiply
|
4276 |
|
|
RRCA ; by 32 (same as five RLCA instructions)
|
4277 |
|
|
RRCA ; now 32 - 256(0)
|
4278 |
|
|
LD C,A ; store result in C
|
4279 |
|
|
LD A,B ; save line in A (1-24)
|
4280 |
|
|
LD B,$00 ; set high byte to 0, prepare for ldir.
|
4281 |
|
|
DEC C ; decrement count 31-255.
|
4282 |
|
|
LD D,H ; copy HL
|
4283 |
|
|
LD E,L ; to DE.
|
4284 |
|
|
LD (HL),$00 ; blank the first byte.
|
4285 |
|
|
INC DE ; make DE point to next byte.
|
4286 |
|
|
LDIR ; ldir will clear lines.
|
4287 |
|
|
LD DE,$0701 ; now address next third adjusting
|
4288 |
|
|
ADD HL,DE ; register E to address left hand side
|
4289 |
|
|
DEC A ; decrease the line count.
|
4290 |
|
|
AND $F8 ; will be 16, 8 or 0 (AND $18 will do).
|
4291 |
|
|
LD B,A ; transfer count to B.
|
4292 |
|
|
JR NZ,L0E4D ; back to CL-LINE-2 if 16 or 8 to do
|
4293 |
|
|
; the next third.
|
4294 |
|
|
|
4295 |
|
|
POP HL ; restore start address.
|
4296 |
|
|
INC H ; address next line down.
|
4297 |
|
|
POP BC ; fetch counts.
|
4298 |
|
|
DEC C ; decrement pixel line count
|
4299 |
|
|
JR NZ,L0E4A ; back to CL-LINE-1 till all done.
|
4300 |
|
|
|
4301 |
|
|
CALL L0E88 ; routine CL-ATTR gets attribute address
|
4302 |
|
|
; in DE and B * 32 in BC.
|
4303 |
|
|
|
4304 |
|
|
LD H,D ; transfer the address
|
4305 |
|
|
LD L,E ; to HL.
|
4306 |
|
|
|
4307 |
|
|
INC DE ; make DE point to next location.
|
4308 |
|
|
|
4309 |
|
|
LD A,($5C8D) ; fetch ATTR_P - permanent attributes
|
4310 |
|
|
BIT 0,(IY+$02) ; test TV_FLAG - lower screen in use ?
|
4311 |
|
|
JR Z,L0E80 ; skip to CL-LINE-3 if not.
|
4312 |
|
|
|
4313 |
|
|
LD A,($5C48) ; else lower screen uses BORDCR as attribute.
|
4314 |
|
|
|
4315 |
|
|
;; CL-LINE-3
|
4316 |
|
|
L0E80: LD (HL),A ; put attribute in first byte.
|
4317 |
|
|
DEC BC ; decrement the counter.
|
4318 |
|
|
LDIR ; copy bytes to set all attributes.
|
4319 |
|
|
POP BC ; restore the line $01-$24.
|
4320 |
|
|
LD C,$21 ; make column $21. (No use is made of this)
|
4321 |
|
|
RET ; return to the calling routine.
|
4322 |
|
|
|
4323 |
|
|
; ------------------
|
4324 |
|
|
; Attribute handling
|
4325 |
|
|
; ------------------
|
4326 |
|
|
; This subroutine is called from CL-LINE or CL-SCROLL with the HL register
|
4327 |
|
|
; pointing to the 'ninth' line and H needs to be decremented before or after
|
4328 |
|
|
; the division. Had it been done first then either present code or that used
|
4329 |
|
|
; at the start of PO-ATTR could have been used.
|
4330 |
|
|
; The Spectrum screen arrangement leads to the L register already holding
|
4331 |
|
|
; the correct value for the attribute file and it is only necessary
|
4332 |
|
|
; to manipulate H to form the correct colour attribute address.
|
4333 |
|
|
|
4334 |
|
|
;; CL-ATTR
|
4335 |
|
|
L0E88: LD A,H ; fetch H to A - $48, $50, or $58.
|
4336 |
|
|
RRCA ; divide by
|
4337 |
|
|
RRCA ; eight.
|
4338 |
|
|
RRCA ; $09, $0A or $0B.
|
4339 |
|
|
DEC A ; $08, $09 or $0A.
|
4340 |
|
|
OR $50 ; $58, $59 or $5A.
|
4341 |
|
|
LD H,A ; save high byte of attributes.
|
4342 |
|
|
|
4343 |
|
|
EX DE,HL ; transfer attribute address to DE
|
4344 |
|
|
LD H,C ; set H to zero - from last LDIR.
|
4345 |
|
|
LD L,B ; load L with the line from B.
|
4346 |
|
|
ADD HL,HL ; multiply
|
4347 |
|
|
ADD HL,HL ; by
|
4348 |
|
|
ADD HL,HL ; thirty two
|
4349 |
|
|
ADD HL,HL ; to give count of attribute
|
4350 |
|
|
ADD HL,HL ; cells to the end of display.
|
4351 |
|
|
|
4352 |
|
|
LD B,H ; transfer the result
|
4353 |
|
|
LD C,L ; to register BC.
|
4354 |
|
|
|
4355 |
|
|
RET ; return.
|
4356 |
|
|
|
4357 |
|
|
; -------------------------------
|
4358 |
|
|
; Handle display with line number
|
4359 |
|
|
; -------------------------------
|
4360 |
|
|
; This subroutine is called from four places to calculate the address
|
4361 |
|
|
; of the start of a screen character line which is supplied in B.
|
4362 |
|
|
|
4363 |
|
|
;; CL-ADDR
|
4364 |
|
|
L0E9B: LD A,$18 ; reverse the line number
|
4365 |
|
|
SUB B ; to range $00 - $17.
|
4366 |
|
|
LD D,A ; save line in D for later.
|
4367 |
|
|
RRCA ; multiply
|
4368 |
|
|
RRCA ; by
|
4369 |
|
|
RRCA ; thirty-two.
|
4370 |
|
|
|
4371 |
|
|
AND $E0 ; mask off low bits to make
|
4372 |
|
|
LD L,A ; L a multiple of 32.
|
4373 |
|
|
|
4374 |
|
|
LD A,D ; bring back the line to A.
|
4375 |
|
|
|
4376 |
|
|
AND $18 ; now $00, $08 or $10.
|
4377 |
|
|
|
4378 |
|
|
OR $40 ; add the base address of screen.
|
4379 |
|
|
|
4380 |
|
|
LD H,A ; HL now has the correct address.
|
4381 |
|
|
RET ; return.
|
4382 |
|
|
|
4383 |
|
|
; -------------------
|
4384 |
|
|
; Handle COPY command
|
4385 |
|
|
; -------------------
|
4386 |
|
|
; This command copies the top 176 lines to the ZX Printer
|
4387 |
|
|
; It is popular to call this from machine code at point
|
4388 |
|
|
; L0EAF with B holding 192 (and interrupts disabled) for a full-screen
|
4389 |
|
|
; copy. This particularly applies to 16K Spectrums as time-critical
|
4390 |
|
|
; machine code routines cannot be written in the first 16K of RAM as
|
4391 |
|
|
; it is shared with the ULA which has precedence over the Z80 chip.
|
4392 |
|
|
|
4393 |
|
|
;; COPY
|
4394 |
|
|
L0EAC: DI ; disable interrupts as this is time-critical.
|
4395 |
|
|
|
4396 |
|
|
LD B,$B0 ; top 176 lines.
|
4397 |
|
|
L0EAF: LD HL,$4000 ; address start of the display file.
|
4398 |
|
|
|
4399 |
|
|
; now enter a loop to handle each pixel line.
|
4400 |
|
|
|
4401 |
|
|
;; COPY-1
|
4402 |
|
|
L0EB2: PUSH HL ; save the screen address.
|
4403 |
|
|
PUSH BC ; and the line counter.
|
4404 |
|
|
|
4405 |
|
|
CALL L0EF4 ; routine COPY-LINE outputs one line.
|
4406 |
|
|
|
4407 |
|
|
POP BC ; restore the line counter.
|
4408 |
|
|
POP HL ; and display address.
|
4409 |
|
|
INC H ; next line down screen within 'thirds'.
|
4410 |
|
|
LD A,H ; high byte to A.
|
4411 |
|
|
AND $07 ; result will be zero if we have left third.
|
4412 |
|
|
JR NZ,L0EC9 ; forward to COPY-2 if not to continue loop.
|
4413 |
|
|
|
4414 |
|
|
LD A,L ; consider low byte first.
|
4415 |
|
|
ADD A,$20 ; increase by 32 - sets carry if back to zero.
|
4416 |
|
|
LD L,A ; will be next group of 8.
|
4417 |
|
|
CCF ; complement - carry set if more lines in
|
4418 |
|
|
; the previous third.
|
4419 |
|
|
SBC A,A ; will be FF, if more, else 00.
|
4420 |
|
|
AND $F8 ; will be F8 (-8) or 00.
|
4421 |
|
|
ADD A,H ; that is subtract 8, if more to do in third.
|
4422 |
|
|
LD H,A ; and reset address.
|
4423 |
|
|
|
4424 |
|
|
;; COPY-2
|
4425 |
|
|
L0EC9: DJNZ L0EB2 ; back to COPY-1 for all lines.
|
4426 |
|
|
|
4427 |
|
|
JR L0EDA ; forward to COPY-END to switch off the printer
|
4428 |
|
|
; motor and enable interrupts.
|
4429 |
|
|
; Note. Nothing else is required.
|
4430 |
|
|
|
4431 |
|
|
; ------------------------------
|
4432 |
|
|
; Pass printer buffer to printer
|
4433 |
|
|
; ------------------------------
|
4434 |
|
|
; This routine is used to copy 8 text lines from the printer buffer
|
4435 |
|
|
; to the ZX Printer. These text lines are mapped linearly so HL does
|
4436 |
|
|
; not need to be adjusted at the end of each line.
|
4437 |
|
|
|
4438 |
|
|
;; COPY-BUFF
|
4439 |
|
|
L0ECD: DI ; disable interrupts
|
4440 |
|
|
LD HL,$5B00 ; the base address of the Printer Buffer.
|
4441 |
|
|
LD B,$08 ; set count to 8 lines of 32 bytes.
|
4442 |
|
|
|
4443 |
|
|
;; COPY-3
|
4444 |
|
|
L0ED3: PUSH BC ; save counter.
|
4445 |
|
|
|
4446 |
|
|
CALL L0EF4 ; routine COPY-LINE outputs 32 bytes
|
4447 |
|
|
|
4448 |
|
|
POP BC ; restore counter.
|
4449 |
|
|
DJNZ L0ED3 ; loop back to COPY-3 for all 8 lines.
|
4450 |
|
|
; then stop motor and clear buffer.
|
4451 |
|
|
|
4452 |
|
|
; Note. the COPY command rejoins here, essentially to execute the next
|
4453 |
|
|
; three instructions.
|
4454 |
|
|
|
4455 |
|
|
;; COPY-END
|
4456 |
|
|
L0EDA: LD A,$04 ; output value 4 to port
|
4457 |
|
|
OUT ($FB),A ; to stop the slowed printer motor.
|
4458 |
|
|
EI ; enable interrupts.
|
4459 |
|
|
|
4460 |
|
|
; --------------------
|
4461 |
|
|
; Clear Printer Buffer
|
4462 |
|
|
; --------------------
|
4463 |
|
|
; This routine clears an arbitrary 256 bytes of memory.
|
4464 |
|
|
; Note. The routine seems designed to clear a buffer that follows the
|
4465 |
|
|
; system variables.
|
4466 |
|
|
; The routine should check a flag or HL address and simply return if COPY
|
4467 |
|
|
; is in use.
|
4468 |
|
|
; As a consequence of this omission the buffer will needlessly
|
4469 |
|
|
; be cleared when COPY is used and the screen/printer position may be set to
|
4470 |
|
|
; the start of the buffer and the line number to 0 (B)
|
4471 |
|
|
; giving an 'Out of Screen' error.
|
4472 |
|
|
; There seems to have been an unsuccessful attempt to circumvent the use
|
4473 |
|
|
; of PR_CC_hi.
|
4474 |
|
|
|
4475 |
|
|
;; CLEAR-PRB
|
4476 |
|
|
L0EDF: LD HL,$5B00 ; the location of the buffer.
|
4477 |
|
|
LD (IY+$46),L ; update PR_CC_lo - set to zero - superfluous.
|
4478 |
|
|
XOR A ; clear the accumulator.
|
4479 |
|
|
LD B,A ; set count to 256 bytes.
|
4480 |
|
|
|
4481 |
|
|
;; PRB-BYTES
|
4482 |
|
|
L0EE7: LD (HL),A ; set addressed location to zero.
|
4483 |
|
|
INC HL ; address next byte - Note. not INC L.
|
4484 |
|
|
DJNZ L0EE7 ; back to PRB-BYTES. repeat for 256 bytes.
|
4485 |
|
|
|
4486 |
|
|
RES 1,(IY+$30) ; set FLAGS2 - signal printer buffer is clear.
|
4487 |
|
|
LD C,$21 ; set the column position .
|
4488 |
|
|
JP L0DD9 ; exit via CL-SET and then PO-STORE.
|
4489 |
|
|
|
4490 |
|
|
; -----------------
|
4491 |
|
|
; Copy line routine
|
4492 |
|
|
; -----------------
|
4493 |
|
|
; This routine is called from COPY and COPY-BUFF to output a line of
|
4494 |
|
|
; 32 bytes to the ZX Printer.
|
4495 |
|
|
; Output to port $FB -
|
4496 |
|
|
; bit 7 set - activate stylus.
|
4497 |
|
|
; bit 7 low - deactivate stylus.
|
4498 |
|
|
; bit 2 set - stops printer.
|
4499 |
|
|
; bit 2 reset - starts printer
|
4500 |
|
|
; bit 1 set - slows printer.
|
4501 |
|
|
; bit 1 reset - normal speed.
|
4502 |
|
|
|
4503 |
|
|
;; COPY-LINE
|
4504 |
|
|
L0EF4: LD A,B ; fetch the counter 1-8 or 1-176
|
4505 |
|
|
CP $03 ; is it 01 or 02 ?.
|
4506 |
|
|
SBC A,A ; result is $FF if so else $00.
|
4507 |
|
|
AND $02 ; result is 02 now else 00.
|
4508 |
|
|
; bit 1 set slows the printer.
|
4509 |
|
|
OUT ($FB),A ; slow the printer for the
|
4510 |
|
|
; last two lines.
|
4511 |
|
|
LD D,A ; save the mask to control the printer later.
|
4512 |
|
|
|
4513 |
|
|
;; COPY-L-1
|
4514 |
|
|
L0EFD: CALL L1F54 ; call BREAK-KEY to read keyboard immediately.
|
4515 |
|
|
JR C,L0F0C ; forward to COPY-L-2 if 'break' not pressed.
|
4516 |
|
|
|
4517 |
|
|
LD A,$04 ; else stop the
|
4518 |
|
|
OUT ($FB),A ; printer motor.
|
4519 |
|
|
EI ; enable interrupts.
|
4520 |
|
|
CALL L0EDF ; call routine CLEAR-PRB.
|
4521 |
|
|
; Note. should not be cleared if COPY in use.
|
4522 |
|
|
|
4523 |
|
|
;; REPORT-Dc
|
4524 |
|
|
L0F0A: RST 08H ; ERROR-1
|
4525 |
|
|
DEFB $0C ; Error Report: BREAK - CONT repeats
|
4526 |
|
|
|
4527 |
|
|
;; COPY-L-2
|
4528 |
|
|
L0F0C: IN A,($FB) ; test now to see if
|
4529 |
|
|
ADD A,A ; a printer is attached.
|
4530 |
|
|
RET M ; return if not - but continue with parent
|
4531 |
|
|
; command.
|
4532 |
|
|
|
4533 |
|
|
JR NC,L0EFD ; back to COPY-L-1 if stylus of printer not
|
4534 |
|
|
; in position.
|
4535 |
|
|
|
4536 |
|
|
LD C,$20 ; set count to 32 bytes.
|
4537 |
|
|
|
4538 |
|
|
;; COPY-L-3
|
4539 |
|
|
L0F14: LD E,(HL) ; fetch a byte from line.
|
4540 |
|
|
INC HL ; address next location. Note. not INC L.
|
4541 |
|
|
LD B,$08 ; count the bits.
|
4542 |
|
|
|
4543 |
|
|
;; COPY-L-4
|
4544 |
|
|
L0F18: RL D ; prepare mask to receive bit.
|
4545 |
|
|
RL E ; rotate leftmost print bit to carry
|
4546 |
|
|
RR D ; and back to bit 7 of D restoring bit 1
|
4547 |
|
|
|
4548 |
|
|
;; COPY-L-5
|
4549 |
|
|
L0F1E: IN A,($FB) ; read the port.
|
4550 |
|
|
RRA ; bit 0 to carry.
|
4551 |
|
|
JR NC,L0F1E ; back to COPY-L-5 if stylus not in position.
|
4552 |
|
|
|
4553 |
|
|
LD A,D ; transfer command bits to A.
|
4554 |
|
|
OUT ($FB),A ; and output to port.
|
4555 |
|
|
DJNZ L0F18 ; loop back to COPY-L-4 for all 8 bits.
|
4556 |
|
|
|
4557 |
|
|
DEC C ; decrease the byte count.
|
4558 |
|
|
JR NZ,L0F14 ; back to COPY-L-3 until 256 bits done.
|
4559 |
|
|
|
4560 |
|
|
RET ; return to calling routine COPY/COPY-BUFF.
|
4561 |
|
|
|
4562 |
|
|
|
4563 |
|
|
; ----------------------------------
|
4564 |
|
|
; Editor routine for BASIC and INPUT
|
4565 |
|
|
; ----------------------------------
|
4566 |
|
|
; The editor is called to prepare or edit a BASIC line.
|
4567 |
|
|
; It is also called from INPUT to input a numeric or string expression.
|
4568 |
|
|
; The behaviour and options are quite different in the various modes
|
4569 |
|
|
; and distinguished by bit 5 of FLAGX.
|
4570 |
|
|
;
|
4571 |
|
|
; This is a compact and highly versatile routine.
|
4572 |
|
|
|
4573 |
|
|
;; EDITOR
|
4574 |
|
|
L0F2C: LD HL,($5C3D) ; fetch ERR_SP
|
4575 |
|
|
PUSH HL ; save on stack
|
4576 |
|
|
|
4577 |
|
|
;; ED-AGAIN
|
4578 |
|
|
L0F30: LD HL,L107F ; address: ED-ERROR
|
4579 |
|
|
PUSH HL ; save address on stack and
|
4580 |
|
|
LD ($5C3D),SP ; make ERR_SP point to it.
|
4581 |
|
|
|
4582 |
|
|
; Note. While in editing/input mode should an error occur then RST 08 will
|
4583 |
|
|
; update X_PTR to the location reached by CH_ADD and jump to ED-ERROR
|
4584 |
|
|
; where the error will be cancelled and the loop begin again from ED-AGAIN
|
4585 |
|
|
; above. The position of the error will be apparent when the lower screen is
|
4586 |
|
|
; reprinted. If no error then the re-iteration is to ED-LOOP below when
|
4587 |
|
|
; input is arriving from the keyboard.
|
4588 |
|
|
|
4589 |
|
|
;; ED-LOOP
|
4590 |
|
|
L0F38: CALL L15D4 ; routine WAIT-KEY gets key possibly
|
4591 |
|
|
; changing the mode.
|
4592 |
|
|
PUSH AF ; save key.
|
4593 |
|
|
LD D,$00 ; and give a short click based
|
4594 |
|
|
LD E,(IY-$01) ; on PIP value for duration.
|
4595 |
|
|
LD HL,$00C8 ; and pitch.
|
4596 |
|
|
CALL L03B5 ; routine BEEPER gives click - effective
|
4597 |
|
|
; with rubber keyboard.
|
4598 |
|
|
POP AF ; get saved key value.
|
4599 |
|
|
LD HL,L0F38 ; address: ED-LOOP is loaded to HL.
|
4600 |
|
|
PUSH HL ; and pushed onto stack.
|
4601 |
|
|
|
4602 |
|
|
; At this point there is a looping return address on the stack, an error
|
4603 |
|
|
; handler and an input stream set up to supply characters.
|
4604 |
|
|
; The character that has been received can now be processed.
|
4605 |
|
|
|
4606 |
|
|
CP $18 ; range 24 to 255 ?
|
4607 |
|
|
JR NC,L0F81 ; forward to ADD-CHAR if so.
|
4608 |
|
|
|
4609 |
|
|
CP $07 ; lower than 7 ?
|
4610 |
|
|
JR C,L0F81 ; forward to ADD-CHAR also.
|
4611 |
|
|
; Note. This is a 'bug' and chr$ 6, the comma
|
4612 |
|
|
; control character, should have had an
|
4613 |
|
|
; entry in the ED-KEYS table.
|
4614 |
|
|
; Steven Vickers, 1984, Pitman.
|
4615 |
|
|
|
4616 |
|
|
CP $10 ; less than 16 ?
|
4617 |
|
|
JR C,L0F92 ; forward to ED-KEYS if editing control
|
4618 |
|
|
; range 7 to 15 dealt with by a table
|
4619 |
|
|
|
4620 |
|
|
LD BC,$0002 ; prepare for ink/paper etc.
|
4621 |
|
|
LD D,A ; save character in D
|
4622 |
|
|
CP $16 ; is it ink/paper/bright etc. ?
|
4623 |
|
|
JR C,L0F6C ; forward to ED-CONTR if so
|
4624 |
|
|
|
4625 |
|
|
; leaves 22d AT and 23d TAB
|
4626 |
|
|
; which can't be entered via KEY-INPUT.
|
4627 |
|
|
; so this code is never normally executed
|
4628 |
|
|
; when the keyboard is used for input.
|
4629 |
|
|
|
4630 |
|
|
INC BC ; if it was AT/TAB - 3 locations required
|
4631 |
|
|
BIT 7,(IY+$37) ; test FLAGX - Is this INPUT LINE ?
|
4632 |
|
|
JP Z,L101E ; jump to ED-IGNORE if not, else
|
4633 |
|
|
|
4634 |
|
|
CALL L15D4 ; routine WAIT-KEY - input address is KEY-NEXT
|
4635 |
|
|
; but is reset to KEY-INPUT
|
4636 |
|
|
LD E,A ; save first in E
|
4637 |
|
|
|
4638 |
|
|
;; ED-CONTR
|
4639 |
|
|
L0F6C: CALL L15D4 ; routine WAIT-KEY for control.
|
4640 |
|
|
; input address will be key-next.
|
4641 |
|
|
|
4642 |
|
|
PUSH DE ; saved code/parameters
|
4643 |
|
|
LD HL,($5C5B) ; fetch address of keyboard cursor from K_CUR
|
4644 |
|
|
RES 0,(IY+$07) ; set MODE to 'L'
|
4645 |
|
|
|
4646 |
|
|
CALL L1655 ; routine MAKE-ROOM makes 2/3 spaces at cursor
|
4647 |
|
|
|
4648 |
|
|
POP BC ; restore code/parameters
|
4649 |
|
|
INC HL ; address first location
|
4650 |
|
|
LD (HL),B ; place code (ink etc.)
|
4651 |
|
|
INC HL ; address next
|
4652 |
|
|
LD (HL),C ; place possible parameter. If only one
|
4653 |
|
|
; then DE points to this location also.
|
4654 |
|
|
JR L0F8B ; forward to ADD-CH-1
|
4655 |
|
|
|
4656 |
|
|
; ------------------------
|
4657 |
|
|
; Add code to current line
|
4658 |
|
|
; ------------------------
|
4659 |
|
|
; this is the branch used to add normal non-control characters
|
4660 |
|
|
; with ED-LOOP as the stacked return address.
|
4661 |
|
|
; it is also the OUTPUT service routine for system channel 'R'.
|
4662 |
|
|
|
4663 |
|
|
;; ADD-CHAR
|
4664 |
|
|
L0F81: RES 0,(IY+$07) ; set MODE to 'L'
|
4665 |
|
|
|
4666 |
|
|
X0F85: LD HL,($5C5B) ; fetch address of keyboard cursor from K_CUR
|
4667 |
|
|
|
4668 |
|
|
CALL L1652 ; routine ONE-SPACE creates one space.
|
4669 |
|
|
|
4670 |
|
|
; either a continuation of above or from ED-CONTR with ED-LOOP on stack.
|
4671 |
|
|
|
4672 |
|
|
;; ADD-CH-1
|
4673 |
|
|
L0F8B: LD (DE),A ; load current character to last new location.
|
4674 |
|
|
INC DE ; address next
|
4675 |
|
|
LD ($5C5B),DE ; and update K_CUR system variable.
|
4676 |
|
|
RET ; return - either a simple return
|
4677 |
|
|
; from ADD-CHAR or to ED-LOOP on stack.
|
4678 |
|
|
|
4679 |
|
|
; ---
|
4680 |
|
|
|
4681 |
|
|
; a branch of the editing loop to deal with control characters
|
4682 |
|
|
; using a look-up table.
|
4683 |
|
|
|
4684 |
|
|
;; ED-KEYS
|
4685 |
|
|
L0F92: LD E,A ; character to E.
|
4686 |
|
|
LD D,$00 ; prepare to add.
|
4687 |
|
|
LD HL,L0FA0 - 7 ; base address of editing keys table. $0F99
|
4688 |
|
|
ADD HL,DE ; add E
|
4689 |
|
|
LD E,(HL) ; fetch offset to E
|
4690 |
|
|
ADD HL,DE ; add offset for address of handling routine.
|
4691 |
|
|
PUSH HL ; push the address on machine stack.
|
4692 |
|
|
LD HL,($5C5B) ; load address of cursor from K_CUR.
|
4693 |
|
|
RET ; Make an indirect jump forward to routine.
|
4694 |
|
|
|
4695 |
|
|
; ------------------
|
4696 |
|
|
; Editing keys table
|
4697 |
|
|
; ------------------
|
4698 |
|
|
; For each code in the range $07 to $0F this table contains a
|
4699 |
|
|
; single offset byte to the routine that services that code.
|
4700 |
|
|
; Note. for what was intended there should also have been an
|
4701 |
|
|
; entry for chr$ 6 with offset to ed-symbol.
|
4702 |
|
|
|
4703 |
|
|
;; ed-keys-t
|
4704 |
|
|
L0FA0: DEFB L0FA9 - $ ; 07d offset $09 to Address: ED-EDIT
|
4705 |
|
|
DEFB L1007 - $ ; 08d offset $66 to Address: ED-LEFT
|
4706 |
|
|
DEFB L100C - $ ; 09d offset $6A to Address: ED-RIGHT
|
4707 |
|
|
DEFB L0FF3 - $ ; 10d offset $50 to Address: ED-DOWN
|
4708 |
|
|
DEFB L1059 - $ ; 11d offset $B5 to Address: ED-UP
|
4709 |
|
|
DEFB L1015 - $ ; 12d offset $70 to Address: ED-DELETE
|
4710 |
|
|
DEFB L1024 - $ ; 13d offset $7E to Address: ED-ENTER
|
4711 |
|
|
DEFB L1076 - $ ; 14d offset $CF to Address: ED-SYMBOL
|
4712 |
|
|
DEFB L107C - $ ; 15d offset $D4 to Address: ED-GRAPH
|
4713 |
|
|
|
4714 |
|
|
; ---------------
|
4715 |
|
|
; Handle EDIT key
|
4716 |
|
|
; ---------------
|
4717 |
|
|
; The user has pressed SHIFT 1 to bring edit line down to bottom of screen.
|
4718 |
|
|
; Alternatively the user wishes to clear the input buffer and start again.
|
4719 |
|
|
; Alternatively ...
|
4720 |
|
|
|
4721 |
|
|
;; ED-EDIT
|
4722 |
|
|
L0FA9: LD HL,($5C49) ; fetch E_PPC the last line number entered.
|
4723 |
|
|
; Note. may not exist and may follow program.
|
4724 |
|
|
BIT 5,(IY+$37) ; test FLAGX - input mode ?
|
4725 |
|
|
JP NZ,L1097 ; jump forward to CLEAR-SP if not in editor.
|
4726 |
|
|
|
4727 |
|
|
CALL L196E ; routine LINE-ADDR to find address of line
|
4728 |
|
|
; or following line if it doesn't exist.
|
4729 |
|
|
CALL L1695 ; routine LINE-NO will get line number from
|
4730 |
|
|
; address or previous line if at end-marker.
|
4731 |
|
|
LD A,D ; if there is no program then DE will
|
4732 |
|
|
OR E ; contain zero so test for this.
|
4733 |
|
|
JP Z,L1097 ; jump to CLEAR-SP if so.
|
4734 |
|
|
|
4735 |
|
|
; Note. at this point we have a validated line number, not just an
|
4736 |
|
|
; approximation and it would be best to update E_PPC with the true
|
4737 |
|
|
; cursor line value which would enable the line cursor to be suppressed
|
4738 |
|
|
; in all situations - see shortly.
|
4739 |
|
|
|
4740 |
|
|
PUSH HL ; save address of line.
|
4741 |
|
|
INC HL ; address low byte of length.
|
4742 |
|
|
LD C,(HL) ; transfer to C
|
4743 |
|
|
INC HL ; next to high byte
|
4744 |
|
|
LD B,(HL) ; transfer to B.
|
4745 |
|
|
LD HL,$000A ; an overhead of ten bytes
|
4746 |
|
|
ADD HL,BC ; is added to length.
|
4747 |
|
|
LD B,H ; transfer adjusted value
|
4748 |
|
|
LD C,L ; to BC register.
|
4749 |
|
|
CALL L1F05 ; routine TEST-ROOM checks free memory.
|
4750 |
|
|
CALL L1097 ; routine CLEAR-SP clears editing area.
|
4751 |
|
|
LD HL,($5C51) ; address CURCHL
|
4752 |
|
|
EX (SP),HL ; swap with line address on stack
|
4753 |
|
|
PUSH HL ; save line address underneath
|
4754 |
|
|
|
4755 |
|
|
LD A,$FF ; select system channel 'R'
|
4756 |
|
|
CALL L1601 ; routine CHAN-OPEN opens it
|
4757 |
|
|
|
4758 |
|
|
POP HL ; drop line address
|
4759 |
|
|
DEC HL ; make it point to first byte of line num.
|
4760 |
|
|
DEC (IY+$0F) ; decrease E_PPC_lo to suppress line cursor.
|
4761 |
|
|
; Note. ineffective when E_PPC is one
|
4762 |
|
|
; greater than last line of program perhaps
|
4763 |
|
|
; as a result of a delete.
|
4764 |
|
|
; credit. Paul Harrison 1982.
|
4765 |
|
|
|
4766 |
|
|
CALL L1855 ; routine OUT-LINE outputs the BASIC line
|
4767 |
|
|
; to the editing area.
|
4768 |
|
|
INC (IY+$0F) ; restore E_PPC_lo to the previous value.
|
4769 |
|
|
LD HL,($5C59) ; address E_LINE in editing area.
|
4770 |
|
|
INC HL ; advance
|
4771 |
|
|
INC HL ; past space
|
4772 |
|
|
INC HL ; and digit characters
|
4773 |
|
|
INC HL ; of line number.
|
4774 |
|
|
|
4775 |
|
|
LD ($5C5B),HL ; update K_CUR to address start of BASIC.
|
4776 |
|
|
POP HL ; restore the address of CURCHL.
|
4777 |
|
|
CALL L1615 ; routine CHAN-FLAG sets flags for it.
|
4778 |
|
|
|
4779 |
|
|
RET ; RETURN to ED-LOOP.
|
4780 |
|
|
|
4781 |
|
|
; -------------------
|
4782 |
|
|
; Cursor down editing
|
4783 |
|
|
; -------------------
|
4784 |
|
|
; The BASIC lines are displayed at the top of the screen and the user
|
4785 |
|
|
; wishes to move the cursor down one line in edit mode.
|
4786 |
|
|
; With INPUT LINE, this key must be used instead of entering STOP.
|
4787 |
|
|
|
4788 |
|
|
;; ED-DOWN
|
4789 |
|
|
L0FF3: BIT 5,(IY+$37) ; test FLAGX - Input Mode ?
|
4790 |
|
|
JR NZ,L1001 ; skip to ED-STOP if so
|
4791 |
|
|
|
4792 |
|
|
LD HL,$5C49 ; address E_PPC - 'current line'
|
4793 |
|
|
CALL L190F ; routine LN-FETCH fetches number of next
|
4794 |
|
|
; line or same if at end of program.
|