OpenCores
URL https://opencores.org/ocsvn/rtf65002/rtf65002/trunk

Subversion Repositories rtf65002

[/] [rtf65002/] [trunk/] [software/] [asm/] [TinyBasic65002.asm] - Blame information for rev 28

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 16 robfinch
;****************************************************************;
2
;                                                                ;
3
;               Tiny BASIC for the Raptor64                              ;
4
;                                                                ;
5
; Derived from a 68000 derivative of Palo Alto Tiny BASIC as     ;
6
; published in the May 1976 issue of Dr. Dobb's Journal.         ;
7
; Adapted to the 68000 by:                                       ;
8
;       Gordon brndly                                                                    ;
9
;       12147 - 51 Street                                                                ;
10
;       Edmonton AB  T5W 3G8                                                         ;
11
;       Canada                                                                               ;
12
;       (updated mailing address for 1996)                                       ;
13
;                                                                ;
14
; Adapted to the RTF65002 by:                                    ;
15
;    Robert Finch                                                ;
16
;    Ontario, Canada                                             ;
17
;        robfinch@opencores.org                              ;
18
;****************************************************************;
19
;    Copyright (C) 2012 by Robert Finch. This program may be     ;
20
;    freely distributed for personal use only. All commercial    ;
21
;                      rights are reserved.                                          ;
22
;****************************************************************;
23
;
24
; Register Usage
25
; r8 = text pointer (global usage)
26
; r3,r4 = inputs parameters to subroutines
27
; r2 = return value
28
;
29
;* Vers. 1.0  1984/7/17 - Original version by Gordon brndly
30
;*      1.1  1984/12/9  - Addition of '0x' print term by Marvin Lipford
31
;*      1.2  1985/4/9   - Bug fix in multiply routine by Rick Murray
32
 
33
;
34
; Standard jump table. You can change these addresses if you are
35
; customizing this interpreter for a different environment.
36
;
37
CR      EQU     0x0D            ;ASCII equates
38
LF      EQU     0x0A
39
TAB     EQU     0x09
40
CTRLC   EQU     0x03
41
CTRLH   EQU     0x08
42
CTRLI   EQU     0x09
43
CTRLJ   EQU     0x0A
44
CTRLK   EQU     0x0B
45
CTRLM   EQU 0x0D
46
CTRLS   EQU     0x13
47
CTRLX   EQU     0x18
48
XON             EQU     0x11
49
XOFF    EQU     0x13
50
 
51 28 robfinch
CursorFlash     EQU             0xFC4
52
IRQFlag         EQU             0xFC6
53 16 robfinch
 
54 28 robfinch
OSSP            EQU             0xF00
55
TXTUNF          EQU             0xF01
56
VARBGN          EQU             0xF02
57
LOPVAR          EQU             0xF03
58
STKGOS          EQU             0xF04
59
CURRNT          EQU             0xF05
60
BUFFER          EQU             0xF06
61 16 robfinch
BUFLEN          EQU             84
62 28 robfinch
LOPPT           EQU             0xF60
63
LOPLN           EQU             0xF61
64
LOPINC          EQU             0xF62
65
LOPLMT          EQU             0xF63
66
NUMWKA          EQU             0xF64
67
STKINP          EQU             0xF74
68
STKBOT          EQU             0xF75
69
usrJmp          EQU             0xF76
70
IRQROUT         EQU             0xF77
71 16 robfinch
 
72
 
73
 
74
                cpu     rtf65002
75
                code
76 28 robfinch
                org             $FFFFEC00
77 16 robfinch
GOSTART:
78
                jmp     CSTART  ;       Cold Start entry point
79
GOWARM:
80
                jmp     WSTART  ;       Warm Start entry point
81
GOOUT:
82
                jmp     OUTC    ;       Jump to character-out routine
83
GOIN:
84
                jmp     INCH    ;Jump to character-in routine
85
GOAUXO:
86
                jmp     AUXOUT  ;       Jump to auxiliary-out routine
87
GOAUXI:
88
                jmp     AUXIN   ;       Jump to auxiliary-in routine
89
GOBYE:
90
                jmp     BYEBYE  ;       Jump to monitor, DOS, etc.
91
;
92
; Modifiable system constants:
93
;
94
                align   4
95 26 robfinch
;THRD_AREA      dw      0x04000000      ; threading switch area 0x04000000-0x40FFFFF
96
;bitmap dw      0x04100000      ; bitmap graphics memory 0x04100000-0x417FFFF
97
TXTBGN  dw      0x04180000      ;TXT            ;beginning of program memory
98
ENDMEM  dw      0x057FFFFF      ;       end of available memory
99
STACKOFFS       dw      0x058FFFFF      ; stack offset - leave a little room for the BIOS stacks
100 16 robfinch
;
101
; The main interpreter starts here:
102
;
103
; Usage
104
; r1 = temp
105
; r8 = text buffer pointer
106
; r12 = end of text in text buffer
107
;
108
        align   4
109 26 robfinch
message "CSTART"
110 16 robfinch
public CSTART:
111
        ; First save off the link register and OS sp value
112
        tsx
113
        stx             OSSP
114
        ldx             STACKOFFS>>2    ; initialize stack pointer
115
        txs
116 26 robfinch
        jsr             RequestIOFocus
117
        jsr             HomeCursor
118
        lda             #0                              ; turn off keyboard echoing
119
        jsr             SetKeyboardEcho
120 16 robfinch
        stz             CursorFlash
121
        ldx             #0x10000020     ; black chars, yellow background
122
;       stx             charToPrint
123
        jsr             ClearScreen
124
        lda             #msgInit        ;       tell who we are
125
        jsr             PRMESG
126
        lda             TXTBGN>>2       ;       init. end-of-program pointer
127
        sta             TXTUNF
128
        lda             ENDMEM>>2       ;       get address of end of memory
129
        sub             #4096   ;       reserve 4K for the stack
130
        sta             STKBOT
131
        sub             #16384 ;   1000 vars
132
        sta     VARBGN
133
        jsr     clearVars   ; clear the variable area
134 18 robfinch
        stz             IRQROUT
135 16 robfinch
        lda     VARBGN   ; calculate number of bytes free
136
        ldy             TXTUNF
137
        sub     r1,r1,r3
138
        ldx             #12             ; max 12 digits
139
        jsr     PRTNUM
140
        lda             #msgBytesFree
141
        jsr             PRMESG
142
WSTART:
143
        stz             LOPVAR   ; initialize internal variables
144
        stz             STKGOS
145
        stz             CURRNT  ;       current line number pointer = 0
146
        ldx             ENDMEM>>2       ;       init S.P. again, just in case
147
        txs
148
        lda             #msgReady       ;       display "Ready"
149
        jsr             PRMESG
150
ST3:
151
        lda             #'>'            ; Prompt with a '>' and
152
        jsr             GETLN           ; read a line.
153
        jsr             TOUPBUF         ; convert to upper case
154
        ld              r12,r8          ; save pointer to end of line
155
        ld              r8,#BUFFER      ; point to the beginning of line
156
        jsr             TSTNUM          ; is there a number there?
157
        jsr             IGNBLK          ; skip trailing blanks
158
; does line no. exist? (or nonzero?)
159
        cpx             #0
160
        beq             DIRECT          ; if not, it's a direct statement
161
        cmp             #$FFFF          ; see if line no. is <= 16 bits
162
        bcc             ST2
163
        beq             ST2
164
        lda             #msgLineRange   ; if not, we've overflowed
165
        jmp             ERROR
166
ST2:
167
    ; ugliness - store a character at potentially an
168
    ; odd address (unaligned).
169
    tax                                 ; r2 = line number
170
        dec             r8
171
    stx         (r8)            ;
172
        jsr             FNDLN           ; find this line in save area
173
        ld              r13,r9          ; save possible line pointer
174
        cmp             #0
175
        beq             ST4                     ; if not found, insert
176
        ; here we found the line, so we're replacing the line
177
        ; in the text area
178
        ; first step - delete the line
179
        lda             #0
180
        jsr             FNDNXT          ; find the next line (into r9)
181
        cmp             #0
182
        bne             ST7
183
        cmp             r9,TXTUNF
184
        beq             ST6                     ; no more lines
185
        bcs             ST6
186
        cmp             r9,r0
187
        beq             ST6
188
ST7:
189
        ld              r1,r9           ; r1 = pointer to next line
190
        ld              r2,r13          ; pointer to line to be deleted
191
        ldy             TXTUNF          ; points to top of save area
192 26 robfinch
        sub             r1,r3,r9        ; r1 = length to move TXTUNF-pointer to next line
193
;       dea                                     ; count is one less
194
        ld              r2,r9           ; r2 = pointer to next line
195
        ld              r3,r13          ; r3 = pointer to line to delete
196
        push    r4
197
ST8:
198
        ld              r4,(x)
199
        st              r4,(y)
200
        inx
201
        iny
202
        dea
203
        bne             ST8
204
        pop             r4
205
;       mvn
206
;       jsr             MVUP            ; move up to delete
207
        sty             TXTUNF          ; update the end pointer
208 16 robfinch
        ; we moved the lines of text after the line being
209
        ; deleted down, so the pointer to the next line
210
        ; needs to be reset
211
        ld              r9,r13
212
        bra             ST4
213
        ; here there were no more lines, so just move the
214
        ; end of text pointer down
215
ST6:
216
        st              r13,TXTUNF
217
        ld              r9,r13
218
ST4:
219
        ; here we're inserting because the line wasn't found
220
        ; or it was deleted     from the text area
221 18 robfinch
        sub             r1,r12,r8               ; calculate the length of new line
222 16 robfinch
        cmp             #2                              ; is it just a line no. & CR? if so, it was just a delete
223
        beq             ST3
224
        bcc             ST3
225
 
226 18 robfinch
        ; compute new end of text
227
        ld              r10,TXTUNF              ; r10 = old TXTUNF
228
        add             r11,r10,r1              ; r11 = new top of TXTUNF (r1=line length)
229 16 robfinch
 
230
        cmp             r11,VARBGN      ; see if there's enough room
231
        bcc             ST5
232
        lda             #msgTooBig      ; if not, say so
233
        jmp             ERROR
234
 
235
        ; open a space in the text area
236
ST5:
237
        st              r11,TXTUNF      ; if so, store new end position
238
        ld              r1,r10          ; points to old end of text
239
        ld              r2,r11          ; points to new end of text
240
        ld              r3,r9       ; points to start of line after insert line
241
        jsr             MVDOWN          ; move things out of the way
242
 
243
        ; copy line into text space
244
        ld              r1,r8           ; set up to do the insertion; move from buffer
245
        ld              r2,r13          ; to vacated space
246
        ld              r3,r12          ; until end of buffer
247
        jsr             MVUP            ; do it
248
        jmp             ST3                     ; go back and get another line
249
 
250
;******************************************************************
251
;
252
; *** Tables *** DIRECT *** EXEC ***
253
;
254
; This section of the code tests a string against a table. When
255
; a match is found, control is transferred to the section of
256
; code according to the table.
257
;
258
; At 'EXEC', r8 should point to the string, r9 should point to
259
; the character table, and r10 should point to the execution
260
; table. At 'DIRECT', r8 should point to the string, r9 and
261
; r10 will be set up to point to TAB1 and TAB1_1, which are
262
; the tables of all direct and statement commands.
263
;
264
; A '.' in the string will terminate the test and the partial
265
; match will be considered as a match, e.g. 'P.', 'PR.','PRI.',
266
; 'PRIN.', or 'PRINT' will all match 'PRINT'.
267
;
268
; There are two tables: the character table and the execution
269
; table. The character table consists of any number of text items.
270
; Each item is a string of characters with the last character's
271
; high bit set to one. The execution table holds a 32-bit
272
; execution addresses that correspond to each entry in the
273
; character table.
274
;
275
; The end of the character table is a 0 byte which corresponds
276
; to the default routine in the execution table, which is
277
; executed if none of the other table items are matched.
278
;
279
; Character-matching tables:
280 26 robfinch
message "TAB1"
281 16 robfinch
TAB1:
282
        db      "LIS",'T'+0x80        ; Direct commands
283
        db      "LOA",'D'+0x80
284
        db      "NE",'W'+0x80
285
        db      "RU",'N'+0x80
286
        db      "SAV",'E'+0x80
287
TAB2:
288
        db      "NEX",'T'+0x80         ; Direct / statement
289
        db      "LE",'T'+0x80
290
        db      "I",'F'+0x80
291
        db      "GOT",'O'+0x80
292
        db      "GOSU",'B'+0x80
293
        db      "RETUR",'N'+0x80
294
        db      "RE",'M'+0x80
295
        db      "FO",'R'+0x80
296
        db      "INPU",'T'+0x80
297
        db      "PRIN",'T'+0x80
298
        db      "POK",'E'+0x80
299
        db      "STO",'P'+0x80
300
        db      "BY",'E'+0x80
301
        db      "SY",'S'+0x80
302
        db      "CL",'S'+0x80
303
    db  "CL",'R'+0x80
304
    db  "RDC",'F'+0x80
305 18 robfinch
    db  "ONIR",'Q'+0x80
306
    db  "WAI",'T'+0x80
307 16 robfinch
        db      0
308
TAB4:
309
        db      "PEE",'K'+0x80         ;Functions
310
        db      "RN",'D'+0x80
311
        db      "AB",'S'+0x80
312 18 robfinch
        db  "SG",'N'+0x80
313 16 robfinch
        db      "TIC",'K'+0x80
314
        db      "SIZ",'E'+0x80
315
        db  "US",'R'+0x80
316
        db      0
317
TAB5:
318
        db      "T",'O'+0x80           ;"TO" in "FOR"
319
        db      0
320
TAB6:
321
        db      "STE",'P'+0x80         ;"STEP" in "FOR"
322
        db      0
323
TAB8:
324
        db      '>','='+0x80           ;Relational operators
325
        db      '<','>'+0x80
326
        db      '>'+0x80
327
        db      '='+0x80
328
        db      '<','='+0x80
329
        db      '<'+0x80
330
        db      0
331
TAB9:
332
    db  "AN",'D'+0x80
333
    db  0
334
TAB10:
335
    db  "O",'R'+0x80
336
    db  0
337
 
338
;* Execution address tables:
339
; We save some bytes by specifiying only the low order 16 bits of the address
340
;
341
TAB1_1:
342
        dh      LISTX                   ;Direct commands
343 28 robfinch
        dh      LOAD3
344 16 robfinch
        dh      NEW
345
        dh      RUN
346 28 robfinch
        dh      SAVE3
347 16 robfinch
TAB2_1:
348
        dh      NEXT            ;       Direct / statement
349
        dh      LET
350
        dh      IF
351
        dh      GOTO
352
        dh      GOSUB
353
        dh      RETURN
354
        dh      IF2                     ; REM
355
        dh      FOR
356
        dh      INPUT
357
        dh      PRINT
358
        dh      POKE
359
        dh      STOP
360
        dh      GOBYE
361
        dh      SYSX
362
        dh      _cls
363
        dh  _clr
364
        dh      _rdcf
365 18 robfinch
        dh  ONIRQ
366
        dh      WAITIRQ
367 16 robfinch
        dh      DEFLT
368
TAB4_1:
369
        dh      PEEK                    ;Functions
370
        dh      RND
371
        dh      ABS
372 18 robfinch
        dh  SGN
373 16 robfinch
        dh      TICKX
374
        dh      SIZEX
375
        dh  USRX
376
        dh      XP40
377
TAB5_1
378
        dh      FR1                     ;"TO" in "FOR"
379
        dh      QWHAT
380
TAB6_1
381
        dh      FR2                     ;"STEP" in "FOR"
382
        dh      FR3
383
TAB8_1
384
        dh      XP11    ;>=             Relational operators
385
        dh      XP12    ;<>
386
        dh      XP13    ;>
387
        dh      XP15    ;=
388
        dh      XP14    ;<=
389
        dh      XP16    ;<
390
        dh      XP17
391
TAB9_1
392
    dh  XP_AND
393
    dh  XP_ANDX
394
TAB10_1
395
    dh  XP_OR
396
    dh  XP_ORX
397
 
398
;*
399
; r3 = match flag (trashed)
400
; r9 = text table
401
; r10 = exec table
402
; r11 = trashed
403 26 robfinch
message "DIRECT"
404 16 robfinch
DIRECT:
405
        ld              r9,#TAB1
406
        ld              r10,#TAB1_1
407
EXEC:
408
        jsr             IGNBLK          ; ignore leading blanks
409 18 robfinch
        ld              r11,r8          ; save the pointer
410 16 robfinch
        eor             r3,r3,r3        ; clear match flag
411
EXLP:
412
        lda             (r8)            ; get the program character
413
        inc             r8
414
        lb              r2,$0,r9        ; get the table character
415
        bne             EXNGO           ; If end of table,
416 18 robfinch
        ld              r8,r11          ;       restore the text pointer and...
417 16 robfinch
        bra             EXGO            ;   execute the default.
418
EXNGO:
419
        cmp             r1,r3           ; Else check for period... if so, execute
420
        beq             EXGO
421
        and             r2,r2,#0x7f     ; ignore the table's high bit
422
        cmp             r2,r1           ;               is there a match?
423
        beq             EXMAT
424
        inc             r10                     ;if not, try the next entry
425
        inc             r10
426 18 robfinch
        ld              r8,r11          ; reset the program pointer
427 16 robfinch
        eor             r3,r3,r3        ; sorry, no match
428
EX1:
429
        lb              r1,0,r9         ; get to the end of the entry
430
        inc             r9
431
        bit             #$80            ; test for bit 7 set
432
        beq             EX1
433
        bra             EXLP            ; back for more matching
434
EXMAT:
435
        ldy             #'.'            ; we've got a match so far
436
        lb              r1,0,r9         ; end of table entry?
437
        inc             r9
438
        bit             #$80            ; test for bit 7 set
439
        beq             EXLP            ; if not, go back for more
440
EXGO:
441
        ; execute the appropriate routine
442 18 robfinch
        lb              r1,1,r10        ; get the low mid order byte
443 26 robfinch
        asl             r1,r1,#8
444 18 robfinch
        orb             r1,r1,0,r10     ; get the low order byte
445
        or              r1,r1,#$FFFF0000        ; add in ROM base
446
        jmp             (r1)
447 16 robfinch
 
448
 
449
;******************************************************************
450
;
451
; What follows is the code to execute direct and statement
452
; commands. Control is transferred to these points via the command
453
; table lookup code of 'DIRECT' and 'EXEC' in the last section.
454
; After the command is executed, control is transferred to other
455
; sections as follows:
456
;
457
; For 'LISTX', 'NEW', and 'STOP': go back to the warm start point.
458
; For 'RUN': go execute the first stored line if any; else go
459
; back to the warm start point.
460
; For 'GOTO' and 'GOSUB': go execute the target line.
461
; For 'RETURN' and 'NEXT'; go back to saved return line.
462
; For all others: if 'CURRNT' is 0, go to warm start; else go
463
; execute next command. (This is done in 'FINISH'.)
464
;
465
;******************************************************************
466
;
467
; *** NEW *** STOP *** RUN (& friends) *** GOTO ***
468
;
469
; 'NEW' sets TXTUNF to point to TXTBGN
470
;
471
 
472
NEW:
473
        jsr             ENDCHK
474
        lda             TXTBGN>>2
475
        sta             TXTUNF  ;       set the end pointer
476
        jsr     clearVars
477
 
478
; 'STOP' goes back to WSTART
479
;
480
STOP:
481
        jsr             ENDCHK
482
        jmp             WSTART          ; WSTART will reset the stack
483
 
484
; 'RUN' finds the first stored line, stores its address
485
; in CURRNT, and starts executing it. Note that only those
486
; commands in TAB2 are legal for a stored program.
487
;
488
; There are 3 more entries in 'RUN':
489
; 'RUNNXL' finds next line, stores it's address and executes it.
490
; 'RUNTSL' stores the address of this line and executes it.
491
; 'RUNSML' continues the execution on same line.
492
;
493
RUN:
494
        jsr             ENDCHK
495
        ld              r8,TXTBGN>>2    ;       set pointer to beginning
496
        st              r8,CURRNT
497
        jsr     clearVars
498
 
499
RUNNXL                                  ; RUN 
500
        lda             CURRNT  ; executing a program?
501
        beq             WSTART  ; if not, we've finished a direct stat.
502 18 robfinch
        lda             IRQROUT         ; are we handling IRQ's ?
503
        beq             RUN1
504
        ld              r0,IRQFlag              ; was there an IRQ ?
505
        beq             RUN1
506
        stz             IRQFlag
507
        jsr             PUSHA           ; the same code as a GOSUB
508
        push    r8
509
        lda             CURRNT
510
        pha                                     ; found it, save old 'CURRNT'...
511
        lda             STKGOS
512
        pha                                     ; and 'STKGOS'
513
        stz             LOPVAR          ; load new values
514
        tsx
515
        stx             STKGOS
516
        ld              r9,IRQROUT
517
        bra             RUNTSL
518
RUN1
519 16 robfinch
        lda             #0          ; else find the next line number
520
        ld              r9,r8
521
        jsr             FNDLNP          ; search for the next line
522 18 robfinch
;       cmp             #0
523
;       bne             RUNTSL
524 16 robfinch
        cmp             r9,TXTUNF; if we've fallen off the end, stop
525
        beq             WSTART
526
        bcs             WSTART
527
 
528
RUNTSL                                  ; RUN 
529
        st              r9,CURRNT       ; set CURRNT to point to the line no.
530
        add             r8,r9,#1        ; set the text pointer to
531
 
532
RUNSML                 ; RUN 
533
        jsr             CHKIO           ; see if a control-C was pressed
534
        ld              r9,#TAB2                ; find command in TAB2
535
        ld              r10,#TAB2_1
536
        jmp             EXEC            ; and execute it
537
 
538
 
539
; 'GOTO expr' evaluates the expression, finds the target
540
; line, and jumps to 'RUNTSL' to do it.
541
;
542
GOTO
543
        jsr             OREXPR          ;evaluate the following expression
544 18 robfinch
        jsr             DisplayWord
545 16 robfinch
        ld      r5,r1
546
        jsr     ENDCHK          ;must find end of line
547
        ld      r1,r5
548
        jsr     FNDLN           ; find the target line
549
        cmp             #0
550
        bne             RUNTSL          ; go do it
551
        lda             #msgBadGotoGosub
552
        jmp             ERROR           ; no such line no.
553
 
554
_clr:
555
    jsr     clearVars
556
    jmp     FINISH
557
 
558
; Clear the variable area of memory
559
clearVars:
560
        push    r6
561
    ld      r6,#2048    ; number of words to clear
562
    lda     VARBGN
563
cv1:
564
    stz     (r1)
565
    ina
566
    dec         r6
567
    bne         cv1
568
    pop         r6
569
    rts
570
 
571 18 robfinch
;******************************************************************
572
; ONIRQ 
573
; ONIRQ sets up an interrupt handler which acts like a specialized
574
; subroutine call. ONIRQ is coded like a GOTO that never executes.
575
;******************************************************************
576
;
577
ONIRQ:
578
        jsr             OREXPR          ;evaluate the following expression
579
        ld      r5,r1
580
        jsr     ENDCHK          ;must find end of line
581
        ld      r1,r5
582
        jsr     FNDLN           ; find the target line
583
        cmp             #0
584
        bne             ONIRQ1
585
        stz             IRQROUT
586
        jmp             FINISH
587
ONIRQ1:
588
        st              r9,IRQROUT
589
        jmp             FINISH
590 16 robfinch
 
591 18 robfinch
 
592
WAITIRQ:
593
        jsr             CHKIO           ; see if a control-C was pressed
594
        ld              r0,IRQFlag
595
        beq             WAITIRQ
596
        jmp             FINISH
597
 
598
 
599 16 robfinch
;******************************************************************
600
; LIST
601
;
602
; LISTX has two forms:
603
; 'LIST' lists all saved lines
604
; 'LIST #' starts listing at the line #
605
; Control-S pauses the listing, control-C stops it.
606
;******************************************************************
607
;
608
LISTX:
609
        jsr             TSTNUM          ; see if there's a line no.
610
        ld      r5,r1
611
        jsr             ENDCHK          ; if not, we get a zero
612
        ld      r1,r5
613
        jsr             FNDLN           ; find this or next line
614
LS1:
615
        cmp             #0
616
        bne             LS4
617
        cmp             r9,TXTUNF
618
        beq             WSTART
619
        bcs             WSTART          ; warm start if we passed the end
620
LS4:
621
        ld              r1,r9
622
        jsr             PRTLN           ; print the line
623
        ld              r9,r1           ; set pointer for next
624
        jsr             CHKIO           ; check for listing halt request
625
        cmp             #0
626
        beq             LS3
627
        cmp             #CTRLS          ; pause the listing?
628
        bne             LS3
629
LS2:
630
        jsr     CHKIO           ; if so, wait for another keypress
631
        cmp             #0
632
        beq             LS2
633
LS3:
634
        lda             #0
635
        jsr             FNDLNP          ; find the next line
636
        bra             LS1
637
 
638
 
639
;******************************************************************
640
; PRINT command is 'PRINT ....:' or 'PRINT ....'
641
; where '....' is a list of expressions, formats, back-arrows,
642
; and strings.  These items a separated by commas.
643
;
644
; A format is a pound sign followed by a number.  It controls
645
; the number of spaces the value of an expression is going to
646
; be printed in.  It stays effective for the rest of the print
647
; command unless changed by another format.  If no format is
648
; specified, 11 positions will be used.
649
;
650
; A string is quoted in a pair of single- or double-quotes.
651
;
652
; An underline (back-arrow) means generate a  without a 
653
;
654
; A  is generated after the entire list has been printed
655
; or if the list is empty.  If the list ends with a semicolon,
656
; however, no  is generated.
657
;******************************************************************
658
;
659
PRINT:
660
        ld              r5,#11          ; D4 = number of print spaces
661
        ldy             #':'
662
        ld              r4,#PR2
663
        jsr             TSTC            ; if null list and ":"
664
        jsr             CRLF            ; give CR-LF and continue
665
        jmp             RUNSML          ;               execution on the same line
666
PR2:
667
        ldy             #CR
668
        ld              r4,#PR0
669
        jsr             TSTC            ;if null list and 
670
        jsr             CRLF            ;also give CR-LF and
671
        jmp             RUNNXL          ;execute the next line
672
PR0:
673
        ldy             #'#'
674
        ld              r4,#PR1
675
        jsr             TSTC            ;else is it a format?
676
        jsr             OREXPR          ; yes, evaluate expression
677 18 robfinch
        ld              r5,r1   ; and save it as print width
678 16 robfinch
        bra             PR3             ; look for more to print
679
PR1:
680
        ldy             #'$'
681
        ld              r4,#PR4
682
        jsr             TSTC    ;       is character expression? (MRL)
683
        jsr             OREXPR  ;       yep. Evaluate expression (MRL)
684
        jsr             GOOUT   ;       print low byte (MRL)
685
        bra             PR3             ;look for more. (MRL)
686
PR4:
687
        jsr             QTSTG   ;       is it a string?
688
        ; the following branch must occupy only two bytes!
689
        bra             PR8             ;       if not, must be an expression
690
PR3:
691
        ldy             #','
692
        ld              r4,#PR6
693
        jsr             TSTC    ;       if ",", go find next
694
        jsr             FIN             ;in the list.
695
        bra             PR0
696
PR6:
697
        jsr             CRLF            ;list ends here
698
        jmp             FINISH
699
PR8:
700
        jsr             OREXPR          ; evaluate the expression
701
        ld              r2,r5           ; set the width
702
        jsr             PRTNUM          ; print its value
703
        bra             PR3                     ; more to print?
704
 
705
FINISH:
706
        jsr             FIN             ; Check end of command
707
        jmp             QWHAT   ; print "What?" if wrong
708
 
709
 
710
;*******************************************************************
711
;
712
; *** GOSUB *** & RETURN ***
713
;
714
; 'GOSUB expr:' or 'GOSUB expr' is like the 'GOTO' command,
715
; except that the current text pointer, stack pointer, etc. are
716
; saved so that execution can be continued after the subroutine
717
; 'RETURN's.  In order that 'GOSUB' can be nested (and even
718
; recursive), the save area must be stacked.  The stack pointer
719
; is saved in 'STKGOS'.  The old 'STKGOS' is saved on the stack.
720
; If we are in the main routine, 'STKGOS' is zero (this was done
721
; in the initialization section of the interpreter), but we still
722
; save it as a flag for no further 'RETURN's.
723
;******************************************************************
724
;
725
GOSUB:
726
        jsr             PUSHA           ; save the current 'FOR' parameters
727
        jsr             OREXPR          ; get line number
728
        jsr             FNDLN           ; find the target line
729
        cmp             #0
730
        bne             gosub1
731
        lda             #msgBadGotoGosub
732
        jmp             ERROR           ; if not there, say "How?"
733
gosub1:
734
        push    r8
735
        lda             CURRNT
736
        pha                                     ; found it, save old 'CURRNT'...
737
        lda             STKGOS
738
        pha                                     ; and 'STKGOS'
739
        stz             LOPVAR          ; load new values
740
        tsx
741
        stx             STKGOS
742
        jmp             RUNTSL
743
 
744
 
745
;******************************************************************
746
; 'RETURN' undoes everything that 'GOSUB' did, and thus
747
; returns the execution to the command after the most recent
748
; 'GOSUB'.  If 'STKGOS' is zero, it indicates that we never had
749
; a 'GOSUB' and is thus an error.
750
;******************************************************************
751
;
752
RETURN:
753
        jsr             ENDCHK          ; there should be just a 
754
        ldx             STKGOS          ; get old stack pointer
755
        bne             return1
756
        lda             #msgRetWoGosub
757
        jmp             ERROR           ; if zero, it doesn't exist
758
return1:
759
        txs                                     ; else restore it
760
        pla
761
        sta             STKGOS          ; and the old 'STKGOS'
762
        pla
763
        sta             CURRNT          ; and the old 'CURRNT'
764
        pop             r8                      ; and the old text pointer
765
        jsr             POPA            ;and the old 'FOR' parameters
766
        jmp             FINISH          ;and we are back home
767
 
768
;******************************************************************
769
; *** FOR *** & NEXT ***
770
;
771
; 'FOR' has two forms:
772
; 'FOR var=exp1 TO exp2 STEP exp1' and 'FOR var=exp1 TO exp2'
773
; The second form means the same thing as the first form with a
774
; STEP of positive 1.  The interpreter will find the variable 'var'
775
; and set its value to the current value of 'exp1'.  It also
776
; evaluates 'exp2' and 'exp1' and saves all these together with
777
; the text pointer, etc. in the 'FOR' save area, which consists of
778
; 'LOPVAR', 'LOPINC', 'LOPLMT', 'LOPLN', and 'LOPPT'.  If there is
779
; already something in the save area (indicated by a non-zero
780
; 'LOPVAR'), then the old save area is saved on the stack before
781
; the new values are stored.  The interpreter will then dig in the
782
; stack and find out if this same variable was used in another
783
; currently active 'FOR' loop.  If that is the case, then the old
784
; 'FOR' loop is deactivated. (i.e. purged from the stack)
785
;******************************************************************
786
;
787
FOR:
788
        jsr             PUSHA           ; save the old 'FOR' save area
789
        jsr             SETVAL          ; set the control variable
790
        sta             LOPVAR          ; save its address
791
        ld              r9,#TAB5
792
        ld              r10,#TAB5_1     ; use 'EXEC' to test for 'TO'
793
        jmp             EXEC
794
FR1:
795
        jsr             OREXPR          ; evaluate the limit
796
        sta             LOPLMT  ; save that
797
        ld              r9,#TAB6
798
        ld              r10,#TAB6_1     ; use 'EXEC' to test for the word 'STEP
799
        jmp             EXEC
800
FR2:
801
        jsr             OREXPR          ; found it, get the step value
802
        bra             FR4
803
FR3:
804
        lda             #1              ; not found, step defaults to 1
805
FR4:
806
        sta             LOPINC  ; save that too
807
FR5:
808
        ldx             CURRNT
809
        stx             LOPLN   ; save address of current line number
810
        st              r8,LOPPT        ; and text pointer
811
        tsx
812
        txy                                     ; dig into the stack to find 'LOPVAR'
813
        ld              r6,LOPVAR
814
        bra             FR7
815
FR6:
816
        add             r3,r3,#5        ; look at next stack frame
817
FR7:
818
        ldx             (y)                     ; is it zero?
819
        beq             FR8                     ; if so, we're done
820
        cmp             r2,r6
821
        bne             FR6                     ; same as current LOPVAR? nope, look some more
822
 
823
    tya                       ; Else remove 5 long words from...
824
        add             r2,r3,#5   ; inside the stack.
825
        tsx
826
        txy
827
        jsr             MVDOWN
828
        pla                                     ; set the SP 5 long words up
829
        pla
830
        pla
831
        pla
832
        pla
833
FR8:
834
    jmp     FINISH              ; and continue execution
835
 
836
 
837
;******************************************************************
838
; 'NEXT var' serves as the logical (not necessarily physical) end
839
; of the 'FOR' loop.  The control variable 'var' is checked with
840
; the 'LOPVAR'.  If they are not the same, the interpreter digs in
841
; the stack to find the right one and purges all those that didn't
842
; match.  Either way, it then adds the 'STEP' to that variable and
843
; checks the result with against the limit value.  If it is within
844
; the limit, control loops back to the command following the
845
; 'FOR'.  If it's outside the limit, the save area is purged and
846
; execution continues.
847
;******************************************************************
848
;
849
NEXT:
850
        lda             #0              ; don't allocate it
851
        jsr             TSTV            ; get address of variable
852
        cmp             #0
853
        bne             NX4
854
        lda             #msgNextVar
855
        bra             ERROR           ; if no variable, say "What?"
856
NX4:
857
        ld              r9,r1   ; save variable's address
858
NX0:
859
        lda             LOPVAR  ; If 'LOPVAR' is zero, we never...
860
        bne             NX5             ; had a FOR loop
861
        lda             #msgNextFor
862
        bra             ERROR
863
NX5:
864
        cmp             r1,r9
865
        beq             NX2             ; else we check them OK, they agree
866
        jsr             POPA            ; nope, let's see the next frame
867
        bra             NX0
868
NX2:
869
        lda             (r9)            ; get control variable's value
870
        ldx             LOPINC
871
        add             r1,r1,r2        ; add in loop increment
872
;       BVS.L   QHOW            say "How?" for 32-bit overflow
873
        sta             (r9)            ; save control variable's new value
874
        ldy             LOPLMT          ; get loop's limit value
875
        cmp             r2,#1
876
        beq             NX1
877
        bpl             NX1                     ; check loop increment, branch if loop increment is positive
878
        cmp             r1,r3
879
        beq             NX3
880
        bmi             NXPurge         ; test against limit
881
        bra     NX3
882
NX1:
883
        cmp             r1,r3
884
        beq             NX3
885
        bpl             NXPurge
886
NX3:
887
        ld              r8,LOPLN        ; Within limit, go back to the...
888
        st              r8,CURRNT
889
        ld              r8,LOPPT        ; saved 'CURRNT' and text pointer.
890
        jmp             FINISH
891
NXPurge:
892
    jsr    POPA        ; purge this loop
893
    jmp     FINISH
894
 
895
 
896
;******************************************************************
897
; *** REM *** IF *** INPUT *** LET (& DEFLT) ***
898
;
899
; 'REM' can be followed by anything and is ignored by the
900
; interpreter.
901
;
902
;REM
903
;    br     IF2             ; skip the rest of the line
904
; 'IF' is followed by an expression, as a condition and one or
905
; more commands (including other 'IF's) separated by colons.
906
; Note that the word 'THEN' is not used.  The interpreter evaluates
907
; the expression.  If it is non-zero, execution continues.  If it
908
; is zero, the commands that follow are ignored and execution
909
; continues on the next line.
910
;******************************************************************
911
;
912
IF:
913
    jsr         OREXPR          ; evaluate the expression
914
IF1:
915
        cmp             #0
916
    bne     RUNSML              ; is it zero? if not, continue
917
IF2:
918 18 robfinch
    ld          r9,r8   ; set lookup pointer
919 16 robfinch
        lda             #0              ; find line #0 (impossible)
920
        jsr             FNDSKP          ; if so, skip the rest of the line
921
        cmp             #0
922
        bcs             WSTART  ; if no next line, do a warm start
923
IF3:
924
        jmp             RUNTSL          ; run the next line
925
 
926
 
927
;******************************************************************
928
; INPUT is called first and establishes a stack frame
929
INPERR:
930
        ldx             STKINP          ; restore the old stack pointer
931
        txs
932
        pla
933
        sta             CURRNT          ; and old 'CURRNT'
934
        pop             r8                      ; and old text pointer
935
        tsx
936
        add             r2,r2,#5        ; fall through will subtract 5
937
        txs
938
 
939
; 'INPUT' is like the 'PRINT' command, and is followed by a list
940
; of items.  If the item is a string in single or double quotes,
941
; or is an underline (back arrow), it has the same effect as in
942
; 'PRINT'.  If an item is a variable, this variable name is
943
; printed out followed by a colon, then the interpreter waits for
944
; an expression to be typed in.  The variable is then set to the
945
; value of this expression.  If the variable is preceeded by a
946
; string (again in single or double quotes), the string will be
947
; displayed followed by a colon.  The interpreter the waits for an
948
; expression to be entered and sets the variable equal to the
949
; expression's value.  If the input expression is invalid, the
950
; interpreter will print "What?", "How?", or "Sorry" and reprint
951
; the prompt and redo the input.  The execution will not terminate
952
; unless you press control-C.  This is handled in 'INPERR'.
953
;
954
INPUT:
955
        push    r7
956
        tsr             sp,r7
957
        sub             r7,r7,#5        ; allocate five words on stack
958
        trs             r7,sp
959
        st              r5,4,r7         ; save off r5 into stack var
960
IP6:
961
        st              r8,(r7)         ; save in case of error
962
        jsr             QTSTG           ; is next item a string?
963
        bra             IP2                     ; nope - this branch must take only two bytes
964
        lda             #1              ; allocate var
965
        jsr             TSTV            ; yes, but is it followed by a variable?
966
        cmp             #0
967
        beq     IP4   ; if not, brnch
968
        or              r10,r1,r0               ; put away the variable's address
969
        bra             IP3                     ; if so, input to variable
970
IP2:
971
        st              r8,1,r7         ; save off in stack var for 'PRTSTG'
972
        lda             #1
973
        jsr             TSTV            ; must be a variable now
974
        cmp             #0
975
        bne             IP7
976
        lda             #msgInputVar
977
        add             r7,r7,#5        ; cleanup stack
978
        trs             r7,sp
979
        pop             r7                      ; so we can get back r7
980
        bra             ERROR           ; "What?" it isn't?
981
IP7:
982
        or              r10,r1,r0       ; put away the variable's address
983
        ld              r5,(r8)         ; get ready for 'PRTSTG' by null terminating
984
        stz             (r8)
985
        lda             1,r7                    ; get back text pointer
986
        jsr             PRTSTG          ; print string as prompt
987
        st              r5,(r8)         ; un-null terminate
988
IP3
989
        st              r8,1,r7         ; save in case of error
990
        lda             CURRNT
991
        sta             2,r7                    ; also save 'CURRNT'
992
        lda             #-1
993
        sta             CURRNT          ; flag that we are in INPUT
994
        stx             STKINP          ; save the stack pointer too
995
        st              r10,3,r7        ; save the variable address
996
        lda             #':'            ; print a colon first
997
        jsr             GETLN           ; then get an input line
998
        ld              r8,#BUFFER      ; point to the buffer
999
        jsr             OREXPR          ; evaluate the input
1000
        ld              r10,3,r7        ; restore the variable address
1001
        sta             (r10)           ; save value in variable
1002
        lda             2,r7            ; restore old 'CURRNT'
1003
        sta             CURRNT
1004
        ld              r8,1,r7         ; and the old text pointer
1005
IP4:
1006
        ldy             #','
1007
        ld              r4,#IP5         ; is the next thing a comma?
1008
        jsr             TSTC
1009
        bra             IP6                     ; yes, more items
1010
IP5:
1011
        ld              r5,4,r7
1012
        add             r7,r7,#5        ; cleanup stack
1013
        trs             r7,sp
1014
        pop             r7
1015
        jmp             FINISH
1016
 
1017
 
1018
DEFLT:
1019
    lda     (r8)
1020
    cmp         #CR
1021
        beq         FINISH          ; empty line is OK else it is 'LET'
1022
 
1023
 
1024
;******************************************************************
1025
; 'LET' is followed by a list of items separated by commas.
1026
; Each item consists of a variable, an equals sign, and an
1027
; expression.  The interpreter evaluates the expression and sets
1028
; the variable to that value.  The interpreter will also handle
1029
; 'LET' commands without the word 'LET'.  This is done by 'DEFLT'.
1030
;******************************************************************
1031
;
1032
LET:
1033
    jsr         SETVAL          ; do the assignment
1034
    ldy         #','
1035
    ld          r4,#FINISH
1036
        jsr             TSTC            ; check for more 'LET' items
1037
        bra         LET
1038
LT1:
1039
    jmp     FINISH              ; until we are finished.
1040
 
1041
 
1042
;******************************************************************
1043
; *** LOAD *** & SAVE ***
1044
;
1045
; These two commands transfer a program to/from an auxiliary
1046
; device such as a cassette, another computer, etc.  The program
1047
; is converted to an easily-stored format: each line starts with
1048
; a colon, the line no. as 4 hex digits, and the rest of the line.
1049
; At the end, a line starting with an '@' sign is sent.  This
1050
; format can be read back with a minimum of processing time by
1051
; the RTF65002
1052
;******************************************************************
1053
;
1054
LOAD
1055
        ld              r8,TXTBGN>>2    ; set pointer to start of prog. area
1056
        lda             #CR                     ; For a CP/M host, tell it we're ready...
1057
        jsr             GOAUXO          ; by sending a CR to finish PIP command.
1058
LOD1:
1059
        jsr             GOAUXI          ; look for start of line
1060
        cmp             #0
1061
        beq             LOD1
1062
        bcc             LOD1
1063
        cmp             #'@'            ; end of program?
1064
        beq             LODEND
1065
        cmp             #$1A
1066
        beq     LODEND  ; or EOF marker
1067
        cmp             #':'
1068
        bne             LOD1    ; if not, is it start of line? if not, wait for it
1069
        jsr             GCHAR           ; get line number
1070
        sta             (r8)            ; store it
1071 18 robfinch
        inc             r8
1072 16 robfinch
LOD2:
1073
        jsr             GOAUXI          ; get another text char.
1074
        cmp             #0
1075
        beq             LOD2
1076
        bcc             LOD2
1077
        sta             (r8)
1078 18 robfinch
        inc             r8                      ; store it
1079 16 robfinch
        cmp             #CR
1080
        bne             LOD2            ; is it the end of the line? if not, go back for more
1081
        bra             LOD1            ; if so, start a new line
1082
LODEND:
1083
        st              r8,TXTUNF       ; set end-of program pointer
1084
        jmp             WSTART          ; back to direct mode
1085
 
1086
 
1087
; get character from input (16 bit value)
1088
GCHAR:
1089
        push    r5
1090
        push    r6
1091
        ld              r6,#3       ; repeat four times
1092
        ld              r5,#0
1093
GCHAR1:
1094
        jsr             GOAUXI          ; get a char
1095
        cmp             #0
1096
        beq             GCHAR1
1097
        bcc             GCHAR1
1098
        jsr             asciiToHex
1099
        asl             r5,r5
1100
        asl             r5,r5
1101
        asl             r5,r5
1102
        asl             r5,r5
1103
        or              r5,r5,r1
1104 18 robfinch
        dec             r6
1105 16 robfinch
        bne             GCHAR1
1106 18 robfinch
        ld              r1,r5
1107 16 robfinch
        pop             r6
1108
        pop             r5
1109
        rts
1110
 
1111
 
1112
; convert an ascii char to hex code
1113
; input
1114
;       r1 = char to convert
1115
 
1116
asciiToHex:
1117
        cmp             #'9'            ; less than '9'
1118
        beq             a2h1
1119
        bcc             a2h1
1120
        sub             #7                      ; shift 'A' to '9'+1
1121
a2h1:
1122
        sub             #'0'
1123
        and             #15                     ; make sure a nybble
1124
        rts
1125
 
1126 28 robfinch
LOAD3:
1127
        jsr             spi_init
1128
        cmp             #0
1129
        bne             WSTART
1130
        lda             #5000
1131
        ldx             #$E00
1132
        jsr             spi_read_sector
1133
        lda             #5001
1134
        ldx             TXTBGN>>2
1135
        asl             r2,r2,#2
1136
LOAD4:
1137
        pha
1138
        jsr             spi_read_sector
1139
        add             r2,r2,#512
1140
        pla
1141
        ina
1142
        ld              r4,TXTBGN>>2
1143
        asl             r4,r4,#2
1144
        add             r4,r4,#65536
1145
        cmp             r2,r4
1146
        bmi             LOAD4
1147
        bra             WSTART
1148 16 robfinch
 
1149 28 robfinch
SAVE3:
1150
        jsr             spi_init
1151
        cmp             #0
1152
        bne             WSTART
1153
        lda             #5000           ; starting sector
1154
        ldx             #$E00           ; starting address to write
1155
        jsr             spi_write_sector
1156
        lda             #5001
1157
        ldx             TXTBGN>>2
1158
        asl             r2,r2,#2
1159
SAVE4:
1160
        pha
1161
        jsr             spi_write_sector
1162
        add             r2,r2,#512
1163
        pla
1164
        ina
1165
        ld              r4,TXTBGN>>2
1166
        asl             r4,r4,#2
1167
        add             r4,r4,#65536
1168
        cmp             r2,r4
1169
        bmi             SAVE4
1170
        bra             WSTART
1171 16 robfinch
 
1172
SAVE:
1173
        ld              r8,TXTBGN>>2    ;set pointer to start of prog. area
1174
        ld              r9,TXTUNF       ;set pointer to end of prog. area
1175
SAVE1:
1176
        jsr             AUXOCRLF    ; send out a CR & LF (CP/M likes this)
1177
        cmp             r8,r9
1178
        bcs             SAVEND          ; are we finished?
1179
        lda             #':'            ; if not, start a line
1180
        jsr             GOAUXO
1181
        lda             (r8)            ; get line number
1182 18 robfinch
        inc             r8
1183 16 robfinch
        jsr             PWORD       ; output line number as 4-digit hex
1184
SAVE2:
1185
        lda             (r8)            ; get a text char.
1186 18 robfinch
        inc             r8
1187 16 robfinch
        cmp             #CR
1188
        beq             SAVE1           ; is it the end of the line? if so, send CR & LF and start new line
1189
        jsr             GOAUXO          ; send it out
1190
        bra             SAVE2           ; go back for more text
1191
SAVEND:
1192
        lda             #'@'            ; send end-of-program indicator
1193
        jsr             GOAUXO
1194
        jsr             AUXOCRLF    ; followed by a CR & LF
1195
        lda             #$1A            ; and a control-Z to end the CP/M file
1196
        jsr             GOAUXO
1197
        bra             WSTART          ; then go do a warm start
1198
 
1199
 
1200
; output a CR LF sequence to auxillary output
1201
; Registers Affected
1202
;   r3 = LF
1203
AUXOCRLF:
1204
    lda         #CR
1205
    jsr         GOAUXO
1206
    lda         #LF
1207
    jsr         GOAUXO
1208
    rts
1209
 
1210
 
1211
; output a word in hex format
1212
; tricky because of the need to reverse the order of the chars
1213
PWORD:
1214
        push    r5
1215
        ld              r5,#NUMWKA+15
1216
        or              r4,r1,r0        ; r4 = value
1217
pword1:
1218
    or      r1,r4,r0    ; r1 = value
1219
    lsr         r4,r4           ; shift over to next nybble
1220
    lsr         r4,r4
1221
    lsr         r4,r4
1222
    lsr         r4,r4
1223
    jsr         toAsciiHex  ; convert LS nybble to ascii hex
1224
    sta     (r5)                ; save in work area
1225
    sub         r5,r5,#1
1226
    cmp         r5,#NUMWKA
1227
    beq         pword1
1228
    bcs         pword1
1229
pword2:
1230
    add         r5,r5,#1
1231
    lda    (r5)     ; get char to output
1232
        jsr             GOAUXO          ; send it
1233
        cmp             r5,#NUMWKA+15
1234
        bcc             pword2
1235
        pop             r5
1236
        rts
1237
 
1238
 
1239
; convert nybble in r2 to ascii hex char2
1240
; r2 = character to convert
1241
 
1242
toAsciiHex:
1243
        and             #15     ; make sure it's a nybble
1244
        cmp             #10     ; > 10 ?
1245
        bcc             tah1
1246
        add             #7      ; bump it up to the letter 'A'
1247
tah1:
1248
        add             #'0'    ; bump up to ascii '0'
1249
        rts
1250
 
1251
 
1252
 
1253
;******************************************************************
1254 18 robfinch
; *** POKE ***
1255 16 robfinch
;
1256 18 robfinch
; 'POKE expr1,expr2' stores the word from 'expr2' into the memory
1257 16 robfinch
; address specified by 'expr1'.
1258
;******************************************************************
1259
;
1260
POKE:
1261
        jsr             OREXPR          ; get the memory address
1262
        ldy             #','
1263
        ld              r4,#PKER        ; it must be followed by a comma
1264
        jsr             TSTC            ; it must be followed by a comma
1265
        pha                                     ; save the address
1266
        jsr             OREXPR          ; get the byte to be POKE'd
1267
        plx                                 ; get the address back
1268
        sta             (x)                     ; store the byte in memory
1269
        jmp             FINISH
1270
PKER:
1271
        lda             #msgComma
1272
        jmp             ERROR           ; if no comma, say "What?"
1273
 
1274
 
1275 18 robfinch
;******************************************************************
1276
; 'SYSX expr' jumps to the machine language subroutine whose
1277
; starting address is specified by 'expr'.  The subroutine can use
1278
; all registers but must leave the stack the way it found it.
1279
; The subroutine returns to the interpreter by executing an RTS.
1280
;******************************************************************
1281 16 robfinch
 
1282
SYSX:
1283
        jsr             OREXPR          ; get the subroutine's address
1284
        cmp             #0
1285
        bne             sysx1           ; make sure we got a valid address
1286
        lda             #msgSYSBad
1287
        jmp             ERROR
1288
sysx1:
1289
        push    r8                      ; save the text pointer
1290
        jsr             (r1)            ; jump to the subroutine
1291
        pop             r8                  ; restore the text pointer
1292
        jmp             FINISH
1293
 
1294
;******************************************************************
1295
; *** EXPR ***
1296
;
1297
; 'EXPR' evaluates arithmetical or logical expressions.
1298
; ::=  OR  ...
1299
; ::= AND  ...
1300
; ::=
1301
;          
1302
; where  is one of the operators in TAB8 and the result
1303
; of these operations is 1 if true and 0 if false.
1304
; ::=(+ or -)(+ or -)(...
1305
; where () are optional and (... are optional repeats.
1306
; ::=( <* or /> )(...
1307
; ::=
1308
;           
1309
;           ()
1310
;  is recursive so that the variable '@' can have an 
1311
; as an index, functions can have an  as arguments, and
1312
;  can be an  in parenthesis.
1313
;
1314
 
1315
; ::= OR  ...
1316
;
1317
OREXPR:
1318
        jsr             ANDEXPR         ; get first 
1319
XP_OR1:
1320
        pha                                     ; save  value
1321
        ld              r9,#TAB10       ; look up a logical operator
1322
        ld              r10,#TAB10_1
1323
        jmp             EXEC            ; go do it
1324
XP_OR:
1325
    jsr         ANDEXPR
1326
    plx
1327
    or      r1,r1,r2
1328
    bra     XP_OR1
1329
XP_ORX:
1330
        pla
1331
    rts
1332
 
1333
 
1334
; ::= AND  ...
1335
;
1336
ANDEXPR:
1337
        jsr             EXPR            ; get first 
1338
XP_AND1:
1339
        pha                                     ; save  value
1340
        ld              r9,#TAB9                ; look up a logical operator
1341
        ld              r10,#TAB9_1
1342
        jmp             EXEC            ; go do it
1343
XP_AND:
1344
    jsr         EXPR
1345
    plx
1346
    and     r1,r1,r2
1347
    bra     XP_AND1
1348
XP_ANDX:
1349
        pla
1350
    rts
1351
 
1352
 
1353
; Determine if the character is a digit
1354
;   Parameters
1355
;       r1 = char to test
1356
;   Returns
1357
;       r1 = 1 if digit, otherwise 0
1358
;
1359
isDigit:
1360
        cmp             #'0'
1361
        bcc             isDigitFalse
1362
        cmp             #'9'+1
1363
        bcs             isDigitFalse
1364
        lda             #1
1365
    rts
1366
isDigitFalse:
1367
    lda         #0
1368
    rts
1369
 
1370
 
1371
; Determine if the character is a alphabetic
1372
;   Parameters
1373
;       r1 = char to test
1374
;   Returns
1375
;       r1 = 1 if alpha, otherwise 0
1376
;
1377
isAlpha:
1378
        cmp             #'A'
1379
        bcc             isAlphaFalse
1380
        cmp             #'Z'
1381
        beq             isAlphaTrue
1382
        bcc             isAlphaTrue
1383
        cmp             #'a'
1384
        bcc             isAlphaFalse
1385
        cmp             #'z'+1
1386
        bcs             isAlphaFalse
1387
isAlphaTrue:
1388
    lda         #1
1389
    rts
1390
isAlphaFalse:
1391
    lda         #0
1392
    rts
1393
 
1394
 
1395
; Determine if the character is a alphanumeric
1396
;   Parameters
1397
;       r1 = char to test
1398
;   Returns
1399
;       r1 = 1 if alpha, otherwise 0
1400
;
1401
isAlnum:
1402
    tax                                         ; save test char
1403
    jsr         isDigit
1404
    cmp         #0
1405
    bne         isDigitx                ; if it is a digit
1406
    txa                                         ; get back test char
1407
    jsr    isAlpha
1408
isDigitx:
1409
    rts
1410
 
1411
 
1412
EXPR:
1413
        jsr             EXPR2
1414
        pha                                     ; save  value
1415
        ld              r9,#TAB8                ; look up a relational operator
1416
        ld              r10,#TAB8_1
1417
        jmp             EXEC            ; go do it
1418
XP11:
1419
        pla
1420
        jsr             XP18    ; is it ">="?
1421
        cmp             r2,r1
1422
        bpl             XPRT1   ; no, return r2=1
1423
        bra             XPRT0   ; else return r2=0
1424
XP12:
1425
        pla
1426
        jsr             XP18    ; is it "<>"?
1427
        cmp             r2,r1
1428
        bne             XPRT1   ; no, return r2=1
1429
        bra             XPRT0   ; else return r2=0
1430
XP13:
1431
        pla
1432
        jsr             XP18    ; is it ">"?
1433
        cmp             r2,r1
1434
        beq             XPRT0
1435
        bpl             XPRT1   ; no, return r2=1
1436
        bra             XPRT0   ; else return r2=0
1437
XP14:
1438
        pla
1439
        jsr             XP18    ; is it "<="?
1440
        cmp             r2,r1
1441
        beq             XPRT1   ; no, return r2=1
1442
        bmi             XPRT1
1443
        bra             XPRT0   ; else return r2=0
1444
XP15:
1445
        pla
1446
        jsr             XP18    ; is it "="?
1447
        cmp             r2,r1
1448
        beq             XPRT1   ; if not, return r2=1
1449
        bra             XPRT0   ; else return r2=0
1450
XP16:
1451
        pla
1452
        jsr             XP18    ; is it "<"?
1453
        cmp             r2,r1
1454
        bmi             XPRT1   ; if not, return r2=1
1455
        bra             XPRT0   ; else return r2=0
1456
XPRT0:
1457
        lda             #0   ; return r1=0 (false)
1458
        rts
1459
XPRT1:
1460
        lda             #1      ; return r1=1 (true)
1461
        rts
1462
 
1463
XP17:                           ; it's not a rel. operator
1464
        pla                             ; return r2=
1465
        rts
1466
 
1467
XP18:
1468
        pha
1469
        jsr             EXPR2           ; do a second 
1470
        plx
1471
        rts
1472
 
1473
; ::=(+ or -)(+ or -)(...
1474 26 robfinch
message "EXPR2"
1475 16 robfinch
EXPR2:
1476
        ldy             #'-'
1477
        ld              r4,#XP21
1478
        jsr             TSTC            ; negative sign?
1479
        lda             #0              ; yes, fake '0-'
1480
        pha
1481
        bra             XP26
1482
XP21:
1483
        ldy             #'+'
1484
        ld              r4,#XP22
1485
        jsr             TSTC            ; positive sign? ignore it
1486
XP22:
1487
        jsr             EXPR3           ; first 
1488
XP23:
1489
        pha                                     ; yes, save the value
1490
        ldy             #'+'
1491
        ld              r4,#XP25
1492
        jsr             TSTC            ; add?
1493
        jsr             EXPR3           ; get the second 
1494
XP24:
1495
        plx
1496
        add             r1,r1,r2        ; add it to the first 
1497
;       BVS.L   QHOW            brnch if there's an overflow
1498
        bra             XP23            ; else go back for more operations
1499
XP25:
1500
        ldy             #'-'
1501
        ld              r4,#XP45
1502
        jsr             TSTC            ; subtract?
1503
XP26:
1504
        jsr             EXPR3           ; get second 
1505
        sub             r1,r0,r1        ; change its sign
1506
        bra             XP24            ; and do an addition
1507
XP45:
1508
        pla
1509
        rts
1510
 
1511
 
1512
; ::=( <* or /> )(...
1513
 
1514
EXPR3:
1515
        jsr     EXPR4           ; get first 
1516
XP31:
1517
        pha                             ; yes, save that first result
1518
        ldy             #'*'
1519
        ld              r4,#XP34
1520
        jsr             TSTC            ; multiply?
1521
        jsr             EXPR4           ; get second 
1522
        plx
1523
        muls    r1,r1,r2        ; multiply the two
1524
        bra             XP31        ; then look for more terms
1525
XP34:
1526
        ldy             #'/'
1527
        ld              r4,#XP47
1528
        jsr             TSTC            ; divide?
1529
        jsr             EXPR4           ; get second 
1530
        tax
1531
        pla
1532
        divs    r1,r1,r2        ; do the division
1533
        bra             XP31            ; go back for any more terms
1534
XP47:
1535
        pla
1536
        rts
1537
 
1538
 
1539
; Functions are jsred through EXPR4
1540
; ::=
1541
;           
1542
;           ()
1543
 
1544
EXPR4:
1545
    ld          r9,#TAB4                ; find possible function
1546
    ld          r10,#TAB4_1
1547
        jmp             EXEC        ; branch to function which does subsequent rts for EXPR4
1548
XP40:                   ; we get here if it wasn't a function
1549
        lda             #0
1550
        jsr             TSTV
1551
        cmp             #0
1552
        beq     XP41            ; nor a variable
1553
        lda             (r1)            ; if a variable, return its value in r1
1554
        rts
1555
XP41:
1556
        jsr             TSTNUM          ; or is it a number?
1557
        cmp             r2,#0
1558
        bne             XP46            ; (if not, # of digits will be zero) if so, return it in r1
1559
        jsr             PARN        ; check for (EXPR)
1560
XP46:
1561
        rts
1562
 
1563
 
1564
; Check for a parenthesized expression
1565
PARN:
1566
        ldy             #'('
1567
        ld              r4,#XP43
1568
        jsr             TSTC            ; else look for ( OREXPR )
1569
        jsr             OREXPR
1570
        ldy             #')'
1571
        ld              r4,#XP43
1572
        jsr             TSTC
1573
XP42:
1574
        rts
1575
XP43:
1576
        pla                             ; get rid of return address
1577
        lda             #msgWhat
1578
        jmp             ERROR
1579
 
1580
 
1581
; ===== Test for a valid variable name.  Returns Z=1 if not
1582
;       found, else returns Z=0 and the address of the
1583
;       variable in r1.
1584
; Parameters
1585
;       r1 = 1 = allocate if not found
1586
; Returns
1587
;       r1 = address of variable, zero if not found
1588
 
1589
TSTV:
1590
        push    r5
1591
        ld              r5,r1           ; r5=allocate flag
1592
        jsr             IGNBLK
1593
        lda             (r8)            ; look at the program text
1594
        cmp             #'@'
1595
        bcc             tstv_notfound   ; C=1: not a variable
1596
        bne             TV1                             ; brnch if not "@" array
1597
        inc             r8                      ; If it is, it should be
1598
        jsr             PARN            ; followed by (EXPR) as its index.
1599
;       BCS.L   QHOW            say "How?" if index is too big
1600
    pha                             ; save the index
1601
        jsr             SIZEX           ; get amount of free memory
1602
        plx                                 ; get back the index
1603
        cmp             r2,r1
1604
        bcc             TV2                     ; see if there's enough memory
1605
        jmp     QSORRY          ; if not, say "Sorry"
1606
TV2:
1607
        lda             VARBGN          ; put address of array element...
1608
        sub     r1,r1,r2       ; into r1 (neg. offset is used)
1609
        bra     TSTVRT
1610
TV1:
1611
    jsr         getVarName      ; get variable name
1612
    cmp         #0
1613
    beq     TSTVRT    ; if not, return r1=0
1614
    ld          r2,r5
1615
    jsr         findVar     ; find or allocate
1616
TSTVRT:
1617
        pop             r5
1618
        rts                                     ; r1<>0 (found)
1619
tstv_notfound:
1620
        pop             r5
1621
        lda             #0                      ; r1=0 if not found
1622
    rts
1623
 
1624
 
1625
; Returns
1626
;   r1 = 2 character variable name + type
1627
;
1628
getVarName:
1629
    push        r5
1630
 
1631
    lda     (r8)                ; get first character
1632
    pha                                 ; save off current name
1633
    jsr         isAlpha
1634
    cmp         #0
1635
    beq     gvn1
1636
    ld      r5,#2       ; loop two more times
1637
 
1638
        ; check for second/third character
1639
gvn4:
1640
        inc             r8
1641
        lda     (r8)            ; do we have another char ?
1642
        jsr             isAlnum
1643
        cmp             #0
1644
        beq     gvn2            ; nope
1645
        pla                                     ; get varname
1646
        asl
1647
        asl
1648
        asl
1649
        asl
1650
        asl
1651
        asl
1652
        asl
1653
        asl
1654
        ldx     (r8)
1655
        or      r1,r1,r2   ; add in new char
1656
    pha                            ; save off name again
1657
    dec         r5
1658
    bne         gvn4
1659
 
1660
    ; now ignore extra variable name characters
1661
gvn6:
1662
    inc         r8
1663
    lda    (r8)
1664
    jsr    isAlnum
1665
    cmp         #0
1666
    bne     gvn6        ; keep looping as long as we have identifier chars
1667
 
1668
    ; check for a variable type
1669
gvn2:
1670
        lda             (r8)
1671
        cmp             #'%'
1672
        beq             gvn3
1673
        cmp             #'$'
1674
        beq             gvn3
1675
        lda             #0
1676
    dec         r8
1677
 
1678
    ; insert variable type indicator and return
1679
gvn3:
1680
    inc         r8
1681
    plx
1682
    asl         r2,r2
1683
    asl         r2,r2
1684
    asl         r2,r2
1685
    asl         r2,r2
1686
    asl         r2,r2
1687
    asl         r2,r2
1688
    asl         r2,r2
1689
    asl         r2,r2
1690
    or      r1,r1,r2    ; add in variable type
1691
    pop         r5
1692
    rts                                 ; return Z = 0, r1 = varname
1693
 
1694
    ; not a variable name
1695
gvn1:
1696
        pla
1697
        pop             r5
1698
    lda         #0       ; return Z = 1 if not a varname
1699
    rts
1700
 
1701
 
1702
; Find variable
1703
;   r1 = varname
1704
;       r2 = allocate flag
1705
; Returns
1706
;   r1 = variable address, Z =0 if found / allocated, Z=1 if not found
1707
 
1708
findVar:
1709
        push    r7
1710
    ldy     VARBGN
1711
fv4:
1712
    ld      r7,(y)      ; get varname / type
1713
    beq     fv3                 ; no more vars ?
1714
    cmp         r1,r7
1715
    beq     fv1                 ; match ?
1716
    iny                                 ; move to next var
1717
    iny
1718
    ld      r7,STKBOT
1719
    cmp         r3,r7
1720
    bcc     fv4                 ; loop back to look at next var
1721
 
1722
    ; variable not found
1723
    ; no more memory
1724
    lda         #msgVarSpace
1725
    jmp     ERROR
1726
;    lw      lr,[sp]
1727
;    lw      r7,4[sp]
1728
;    add     sp,sp,#8
1729
;    lw      r1,#0
1730
;    rts
1731
 
1732
    ; variable not found
1733
    ; allocate new ?
1734
fv3:
1735
        cpx             #0
1736
        beq             fv2
1737
    sta     (r3)     ; save varname / type
1738
    ; found variable
1739
    ; return address
1740
fv1:
1741
    add         r1,r3,#1
1742
        pop             r7
1743
    rts                     ; Z = 0, r1 = address
1744
 
1745
    ; didn't find var and not allocating
1746
fv2:
1747
    pop         r7
1748
        lda             #0              ; Z = 1, r1 = 0
1749
    rts
1750
 
1751
 
1752
; ===== The PEEK function returns the byte stored at the address
1753
;       contained in the following expression.
1754
;
1755
PEEK:
1756
        jsr             PARN            ; get the memory address
1757
        lda             (r1)            ; get the addressed byte
1758
        rts
1759
 
1760
 
1761
; user function jsr
1762
; call the user function with argument in r1
1763
USRX:
1764
        jsr             PARN            ; get expression value
1765
        push    r8                      ; save the text pointer
1766 18 robfinch
        ldx             #0
1767
        jsr             (usrJmp,x)      ; get usr vector, jump to the subroutine
1768 16 robfinch
        pop             r8                      ; restore the text pointer
1769
        rts
1770
 
1771
 
1772
; ===== The RND function returns a random number from 1 to
1773
;       the value of the following expression in D0.
1774
;
1775
RND:
1776
        jsr             PARN            ; get the upper limit
1777
        cmp             #0
1778
        beq             rnd2            ; it must be positive and non-zero
1779
        bcc             rnd1
1780
        tax
1781
        ;gran                           ; generate a random number
1782
        ;mfspr  r1,rand         ; get the number
1783
        tsr             LFSR,r1
1784
;       jsr             modu4           ; RND(n)=MOD(number,n)+1
1785
        mod             r1,r1,r2
1786
        ina
1787
        rts
1788
rnd1:
1789
        lda             #msgRNDBad
1790
        jmp             ERROR
1791
rnd2:
1792
        tsr             LFSR,r1
1793
;       gran
1794
;       mfspr   r1,rand
1795
        rts
1796
 
1797
 
1798
; r = a mod b
1799
; a = r1
1800
; b = r2
1801
; r = r6
1802
;modu4:
1803
;       push    r3
1804
;       push    r5
1805
;       push    r6
1806
;       push    r7
1807
;       ld      r7,#31          ; n = 32
1808
;       eor             r5,r5,r5        ; w = 0
1809
;;      eor             r6,r6,r6        ; r = 0
1810
;mod2:
1811
;       rol                                     ; a <<= 1
1812
;       and             r3,r1,#1
1813
;       asl             r6                      ; r <<= 1
1814
;       or              r6,r6,r3
1815
;       and             #-2
1816
;       cmp             r2,r6
1817
;       bmi             mod1            ; b < r ?
1818
;       sub             r6,r6,r2        ; r -= b
1819
;mod1:
1820
;       dec             r7                      ; n--
1821
;       bne             mod2
1822
;       ld              r1,r6
1823
;       pop             r7
1824
;       pop             r6
1825
;       pop             r5
1826
;       pop             r3
1827
;       rts
1828
;
1829
 
1830
; ===== The ABS function returns an absolute value in r2.
1831
;
1832
ABS:
1833
        jsr             PARN            ; get the following expr.'s value
1834
        cmp             #0
1835
        bmi             ABS1
1836
        rts
1837
ABS1:
1838
        sub             r1,r0,r1
1839
        rts
1840
 
1841
;==== The TICK function returns the cpu tick value in r1.
1842
;
1843
TICKX:
1844
        tsr             TICK,r1
1845
        rts
1846
 
1847
; ===== The SGN function returns the sign in r1. +1,0, or -1
1848
;
1849
SGN:
1850
        jsr             PARN            ; get the following expr.'s value
1851
        cmp             #0
1852
        beq             SGN1
1853
        bmi             SGN2
1854
        lda             #1
1855
        rts
1856
SGN2:
1857
        lda             #-1
1858
        rts
1859
SGN1:
1860
        rts
1861
 
1862
; ===== The SIZE function returns the size of free memory in r1.
1863
;
1864
SIZEX:
1865
        lda             VARBGN          ; get the number of free bytes...
1866
        ldx             TXTUNF          ; between 'TXTUNF' and 'VARBGN'
1867
        sub             r1,r1,r2
1868
        rts                                     ; return the number in r1
1869
 
1870
 
1871
;******************************************************************
1872
;
1873
; *** SETVAL *** FIN *** ENDCHK *** ERROR (& friends) ***
1874
;
1875
; 'SETVAL' expects a variable, followed by an equal sign and then
1876
; an expression.  It evaluates the expression and sets the variable
1877
; to that value.
1878
;
1879
; returns
1880
; r2 = variable's address
1881
;
1882
SETVAL:
1883
    lda         #1              ; allocate var
1884
    jsr         TSTV            ; variable name?
1885
    cmp         #0
1886
    bne         sv2
1887
        lda             #msgVar
1888
        jmp             ERROR
1889
sv2:
1890
        pha                         ; save the variable's address
1891
        ldy             #'='
1892
        ld              r4,#SV1
1893
        jsr             TSTC            ; get past the "=" sign
1894
        jsr             OREXPR          ; evaluate the expression
1895
        plx                                 ; get back the variable's address
1896
        sta     (x)                 ; and save value in the variable
1897
        txa                                     ; return r1 = variable address
1898
        rts
1899
SV1:
1900
    jmp     QWHAT               ; if no "=" sign
1901
 
1902
 
1903 18 robfinch
; 'FIN' checks the end of a command.  If it ended with ":",
1904
; execution continues.  If it ended with a CR, it finds the
1905
; the next line and continues from there.
1906
;
1907 16 robfinch
FIN:
1908
        ldy             #':'
1909
        ld              r4,#FI1
1910
        jsr             TSTC            ; *** FIN ***
1911
        pla                                     ; if ":", discard return address
1912
        jmp             RUNSML          ; continue on the same line
1913
FI1:
1914
        ldy             #CR
1915
        ld              r4,#FI2
1916
        jsr             TSTC            ; not ":", is it a CR?
1917
                                                ; else return to the caller
1918
        pla                                     ; yes, purge return address
1919
        jmp             RUNNXL          ; execute the next line
1920
FI2:
1921
        rts                                     ; else return to the caller
1922
 
1923
 
1924 18 robfinch
; 'ENDCHK' checks if a command is ended with a CR. This is
1925
; required in certain commands, such as GOTO, RETURN, STOP, etc.
1926
;
1927 16 robfinch
; Check that there is nothing else on the line
1928
; Registers Affected
1929
;   r1
1930
;
1931
ENDCHK:
1932
        jsr             IGNBLK
1933
        lda             (r8)
1934
        cmp             #CR
1935
        beq             ec1     ; does it end with a CR?
1936
        lda             #msgExtraChars
1937
        jmp             ERROR
1938
ec1:
1939
        rts
1940
 
1941 18 robfinch
; 'ERROR' prints the string pointed to by r1. It then prints the
1942
; line pointed to by CURRNT with a "?" inserted at where the
1943
; old text pointer (should be on top of the stack) points to.
1944
; Execution of Tiny BASIC is stopped and a warm start is done.
1945
; If CURRNT is zero (indicating a direct command), the direct
1946
; command is not printed. If CURRNT is -1 (indicating
1947
; 'INPUT' command in progress), the input line is not printed
1948
; and execution is not terminated but continues at 'INPERR'.
1949
;
1950
; Related to 'ERROR' are the following:
1951
; 'QWHAT' saves text pointer on stack and gets "What?" message.
1952
; 'AWHAT' just gets the "What?" message and jumps to 'ERROR'.
1953
; 'QSORRY' and 'ASORRY' do the same kind of thing.
1954
; 'QHOW' and 'AHOW' also do this for "How?".
1955
;
1956 16 robfinch
TOOBIG:
1957
        lda             #msgTooBig
1958
        bra             ERROR
1959
QSORRY:
1960
    lda         #SRYMSG
1961
        bra         ERROR
1962
QWHAT:
1963
        lda             #msgWhat
1964
ERROR:
1965
        jsr             PRMESG          ; display the error message
1966 18 robfinch
        lda             CURRNT          ; get the current line pointer
1967 16 robfinch
        beq             ERROR1          ; if zero, do a warm start
1968
        cmp             #-1
1969
        beq             INPERR          ; is the line no. pointer = -1? if so, redo input
1970
        ld              r5,(r8)         ; save the char. pointed to
1971
        stz             (r8)            ; put a zero where the error is
1972
        lda             CURRNT          ; point to start of current line
1973
        jsr             PRTLN           ; display the line in error up to the 0
1974 18 robfinch
        ld      r6,r1       ; save off end pointer
1975 16 robfinch
        st              r5,(r8)         ; restore the character
1976
        lda             #'?'            ; display a "?"
1977
        jsr             GOOUT
1978
        ldx             #0                      ; stop char = 0
1979
        sub             r1,r6,#1        ; point back to the error char.
1980
        jsr             PRTSTG          ; display the rest of the line
1981
ERROR1:
1982
        jmp         WSTART              ; and do a warm start
1983
 
1984
;******************************************************************
1985
;
1986
; *** GETLN *** FNDLN (& friends) ***
1987
;
1988
; 'GETLN' reads in input line into 'BUFFER'. It first prompts with
1989
; the character in r3 (given by the caller), then it fills the
1990
; buffer and echos. It ignores LF's but still echos
1991
; them back. Control-H is used to delete the last character
1992
; entered (if there is one), and control-X is used to delete the
1993
; whole line and start over again. CR signals the end of a line,
1994
; and causes 'GETLN' to return.
1995
;
1996
;
1997
GETLN:
1998
        push    r5
1999
        jsr             GOOUT           ; display the prompt
2000
        lda             #1
2001
        sta             CursorFlash     ; turn on cursor flash
2002
        lda             #' '            ; and a space
2003
        jsr             GOOUT
2004
        ld              r8,#BUFFER      ; r8 is the buffer pointer
2005
GL1:
2006
        jsr             CHKIO           ; check keyboard
2007
        cmp             #0
2008
        beq             GL1                     ; wait for a char. to come in
2009
        cmp             #CTRLH
2010
        beq             GL3                     ; delete last character? if so
2011
        cmp             #CTRLX
2012
        beq             GL4                     ; delete the whole line?
2013
        cmp             #CR
2014
        beq             GL2                     ; accept a CR
2015
        cmp             #' '
2016
        bcc             GL1                     ; if other control char., discard it
2017
GL2:
2018
        sta             (r8)            ; save the char.
2019
        inc             r8
2020
        pha
2021
        jsr             GOOUT           ; echo the char back out
2022
        pla                                     ; get char back (GOOUT destroys r1)
2023
        cmp             #CR
2024
        beq             GL7                     ; if it's a CR, end the line
2025
        cmp             r8,#BUFFER+BUFLEN-1     ; any more room?
2026
        bcc             GL1                     ; yes: get some more, else delete last char.
2027
GL3:
2028
        lda             #CTRLH  ; delete a char. if possible
2029
        jsr             GOOUT
2030
        lda             #' '
2031
        jsr             GOOUT
2032
        cmp             r8,#BUFFER      ; any char.'s left?
2033
        bcc             GL1                     ; if not
2034
        beq             GL1
2035
        lda             #CTRLH          ; if so, finish the BS-space-BS sequence
2036
        jsr             GOOUT
2037
        dec             r8                      ; decrement the text pointer
2038
        bra             GL1                     ; back for more
2039
GL4:
2040 18 robfinch
        ld              r1,r8           ; delete the whole line
2041 16 robfinch
        sub             r5,r1,#BUFFER   ; figure out how many backspaces we need
2042
        beq             GL6                             ; if none needed, brnch
2043
        dec             r5                      ; loop count is one less
2044
GL5:
2045
        lda             #CTRLH          ; and display BS-space-BS sequences
2046
        jsr             GOOUT
2047
        lda             #' '
2048
        jsr             GOOUT
2049
        lda             #CTRLH
2050
        jsr             GOOUT
2051
        dec             r5
2052
        bne             GL5
2053
GL6:
2054
        ld              r8,#BUFFER      ; reinitialize the text pointer
2055
        bra             GL1                     ; and go back for more
2056
GL7:
2057
        lda             #0              ; turn off cursor flash
2058
        stz             (r8)            ; null terminate line
2059
        stz             CursorFlash
2060
        lda             #LF             ; echo a LF for the CR
2061
        jsr             GOOUT
2062
        pop             r5
2063
        rts
2064
 
2065
 
2066
; 'FNDLN' finds a line with a given line no. (in r1) in the
2067
; text save area.  r9 is used as the text pointer. If the line
2068
; is found, r9 will point to the beginning of that line
2069
; (i.e. the high byte of the line no.), and r1 = 1.
2070
; If that line is not there and a line with a higher line no.
2071
; is found, r9 points there and r1 = 0. If we reached
2072
; the end of the text save area and cannot find the line, flags
2073
; r9 = 0, r1 = 0.
2074
; r1=1 if line found
2075
; r0 = 1        <= line is found
2076
;       r9 = pointer to line
2077
; r0 = 0    <= line is not found
2078
;       r9 = zero, if end of text area
2079
;       r9 = otherwise higher line number
2080
;
2081
; 'FNDLN' will initialize r9 to the beginning of the text save
2082
; area to start the search. Some other entries of this routine
2083
; will not initialize r9 and do the search.
2084
; 'FNDLNP' will start with r9 and search for the line no.
2085
; 'FNDNXT' will bump r9 by 2, find a CR and then start search.
2086
; 'FNDSKP' uses r9 to find a CR, and then starts the search.
2087
; return Z=1 if line is found, r9 = pointer to line
2088
;
2089
; Parameters
2090
;       r1 = line number to find
2091
;
2092
FNDLN:
2093
        cmp             #$FFFF
2094
        bcc             fl1     ; line no. must be < 65535
2095
        lda             #msgLineRange
2096
        jmp             ERROR
2097
fl1:
2098
        ld              r9,TXTBGN>>2    ; init. the text save pointer
2099
 
2100
FNDLNP:
2101
        cmp             r9,TXTUNF       ; check if we passed the end
2102
        beq             FNDRET1
2103
        bcs             FNDRET1         ; if so, return with r9=0,r1=0
2104
        ldx             (r9)            ; get line number
2105
        cmp             r1,r2
2106
        beq             FNDRET2
2107
        bcs             FNDNXT  ; is this the line we want? no, not there yet
2108
FNDRET:
2109
        lda             #0      ; line not found, but r9=next line pointer
2110
        rts                     ; return the cond. codes
2111
FNDRET1:
2112
;       eor             r9,r9,r9        ; no higher line
2113
        lda             #0      ; line not found
2114
        rts
2115
FNDRET2:
2116
        lda             #1              ; line found
2117
        rts
2118
 
2119
FNDNXT:
2120
        inc             r9      ; find the next line
2121
 
2122
FNDSKP:
2123
        ldx             (r9)
2124
        inc             r9
2125
        cpx             #CR
2126
        bne             FNDSKP          ; try to find a CR, keep looking
2127
        bra             FNDLNP          ; check if end of text
2128
 
2129
 
2130
;******************************************************************
2131
; 'MVUP' moves a block up from where r1 points to where r2 points
2132
; until r1=r3
2133
;
2134
MVUP1:
2135
        ld              r4,(r1)
2136
        st              r4,(r2)
2137
        ina
2138
        inx
2139
MVUP:
2140
        cmp             r1,r3
2141
        bne             MVUP1
2142
MVRET:
2143
        rts
2144
 
2145
 
2146
; 'MVDOWN' moves a block down from where r1 points to where r2
2147
; points until r1=r3
2148
;
2149
MVDOWN1:
2150
        dea
2151
        dex
2152
        ld              r4,(r1)
2153
        st              r4,(r2)
2154
MVDOWN:
2155
        cmp             r1,r3
2156
        bne             MVDOWN1
2157
        rts
2158
 
2159
 
2160
; 'POPA' restores the 'FOR' loop variable save area from the stack
2161
;
2162
; 'PUSHA' stacks for 'FOR' loop variable save area onto the stack
2163
;
2164
; Note: a single zero word is stored on the stack in the
2165
; case that no FOR loops need to be saved. This needs to be
2166
; done because PUSHA / POPA is called all the time.
2167 26 robfinch
message "POPA"
2168 16 robfinch
POPA:
2169
        ply
2170
        pla
2171
        sta             LOPVAR  ; restore LOPVAR, but zero means no more
2172
        beq             PP1
2173
        pla
2174
        sta             LOPINC
2175
        pla
2176
        sta             LOPLMT
2177
        pla
2178
        sta             LOPLN
2179
        pla
2180
        sta             LOPPT
2181
PP1:
2182
        jmp             (y)
2183
 
2184
 
2185
PUSHA:
2186
        ply
2187
        lda             STKBOT          ; Are we running out of stack room?
2188
        add             r1,r1,#5        ; we might need this many words
2189
        tsx
2190
        cmp             r2,r1
2191
        bcc             QSORRY          ; out of stack space
2192
        ldx             LOPVAR          ; save loop variables
2193
        beq             PU1                     ; if LOPVAR is zero, that's all
2194
        lda             LOPPT
2195
        pha
2196
        lda             LOPLN
2197
        pha
2198
        lda             LOPLMT
2199
        pha
2200
        lda             LOPINC
2201
        pha
2202
PU1:
2203
        phx
2204
        jmp             (y)
2205
 
2206
 
2207
 
2208
;******************************************************************
2209
;
2210
; 'PRTSTG' prints a string pointed to by r1. It stops printing
2211
; and returns to the caller when either a CR is printed or when
2212
; the next byte is the same as what was passed in r2 by the
2213
; caller.
2214
;
2215
; 'PRTLN' prints the saved text line pointed to by r3
2216
; with line no. and all.
2217
;
2218
 
2219
; r1 = pointer to string
2220
; r2 = stop character
2221
; return r1 = pointer to end of line + 1
2222
 
2223
PRTSTG:
2224
        push    r5
2225
        push    r6
2226
        push    r7
2227
    ld      r5,r1           ; r5 = pointer
2228
    ld      r6,r2           ; r6 = stop char
2229
PS1:
2230
    ld      r7,(r5)     ; get a text character
2231
    inc         r5
2232
    cmp         r7,r6
2233
        beq         PRTRET              ; same as stop character? if so, return
2234
        ld      r1,r7
2235
        jsr             GOOUT           ; display the char.
2236
        cmp             r7,#CR
2237
        bne     PS1                     ; is it a C.R.? no, go back for more
2238
        lda             #LF      ; yes, add a L.F.
2239
        jsr             GOOUT
2240
PRTRET:
2241
    ld      r2,r7           ; return r2 = stop char
2242
        ld              r1,r5           ; return r1 = line pointer
2243
        pop             r7
2244
        pop             r6
2245
        pop             r5
2246
    rts                                 ; then return
2247
 
2248
 
2249
; 'QTSTG' looks for an underline (back-arrow on some systems),
2250
; single-quote, or double-quote.  If none of these are found, returns
2251
; to the caller.  If underline, outputs a CR without a LF.  If single
2252
; or double quote, prints the quoted string and demands a matching
2253
; end quote.  After the printing, the next i-word of the caller is
2254
; skipped over (usually a branch instruction).
2255
;
2256
QTSTG:
2257
        ldy             #'"'
2258
        ld              r4,#QT3
2259
        jsr             TSTC            ; *** QTSTG ***
2260
        ldx             #'"'            ; it is a "
2261
QT1:
2262
        ld              r1,r8
2263
        jsr             PRTSTG          ; print until another
2264
        ld              r8,r1
2265
        cpx             #CR
2266
        bne             QT2                     ; was last one a CR?
2267
        jmp             RUNNXL          ; if so run next line
2268
QT3:
2269
        ldy             #''''
2270
        ld              r4,#QT4
2271
        jsr             TSTC            ; is it a single quote?
2272
        ldx             #''''   ; if so, do same as above
2273
        bra             QT1
2274
QT4:
2275
        ldy             #'_'
2276
        ld              r4,#QT5
2277
        jsr             TSTC            ; is it an underline?
2278
        lda             #CR             ; if so, output a CR without LF
2279
        jsr             GOOUT
2280
QT2:
2281
        pla                                     ; get return address
2282
        ina                                     ; add 2 to it in order to skip following branch
2283
        ina
2284
        jmp             (r1)            ; skip over next i-word when returning
2285
QT5:                                            ; not " ' or _
2286
        rts
2287
 
2288
; Output a CR LF sequence
2289
;
2290
prCRLF:
2291
        lda             #CR
2292
        jsr             GOOUT
2293
        lda             #LF
2294
        jsr             GOOUT
2295
        rts
2296
 
2297 26 robfinch
; 'PRTNUM' prints the 32 bit number in r1, leading blanks are added if
2298
; needed to pad the number of spaces to the number in r2.
2299 16 robfinch
; However, if the number of digits is larger than the no. in
2300 26 robfinch
; r2, all digits are printed anyway. Negative sign is also
2301 16 robfinch
; printed and counted in, positive sign is not.
2302
;
2303
; r1 = number to print
2304
; r2 = number of digits
2305
; Register Usage
2306
;       r5 = number of padding spaces
2307
public PRTNUM:
2308
        push    r3
2309
        push    r5
2310
        push    r6
2311
        push    r7
2312
        ld              r7,#NUMWKA      ; r7 = pointer to numeric work area
2313
        ld              r6,r1           ; save number for later
2314
        ld              r5,r2           ; r5 = min number of chars
2315
        cmp             #0
2316
        bpl             PN2                     ; is it negative? if not
2317
        sub             r1,r0,r1        ; else make it positive
2318
        dec             r5                      ; one less for width count
2319
PN2:
2320
        ld              r3,#10
2321
PN1:
2322
        mod             r2,r1,r3        ; r2 = r1 mod 10
2323
        div             r1,r1,r3        ; r1 /= 10 divide by 10
2324
        add             r2,r2,#'0'      ; convert remainder to ascii
2325
        stx             (r7)            ; and store in buffer
2326
        inc             r7
2327
        dec             r5                      ; decrement width
2328
        cmp             #0
2329
        bne             PN1
2330
PN6:
2331
        cmp             r5,r0
2332 26 robfinch
        bmi             PN4             ; test pad count, skip padding if not needed
2333 16 robfinch
        beq             PN4
2334
PN3:
2335
        lda             #' '            ; display the required leading spaces
2336
        jsr             GOOUT
2337
        dec             r5
2338
        bne             PN3
2339
PN4:
2340
        cmp             r6,r0
2341
        bpl             PN5                     ; is number negative?
2342
        lda             #'-'            ; if so, display the sign
2343
        jsr             GOOUT
2344
PN5:
2345
        dec             r7
2346
        lda             (r7)            ; now unstack the digits and display
2347
        jsr             GOOUT
2348
        cmp             r7,#NUMWKA
2349
        beq             PNRET
2350
        bcs             PN5
2351
PNRET:
2352
        pop             r7
2353
        pop             r6
2354
        pop             r5
2355
        pop             r3
2356
        rts
2357
 
2358
; r1 = number to print
2359
; r2 = number of digits
2360
public PRTHEXNUM:
2361
        push    r4
2362
        push    r5
2363
        push    r6
2364
        push    r7
2365
        push    r8
2366
        ld              r7,#NUMWKA      ; r7 = pointer to numeric work area
2367
        ld              r6,r1           ; save number for later
2368
;       setlo   r5,#20          ; r5 = min number of chars
2369
        ld              r5,r2
2370
        ld              r4,r1
2371
        cmp             r4,r0
2372
        bpl             PHN2            ; is it negative? if not
2373
        sub             r4,r0,r4        ; else make it positive
2374
        dec             r5                      ; one less for width count
2375
PHN2
2376
        ld              r8,#10          ; maximum of 10 digits
2377
PHN1:
2378
        ld              r1,r4
2379
        and             #15
2380
        cmp             #10
2381
        bcc             PHN7
2382
        add             #'A'-10
2383
        bra             PHN8
2384
PHN7:
2385
        add             #'0'            ; convert remainder to ascii
2386
PHN8:
2387
        sta             (r7)            ; and store in buffer
2388
        inc             r7
2389
        dec             r5                      ; decrement width
2390
        lsr             r4,r4
2391
        lsr             r4,r4
2392
        lsr             r4,r4
2393
        lsr             r4,r4
2394
        beq             PHN6                    ; is it zero yet ?
2395
        dec             r8
2396
        bne             PHN1
2397
PHN6:   ; test pad count
2398
        cmp             r5,r0
2399
        beq             PHN4
2400
        bcc             PHN4    ; skip padding if not needed
2401
PHN3:
2402
        lda             #' '            ; display the required leading spaces
2403
        jsr             GOOUT
2404
        dec             r5
2405
        bne             PHN3
2406
PHN4:
2407
        cmp             r6,r0
2408
        bcs             PHN5    ; is number negative?
2409
        lda             #'-'            ; if so, display the sign
2410
        jsr             GOOUT
2411
PHN5:
2412
        dec             r7
2413
        lda             (r7)            ; now unstack the digits and display
2414
        jsr             GOOUT
2415
        cmp             r7,#NUMWKA
2416
        beq             PHNRET
2417
        bcs             PHN5
2418
PHNRET:
2419
        pop             r8
2420
        pop             r7
2421
        pop             r6
2422
        pop             r5
2423
        pop             r4
2424
        rts
2425
 
2426
 
2427
; r1 = pointer to line
2428
; returns r1 = pointer to end of line + 1
2429
PRTLN:
2430
        push    r5
2431
    ld          r5,r1           ; r5 = pointer
2432
    lda         (r5)            ; get the binary line number
2433
    inc         r5
2434
    ldx         #12       ; display a 0 or more digit line no.
2435
        jsr             PRTNUM
2436
        lda             #' '     ; followed by a blank
2437
        jsr             GOOUT
2438
        ldx             #0       ; stop char. is a zero
2439
        ld              r1,r5
2440
        jsr     PRTSTG          ; display the rest of the line
2441
        pop             r5
2442
        rts
2443
 
2444
 
2445
; ===== Test text byte following the call to this subroutine. If it
2446
;       equals the byte pointed to by r8, return to the code following
2447
;       the call. If they are not equal, brnch to the point
2448
;       indicated in r4.
2449
;
2450
; Registers Affected
2451
;   r3,r8
2452
; Returns
2453
;       r8 = updated text pointer
2454
;
2455
TSTC
2456
        pha
2457
        jsr             IGNBLK          ; ignore leading blanks
2458
        lda             (r8)
2459
        cmp             r3,r1
2460
        beq             TC1                     ; is it = to what r8 points to? if so
2461
        pla
2462
        ply                                     ; increment stack pointer (get rid of return address)
2463
        jmp             (r4)            ; jump to the routine
2464
TC1:
2465
        inc             r8                      ; if equal, bump text pointer
2466
        pla
2467
        rts
2468
 
2469
; ===== See if the text pointed to by r8 is a number. If so,
2470
;       return the number in r2 and the number of digits in r3,
2471
;       else return zero in r2 and r3.
2472
; Registers Affected
2473
;   r1,r2,r3,r4
2474
; Returns
2475
;       r1 = number
2476
;       r2 = number of digits in number
2477
;       r8 = updated text pointer
2478
;
2479
TSTNUM:
2480
        phy
2481
        jsr             IGNBLK          ; skip over blanks
2482
        lda             #0              ; initialize return parameters
2483
        ldx             #0
2484
        ld              r15,#10
2485
TN1:
2486
        ldy             (r8)
2487
        cpy             #'0'            ; is it less than zero?
2488
        bcc             TSNMRET
2489
        cpy             #'9'+1          ; is it greater than nine?
2490
        bcs             TSNMRET
2491
        cmp             r1,#$7FFFFFF    ; see if there's room for new digit
2492
        bcc             TN2
2493
        beq             TN2
2494
        lda             #msgNumTooBig
2495
        jmp             ERROR           ; if not, we've overflowd
2496
TN2:
2497
        inc             r8                      ; adjust text pointer
2498
        mul             r1,r1,r15       ; quickly multiply result by 10
2499
        and             r3,r3,#$0F      ; add in the new digit
2500
        add             r1,r1,r3
2501
        inx                                     ; increment the no. of digits
2502
        bra             TN1
2503
TSNMRET:
2504
        ply
2505
        rts
2506
 
2507
 
2508
;===== Skip over blanks in the text pointed to by r8.
2509
;
2510
; Registers Affected:
2511
;       r8
2512
; Returns
2513
;       r8 = pointer updateded past any spaces or tabs
2514
;
2515
IGNBLK:
2516
        pha
2517
IGB2:
2518
        lda             (r8)                    ; get char
2519
        cmp             #' '
2520
        beq             IGB1    ; see if it's a space
2521
        cmp             #'\t'
2522
        bne             IGBRET  ; or a tab
2523
IGB1:
2524
        inc             r8              ; increment the text pointer
2525
        bra             IGB2
2526
IGBRET:
2527
        pla
2528
        rts
2529
 
2530
; ===== Convert the line of text in the input buffer to upper
2531
;       case (except for stuff between quotes).
2532
;
2533
; Registers Affected
2534
;   r1,r3
2535
; Returns
2536
;       r8 = pointing to end of text in buffer
2537
;
2538
TOUPBUF:
2539
        ld              r8,#BUFFER      ; set up text pointer
2540
        eor             r3,r3,r3        ; clear quote flag
2541
TOUPB1:
2542
        lda             (r8)            ; get the next text char.
2543
        inc             r8
2544
        cmp             #CR
2545
        beq             TOUPBRT         ; is it end of line?
2546
        cmp             #'"'
2547
        beq             DOQUO   ; a double quote?
2548
        cmp             #''''
2549
        beq             DOQUO   ; or a single quote?
2550
        cpy             #0
2551
        bne             TOUPB1  ; inside quotes?
2552
        jsr             toUpper         ; convert to upper case
2553
        sta             -1,r8   ; store it
2554
        bra             TOUPB1          ; and go back for more
2555
DOQUO:
2556
        cpy             #0
2557
        bne             DOQUO1; are we inside quotes?
2558
        tay                             ; if not, toggle inside-quotes flag
2559
        bra             TOUPB1
2560
DOQUO1:
2561
        cmp             r3,r1
2562
        bne             TOUPB1          ; make sure we're ending proper quote
2563
        eor             r3,r3,r3        ; else clear quote flag
2564
        bra             TOUPB1
2565
TOUPBRT:
2566
        rts
2567
 
2568
 
2569
; ===== Convert the character in r1 to upper case
2570
;
2571
toUpper
2572
        cmp             #'a'            ; is it < 'a'?
2573
        bcc             TOUPRET
2574
        cmp             #'z'+1          ; or > 'z'?
2575
        bcs             TOUPRET
2576
        sub             #32     ; if not, make it upper case
2577
TOUPRET
2578
        rts
2579
 
2580
 
2581
; 'CHKIO' checks the input. If there's no input, it will return
2582
; to the caller with the r1=0. If there is input, the input byte is in r1.
2583
; However, if a control-C is read, 'CHKIO' will warm-start BASIC and will
2584
; not return to the caller.
2585
;
2586 26 robfinch
message "CHKIO"
2587 16 robfinch
CHKIO:
2588
        jsr             GOIN            ; get input if possible
2589
        cmp             #0
2590
        beq             CHKRET2         ; if Zero, no input
2591
        cmp             #CTRLC
2592
        bne             CHKRET  ; is it control-C?
2593
        pla                                     ; dump return address
2594
        jmp             WSTART          ; if so, do a warm start
2595
CHKRET2:
2596
        lda             #0
2597
CHKRET:
2598
        rts
2599
 
2600
; ===== Display a CR-LF sequence
2601
;
2602
CRLF:
2603
        lda             #CLMSG
2604
 
2605
 
2606
; ===== Display a zero-ended string pointed to by register r1
2607
; Registers Affected
2608
;   r1,r2,r4
2609
;
2610
PRMESG:
2611
        push    r5
2612
        or      r5,r1,r0    ; r5 = pointer to message
2613
PRMESG1:
2614
        inc             r5
2615
        lb              r1,-1,r5                ;       get the char.
2616
        beq             PRMRET
2617
        jsr             GOOUT           ;else display it trashes r4
2618
        bra             PRMESG1
2619
PRMRET:
2620
        or              r1,r5,r0
2621
        pop             r5
2622
        rts
2623
 
2624
 
2625
; ===== Display a zero-ended string pointed to by register r1
2626
; Registers Affected
2627
;   r1,r2,r3
2628
;
2629
PRMESGAUX:
2630
        phy
2631
        tay                                     ; y = pointer
2632
PRMESGA1:
2633
        iny
2634
        lb              r1,-1,y         ;       get the char.
2635
        beq             PRMRETA
2636
        jsr             GOAUXO          ;else display it
2637
        bra             PRMESGA1
2638
PRMRETA:
2639
        tya
2640
        ply
2641
        rts
2642
 
2643
;*****************************************************
2644
; The following routines are the only ones that need *
2645
; to be changed for a different I/O environment.     *
2646
;*****************************************************
2647
 
2648
 
2649
; ===== Output character to the console (Port 1) from register r1
2650
;       (Preserves all registers.)
2651
;
2652
OUTC:
2653
        jmp             DisplayChar
2654
 
2655
 
2656
; ===== Input a character from the console into register R1 (or
2657
;       return Zero status if there's no character available).
2658
;
2659
INCH:
2660 26 robfinch
;       jsr             KeybdCheckForKeyDirect
2661
;       cmp             #0
2662
;       beq             INCH1
2663
        jsr             KeybdGetChar
2664
        cmp             #-1
2665 16 robfinch
        beq             INCH1
2666 26 robfinch
        rts
2667 16 robfinch
INCH1:
2668 26 robfinch
        ina             ; return a zero for no-char
2669 16 robfinch
        rts
2670
 
2671
;*
2672
;* ===== Input a character from the host into register r1 (or
2673
;*      return Zero status if there's no character available).
2674
;*
2675
AUXIN:
2676
        jsr             SerialGetChar
2677
        cmp             #-1
2678
        beq             AXIRET_ZERO
2679
        and             #$7F                            ;zero out the high bit
2680
AXIRET:
2681
        rts
2682
AXIRET_ZERO:
2683
        lda             #0
2684
        rts
2685
 
2686
; ===== Output character to the host (Port 2) from register r1
2687
;       (Preserves all registers.)
2688
;
2689
AUXOUT
2690
        jmp             SerialPutChar   ; call boot rom routine
2691
 
2692
 
2693
_cls
2694
        jsr             ClearScreen
2695 26 robfinch
        jsr             HomeCursor
2696 16 robfinch
        jmp             FINISH
2697
 
2698
_wait10
2699
        rts
2700
_getATAStatus
2701
        rts
2702
_waitCFNotBusy
2703
        rts
2704
_rdcf
2705
        jmp             FINISH
2706
rdcf6
2707
        bra             ERROR
2708
 
2709
 
2710
; ===== Return to the resident monitor, operating system, etc.
2711
;
2712
BYEBYE:
2713 26 robfinch
        jsr             ReleaseIOFocus
2714 16 robfinch
        ldx             OSSP
2715
        txs
2716
        rts
2717
 
2718
;       MOVE.B  #228,D7         return to Tutor
2719
;       TRAP    #14
2720
 
2721
msgInit db      CR,LF,"RTF65002 Tiny BASIC v1.0",CR,LF,"(C) 2013  Robert Finch",CR,LF,LF,0
2722
OKMSG   db      CR,LF,"OK",CR,LF,0
2723
msgWhat db      "What?",CR,LF,0
2724
SRYMSG  db      "Sorry."
2725
CLMSG   db      CR,LF,0
2726
msgReadError    db      "Compact FLASH read error",CR,LF,0
2727
msgNumTooBig    db      "Number is too big",CR,LF,0
2728
msgDivZero              db      "Division by zero",CR,LF,0
2729
msgVarSpace     db  "Out of variable space",CR,LF,0
2730
msgBytesFree    db      " words free",CR,LF,0
2731
msgReady                db      CR,LF,"Ready",CR,LF,0
2732
msgComma                db      "Expecting a comma",CR,LF,0
2733
msgLineRange    db      "Line number too big",CR,LF,0
2734
msgVar                  db      "Expecting a variable",CR,LF,0
2735
msgRNDBad               db      "RND bad parameter",CR,LF,0
2736
msgSYSBad               db      "SYS bad address",CR,LF,0
2737
msgInputVar             db      "INPUT expecting a variable",CR,LF,0
2738
msgNextFor              db      "NEXT without FOR",CR,LF,0
2739
msgNextVar              db      "NEXT expecting a defined variable",CR,LF,0
2740
msgBadGotoGosub db      "GOTO/GOSUB bad line number",CR,LF,0
2741
msgRetWoGosub   db      "RETURN without GOSUB",CR,LF,0
2742
msgTooBig               db      "Program is too big",CR,LF,0
2743
msgExtraChars   db      "Extra characters on line ignored",CR,LF,0
2744
 
2745
        align   4
2746
LSTROM  equ     *               ; end of possible ROM area
2747
;       END
2748
 
2749
;*
2750
;* ===== Return to the resident monitor, operating system, etc.
2751
;*
2752
;BYEBYE:
2753
;       jmp             Monitor
2754
;    MOVE.B     #228,D7         ;return to Tutor
2755
;       TRAP    #14
2756
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.