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

Subversion Repositories rtf65002

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

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

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

powered by: WebSVN 2.1.0

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