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

Subversion Repositories rtf65002

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

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

powered by: WebSVN 2.1.0

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