Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [rom/] [basicextn.asm] - Blame information for rev 384

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 133 winston
;The MIT License
2
;
3
;Copyright (c) 2008 Dylan Smith
4
;
5
;Permission is hereby granted, free of charge, to any person obtaining a copy
6
;of this software and associated documentation files (the "Software"), to deal
7
;in the Software without restriction, including without limitation the rights
8
;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
;copies of the Software, and to permit persons to whom the Software is
10
;furnished to do so, subject to the following conditions:
11
;
12
;The above copyright notice and this permission notice shall be included in
13
;all copies or substantial portions of the Software.
14
;
15
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
;THE SOFTWARE.
22
 
23
; BASIC extensions.
24
; Checking for extensions is performed here, but the page 0 ROM does
25
; not actually extend BASIC. The routines are provided for other code
26
; to extend BASIC.
27
;
28
; BASIC sets the IY flag to point to the system variables area, this
29
; is used extensively to examine flags and sysvars. The tokens 'D_xxx'
30
; are a displacement for (iy+d) operations.
31 172 winston
;
32
; Credits - Garry Lancaster for pointers on how the ZX error
33
; handler works and some sample code.
34
; Melbourne House for the Complete Shadow ROM disassembly, which was very
35
; instructive in this endeavour.
36 384 winston
.include        "sysvars.inc"
37
.include        "zxrom.inc"
38
.include        "zxsysvars.inc"
39
.include        "spectranet.inc"
40
 
41 133 winston
;---------------------------------------------------------------------------
42
; F_addbasext: Adds a new BASIC command or extension.
43
; Parameters: HL = pointer to info table for new command.
44
; The table is formatted as follows, and is 6 bytes long:
45
;  byte 0   - ZX error code that's relevant to the command
46
;  byte 1,2 - pointer to command string
47
;  byte 3   - ROM page (0 if none)
48
;  byte 4,5 - pointer to routine to call
49
; Carry flag is set if we have run out of space.
50 384 winston
.text
51
.globl F_addbasicext
52
F_addbasicext:
53 133 winston
        ld de, (v_tabletop)     ; get the current table pointer
54
        ld a, 0xFB              ; last byte possible
55
        cp e
56
        ret c                   ; e > a
57
        ld bc, 6                ; 6 bytes
58
        ldir
59
        ld (v_tabletop), de     ; save new table pointer
60 173 winston
        dec de
61
        dec de
62
        dec de                  ; point DE at the page byte
63 200 winston
        ld a, (de)
64 173 winston
        cp 0xFF                 ; if it's 0xFF then we find the ROM page
65
        ccf
66
        ret nz
67
        ld a, (v_pgb)           ; copy the currently paged page
68 200 winston
        ld (de), a
69 173 winston
        and a                   ; reset carry flag
70 133 winston
        ret
71
 
72
;---------------------------------------------------------------------------
73
; The main RST 8 error recovery handler.
74
; This is jumped to when RST 8 is trapped, and looks to see if the ROM
75
; has passed us something of interest.
76
; Note that changing the Spectranet system variable 'v_rst8vector' allows
77
; you to completely replace this routine with something else.
78 384 winston
.globl J_rst8handler
79
J_rst8handler:
80 133 winston
        ld a, (v_tabletop)      ; Check there's something to do
81
        and a                   ; if the LSB of tabletop is 0, nothing to do
82
        jp z, J_rst8done
83
        ex de, hl               ; address of code is in DE
84
        rst CALLBAS
85
        defw ZX_GET_ERR         ; get the error code (which may be in ZX ROM)
86
        cp 0x0B                 ; Nonsense in BASIC?
87 384 winston
        jr z, .handled1
88 255 winston
;       cp 0x07                 ; End of file?
89
;       jp z, J_handleeof
90 244 winston
        jp J_rst8done
91 384 winston
.handled1:
92 133 winston
        ld (ZX_ERR_NR), a       ; Save the error number in ZX sysvars
93
        ld (v_errnr_save), a    ; and ours.
94
        ld hl, (ZX_CH_ADD)      ; save current CH_ADD
95
        ld (v_chaddsave), hl
96
        pop af                  ; discard top value of the stack
97
        bit 5, (iy + D_FLAGX)   ; Input mode?
98
        jp nz, J_romerr
99
        ld a, (v_interpflags)   ; Check our flags
100
        bit 0, a                ; This is set to 1 if we are running our cmds
101
        jp nz, J_romerr         ; so we shouldn't really get here.
102
        or 1                    ; set 'our command' flag
103
        ld (v_interpflags), a
104
        bit 7, (iy + D_FLAGS)   ; Syntax time or runtime?
105 384 winston
        jr nz, .runtime1
106 133 winston
        ld a, 0xFF              ; signal syntax time
107
        ld (ZX_PPC_HI), a
108 384 winston
.runtime1:
109 133 winston
        ld b, (iy + D_SUBPPC)   ; Statement counter
110
        ld c, 0                 ; Quote mark counter
111
        bit 7, (iy + D_PPC_HI)  ; Program area?
112 384 winston
        jr z, .progline1
113 133 winston
        push bc                 ; Save counters
114
        rst CALLBAS
115
        defw ZX_E_LINE_NO       ; Call E_LINE_NO to update CH_ADD to 1st char
116
        pop bc
117
        rst CALLBAS
118
        defw ZX_GET_CHAR        ; HL=first char in line
119 384 winston
        jr .sstat1              ; jump forward to the DJNZ
120 133 winston
        ; the following mess sorts out rewinding CH_ADD and removing
121
        ; floating point values.
122 384 winston
.progline1:
123 133 winston
        ld hl, (ZX_PROG)        ; get address of program
124 384 winston
.sc_l_loop1:
125 133 winston
        ld a, (ZX_PPC_HI)       ; compare with current line
126
        cp (hl)
127 384 winston
        jr nc, .testlow1                ; jump if <= line to be searched for
128
.nreport11:
129 133 winston
        ld hl, STR_badcmd       ; Return with our equiv of nonsense in BASIC
130
        ld a, 1
131
        jp J_reporterr
132 384 winston
.testlow1:
133 133 winston
        inc hl                  ; lsb of line number
134 384 winston
        jr nz, .line_len1       ; jump if current line is not the expected one
135 133 winston
        ld a, (ZX_PPC_LO)       ; Compare the next byte
136
        cp (hl)
137 384 winston
        jr c, .nreport11                ; Error if the line does not exist
138
.line_len1:
139 133 winston
        inc hl                  ; inc the pointer
140
        ld e, (hl)
141
        inc hl
142
        ld d, (hl)              ; fetch length into DE
143
        inc hl                  ; point to the start of the line
144 384 winston
        jr z, .sstat1           ; jump if the line is found
145 133 winston
        add hl, de              ; increment pointer to next line
146 384 winston
        jr .sc_l_loop1          ; continue until found
147
.skip_num1:
148 133 winston
        ld de, 0x06             ; length of a float
149
        add hl, de              ; skip the float
150 384 winston
.each_st1:
151 133 winston
        ld a, (hl)              ; Get a char from the line
152
        cp 0x0E                 ; Number marker?
153 384 winston
        jr z, .skip_num1                ; Skip the number
154 133 winston
        inc hl                  ; point to next char
155
        cp '"'                  ; Quote symbol?
156 384 winston
        jr nz, .chkend1         ; No
157 133 winston
        dec c                   ; decrement " counter
158 384 winston
.chkend1:
159 133 winston
        cp ':'                  ; Colon?
160 384 winston
        jr z, .chkeven1         ; Yes
161 133 winston
        cp 0xCB                 ; THEN token?
162 384 winston
        jr nz, .chkend_l1
163
.chkeven1:
164 133 winston
        bit 0, c                ; Even number of " chars?
165 384 winston
        jr z, .sstat1           ; Jump if the statement is finished
166
.chkend_l1:
167 133 winston
        cp 0x80                 ; Line finished?
168 384 winston
        jr nz, .each_st1                ; No, continue the loop
169
        jr .nreport11           ; Give an error - wrong number of quotes
170
.sstat1:
171
        djnz .each_st1          ; Continue with next stmt
172 133 winston
        dec hl                  ; HL now points to start address of stmt
173
        ld (ZX_CH_ADD), hl      ; store in CH_ADD
174
        bit 7, (iy + D_FLAGS)   ; Checking syntax?
175 384 winston
        jr nz, .cl_work1
176 133 winston
        bit 7, (iy + D_PPC_HI)  ; Give error if line is not in editing area
177
        jp z, J_err_6
178
 
179
        ; Remove all 6 byte FP numbers put in by the ZX ROM interpreter
180
        dec hl                  ; balance inc below
181
        ld c, 0                 ; clear C
182 384 winston
.rcln_num1:
183 133 winston
        inc hl                  ; Point to next char
184
        ld a, (hl)              ; Get char
185
        cp 0x0E                 ; Start of a number?
186 384 winston
        jr nz, .nextnum1                ; no
187 133 winston
        push bc                 ; save BC
188
        rst CALLBAS             ; call RECLAIM-2 in ZX ROM
189
        defw ZX_RECLAIM_2       ; to reclaim the number
190
        push hl                 ; save the pointer to the number
191
        ld de, (v_chaddsave)    ; jp forward if the 6 bytes were
192
        and a                   ; reclaimed after the char pointed to
193
        sbc hl, de              ; in the saved CH_ADD
194 384 winston
        jr nc, .nxt_11
195 133 winston
        ex de, hl               ; otherwise update saved ch_add
196
        ld bc, 6                ; was moved 6 bytes down
197
        and a
198
        sbc hl, bc
199
        ld (v_chaddsave), hl    ; save the new value
200 384 winston
.nxt_11:
201 133 winston
        pop hl                  ; restore pointer and counter
202
        pop bc
203 384 winston
.nextnum1:
204 133 winston
        ld a, (hl)              ; jump back until the line is finished
205
        cp 0x0D
206 384 winston
        jr nz, .rcln_num1
207
.cl_work1:                      ; Clear workspace
208 133 winston
        rst CALLBAS
209
        defw ZX_SET_WORK        ; ZX SET-WORK routine
210
        call F_parser           ; If this returns, command not found.
211 384 winston
.globl J_err_6
212
J_err_6:
213 133 winston
        ld hl, (v_chaddsave)    ; restore initial CH_ADD
214
        ld (ZX_CH_ADD), hl
215
        jp J_romerr             ; Main rom error handler
216
 
217
;---------------------------------------------------------------------------
218
; J_rst8done
219
; Early escape from RST 8 routine when we've identified the error code
220
; isn't something we're interested in. It restores the stack and restarts
221
; the ZX ROM's RST8 routine.
222 384 winston
J_rst8done:
223 133 winston
        ld hl, 0x000B           ; return address, after 'ld hl, (CH_ADD)'
224
        ex (sp), hl             ; put it on the stack, discarding old value
225
        ld hl, (ZX_CH_ADD)      ; 1st instruction in ZX ROM RST8 routine
226 384 winston
        jp PAGEOUT
227 133 winston
 
228
;---------------------------------------------------------------------------
229
; J_zxrom_exit
230
; This exits to the BASIC ROM, resetting our private flags.
231
; First stack entry should contain address where control should be returned.
232 384 winston
J_zxrom_exit:
233 133 winston
        xor a
234
        ld (v_interpflags), a   ; reset our flags
235 384 winston
        jp PAGEOUT
236 133 winston
 
237
;--------------------------------------------------------------------------
238
; F_statement_end / J_exit_success
239
; This performs 'end of statement' actions. If the statment isn't actually
240
; ended it triggers the ROM error routine.
241
; Jumping in at J_exit_success performs the post-command actions.
242 384 winston
.globl F_statement_end
243
F_statement_end:
244 133 winston
        cp 0x0D                 ; ZX char for enter
245 384 winston
        jr z, .synorrun2                ; if so check for syntax or run time
246 133 winston
        cp ':'                  ; The other statement end char is :
247 384 winston
        jr z, .synorrun2                ; If neither, return with 'nonsense' code
248 133 winston
        ld hl, STR_badcmd
249
        ld a, 1
250
        jp J_sherror
251 384 winston
.synorrun2:
252 133 winston
        bit 7, (iy + D_FLAGS)   ; Syntax time or run time?
253
        ret nz                  ; Run time - return and allow exec actions.
254 384 winston
.globl J_exit_success
255
J_exit_success:
256 133 winston
        ei                      ; ensure interrupts are enabled (else we hang)
257
        ld sp, (ZX_ERR_SP)      ; restore the stack
258
        ld (iy + D_ERR_NR), 0xFF ; clear error status
259
        ld hl, ZX_STMT_NEXT     ; return address in BASIC ROM
260
        bit 7, (iy + D_FLAGS)   ; Syntax or run time?
261 384 winston
        jr z, .syntaxtime2      ; Do the syntax time return action
262 133 winston
        ld a, 0x7F              ; Check for BREAK - port 0x7FFE
263
        in a, (0xFE)
264
        rra
265 384 winston
        jr c, .runtime2         ; BREAK is not being pressed
266 133 winston
        ld a, 0xFE              ; port 0xFEFE
267
        in a, (0xFE)
268 384 winston
        jr nc, .break2          ; BREAK was pressed
269
.runtime2:
270 133 winston
        ld hl, ZX_STMT_R_1      ; ROM return address at runtime
271 384 winston
.syntaxtime2:
272 133 winston
        push hl
273
        jp J_zxrom_exit         ; Page out and return to Spectrum ROM
274 384 winston
.break2:
275 133 winston
        ld (iy + D_ERR_NR), 0x14 ; L - BREAK into program and fall out
276
                                ; via J_romerr
277
;---------------------------------------------------------------------------
278
; J_romerr/J_sterror
279
; Exit with an error with the '?' marker set to the right place.
280
; J_romerr also sets bit 3 of TV_FLAGS.
281 384 winston
J_romerr:
282 133 winston
        res 3, (iy + D_TV_FLAG) ; mode unchanged
283 384 winston
J_sterror:
284 133 winston
        ld sp, (ZX_ERR_SP)      ; reset the stack
285
        ld hl, (ZX_CH_ADD)      ; copy character reached
286
        ld (ZX_X_PTR), hl       ; to the place where the ? marker should be
287
        ld hl, ZX_SET_STK       ; return via SET_STK routine in BASIC ROM
288
        push hl
289
        jp J_zxrom_exit
290
 
291
;--------------------------------------------------------------------------
292
; J_sherror
293
; Exits via J_sterror if syntax checking, or falls through into
294
; J_reporterr if not
295 384 winston
J_sherror:
296 133 winston
        bit 7, (iy + D_FLAGS)   ; Syntax or runtime?
297
        jr z, J_sterror
298
;--------------------------------------------------------------------------
299
; J_reporterr
300
; Reports an error message and returns control to the ZX BASIC ROM.
301
; Pass the error number in A, error string in HL.
302 384 winston
.globl J_reporterr
303
J_reporterr:
304 133 winston
        push hl                 ; save pointer to message
305
        ld (ZX_ERR_NR), a       ; save the error number
306
        xor a                   ; clear interpreter flags
307
        ld (v_interpflags), a
308
        res 5, (iy + D_FLAGS)   ; ready for new key
309
        ld h, a
310
        ld l, a
311
        ld (ZX_FLAGX), a        ; clear FLAGX
312
        ld (ZX_X_PTR_HI), a     ; clear X_PTR_HI
313
        ld (ZX_DEFADD), hl      ; clear DEFADD
314
        inc l                   ; hl = 1
315
        ld (0x5C16), hl         ; stream 0 = 0x0001 (K channel)
316
        rst CALLBAS
317
        defw ZX_SET_MIN         ; clear calculator
318
        res 5, (iy + D_FLAGS)   ; editing mode
319
        rst CALLBAS
320
        defw ZX_CLS_LOWER       ; clear lower 2 lines
321
        set 5, (iy + D_TV_FLAG) ; set TV flags accordingly
322
        res 3, (iy + D_TV_FLAG)
323
        pop hl                  ; get error string back
324 384 winston
.reportloop2:                   ; string pointed to by HL is null terminated
325 133 winston
        ld a, (hl)              ; get char
326
        and a                   ; null terminator?
327 384 winston
        jr z, .endreport2
328 133 winston
        push hl
329
        rst CALLBAS
330
        defw ZX_PRINT_A_1       ; Print the character
331
        pop hl
332
        inc hl
333 384 winston
        jr .reportloop2
334
.endreport2:
335 133 winston
        ld sp, (ZX_ERR_SP)      ; reset stack
336
        inc sp                  ; ignore first address
337
        inc sp
338
        ld hl, ZX_ERRMSG_RET    ; return halfway through ZX BASIC errmsg routine
339
        push hl
340
        jp J_zxrom_exit
341
 
342
;---------------------------------------------------------------------------
343
; Generic default error message, morally equivalent to 'Nonsense in BASIC'
344
; but different so it's easy to tell we generated it.
345 384 winston
STR_badcmd:     defb "Bad command",0
346 133 winston
 
347
;===========================================================================
348
; The extra command parser.
349
; This uses a table (normally at 0x3A00) of vectors which point to
350
; the strings defining new commands, the error code that they respond to
351
; (normally Nonsense in BASIC, 0x0B), the ROM page they are in (if any)
352
; and address of the routine that handles the command.
353
 
354
;---------------------------------------------------------------------------
355
; F_parser
356
; A simple command parser.
357 384 winston
.globl F_parser
358
F_parser:
359 133 winston
        ld a, (v_pgb)           ; get current page B
360
        ld (v_origpageb), a     ; and save it
361
        ld hl, TABLE_basext     ; start at the start of the parser's table
362 384 winston
.ploop3:
363 133 winston
        ld a, (hl)              ; get the error code this command responds to
364
        and a                   ; if it's zero, the table has ended
365 384 winston
        jr z, .notfound3
366 133 winston
        inc hl
367
        ld e, (hl)              ; get the address of the command string
368
        inc hl
369
        ld d, (hl)
370
        inc hl
371
        ld a, (hl)              ; which page?
372
        inc hl
373
        and a                   ; Z set if none
374
        call nz, F_setpageB     ; page this page into page area B
375
        ex de, hl               ; put string address in hl
376
        push de                 ; save table pointer
377
        call F_pstrcmp          ; compare it with what's at CH_ADD
378
        pop hl                  ; restore table pointer into hl
379 384 winston
        jr nz, .skip3           ; skip fetching the address if no match
380 133 winston
        ld e, (hl)              ; fetch address
381
        inc hl
382
        ld d, (hl)
383
        inc hl
384
        ex de, hl
385
        pop de                  ; fix the stack by removing return addr
386
        jp (hl)                 ; jump to the address specified.
387 384 winston
.skip3:
388 133 winston
        inc hl
389
        inc hl
390 384 winston
        jr .ploop3
391
.notfound3:
392 133 winston
        ld a, (v_origpageb)     ; restore page B
393
        call F_setpageB
394
        ret
395
 
396
;------------------------------------------------------------------------
397
; F_pstrcmp
398
; HL = pointer to string to compare
399
; Returns with zero flag set if strings match.
400 384 winston
.globl F_pstrcmp
401
F_pstrcmp:
402 133 winston
        ld de, (ZX_CH_ADD)
403
        inc de
404 384 winston
.loop4:
405 133 winston
        ld a, (de)
406
        ; is the character in the string pointed to by HL a
407 384 winston
        ; null, return, colon or space - i.e4. separator character?
408 133 winston
        cp ' '
409 384 winston
        jr z, .match4
410 133 winston
        cp ':'
411 384 winston
        jr z, .match4
412 133 winston
        cp 0x0D
413 384 winston
        jr z, .match4
414 133 winston
        cp (hl)                 ; does it match the target string?
415
        inc hl                  ; yes, so match the next char
416
        inc de
417 384 winston
        jr z, .loop4
418 133 winston
        or 1                    ; make sure zero flag is not set
419
        ret
420 384 winston
.match4:
421 133 winston
        ld (ZX_CH_ADD), de      ; save syntax buffer pointer in CH_ADD
422
        ld b, a                 ; save char
423
        ; string matched so far - check it's actually ended, too.
424
        xor a
425
        cp (hl)                 ; set zero flag if OK
426
        ld a, b                 ; return with char at CH_ADD
427
        ret
428
 
429